ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/modules/m_who.c
Revision: 7645
Committed: Sat Jul 16 17:57:13 2016 UTC (9 years, 1 month ago) by michael
Content type: text/x-csrc
File size: 10910 byte(s)
Log Message:
- m_who.c:m_who(): swap tests

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 7006 * Copyright (c) 1997-2016 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 michael 4565 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19 adx 30 * 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 michael 3347 #include "server.h"
36 adx 30 #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 6405 enum { WHO_MAX_REPLIES = 500 };
44 michael 4508
45    
46 michael 2088 /* do_who()
47     *
48     * inputs - pointer to client requesting who
49     * - pointer to client to do who on
50     * - The reported name
51     * - channel flags
52     * output - NONE
53     * side effects - do a who on given person
54     */
55 adx 30 static void
56 michael 6446 do_who(struct Client *source_p, const struct Client *target_p,
57 michael 4618 const char *name, const char *op_flags)
58 adx 30 {
59 michael 3246 char status[IRCD_BUFSIZE] = "";
60 adx 30
61 michael 2088 if (HasUMode(source_p, UMODE_OPER))
62 michael 2549 snprintf(status, sizeof(status), "%c%s%s%s", target_p->away[0] ? 'G' : 'H',
63     HasUMode(target_p, UMODE_REGISTERED) ? "r" : "",
64 michael 2088 HasUMode(target_p, UMODE_OPER) ? "*" : "", op_flags);
65     else
66 michael 2549 snprintf(status, sizeof(status), "%c%s%s%s", target_p->away[0] ? 'G' : 'H',
67     HasUMode(target_p, UMODE_REGISTERED) ? "r" : "",
68 michael 2088 HasUMode(target_p, UMODE_OPER) &&
69     !HasUMode(target_p, UMODE_HIDDEN) ? "*" : "", op_flags);
70 adx 30
71 michael 2748 if (ConfigServerHide.hide_servers || IsHidden(target_p->servptr))
72 michael 3109 sendto_one_numeric(source_p, &me, RPL_WHOREPLY,
73 michael 4618 (name) ? (name) : "*",
74 michael 2088 target_p->username, target_p->host,
75     HasUMode(source_p, UMODE_OPER) ? target_p->servptr->name : "*",
76 michael 2756 target_p->name, status,
77     HasUMode(source_p, UMODE_OPER) ? target_p->hopcount : 0, target_p->info);
78 adx 30 else
79 michael 3109 sendto_one_numeric(source_p, &me, RPL_WHOREPLY,
80 michael 4618 (name) ? (name) : "*", target_p->username,
81 michael 2088 target_p->host, target_p->servptr->name, target_p->name,
82     status, target_p->hopcount, target_p->info);
83 adx 30 }
84    
85 michael 7641 /*!
86     * \param source_p Pointer to client requesting who
87     * \param target_p Pointer to client to do who on
88     * \param mask Mask to match
89     * \return 1 if mask matches, 0 otherwise
90     */
91     static int
92     who_matches(struct Client *source_p, struct Client *target_p, const char *mask)
93     {
94     if (!mask)
95     return 1;
96    
97     if (!match(mask, target_p->name))
98     return 1;
99    
100     if (!match(mask, target_p->username))
101     return 1;
102    
103     if (!match(mask, target_p->host))
104     return 1;
105    
106     if (!match(mask, target_p->info))
107     return 1;
108    
109 michael 7643 if (HasUMode(source_p, UMODE_OPER))
110     if (!match(mask, target_p->sockhost))
111     return 1;
112    
113 michael 7641 if (HasUMode(source_p, UMODE_OPER) ||
114     (!ConfigServerHide.hide_servers && !IsHidden(target_p->servptr)))
115     if (!match(mask, target_p->servptr->name))
116     return 1;
117    
118     return 0;
119     }
120    
121 adx 30 /* who_common_channel
122     * inputs - pointer to client requesting who
123     * - pointer to channel member chain.
124     * - char * mask to match
125     * - int if oper on a server or not
126     * - pointer to int maxmatches
127     * output - NONE
128     * side effects - lists matching clients on specified channel,
129     * marks matched clients.
130     *
131     */
132     static void
133 michael 6705 who_common_channel(struct Client *source_p, struct Channel *chptr, const char *mask,
134 michael 3911 int server_oper, unsigned int *maxmatches)
135 adx 30 {
136 michael 4815 dlink_node *node = NULL;
137 adx 30
138 michael 4815 DLINK_FOREACH(node, chptr->members.head)
139 adx 30 {
140 michael 4815 struct Client *target_p = ((struct Membership *)node->data)->client_p;
141 adx 30
142 michael 1219 if (!HasUMode(target_p, UMODE_INVISIBLE) || HasFlag(target_p, FLAGS_MARK))
143 adx 30 continue;
144    
145 michael 1295 if (server_oper)
146     if (!HasUMode(target_p, UMODE_OPER) ||
147     (HasUMode(target_p, UMODE_HIDDEN) && !HasUMode(source_p, UMODE_OPER)))
148     continue;
149 adx 30
150 michael 1219 AddFlag(target_p, FLAGS_MARK);
151 adx 30
152 michael 7641 if (who_matches(source_p, target_p, mask))
153 adx 30 {
154     do_who(source_p, target_p, NULL, "");
155    
156     if (*maxmatches > 0)
157     {
158 adx 268 if (--(*maxmatches) == 0)
159 michael 4508 {
160 michael 5639 sendto_one_numeric(source_p, &me, ERR_WHOLIMEXCEED, WHO_MAX_REPLIES, "WHO");
161 adx 268 return;
162 michael 4508 }
163 adx 30 }
164     }
165     }
166     }
167    
168     /* who_global()
169     *
170     * inputs - pointer to client requesting who
171     * - char * mask to match
172     * - int if oper on a server or not
173     * output - NONE
174     * side effects - do a global scan of all clients looking for match
175     * this is slightly expensive on EFnet ...
176     */
177     static void
178 michael 6705 who_global(struct Client *source_p, const char *mask, int server_oper)
179 adx 30 {
180 michael 4815 dlink_node *node = NULL;
181 michael 5639 unsigned int maxmatches = WHO_MAX_REPLIES;
182 michael 7330 static uintmax_t last_used = 0;
183 adx 30
184 michael 1219 if (!HasUMode(source_p, UMODE_OPER))
185 adx 268 {
186 michael 4340 if ((last_used + ConfigGeneral.pace_wait) > CurrentTime)
187 adx 268 {
188 michael 4759 sendto_one_numeric(source_p, &me, RPL_LOAD2HI, "WHO");
189 adx 268 return;
190     }
191 michael 980
192     last_used = CurrentTime;
193 adx 268 }
194    
195 michael 3346 /* First, list all matching invisible clients on common channels */
196 michael 4815 DLINK_FOREACH(node, source_p->channel.head)
197 adx 30 {
198 michael 4815 struct Channel *chptr = ((struct Membership *)node->data)->chptr;
199 adx 30 who_common_channel(source_p, chptr, mask, server_oper, &maxmatches);
200     }
201    
202 michael 3346 /* Second, list all matching visible clients */
203 michael 4815 DLINK_FOREACH(node, global_client_list.head)
204 adx 30 {
205 michael 4815 struct Client *target_p = node->data;
206 adx 30
207     if (!IsClient(target_p))
208     continue;
209    
210 michael 1219 if (HasUMode(target_p, UMODE_INVISIBLE))
211 adx 30 {
212 michael 1219 DelFlag(target_p, FLAGS_MARK);
213 adx 30 continue;
214     }
215    
216 michael 1295 if (server_oper)
217     if (!HasUMode(target_p, UMODE_OPER) ||
218     (HasUMode(target_p, UMODE_HIDDEN) && !HasUMode(source_p, UMODE_OPER)))
219     continue;
220 adx 30
221 michael 7641 if (who_matches(source_p, target_p, mask))
222 adx 30 {
223     do_who(source_p, target_p, NULL, "");
224    
225     if (maxmatches > 0)
226     {
227     if (--maxmatches == 0)
228 michael 4508 {
229 michael 5639 sendto_one_numeric(source_p, &me, ERR_WHOLIMEXCEED, WHO_MAX_REPLIES, "WHO");
230 adx 268 return;
231 michael 4508 }
232 adx 30 }
233     }
234     }
235     }
236    
237     /* do_who_on_channel()
238     *
239     * inputs - pointer to client requesting who
240     * - pointer to channel to do who on
241     * - The "real name" of this channel
242     * - int if source_p is a server oper or not
243     * - int if client is member or not
244     * - int server_op flag
245     * output - NONE
246     * side effects - do a who on given channel
247     */
248     static void
249     do_who_on_channel(struct Client *source_p, struct Channel *chptr,
250 michael 4815 int is_member, int server_oper)
251 adx 30 {
252 michael 4815 dlink_node *node = NULL;
253 adx 30
254 michael 4815 DLINK_FOREACH(node, chptr->members.head)
255 adx 30 {
256 michael 4815 struct Membership *member = node->data;
257     struct Client *target_p = member->client_p;
258 adx 30
259 michael 4815 if (is_member || !HasUMode(target_p, UMODE_INVISIBLE))
260 adx 30 {
261 michael 1295 if (server_oper)
262     if (!HasUMode(target_p, UMODE_OPER) ||
263     (HasUMode(target_p, UMODE_HIDDEN) && !HasUMode(source_p, UMODE_OPER)))
264     continue;
265 michael 4815 do_who(source_p, target_p, chptr->name, get_member_status(member, !!HasCap(source_p, CAP_MULTI_PREFIX)));
266 adx 30 }
267     }
268     }
269    
270 michael 3346 /*! \brief WHO command handler
271     *
272     * \param source_p Pointer to allocated Client struct from which the message
273     * originally comes from. This can be a local or remote client.
274     * \param parc Integer holding the number of supplied arguments.
275     * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
276     * pointers.
277     * \note Valid arguments for this command are:
278     * - parv[0] = command
279     * - parv[1] = nickname/channelname
280     * - parv[2] = additional selection flag, only 'o' for now
281     */
282 michael 2820 static int
283 michael 3156 m_who(struct Client *source_p, int parc, char *parv[])
284 adx 30 {
285 michael 2088 struct Client *target_p = NULL;
286     struct Channel *chptr = NULL;
287     char *mask = parv[1];
288 michael 4815 dlink_node *node = NULL;
289 michael 6446 const int server_oper = parc > 2 && *parv[2] == 'o'; /* Show OPERS only */
290 adx 30
291 michael 2088 /* See if mask is there, collapse it or return if not there */
292     if (EmptyString(mask))
293     {
294 michael 5884 who_global(source_p, NULL, server_oper);
295 michael 3109 sendto_one_numeric(source_p, &me, RPL_ENDOFWHO, "*");
296 michael 2820 return 0;
297 michael 2088 }
298 adx 30
299 michael 3346 /* Mask isn't NULL at this point. repeat after me... -db */
300 michael 2088 collapse(mask);
301    
302     /* '/who #some_channel' */
303     if (IsChanPrefix(*mask))
304 adx 30 {
305 michael 2088 /* List all users on a given channel */
306 michael 3246 if ((chptr = hash_find_channel(mask)))
307 michael 2088 {
308 michael 7645 if (HasUMode(source_p, UMODE_ADMIN) || IsMember(source_p, chptr))
309 michael 4529 do_who_on_channel(source_p, chptr, 1, server_oper);
310 michael 2088 else if (!SecretChannel(chptr))
311 michael 4529 do_who_on_channel(source_p, chptr, 0, server_oper);
312 michael 2088 }
313    
314 michael 3109 sendto_one_numeric(source_p, &me, RPL_ENDOFWHO, mask);
315 michael 2820 return 0;
316 adx 30 }
317 michael 2088
318     /* '/who nick' */
319 michael 4996 if ((target_p = find_person(source_p, mask)) &&
320 michael 4823 (!server_oper || HasUMode(target_p, UMODE_OPER)))
321 michael 2088 {
322 michael 4815 DLINK_FOREACH(node, target_p->channel.head)
323 michael 2088 {
324 michael 4815 chptr = ((struct Membership *)node->data)->chptr;
325 michael 2088 if (PubChannel(chptr) || IsMember(source_p, chptr))
326     break;
327     }
328    
329 michael 4815 if (node)
330 michael 4618 do_who(source_p, target_p, chptr->name,
331 michael 4815 get_member_status(node->data, !!HasCap(source_p, CAP_MULTI_PREFIX)));
332 michael 2088 else
333     do_who(source_p, target_p, NULL, "");
334    
335 michael 3109 sendto_one_numeric(source_p, &me, RPL_ENDOFWHO, mask);
336 michael 2820 return 0;
337 michael 2088 }
338    
339 michael 2091 /* '/who *' */
340     if (!strcmp(mask, "*"))
341     {
342 michael 4815 if ((node = source_p->channel.head))
343 michael 2091 {
344 michael 4815 chptr = ((struct Membership *)node->data)->chptr;
345 michael 4529 do_who_on_channel(source_p, chptr, 1, server_oper);
346 michael 2091 }
347    
348 michael 3109 sendto_one_numeric(source_p, &me, RPL_ENDOFWHO, "*");
349 michael 2820 return 0;
350 michael 2091 }
351    
352 michael 2088 /* '/who 0' */
353     if (!strcmp(mask, "0"))
354     who_global(source_p, NULL, server_oper);
355     else
356     who_global(source_p, mask, server_oper);
357    
358     /* Wasn't a nick, wasn't a channel, wasn't a '*' so ... */
359 michael 3109 sendto_one_numeric(source_p, &me, RPL_ENDOFWHO, mask);
360 michael 2820 return 0;
361 adx 30 }
362 michael 1230
363 michael 2820 static struct Message who_msgtab =
364     {
365 michael 5881 .cmd = "WHO",
366     .args_max = MAXPARA,
367     .handlers[UNREGISTERED_HANDLER] = m_unregistered,
368     .handlers[CLIENT_HANDLER] = m_who,
369     .handlers[SERVER_HANDLER] = m_ignore,
370     .handlers[ENCAP_HANDLER] = m_ignore,
371     .handlers[OPER_HANDLER] = m_who
372 michael 1230 };
373    
374     static void
375     module_init(void)
376     {
377     mod_add_cmd(&who_msgtab);
378     }
379    
380     static void
381     module_exit(void)
382     {
383     mod_del_cmd(&who_msgtab);
384     }
385    
386 michael 2820 struct module module_entry =
387     {
388 michael 1230 .version = "$Revision$",
389     .modinit = module_init,
390     .modexit = module_exit,
391     };

Properties

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