citadel
About: Citadel is an advanced messaging and collaboration system for groupware and BBS applications (preferred OS: Linux).
  Fossies Dox: citadel.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

serv_roomchat.c
Go to the documentation of this file.
1/*
2 * This module handles instant messaging between users.
3 *
4 * Copyright (c) 2012 by the citadel.org team
5 *
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.
8 *
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.
13 */
14#include "sysdep.h"
15#include <stdlib.h>
16#include <unistd.h>
17#include <stdio.h>
18#include <fcntl.h>
19#include <signal.h>
20#include <pwd.h>
21#include <errno.h>
22#include <sys/types.h>
23#include <assert.h>
24#include <time.h>
25#include <sys/wait.h>
26#include <string.h>
27#include <limits.h>
28#include <libcitadel.h>
29#include "citadel.h"
30#include "server.h"
31#include "citserver.h"
32#include "support.h"
33#include "config.h"
34#include "msgbase.h"
35#include "user_ops.h"
36#include "ctdl_module.h"
37
38struct chatmsg {
39 struct chatmsg *next;
40 time_t timestamp;
41 int seq;
42 long roomnum;
43 char *sender;
44 char *msgtext;
45};
46
47struct chatmsg *first_chat_msg = NULL;
48struct chatmsg *last_chat_msg = NULL;
49
50
51/*
52 * Periodically called for housekeeping. Expire old chat messages so they don't take up memory forever.
53 */
54void roomchat_timer(void) {
55 struct chatmsg *ptr;
56
58
59 while ((first_chat_msg != NULL) && ((time(NULL) - first_chat_msg->timestamp) > 300)) {
60 ptr = first_chat_msg->next;
64 first_chat_msg = ptr;
65 if (first_chat_msg == NULL) {
66 last_chat_msg = NULL;
67 }
68 }
69
71}
72
73
74/*
75 * Perform shutdown-related activities...
76 */
78 /* if we ever start logging chats, we have to flush them to disk here .*/
79}
80
81
82/*
83 * Add a message into the chat queue
84 */
85void add_to_chat_queue(char *msg) {
86 static int seq = 0;
87
88 struct chatmsg *m = malloc(sizeof(struct chatmsg));
89 if (!m) return;
90
91 m->next = NULL;
92 m->timestamp = time(NULL);
93 m->roomnum = CC->room.QRnumber;
94 m->sender = strdup(CC->user.fullname);
95 m->msgtext = strdup(msg);
96
97 if ((m->sender == NULL) || (m->msgtext == NULL)) {
98 free(m->sender);
99 free(m->msgtext);
100 free(m);
101 return;
102 }
103
105 m->seq = ++seq;
106
107 if (first_chat_msg == NULL) {
108 assert(last_chat_msg == NULL);
109 first_chat_msg = m;
110 last_chat_msg = m;
111 }
112 else {
113 assert(last_chat_msg != NULL);
114 assert(last_chat_msg->next == NULL);
115 last_chat_msg->next = m;
116 last_chat_msg = m;
117 }
118
120}
121
122
123/*
124 * Transmit a message into a room chat
125 */
126void roomchat_send(char *argbuf) {
127 char buf[1024];
128
129 if ((CC->cs_flags & CS_CHAT) == 0) {
130 cprintf("%d Session is not in chat mode.\n", ERROR);
131 return;
132 }
133
134 cprintf("%d send now\n", SEND_LISTING);
135 while (client_getln(buf, sizeof buf) >= 0 && strcmp(buf, "000")) {
137 }
138}
139
140
141/*
142 * Poll room for incoming chat messages
143 */
144void roomchat_poll(char *argbuf) {
145 int newer_than = 0;
146 struct chatmsg *found = NULL;
147 struct chatmsg *ptr = NULL;
148
149 newer_than = extract_int(argbuf, 1);
150
151 if ((CC->cs_flags & CS_CHAT) == 0) {
152 cprintf("%d Session is not in chat mode.\n", ERROR);
153 return;
154 }
155
157 for (ptr = first_chat_msg; ((ptr != NULL) && (found == NULL)); ptr = ptr->next) {
158 if ((ptr->seq > newer_than) && (ptr->roomnum == CC->room.QRnumber)) {
159 found = ptr;
160 }
161 }
163
164 if (found == NULL) {
165 cprintf("%d no messages\n", ERROR + MESSAGE_NOT_FOUND);
166 return;
167 }
168
169 cprintf("%d %d|%ld|%s\n", LISTING_FOLLOWS, found->seq, found->timestamp, found->sender);
170 cprintf("%s\n", found->msgtext);
171 cprintf("000\n");
172}
173
174
175
176/*
177 * list users in chat in this room
178 */
179void roomchat_rwho(char *argbuf) {
180 struct CitContext *nptr;
181 int nContexts, i;
182
183 if ((CC->cs_flags & CS_CHAT) == 0) {
184 cprintf("%d Session is not in chat mode.\n", ERROR);
185 return;
186 }
187
189
190 nptr = CtdlGetContextArray(&nContexts) ; // grab a copy of the wholist
191 if (nptr) {
192 for (i=0; i<nContexts; i++) { // list the users
193 if ( (nptr[i].room.QRnumber == CC->room.QRnumber)
194 && (nptr[i].cs_flags & CS_CHAT)
195 ) {
196 cprintf("%s\n", nptr[i].user.fullname);
197 }
198 }
199 free(nptr); // free our copy
200 }
201
202 cprintf("000\n");
203}
204
205
206
207/*
208 * Participate in real time chat in a room
209 */
210void cmd_rcht(char *argbuf)
211{
212 char subcmd[16];
213
214 if (CtdlAccessCheck(ac_logged_in)) return;
215
216 extract_token(subcmd, argbuf, 0, '|', sizeof subcmd);
217
218 if (!strcasecmp(subcmd, "enter")) {
219 CC->cs_flags |= CS_CHAT;
220 cprintf("%d Entering chat mode.\n", CIT_OK);
221 }
222 else if (!strcasecmp(subcmd, "exit")) {
223 CC->cs_flags &= ~CS_CHAT;
224 cprintf("%d Exiting chat mode.\n", CIT_OK);
225 }
226 else if (!strcasecmp(subcmd, "send")) {
227 roomchat_send(argbuf);
228 }
229 else if (!strcasecmp(subcmd, "poll")) {
230 roomchat_poll(argbuf);
231 }
232 else if (!strcasecmp(subcmd, "rwho")) {
233 roomchat_rwho(argbuf);
234 }
235 else {
236 cprintf("%d Invalid subcommand\n", ERROR + CMD_NOT_SUPPORTED);
237 }
238}
239
240
242{
243 if (!threading)
244 {
245 CtdlRegisterProtoHook(cmd_rcht, "RCHT", "Participate in real time chat in a room");
248 }
249
250 /* return our module name for the log */
251 return "roomchat";
252}
char CtdlCheckExpress(void)
Definition: citserver.c:168
CitContext * CtdlGetContextArray(int *count)
Definition: context.c:445
#define CC
Definition: context.h:140
int CtdlAccessCheck(int)
Definition: user_ops.c:387
#define PRIO_SHUTDOWN
Definition: ctdl_module.h:91
void CtdlRegisterSessionHook(void(*fcn_ptr)(void), int EventType, int Priority)
#define PRIO_CLEANUP
Definition: ctdl_module.h:75
@ ac_logged_in
Definition: ctdl_module.h:244
void CtdlRegisterProtoHook(void(*handler)(char *), char *cmd, char *desc)
#define CTDL_MODULE_INIT(module_name)
Definition: ctdl_module.h:50
#define CIT_OK
Definition: ipcdef.h:6
#define LISTING_FOLLOWS
Definition: ipcdef.h:5
#define CMD_NOT_SUPPORTED
Definition: ipcdef.h:18
#define ERROR
Definition: ipcdef.h:9
#define SEND_LISTING
Definition: ipcdef.h:8
#define MESSAGE_NOT_FOUND
Definition: ipcdef.h:34
void * malloc(size_t)
void free(void *)
void cmd_rcht(char *argbuf)
void add_to_chat_queue(char *msg)
Definition: serv_roomchat.c:85
void roomchat_shutdown(void)
Definition: serv_roomchat.c:77
void roomchat_timer(void)
Definition: serv_roomchat.c:54
void roomchat_rwho(char *argbuf)
struct chatmsg * last_chat_msg
Definition: serv_roomchat.c:48
void roomchat_send(char *argbuf)
struct chatmsg * first_chat_msg
Definition: serv_roomchat.c:47
void roomchat_poll(char *argbuf)
#define EVT_TIMER
Definition: server.h:224
@ S_CHATQUEUE
Definition: server.h:139
#define CS_CHAT
Definition: server.h:111
#define EVT_SHUTDOWN
Definition: server.h:226
struct ctdluser user
Definition: context.h:109
unsigned cs_flags
Definition: context.h:77
struct ctdlroom room
Definition: context.h:110
char * sender
Definition: serv_roomchat.c:43
char * msgtext
Definition: serv_roomchat.c:44
time_t timestamp
Definition: serv_roomchat.c:40
long roomnum
Definition: serv_roomchat.c:42
struct chatmsg * next
Definition: serv_roomchat.c:39
long QRnumber
Definition: citadel.h:119
char fullname[64]
Definition: citadel.h:90
void cprintf(const char *format,...)
Definition: sysdep.c:381
int client_getln(char *buf, int bufsize)
Definition: sysdep.c:548
void begin_critical_section(int which_one)
Definition: threads.c:67
void end_critical_section(int which_one)
Definition: threads.c:85