ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/branches/8.2.x/modules/m_who.c
Revision: 5880
Committed: Sun May 3 16:01:42 2015 UTC (11 years, 3 months ago) by michael
Content type: text/x-csrc
File size: 10526 byte(s)
Log Message:
- Use C99-style initializers in all struct Message items
- Removed MFLG_SLOW
- Removed DUMMY_HANDLER

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 5346 * Copyright (c) 1997-2015 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 4564 * 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 5640 #define WHO_MAX_REPLIES 500
44 michael 4509
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 2088 do_who(struct Client *source_p, struct Client *target_p,
57 michael 4617 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 4617 (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 4617 (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     /* who_common_channel
86     * inputs - pointer to client requesting who
87     * - pointer to channel member chain.
88     * - char * mask to match
89     * - int if oper on a server or not
90     * - pointer to int maxmatches
91     * output - NONE
92     * side effects - lists matching clients on specified channel,
93     * marks matched clients.
94     *
95     */
96     static void
97 michael 3910 who_common_channel(struct Client *source_p, struct Channel *chptr, char *mask,
98     int server_oper, unsigned int *maxmatches)
99 adx 30 {
100 michael 4816 dlink_node *node = NULL;
101 adx 30
102 michael 4816 DLINK_FOREACH(node, chptr->members.head)
103 adx 30 {
104 michael 4816 struct Client *target_p = ((struct Membership *)node->data)->client_p;
105 adx 30
106 michael 1219 if (!HasUMode(target_p, UMODE_INVISIBLE) || HasFlag(target_p, FLAGS_MARK))
107 adx 30 continue;
108    
109 michael 1295 if (server_oper)
110     if (!HasUMode(target_p, UMODE_OPER) ||
111     (HasUMode(target_p, UMODE_HIDDEN) && !HasUMode(source_p, UMODE_OPER)))
112     continue;
113 adx 30
114 michael 1219 AddFlag(target_p, FLAGS_MARK);
115 adx 30
116     if ((mask == NULL) ||
117 michael 1652 !match(mask, target_p->name) || !match(mask, target_p->username) ||
118 michael 2820 !match(mask, target_p->host) ||
119 michael 1219 ((!ConfigServerHide.hide_servers || HasUMode(source_p, UMODE_OPER)) &&
120 michael 1652 !match(mask, target_p->servptr->name)) ||
121     !match(mask, target_p->info))
122 adx 30 {
123     do_who(source_p, target_p, NULL, "");
124    
125     if (*maxmatches > 0)
126     {
127 adx 268 if (--(*maxmatches) == 0)
128 michael 4509 {
129 michael 5640 sendto_one_numeric(source_p, &me, ERR_WHOLIMEXCEED, WHO_MAX_REPLIES, "WHO");
130 adx 268 return;
131 michael 4509 }
132 adx 30 }
133     }
134     }
135     }
136    
137     /* who_global()
138     *
139     * inputs - pointer to client requesting who
140     * - char * mask to match
141     * - int if oper on a server or not
142     * output - NONE
143     * side effects - do a global scan of all clients looking for match
144     * this is slightly expensive on EFnet ...
145     */
146     static void
147     who_global(struct Client *source_p, char *mask, int server_oper)
148     {
149 michael 4816 dlink_node *node = NULL;
150 michael 5640 unsigned int maxmatches = WHO_MAX_REPLIES;
151 michael 1230 static time_t last_used = 0;
152 adx 30
153 michael 1219 if (!HasUMode(source_p, UMODE_OPER))
154 adx 268 {
155 michael 4341 if ((last_used + ConfigGeneral.pace_wait) > CurrentTime)
156 adx 268 {
157 michael 4758 sendto_one_numeric(source_p, &me, RPL_LOAD2HI, "WHO");
158 adx 268 return;
159     }
160 michael 980
161     last_used = CurrentTime;
162 adx 268 }
163    
164 michael 3346 /* First, list all matching invisible clients on common channels */
165 michael 4816 DLINK_FOREACH(node, source_p->channel.head)
166 adx 30 {
167 michael 4816 struct Channel *chptr = ((struct Membership *)node->data)->chptr;
168 adx 30 who_common_channel(source_p, chptr, mask, server_oper, &maxmatches);
169     }
170    
171 michael 3346 /* Second, list all matching visible clients */
172 michael 4816 DLINK_FOREACH(node, global_client_list.head)
173 adx 30 {
174 michael 4816 struct Client *target_p = node->data;
175 adx 30
176     if (!IsClient(target_p))
177     continue;
178    
179 michael 1219 if (HasUMode(target_p, UMODE_INVISIBLE))
180 adx 30 {
181 michael 1219 DelFlag(target_p, FLAGS_MARK);
182 adx 30 continue;
183     }
184    
185 michael 1295 if (server_oper)
186     if (!HasUMode(target_p, UMODE_OPER) ||
187     (HasUMode(target_p, UMODE_HIDDEN) && !HasUMode(source_p, UMODE_OPER)))
188     continue;
189 adx 30
190     if (!mask ||
191 michael 1652 !match(mask, target_p->name) || !match(mask, target_p->username) ||
192     !match(mask, target_p->host) || !match(mask, target_p->servptr->name) ||
193     !match(mask, target_p->info))
194 adx 30 {
195     do_who(source_p, target_p, NULL, "");
196    
197     if (maxmatches > 0)
198     {
199     if (--maxmatches == 0)
200 michael 4509 {
201 michael 5640 sendto_one_numeric(source_p, &me, ERR_WHOLIMEXCEED, WHO_MAX_REPLIES, "WHO");
202 adx 268 return;
203 michael 4509 }
204 adx 30 }
205     }
206     }
207     }
208    
209     /* do_who_on_channel()
210     *
211     * inputs - pointer to client requesting who
212     * - pointer to channel to do who on
213     * - The "real name" of this channel
214     * - int if source_p is a server oper or not
215     * - int if client is member or not
216     * - int server_op flag
217     * output - NONE
218     * side effects - do a who on given channel
219     */
220     static void
221     do_who_on_channel(struct Client *source_p, struct Channel *chptr,
222 michael 4816 int is_member, int server_oper)
223 adx 30 {
224 michael 4816 dlink_node *node = NULL;
225 adx 30
226 michael 4816 DLINK_FOREACH(node, chptr->members.head)
227 adx 30 {
228 michael 4816 struct Membership *member = node->data;
229     struct Client *target_p = member->client_p;
230 adx 30
231 michael 4816 if (is_member || !HasUMode(target_p, UMODE_INVISIBLE))
232 adx 30 {
233 michael 1295 if (server_oper)
234     if (!HasUMode(target_p, UMODE_OPER) ||
235     (HasUMode(target_p, UMODE_HIDDEN) && !HasUMode(source_p, UMODE_OPER)))
236     continue;
237 michael 4816 do_who(source_p, target_p, chptr->name, get_member_status(member, !!HasCap(source_p, CAP_MULTI_PREFIX)));
238 adx 30 }
239     }
240     }
241    
242 michael 3346 /*! \brief WHO command handler
243     *
244     * \param source_p Pointer to allocated Client struct from which the message
245     * originally comes from. This can be a local or remote client.
246     * \param parc Integer holding the number of supplied arguments.
247     * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
248     * pointers.
249     * \note Valid arguments for this command are:
250     * - parv[0] = command
251     * - parv[1] = nickname/channelname
252     * - parv[2] = additional selection flag, only 'o' for now
253     */
254 michael 2820 static int
255 michael 3156 m_who(struct Client *source_p, int parc, char *parv[])
256 adx 30 {
257 michael 2088 struct Client *target_p = NULL;
258     struct Channel *chptr = NULL;
259     char *mask = parv[1];
260 michael 4816 dlink_node *node = NULL;
261 michael 5640 const int server_oper = parc > 2 ? (*parv[2] == 'o') : 0; /* Show OPERS only */
262 adx 30
263 michael 2088 /* See if mask is there, collapse it or return if not there */
264     if (EmptyString(mask))
265     {
266     who_global(source_p, mask, server_oper);
267 michael 3109 sendto_one_numeric(source_p, &me, RPL_ENDOFWHO, "*");
268 michael 2820 return 0;
269 michael 2088 }
270 adx 30
271 michael 3346 /* Mask isn't NULL at this point. repeat after me... -db */
272 michael 2088 collapse(mask);
273    
274     /* '/who #some_channel' */
275     if (IsChanPrefix(*mask))
276 adx 30 {
277 michael 2088 /* List all users on a given channel */
278 michael 3246 if ((chptr = hash_find_channel(mask)))
279 michael 2088 {
280 michael 3270 if (IsMember(source_p, chptr) || HasUMode(source_p, UMODE_ADMIN))
281 michael 4530 do_who_on_channel(source_p, chptr, 1, server_oper);
282 michael 2088 else if (!SecretChannel(chptr))
283 michael 4530 do_who_on_channel(source_p, chptr, 0, server_oper);
284 michael 2088 }
285    
286 michael 3109 sendto_one_numeric(source_p, &me, RPL_ENDOFWHO, mask);
287 michael 2820 return 0;
288 adx 30 }
289 michael 2088
290     /* '/who nick' */
291 michael 4997 if ((target_p = find_person(source_p, mask)) &&
292 michael 4824 (!server_oper || HasUMode(target_p, UMODE_OPER)))
293 michael 2088 {
294 michael 4816 DLINK_FOREACH(node, target_p->channel.head)
295 michael 2088 {
296 michael 4816 chptr = ((struct Membership *)node->data)->chptr;
297 michael 2088 if (PubChannel(chptr) || IsMember(source_p, chptr))
298     break;
299     }
300    
301 michael 4816 if (node)
302 michael 4617 do_who(source_p, target_p, chptr->name,
303 michael 4816 get_member_status(node->data, !!HasCap(source_p, CAP_MULTI_PREFIX)));
304 michael 2088 else
305     do_who(source_p, target_p, NULL, "");
306    
307 michael 3109 sendto_one_numeric(source_p, &me, RPL_ENDOFWHO, mask);
308 michael 2820 return 0;
309 michael 2088 }
310    
311 michael 2091 /* '/who *' */
312     if (!strcmp(mask, "*"))
313     {
314 michael 4816 if ((node = source_p->channel.head))
315 michael 2091 {
316 michael 4816 chptr = ((struct Membership *)node->data)->chptr;
317 michael 4530 do_who_on_channel(source_p, chptr, 1, server_oper);
318 michael 2091 }
319    
320 michael 3109 sendto_one_numeric(source_p, &me, RPL_ENDOFWHO, "*");
321 michael 2820 return 0;
322 michael 2091 }
323    
324 michael 2088 /* '/who 0' */
325     if (!strcmp(mask, "0"))
326     who_global(source_p, NULL, server_oper);
327     else
328     who_global(source_p, mask, server_oper);
329    
330     /* Wasn't a nick, wasn't a channel, wasn't a '*' so ... */
331 michael 3109 sendto_one_numeric(source_p, &me, RPL_ENDOFWHO, mask);
332 michael 2820 return 0;
333 adx 30 }
334 michael 1230
335 michael 2820 static struct Message who_msgtab =
336     {
337 michael 5880 .cmd = "WHO",
338     .args_min = 2,
339     .args_max = MAXPARA,
340     .handlers[UNREGISTERED_HANDLER] = m_unregistered,
341     .handlers[CLIENT_HANDLER] = m_who,
342     .handlers[SERVER_HANDLER] = m_ignore,
343     .handlers[ENCAP_HANDLER] = m_ignore,
344     .handlers[OPER_HANDLER] = m_who
345 michael 1230 };
346    
347     static void
348     module_init(void)
349     {
350     mod_add_cmd(&who_msgtab);
351     }
352    
353     static void
354     module_exit(void)
355     {
356     mod_del_cmd(&who_msgtab);
357     }
358    
359 michael 2820 struct module module_entry =
360     {
361 michael 1230 .version = "$Revision$",
362     .modinit = module_init,
363     .modexit = module_exit,
364     };

Properties

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