2 * This module implements server commands related to the display and
3 * manipulation of the "Who's online" list.
5 * Copyright (c) 1987-2012 by the citadel.org team
7 * This program is open source software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 3.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
25 #include <sys/types.h>
27 #if TIME_WITH_SYS_TIME
28 # include <sys/time.h>
32 # include <sys/time.h>
41 #include <libcitadel.h>
44 #include "citserver.h"
53 #include "ctdl_module.h"
55 /* Don't show the names of private rooms unless the viewing
56 * user also knows the rooms.
58 void GenerateRoomDisplay(char *real_room,
64 strcpy(real_room, viewed->room.QRname);
65 if (viewed->room.QRflags & QR_MAILBOX) {
66 strcpy(real_room, &real_room[11]);
68 if (viewed->room.QRflags & QR_PRIVATE) {
69 CtdlRoomAccess(&viewed->room, &viewer->user, &ra, NULL);
70 if ( (ra & UA_KNOWN) == 0) {
71 strcpy(real_room, " ");
75 if (viewed->cs_flags & CS_CHAT) {
76 while (strlen(real_room) < 14) {
77 strcat(real_room, " ");
79 strcpy(&real_room[14], "<chat>");
87 * display who's online
89 void cmd_rwho(char *argbuf) {
90 struct CitContext *nptr;
98 char real_room[ROOMNAMELEN], room[ROOMNAMELEN];
99 char host[64], flags[5];
101 /* So that we don't keep the context list locked for a long time
102 * we create a copy of it first
104 nptr = CtdlGetContextArray(&nContexts) ;
107 /* Couldn't malloc so we have to bail but stick to the protocol */
108 cprintf("%d%c \n", LISTING_FOLLOWS, CtdlCheckExpress() );
113 aide = ( (CC->user.axlevel >= AxAideU) || (CC->internal_pgm) ) ;
114 cprintf("%d%c \n", LISTING_FOLLOWS, CtdlCheckExpress() );
116 for (i=0; i<nContexts; i++)
124 if (!aide && nptr[i].state == CON_SYS)
127 if (!aide && nptr[i].kill_me != 0)
130 if (nptr[i].cs_flags & CS_POSTING)
135 if (nptr[i].fake_username[0])
137 strcpy(un, nptr[i].fake_username);
142 strcpy(un, nptr[i].curr_user);
144 if (nptr[i].fake_hostname[0])
146 strcpy(host, nptr[i].fake_hostname);
151 strcpy(host, nptr[i].cs_host);
153 GenerateRoomDisplay(real_room, &nptr[i], CC);
155 if (nptr[i].fake_roomname[0]) {
156 strcpy(room, nptr[i].fake_roomname);
161 strcpy(room, real_room);
164 if ((aide) && (spoofed)) {
168 if ((nptr[i].cs_flags & CS_STEALTH) && (aide)) {
172 if (((nptr[i].cs_flags&CS_STEALTH)==0) || (aide))
174 cprintf("%d|%s|%s|%s|%s|%ld|%s|%s|",
175 nptr[i].cs_pid, un, room,
176 host, nptr[i].cs_clientname,
177 (long)(nptr[i].lastidle),
178 nptr[i].lastcmdname, flags
181 if ((user_spoofed) && (aide)) {
182 cprintf("%s|", nptr[i].curr_user);
188 if ((room_spoofed) && (aide)) {
189 cprintf("%s|", real_room);
195 if ((host_spoofed) && (aide)) {
196 cprintf("%s|", nptr[i].cs_host);
202 cprintf("%d\n", nptr[i].logged_in);
206 /* release out copy of the context list */
209 /* Now it's magic time. Before we finish, call any EVT_RWHO hooks
210 * so that external paging modules such as serv_icq can add more
211 * content to the Wholist.
213 PerformSessionHooks(EVT_RWHO);
219 * check for async io jobs that are stuck (didn't ping back for 10 mins)
221 void dead_io_check(void) {
222 struct CitContext *nptr;
224 char real_room[ROOMNAMELEN];
226 /* So that we don't keep the context list locked for a long time
227 * we create a copy of it first
229 nptr = CtdlGetContextArray(&nContexts) ;
232 /* Couldn't malloc so we have to bail but stick to the protocol */
236 time_t now = time(NULL);
239 for (i=0; i<nContexts; i++)
241 if ((nptr[i].state != CON_SYS) || (nptr[i].IO == NULL) || (nptr[i].lastcmd == 0))
244 if (nptr[i].kill_me != 0)
246 idle = now - nptr[i].lastcmd;
250 GenerateRoomDisplay(real_room, &nptr[i], CC);
253 "Found stuck event context: CC[%d] "
257 "while talking to host: '%s' "
259 "stuck in IO State: '%s' "
262 "Triggering context termination now!",
269 nptr[i].cs_clientname,
275 CtdlTerminateOtherSession(nptr[i].cs_pid);
278 /* release out copy of the context list */
284 * Masquerade roomname
286 void cmd_rchg(char *argbuf)
288 char newroomname[ROOMNAMELEN];
290 extract_token(newroomname, argbuf, 0, '|', sizeof newroomname);
291 newroomname[ROOMNAMELEN-1] = 0;
292 if (!IsEmptyStr(newroomname)) {
293 safestrncpy(CC->fake_roomname, newroomname,
294 sizeof(CC->fake_roomname) );
297 safestrncpy(CC->fake_roomname, "", sizeof CC->fake_roomname);
299 cprintf("%d OK\n", CIT_OK);
303 * Masquerade hostname
305 void cmd_hchg(char *argbuf)
307 char newhostname[64];
309 extract_token(newhostname, argbuf, 0, '|', sizeof newhostname);
310 if (!IsEmptyStr(newhostname)) {
311 safestrncpy(CC->fake_hostname, newhostname,
312 sizeof(CC->fake_hostname) );
315 safestrncpy(CC->fake_hostname, "", sizeof CC->fake_hostname);
317 cprintf("%d OK\n", CIT_OK);
322 * Masquerade username (aides only)
324 void cmd_uchg(char *argbuf)
327 char newusername[USERNAME_SIZE];
329 extract_token(newusername, argbuf, 0, '|', sizeof newusername);
331 if (CtdlAccessCheck(ac_aide)) return;
333 if (!IsEmptyStr(newusername)) {
334 CC->cs_flags &= ~CS_STEALTH;
335 memset(CC->fake_username, 0, 32);
336 if (strncasecmp(newusername, CC->curr_user,
337 strlen(CC->curr_user)))
338 safestrncpy(CC->fake_username, newusername,
339 sizeof(CC->fake_username));
342 CC->fake_username[0] = '\0';
343 CC->cs_flags |= CS_STEALTH;
345 cprintf("%d\n",CIT_OK);
352 * enter or exit "stealth mode"
354 void cmd_stel(char *cmdbuf)
358 requested_mode = extract_int(cmdbuf,0);
360 if (CtdlAccessCheck(ac_logged_in)) return;
362 if (requested_mode == 1) {
363 CC->cs_flags = CC->cs_flags | CS_STEALTH;
364 PerformSessionHooks(EVT_STEALTH);
366 if (requested_mode == 0) {
367 CC->cs_flags = CC->cs_flags & ~CS_STEALTH;
368 PerformSessionHooks(EVT_UNSTEALTH);
371 cprintf("%d %d\n", CIT_OK,
372 ((CC->cs_flags & CS_STEALTH) ? 1 : 0) );
376 CTDL_MODULE_INIT(rwho)
380 CtdlRegisterProtoHook(cmd_rwho, "RWHO", "Display who is online");
381 CtdlRegisterProtoHook(cmd_hchg, "HCHG", "Masquerade hostname");
382 CtdlRegisterProtoHook(cmd_rchg, "RCHG", "Masquerade roomname");
383 CtdlRegisterProtoHook(cmd_uchg, "UCHG", "Masquerade username");
384 CtdlRegisterProtoHook(cmd_stel, "STEL", "Enter/exit stealth mode");
385 //CtdlRegisterSessionHook(dead_io_check, EVT_TIMER, PRIO_QUEUE + 50);
389 /* return our module name for the log */