Now the RWHO command processes the context list in a safe manner.
[citadel.git] / citadel / modules / rwho / serv_rwho.c
1 /*
2  * $Id$
3  *
4  * This module implements server commands related to the display and
5  * manipulation of the "Who's online" list.
6  *
7  */
8
9 #include "sysdep.h"
10 #include <stdlib.h>
11 #include <unistd.h>
12 #include <stdio.h>
13 #include <fcntl.h>
14 #include <signal.h>
15 #include <pwd.h>
16 #include <errno.h>
17 #include <sys/types.h>
18
19 #if TIME_WITH_SYS_TIME
20 # include <sys/time.h>
21 # include <time.h>
22 #else
23 # if HAVE_SYS_TIME_H
24 #  include <sys/time.h>
25 # else
26 #  include <time.h>
27 # endif
28 #endif
29
30 #include <sys/wait.h>
31 #include <string.h>
32 #include <limits.h>
33 #include <libcitadel.h>
34 #include "citadel.h"
35 #include "server.h"
36 #include "citserver.h"
37 #include "support.h"
38 #include "config.h"
39 #include "control.h"
40 #include "room_ops.h"
41 #include "user_ops.h"
42 #include "policy.h"
43 #include "database.h"
44 #include "msgbase.h"
45
46
47 #include "ctdl_module.h"
48
49
50 /*
51  * display who's online
52  */
53 void cmd_rwho(char *argbuf) {
54         struct CitContext *cptr;
55         struct CitContext *nptr;
56         int nContexts, i;
57         int spoofed = 0;
58         int user_spoofed = 0;
59         int room_spoofed = 0;
60         int host_spoofed = 0;
61         int aide;
62         char un[40];
63         char real_room[ROOMNAMELEN], room[ROOMNAMELEN];
64         char host[64], flags[5];
65         
66         /* So that we don't keep the context list locked for a long time
67          * we create a copy of it first
68          */
69         
70
71         nContexts = num_sessions;
72         nptr = malloc(sizeof(struct CitContext) * nContexts);
73         if (!nptr)
74         {
75                 /* Couldn't malloc so we have to bail but stick to the protocol */
76                 cprintf("%d%c \n", LISTING_FOLLOWS, CtdlCheckExpress() );
77                 cprintf("000\n");
78                 return;
79         }
80         begin_critical_section(S_SESSION_TABLE);
81         for (cptr = ContextList, i=0; cptr != NULL && i < nContexts; cptr = cptr->next, i++)
82         {
83                 memcpy(&nptr[i], cptr, sizeof (struct CitContext));
84         }
85         end_critical_section (S_SESSION_TABLE);
86         
87         aide = CC->user.axlevel >= 6;
88         cprintf("%d%c \n", LISTING_FOLLOWS, CtdlCheckExpress() );
89         
90         for (i=0; i<nContexts; i++) 
91         {
92                 flags[0] = '\0';
93                 spoofed = 0;
94                 user_spoofed = 0;
95                 room_spoofed = 0;
96                 host_spoofed = 0;
97                 
98                 if (nptr[i].cs_flags & CS_POSTING)
99                    strcat(flags, "*");
100                 else
101                    strcat(flags, ".");
102                    
103                 if (nptr[i].fake_username[0])
104                 {
105                    strcpy(un, nptr[i].fake_username);
106                    spoofed = 1;
107                    user_spoofed = 1;
108                 }
109                 else
110                    strcpy(un, nptr[i].curr_user);
111                    
112                 if (nptr[i].fake_hostname[0])
113                 {
114                    strcpy(host, nptr[i].fake_hostname);
115                    spoofed = 1;
116                    host_spoofed = 1;
117                 }
118                 else
119                    strcpy(host, nptr[i].cs_host);
120
121                 GenerateRoomDisplay(real_room, &nptr[i], CC);
122
123                 if (nptr[i].fake_roomname[0]) {
124                         strcpy(room, nptr[i].fake_roomname);
125                         spoofed = 1;
126                         room_spoofed = 1;
127                 }
128                 else {
129                         strcpy(room, real_room);
130                 }
131                 
132                 if ((aide) && (spoofed)) {
133                         strcat(flags, "+");
134                 }
135                 
136                 if ((nptr[i].cs_flags & CS_STEALTH) && (aide)) {
137                         strcat(flags, "-");
138                 }
139                 
140                 if (((nptr[i].cs_flags&CS_STEALTH)==0) || (aide))
141                 {
142                         cprintf("%d|%s|%s|%s|%s|%ld|%s|%s|",
143                                 nptr[i].cs_pid, un, room,
144                                 host, nptr[i].cs_clientname,
145                                 (long)(nptr[i].lastidle),
146                                 nptr[i].lastcmdname, flags
147                         );
148
149                         if ((user_spoofed) && (aide)) {
150                                 cprintf("%s|", nptr[i].curr_user);
151                         }
152                         else {
153                                 cprintf("|");
154                         }
155         
156                         if ((room_spoofed) && (aide)) {
157                                 cprintf("%s|", real_room);
158                         }
159                         else {
160                                 cprintf("|");
161                         }
162         
163                         if ((host_spoofed) && (aide)) {
164                                 cprintf("%s|", nptr[i].cs_host);
165                         }
166                         else {
167                                 cprintf("|");
168                         }
169         
170                         cprintf("%d\n", nptr[i].logged_in);
171                 }
172         }
173         
174         /* release out copy of the context list */
175         free(nptr);
176
177         /* Now it's magic time.  Before we finish, call any EVT_RWHO hooks
178          * so that external paging modules such as serv_icq can add more
179          * content to the Wholist.
180          */
181         PerformSessionHooks(EVT_RWHO);
182         cprintf("000\n");
183 }
184
185
186 /*
187  * Masquerade roomname
188  */
189 void cmd_rchg(char *argbuf)
190 {
191         char newroomname[ROOMNAMELEN];
192
193         extract_token(newroomname, argbuf, 0, '|', sizeof newroomname);
194         newroomname[ROOMNAMELEN-1] = 0;
195         if (!IsEmptyStr(newroomname)) {
196                 safestrncpy(CC->fake_roomname, newroomname,
197                         sizeof(CC->fake_roomname) );
198         }
199         else {
200                 safestrncpy(CC->fake_roomname, "", sizeof CC->fake_roomname);
201         }
202         cprintf("%d OK\n", CIT_OK);
203 }
204
205 /*
206  * Masquerade hostname 
207  */
208 void cmd_hchg(char *argbuf)
209 {
210         char newhostname[64];
211
212         extract_token(newhostname, argbuf, 0, '|', sizeof newhostname);
213         if (!IsEmptyStr(newhostname)) {
214                 safestrncpy(CC->fake_hostname, newhostname,
215                         sizeof(CC->fake_hostname) );
216         }
217         else {
218                 safestrncpy(CC->fake_hostname, "", sizeof CC->fake_hostname);
219         }
220         cprintf("%d OK\n", CIT_OK);
221 }
222
223
224 /*
225  * Masquerade username (aides only)
226  */
227 void cmd_uchg(char *argbuf)
228 {
229
230         char newusername[USERNAME_SIZE];
231
232         extract_token(newusername, argbuf, 0, '|', sizeof newusername);
233
234         if (CtdlAccessCheck(ac_aide)) return;
235
236         if (!IsEmptyStr(newusername)) {
237                 CC->cs_flags &= ~CS_STEALTH;
238                 memset(CC->fake_username, 0, 32);
239                 if (strncasecmp(newusername, CC->curr_user,
240                                 strlen(CC->curr_user)))
241                         safestrncpy(CC->fake_username, newusername,
242                                 sizeof(CC->fake_username));
243         }
244         else {
245                 CC->fake_username[0] = '\0';
246                 CC->cs_flags |= CS_STEALTH;
247         }
248         cprintf("%d\n",CIT_OK);
249 }
250
251
252
253
254 /*
255  * enter or exit "stealth mode"
256  */
257 void cmd_stel(char *cmdbuf)
258 {
259         int requested_mode;
260
261         requested_mode = extract_int(cmdbuf,0);
262
263         if (CtdlAccessCheck(ac_logged_in)) return;
264
265         if (requested_mode == 1) {
266                 CC->cs_flags = CC->cs_flags | CS_STEALTH;
267                 PerformSessionHooks(EVT_STEALTH);
268         }
269         if (requested_mode == 0) {
270                 CC->cs_flags = CC->cs_flags & ~CS_STEALTH;
271                 PerformSessionHooks(EVT_UNSTEALTH);
272         }
273
274         cprintf("%d %d\n", CIT_OK,
275                 ((CC->cs_flags & CS_STEALTH) ? 1 : 0) );
276 }
277
278
279 CTDL_MODULE_INIT(rwho)
280 {
281         if(!threading)
282         {
283                 CtdlRegisterProtoHook(cmd_rwho, "RWHO", "Display who is online");
284                 CtdlRegisterProtoHook(cmd_hchg, "HCHG", "Masquerade hostname");
285                 CtdlRegisterProtoHook(cmd_rchg, "RCHG", "Masquerade roomname");
286                 CtdlRegisterProtoHook(cmd_uchg, "UCHG", "Masquerade username");
287                 CtdlRegisterProtoHook(cmd_stel, "STEL", "Enter/exit stealth mode");
288         }
289         
290         /* return our Subversion id for the Log */
291         return "$Id$";
292 }