Merge branch 'master' of ssh://git.citadel.org/appl/gitroot/citadel
[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
56 /*
57  * display who's online
58  */
59 void cmd_rwho(char *argbuf) {
60         struct CitContext *nptr;
61         int nContexts, i;
62         int spoofed = 0;
63         int user_spoofed = 0;
64         int room_spoofed = 0;
65         int host_spoofed = 0;
66         int aide;
67         char un[40];
68         char real_room[ROOMNAMELEN], room[ROOMNAMELEN];
69         char host[64], flags[5];
70         
71         /* So that we don't keep the context list locked for a long time
72          * we create a copy of it first
73          */
74         nptr = CtdlGetContextArray(&nContexts) ;
75         if (!nptr)
76         {
77                 /* Couldn't malloc so we have to bail but stick to the protocol */
78                 cprintf("%d%c \n", LISTING_FOLLOWS, CtdlCheckExpress() );
79                 cprintf("000\n");
80                 return;
81         }
82         
83         aide = ( (CC->user.axlevel >= AxAideU) || (CC->internal_pgm) ) ;
84         cprintf("%d%c \n", LISTING_FOLLOWS, CtdlCheckExpress() );
85         
86         for (i=0; i<nContexts; i++) 
87         {
88                 flags[0] = '\0';
89                 spoofed = 0;
90                 user_spoofed = 0;
91                 room_spoofed = 0;
92                 host_spoofed = 0;
93                 
94                 if (!aide && nptr[i].state == CON_SYS)
95                         continue;
96
97                 if (!aide && nptr[i].kill_me != 0)
98                         continue;
99
100                 if (nptr[i].cs_flags & CS_POSTING)
101                    strcat(flags, "*");
102                 else
103                    strcat(flags, ".");
104                    
105                 if (nptr[i].fake_username[0])
106                 {
107                    strcpy(un, nptr[i].fake_username);
108                    spoofed = 1;
109                    user_spoofed = 1;
110                 }
111                 else
112                    strcpy(un, nptr[i].curr_user);
113                    
114                 if (nptr[i].fake_hostname[0])
115                 {
116                    strcpy(host, nptr[i].fake_hostname);
117                    spoofed = 1;
118                    host_spoofed = 1;
119                 }
120                 else
121                    strcpy(host, nptr[i].cs_host);
122
123                 GenerateRoomDisplay(real_room, &nptr[i], CC);
124
125                 if (nptr[i].fake_roomname[0]) {
126                         strcpy(room, nptr[i].fake_roomname);
127                         spoofed = 1;
128                         room_spoofed = 1;
129                 }
130                 else {
131                         strcpy(room, real_room);
132                 }
133                 
134                 if ((aide) && (spoofed)) {
135                         strcat(flags, "+");
136                 }
137                 
138                 if ((nptr[i].cs_flags & CS_STEALTH) && (aide)) {
139                         strcat(flags, "-");
140                 }
141                 
142                 if (((nptr[i].cs_flags&CS_STEALTH)==0) || (aide))
143                 {
144                         cprintf("%d|%s|%s|%s|%s|%ld|%s|%s|",
145                                 nptr[i].cs_pid, un, room,
146                                 host, nptr[i].cs_clientname,
147                                 (long)(nptr[i].lastidle),
148                                 nptr[i].lastcmdname, flags
149                         );
150
151                         if ((user_spoofed) && (aide)) {
152                                 cprintf("%s|", nptr[i].curr_user);
153                         }
154                         else {
155                                 cprintf("|");
156                         }
157         
158                         if ((room_spoofed) && (aide)) {
159                                 cprintf("%s|", real_room);
160                         }
161                         else {
162                                 cprintf("|");
163                         }
164         
165                         if ((host_spoofed) && (aide)) {
166                                 cprintf("%s|", nptr[i].cs_host);
167                         }
168                         else {
169                                 cprintf("|");
170                         }
171         
172                         cprintf("%d\n", nptr[i].logged_in);
173                 }
174         }
175         
176         /* release out copy of the context list */
177         free(nptr);
178
179         /* Now it's magic time.  Before we finish, call any EVT_RWHO hooks
180          * so that external paging modules such as serv_icq can add more
181          * content to the Wholist.
182          */
183         PerformSessionHooks(EVT_RWHO);
184         cprintf("000\n");
185 }
186
187
188 /*
189  * Masquerade roomname
190  */
191 void cmd_rchg(char *argbuf)
192 {
193         char newroomname[ROOMNAMELEN];
194
195         extract_token(newroomname, argbuf, 0, '|', sizeof newroomname);
196         newroomname[ROOMNAMELEN-1] = 0;
197         if (!IsEmptyStr(newroomname)) {
198                 safestrncpy(CC->fake_roomname, newroomname,
199                         sizeof(CC->fake_roomname) );
200         }
201         else {
202                 safestrncpy(CC->fake_roomname, "", sizeof CC->fake_roomname);
203         }
204         cprintf("%d OK\n", CIT_OK);
205 }
206
207 /*
208  * Masquerade hostname 
209  */
210 void cmd_hchg(char *argbuf)
211 {
212         char newhostname[64];
213
214         extract_token(newhostname, argbuf, 0, '|', sizeof newhostname);
215         if (!IsEmptyStr(newhostname)) {
216                 safestrncpy(CC->fake_hostname, newhostname,
217                         sizeof(CC->fake_hostname) );
218         }
219         else {
220                 safestrncpy(CC->fake_hostname, "", sizeof CC->fake_hostname);
221         }
222         cprintf("%d OK\n", CIT_OK);
223 }
224
225
226 /*
227  * Masquerade username (aides only)
228  */
229 void cmd_uchg(char *argbuf)
230 {
231
232         char newusername[USERNAME_SIZE];
233
234         extract_token(newusername, argbuf, 0, '|', sizeof newusername);
235
236         if (CtdlAccessCheck(ac_aide)) return;
237
238         if (!IsEmptyStr(newusername)) {
239                 CC->cs_flags &= ~CS_STEALTH;
240                 memset(CC->fake_username, 0, 32);
241                 if (strncasecmp(newusername, CC->curr_user,
242                                 strlen(CC->curr_user)))
243                         safestrncpy(CC->fake_username, newusername,
244                                 sizeof(CC->fake_username));
245         }
246         else {
247                 CC->fake_username[0] = '\0';
248                 CC->cs_flags |= CS_STEALTH;
249         }
250         cprintf("%d\n",CIT_OK);
251 }
252
253
254
255
256 /*
257  * enter or exit "stealth mode"
258  */
259 void cmd_stel(char *cmdbuf)
260 {
261         int requested_mode;
262
263         requested_mode = extract_int(cmdbuf,0);
264
265         if (CtdlAccessCheck(ac_logged_in)) return;
266
267         if (requested_mode == 1) {
268                 CC->cs_flags = CC->cs_flags | CS_STEALTH;
269                 PerformSessionHooks(EVT_STEALTH);
270         }
271         if (requested_mode == 0) {
272                 CC->cs_flags = CC->cs_flags & ~CS_STEALTH;
273                 PerformSessionHooks(EVT_UNSTEALTH);
274         }
275
276         cprintf("%d %d\n", CIT_OK,
277                 ((CC->cs_flags & CS_STEALTH) ? 1 : 0) );
278 }
279
280
281 CTDL_MODULE_INIT(rwho)
282 {
283         if(!threading)
284         {
285                 CtdlRegisterProtoHook(cmd_rwho, "RWHO", "Display who is online");
286                 CtdlRegisterProtoHook(cmd_hchg, "HCHG", "Masquerade hostname");
287                 CtdlRegisterProtoHook(cmd_rchg, "RCHG", "Masquerade roomname");
288                 CtdlRegisterProtoHook(cmd_uchg, "UCHG", "Masquerade username");
289                 CtdlRegisterProtoHook(cmd_stel, "STEL", "Enter/exit stealth mode");
290         }
291         
292         /* return our module name for the log */
293         return "rwho";
294 }