8967aca3610d2b50c01547aae540838dccdc658e
[citadel.git] / citadel / modules / rwho / serv_rwho.c
1 /*
2  * This module implements server commands related to the display and
3  * manipulation of the "Who's online" list.
4  *
5  * Copyright (c) 1987-2012 by the citadel.org team
6  *
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.
9  *
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.
14  *
15  */
16
17 #include "sysdep.h"
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <stdio.h>
21 #include <fcntl.h>
22 #include <signal.h>
23 #include <pwd.h>
24 #include <errno.h>
25 #include <sys/types.h>
26
27 #if TIME_WITH_SYS_TIME
28 # include <sys/time.h>
29 # include <time.h>
30 #else
31 # if HAVE_SYS_TIME_H
32 #  include <sys/time.h>
33 # else
34 #  include <time.h>
35 # endif
36 #endif
37
38 #include <sys/wait.h>
39 #include <string.h>
40 #include <limits.h>
41 #include <libcitadel.h>
42 #include "citadel.h"
43 #include "server.h"
44 #include "citserver.h"
45 #include "support.h"
46 #include "config.h"
47 #include "control.h"
48 #include "user_ops.h"
49 #include "database.h"
50 #include "msgbase.h"
51
52
53 #include "ctdl_module.h"
54
55 /* Don't show the names of private rooms unless the viewing
56  * user also knows the rooms.
57  */
58 void GenerateRoomDisplay(char *real_room,
59                         CitContext *viewed,
60                         CitContext *viewer) {
61
62         int ra;
63
64         strcpy(real_room, viewed->room.QRname);
65         if (viewed->room.QRflags & QR_MAILBOX) {
66                 strcpy(real_room, &real_room[11]);
67         }
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, " ");
72                 }
73         }
74
75         if (viewed->cs_flags & CS_CHAT) {
76                 while (strlen(real_room) < 14) {
77                         strcat(real_room, " ");
78                 }
79                 strcpy(&real_room[14], "<chat>");
80         }
81
82 }
83
84
85
86 /*
87  * display who's online
88  */
89 void cmd_rwho(char *argbuf) {
90         struct CitContext *nptr;
91         int nContexts, i;
92         int spoofed = 0;
93         int user_spoofed = 0;
94         int room_spoofed = 0;
95         int host_spoofed = 0;
96         int aide;
97         char un[40];
98         char real_room[ROOMNAMELEN], room[ROOMNAMELEN];
99         char host[64], flags[5];
100         
101         /* So that we don't keep the context list locked for a long time
102          * we create a copy of it first
103          */
104         nptr = CtdlGetContextArray(&nContexts) ;
105         if (!nptr)
106         {
107                 /* Couldn't malloc so we have to bail but stick to the protocol */
108                 cprintf("%d%c \n", LISTING_FOLLOWS, CtdlCheckExpress() );
109                 cprintf("000\n");
110                 return;
111         }
112         
113         aide = ( (CC->user.axlevel >= AxAideU) || (CC->internal_pgm) ) ;
114         cprintf("%d%c \n", LISTING_FOLLOWS, CtdlCheckExpress() );
115         
116         for (i=0; i<nContexts; i++) 
117         {
118                 flags[0] = '\0';
119                 spoofed = 0;
120                 user_spoofed = 0;
121                 room_spoofed = 0;
122                 host_spoofed = 0;
123                 
124                 if (!aide && nptr[i].state == CON_SYS)
125                         continue;
126
127                 if (!aide && nptr[i].kill_me != 0)
128                         continue;
129
130                 if (nptr[i].cs_flags & CS_POSTING)
131                    strcat(flags, "*");
132                 else
133                    strcat(flags, ".");
134                    
135                 if (nptr[i].fake_username[0])
136                 {
137                    strcpy(un, nptr[i].fake_username);
138                    spoofed = 1;
139                    user_spoofed = 1;
140                 }
141                 else
142                    strcpy(un, nptr[i].curr_user);
143                    
144                 if (nptr[i].fake_hostname[0])
145                 {
146                    strcpy(host, nptr[i].fake_hostname);
147                    spoofed = 1;
148                    host_spoofed = 1;
149                 }
150                 else
151                    strcpy(host, nptr[i].cs_host);
152
153                 GenerateRoomDisplay(real_room, &nptr[i], CC);
154
155                 if (nptr[i].fake_roomname[0]) {
156                         strcpy(room, nptr[i].fake_roomname);
157                         spoofed = 1;
158                         room_spoofed = 1;
159                 }
160                 else {
161                         strcpy(room, real_room);
162                 }
163                 
164                 if ((aide) && (spoofed)) {
165                         strcat(flags, "+");
166                 }
167                 
168                 if ((nptr[i].cs_flags & CS_STEALTH) && (aide)) {
169                         strcat(flags, "-");
170                 }
171                 
172                 if (((nptr[i].cs_flags&CS_STEALTH)==0) || (aide))
173                 {
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
179                         );
180
181                         if ((user_spoofed) && (aide)) {
182                                 cprintf("%s|", nptr[i].curr_user);
183                         }
184                         else {
185                                 cprintf("|");
186                         }
187         
188                         if ((room_spoofed) && (aide)) {
189                                 cprintf("%s|", real_room);
190                         }
191                         else {
192                                 cprintf("|");
193                         }
194         
195                         if ((host_spoofed) && (aide)) {
196                                 cprintf("%s|", nptr[i].cs_host);
197                         }
198                         else {
199                                 cprintf("|");
200                         }
201         
202                         cprintf("%d\n", nptr[i].logged_in);
203                 }
204         }
205         
206         /* release out copy of the context list */
207         free(nptr);
208
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.
212          */
213         PerformSessionHooks(EVT_RWHO);
214         cprintf("000\n");
215 }
216
217 #if 0
218 /*
219  * check for async io jobs that are stuck (didn't ping back for 10 mins)
220  */
221 void dead_io_check(void) {
222         struct CitContext *nptr;
223         int nContexts, i;
224         char real_room[ROOMNAMELEN];
225         
226         /* So that we don't keep the context list locked for a long time
227          * we create a copy of it first
228          */
229         nptr = CtdlGetContextArray(&nContexts) ;
230         if (!nptr)
231         {
232                 /* Couldn't malloc so we have to bail but stick to the protocol */
233                 return;
234         }
235
236         time_t now = time(NULL);
237         time_t idle;
238
239         for (i=0; i<nContexts; i++) 
240         {
241                 if ((nptr[i].state != CON_SYS) || (nptr[i].IO == NULL) || (nptr[i].lastcmd == 0))
242                         continue;
243
244                 if (nptr[i].kill_me != 0)
245                         continue;
246                 idle = now - nptr[i].lastcmd;
247                 if (idle < 600) 
248                         continue;
249
250                 GenerateRoomDisplay(real_room, &nptr[i], CC);
251
252                 syslog(LOG_WARNING,
253                        "Found stuck event context: CC[%d] "
254
255                        "Username: '%s' "
256                        "Room: '%s' "
257                        "while talking to host: '%s' "
258                        "Status: '%s' "
259                        "stuck in IO State: '%s' "
260
261                        "idle since: %d:%d "
262                        "Triggering context termination now!",
263
264                        nptr[i].cs_pid,
265
266                        nptr[i].curr_user,
267                        real_room,
268                        nptr[i].cs_host,
269                        nptr[i].cs_clientname,
270                        nptr[i].lastcmdname,
271
272                        (int) idle / 60,
273                        (int) idle % 60);
274
275                 CtdlTerminateOtherSession(nptr[i].cs_pid);
276         }
277         
278         /* release out copy of the context list */
279         free(nptr);
280 }
281 #endif
282
283 /*
284  * Masquerade roomname
285  */
286 void cmd_rchg(char *argbuf)
287 {
288         char newroomname[ROOMNAMELEN];
289
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) );
295         }
296         else {
297                 safestrncpy(CC->fake_roomname, "", sizeof CC->fake_roomname);
298         }
299         cprintf("%d OK\n", CIT_OK);
300 }
301
302 /*
303  * Masquerade hostname 
304  */
305 void cmd_hchg(char *argbuf)
306 {
307         char newhostname[64];
308
309         extract_token(newhostname, argbuf, 0, '|', sizeof newhostname);
310         if (!IsEmptyStr(newhostname)) {
311                 safestrncpy(CC->fake_hostname, newhostname,
312                         sizeof(CC->fake_hostname) );
313         }
314         else {
315                 safestrncpy(CC->fake_hostname, "", sizeof CC->fake_hostname);
316         }
317         cprintf("%d OK\n", CIT_OK);
318 }
319
320
321 /*
322  * Masquerade username (aides only)
323  */
324 void cmd_uchg(char *argbuf)
325 {
326
327         char newusername[USERNAME_SIZE];
328
329         extract_token(newusername, argbuf, 0, '|', sizeof newusername);
330
331         if (CtdlAccessCheck(ac_aide)) return;
332
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));
340         }
341         else {
342                 CC->fake_username[0] = '\0';
343                 CC->cs_flags |= CS_STEALTH;
344         }
345         cprintf("%d\n",CIT_OK);
346 }
347
348
349
350
351 /*
352  * enter or exit "stealth mode"
353  */
354 void cmd_stel(char *cmdbuf)
355 {
356         int requested_mode;
357
358         requested_mode = extract_int(cmdbuf,0);
359
360         if (CtdlAccessCheck(ac_logged_in)) return;
361
362         if (requested_mode == 1) {
363                 CC->cs_flags = CC->cs_flags | CS_STEALTH;
364                 PerformSessionHooks(EVT_STEALTH);
365         }
366         if (requested_mode == 0) {
367                 CC->cs_flags = CC->cs_flags & ~CS_STEALTH;
368                 PerformSessionHooks(EVT_UNSTEALTH);
369         }
370
371         cprintf("%d %d\n", CIT_OK,
372                 ((CC->cs_flags & CS_STEALTH) ? 1 : 0) );
373 }
374
375
376 CTDL_MODULE_INIT(rwho)
377 {
378         if(!threading)
379         {
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);
386
387         }
388         
389         /* return our module name for the log */
390         return "rwho";
391 }