ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/modules/m_who.c
Revision: 3270
Committed: Sat Apr 5 22:41:19 2014 UTC (11 years, 4 months ago) by michael
Content type: text/x-csrc
File size: 9939 byte(s)
Log Message:
- m_who.c:m_who(): admins may now see all channel members via "WHO #channel"
  regardless of channel mode +s

File Contents

# User Rev Content
1 adx 30 /*
2 michael 2820 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 adx 30 *
4 michael 2820 * Copyright (c) 1997-2014 ircd-hybrid development team
5 adx 30 *
6     * This program is free software; you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation; either version 2 of the License, or
9     * (at your option) any later version.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19     * USA
20     */
21 michael 1011
22 michael 2820 /*! \file m_who.c
23     * \brief Includes required functions for processing the WHO command.
24     * \version $Id$
25     */
26    
27 adx 30 #include "stdinc.h"
28 michael 1011 #include "list.h"
29 adx 30 #include "client.h"
30     #include "channel.h"
31     #include "channel_mode.h"
32     #include "hash.h"
33     #include "ircd.h"
34     #include "numeric.h"
35     #include "s_serv.h"
36     #include "send.h"
37     #include "irc_string.h"
38 michael 1309 #include "conf.h"
39 adx 30 #include "parse.h"
40     #include "modules.h"
41    
42    
43 michael 2088 /* do_who()
44     *
45     * inputs - pointer to client requesting who
46     * - pointer to client to do who on
47     * - The reported name
48     * - channel flags
49     * output - NONE
50     * side effects - do a who on given person
51     */
52 adx 30 static void
53 michael 2088 do_who(struct Client *source_p, struct Client *target_p,
54     const char *chname, const char *op_flags)
55 adx 30 {
56 michael 3246 char status[IRCD_BUFSIZE] = "";
57 adx 30
58 michael 2088 if (HasUMode(source_p, UMODE_OPER))
59 michael 2549 snprintf(status, sizeof(status), "%c%s%s%s", target_p->away[0] ? 'G' : 'H',
60     HasUMode(target_p, UMODE_REGISTERED) ? "r" : "",
61 michael 2088 HasUMode(target_p, UMODE_OPER) ? "*" : "", op_flags);
62     else
63 michael 2549 snprintf(status, sizeof(status), "%c%s%s%s", target_p->away[0] ? 'G' : 'H',
64     HasUMode(target_p, UMODE_REGISTERED) ? "r" : "",
65 michael 2088 HasUMode(target_p, UMODE_OPER) &&
66     !HasUMode(target_p, UMODE_HIDDEN) ? "*" : "", op_flags);
67 adx 30
68 michael 2748 if (ConfigServerHide.hide_servers || IsHidden(target_p->servptr))
69 michael 3109 sendto_one_numeric(source_p, &me, RPL_WHOREPLY,
70 michael 2088 (chname) ? (chname) : "*",
71     target_p->username, target_p->host,
72     HasUMode(source_p, UMODE_OPER) ? target_p->servptr->name : "*",
73 michael 2756 target_p->name, status,
74     HasUMode(source_p, UMODE_OPER) ? target_p->hopcount : 0, target_p->info);
75 adx 30 else
76 michael 3109 sendto_one_numeric(source_p, &me, RPL_WHOREPLY,
77 michael 2088 (chname) ? (chname) : "*", target_p->username,
78     target_p->host, target_p->servptr->name, target_p->name,
79     status, target_p->hopcount, target_p->info);
80 adx 30 }
81    
82     /* who_common_channel
83     * inputs - pointer to client requesting who
84     * - pointer to channel member chain.
85     * - char * mask to match
86     * - int if oper on a server or not
87     * - pointer to int maxmatches
88     * output - NONE
89     * side effects - lists matching clients on specified channel,
90     * marks matched clients.
91     *
92     */
93     static void
94     who_common_channel(struct Client *source_p, struct Channel *chptr,
95     char *mask, int server_oper, int *maxmatches)
96     {
97 michael 1295 dlink_node *ptr = NULL;
98 adx 30
99     DLINK_FOREACH(ptr, chptr->members.head)
100     {
101 michael 1295 struct Client *target_p = ((struct Membership *)ptr->data)->client_p;
102 adx 30
103 michael 1219 if (!HasUMode(target_p, UMODE_INVISIBLE) || HasFlag(target_p, FLAGS_MARK))
104 adx 30 continue;
105    
106 michael 1295 if (server_oper)
107     if (!HasUMode(target_p, UMODE_OPER) ||
108     (HasUMode(target_p, UMODE_HIDDEN) && !HasUMode(source_p, UMODE_OPER)))
109     continue;
110 adx 30
111 michael 1219 AddFlag(target_p, FLAGS_MARK);
112 adx 30
113     if ((mask == NULL) ||
114 michael 1652 !match(mask, target_p->name) || !match(mask, target_p->username) ||
115 michael 2820 !match(mask, target_p->host) ||
116 michael 1219 ((!ConfigServerHide.hide_servers || HasUMode(source_p, UMODE_OPER)) &&
117 michael 1652 !match(mask, target_p->servptr->name)) ||
118     !match(mask, target_p->info))
119 adx 30 {
120     do_who(source_p, target_p, NULL, "");
121    
122     if (*maxmatches > 0)
123     {
124 adx 268 if (--(*maxmatches) == 0)
125     return;
126 adx 30 }
127     }
128     }
129     }
130    
131     /* who_global()
132     *
133     * inputs - pointer to client requesting who
134     * - char * mask to match
135     * - int if oper on a server or not
136     * output - NONE
137     * side effects - do a global scan of all clients looking for match
138     * this is slightly expensive on EFnet ...
139     */
140     static void
141     who_global(struct Client *source_p, char *mask, int server_oper)
142     {
143     struct Channel *chptr;
144     struct Client *target_p;
145 michael 2091 dlink_node *lp = NULL, *gcptr = NULL;
146 adx 30 int maxmatches = 500;
147 michael 1230 static time_t last_used = 0;
148 adx 30
149 michael 1219 if (!HasUMode(source_p, UMODE_OPER))
150 adx 268 {
151     if ((last_used + ConfigFileEntry.pace_wait) > CurrentTime)
152     {
153     /* safe enough to give this on a local connect only */
154 michael 3109 sendto_one_numeric(source_p, &me, RPL_LOAD2HI);
155 adx 268 return;
156     }
157 michael 980
158     last_used = CurrentTime;
159 adx 268 }
160    
161 adx 30 /* first, list all matching invisible clients on common channels */
162 michael 2091 DLINK_FOREACH(lp, source_p->channel.head)
163 adx 30 {
164     chptr = ((struct Membership *)lp->data)->chptr;
165     who_common_channel(source_p, chptr, mask, server_oper, &maxmatches);
166     }
167    
168     /* second, list all matching visible clients */
169 michael 2091 DLINK_FOREACH(gcptr, global_client_list.head)
170 adx 30 {
171     target_p = gcptr->data;
172    
173     if (!IsClient(target_p))
174     continue;
175    
176 michael 1219 if (HasUMode(target_p, UMODE_INVISIBLE))
177 adx 30 {
178 michael 1219 DelFlag(target_p, FLAGS_MARK);
179 adx 30 continue;
180     }
181    
182 michael 1295 if (server_oper)
183     if (!HasUMode(target_p, UMODE_OPER) ||
184     (HasUMode(target_p, UMODE_HIDDEN) && !HasUMode(source_p, UMODE_OPER)))
185     continue;
186 adx 30
187     if (!mask ||
188 michael 1652 !match(mask, target_p->name) || !match(mask, target_p->username) ||
189     !match(mask, target_p->host) || !match(mask, target_p->servptr->name) ||
190     !match(mask, target_p->info))
191 adx 30 {
192     do_who(source_p, target_p, NULL, "");
193    
194     if (maxmatches > 0)
195     {
196     if (--maxmatches == 0)
197 adx 268 return;
198 adx 30 }
199     }
200     }
201     }
202    
203     /* do_who_on_channel()
204     *
205     * inputs - pointer to client requesting who
206     * - pointer to channel to do who on
207     * - The "real name" of this channel
208     * - int if source_p is a server oper or not
209     * - int if client is member or not
210     * - int server_op flag
211     * output - NONE
212     * side effects - do a who on given channel
213     */
214     static void
215     do_who_on_channel(struct Client *source_p, struct Channel *chptr,
216     const char *chname, int member, int server_oper)
217     {
218 michael 2091 dlink_node *ptr = NULL;
219 adx 30
220 michael 2091 DLINK_FOREACH(ptr, chptr->members.head)
221 adx 30 {
222 michael 2088 struct Membership *ms = ptr->data;
223     struct Client *target_p = ms->client_p;
224 adx 30
225 michael 1219 if (member || !HasUMode(target_p, UMODE_INVISIBLE))
226 adx 30 {
227 michael 1295 if (server_oper)
228     if (!HasUMode(target_p, UMODE_OPER) ||
229     (HasUMode(target_p, UMODE_HIDDEN) && !HasUMode(source_p, UMODE_OPER)))
230     continue;
231 michael 1146 do_who(source_p, target_p, chname, get_member_status(ms, !!HasCap(source_p, CAP_MULTI_PREFIX)));
232 adx 30 }
233     }
234     }
235    
236 michael 2088 /*
237     ** m_who
238 michael 3096 ** parv[0] = command
239 michael 2088 ** parv[1] = nickname mask list
240     ** parv[2] = additional selection flag, only 'o' for now.
241     */
242 michael 2820 static int
243 michael 3156 m_who(struct Client *source_p, int parc, char *parv[])
244 adx 30 {
245 michael 2088 struct Client *target_p = NULL;
246     struct Channel *chptr = NULL;
247     char *mask = parv[1];
248 michael 3246 dlink_node *ptr = NULL;
249 michael 2088 int server_oper = parc > 2 ? (*parv[2] == 'o') : 0; /* Show OPERS only */
250 adx 30
251 michael 2088 /* See if mask is there, collapse it or return if not there */
252     if (EmptyString(mask))
253     {
254     who_global(source_p, mask, server_oper);
255 michael 3109 sendto_one_numeric(source_p, &me, RPL_ENDOFWHO, "*");
256 michael 2820 return 0;
257 michael 2088 }
258 adx 30
259 michael 2088 /* mask isn't NULL at this point. repeat after me... -db */
260     collapse(mask);
261    
262     /* '/who #some_channel' */
263     if (IsChanPrefix(*mask))
264 adx 30 {
265 michael 2088 /* List all users on a given channel */
266 michael 3246 if ((chptr = hash_find_channel(mask)))
267 michael 2088 {
268 michael 3270 if (IsMember(source_p, chptr) || HasUMode(source_p, UMODE_ADMIN))
269 michael 2088 do_who_on_channel(source_p, chptr, chptr->chname, 1, server_oper);
270     else if (!SecretChannel(chptr))
271     do_who_on_channel(source_p, chptr, chptr->chname, 0, server_oper);
272     }
273    
274 michael 3109 sendto_one_numeric(source_p, &me, RPL_ENDOFWHO, mask);
275 michael 2820 return 0;
276 adx 30 }
277 michael 2088
278     /* '/who nick' */
279 michael 3246 if (((target_p = hash_find_client(mask))) &&
280 michael 2088 IsClient(target_p) && (!server_oper || HasUMode(target_p, UMODE_OPER)))
281     {
282 michael 3246 DLINK_FOREACH(ptr, target_p->channel.head)
283 michael 2088 {
284 michael 3246 chptr = ((struct Membership *)ptr->data)->chptr;
285 michael 2088 if (PubChannel(chptr) || IsMember(source_p, chptr))
286     break;
287     }
288    
289 michael 3246 if (ptr)
290 michael 2088 do_who(source_p, target_p, chptr->chname,
291 michael 3246 get_member_status(ptr->data, !!HasCap(source_p, CAP_MULTI_PREFIX)));
292 michael 2088 else
293     do_who(source_p, target_p, NULL, "");
294    
295 michael 3109 sendto_one_numeric(source_p, &me, RPL_ENDOFWHO, mask);
296 michael 2820 return 0;
297 michael 2088 }
298    
299 michael 2091 /* '/who *' */
300     if (!strcmp(mask, "*"))
301     {
302 michael 3246 if ((ptr = source_p->channel.head))
303 michael 2091 {
304 michael 3246 chptr = ((struct Membership *)ptr->data)->chptr;
305     do_who_on_channel(source_p, chptr, chptr->chname, 1,
306 michael 2091 server_oper);
307     }
308    
309 michael 3109 sendto_one_numeric(source_p, &me, RPL_ENDOFWHO, "*");
310 michael 2820 return 0;
311 michael 2091 }
312    
313 michael 2088 /* '/who 0' */
314     if (!strcmp(mask, "0"))
315     who_global(source_p, NULL, server_oper);
316     else
317     who_global(source_p, mask, server_oper);
318    
319     /* Wasn't a nick, wasn't a channel, wasn't a '*' so ... */
320 michael 3109 sendto_one_numeric(source_p, &me, RPL_ENDOFWHO, mask);
321 michael 2820 return 0;
322 adx 30 }
323 michael 1230
324 michael 2820 static struct Message who_msgtab =
325     {
326 michael 1230 "WHO", 0, 0, 2, MAXPARA, MFLG_SLOW, 0,
327 michael 2820 { m_unregistered, m_who, m_ignore, m_ignore, m_who, m_ignore }
328 michael 1230 };
329    
330     static void
331     module_init(void)
332     {
333     mod_add_cmd(&who_msgtab);
334     }
335    
336     static void
337     module_exit(void)
338     {
339     mod_del_cmd(&who_msgtab);
340     }
341    
342 michael 2820 struct module module_entry =
343     {
344 michael 1230 .node = { NULL, NULL, NULL },
345     .name = NULL,
346     .version = "$Revision$",
347     .handle = NULL,
348     .modinit = module_init,
349     .modexit = module_exit,
350     .flags = 0
351     };

Properties

Name Value
svn:eol-style native
svn:keywords Id Revision