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: 4617
Committed: Sun Sep 7 13:00:55 2014 UTC (10 years, 11 months ago) by michael
Content type: text/x-csrc
File size: 10434 byte(s)
Log Message:
- Renamed Channel::chname to Channel::name

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 *
4 * Copyright (c) 1997-2014 ircd-hybrid development team
5 *
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19 * USA
20 */
21
22 /*! \file m_who.c
23 * \brief Includes required functions for processing the WHO command.
24 * \version $Id$
25 */
26
27 #include "stdinc.h"
28 #include "list.h"
29 #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 "server.h"
36 #include "send.h"
37 #include "irc_string.h"
38 #include "conf.h"
39 #include "parse.h"
40 #include "modules.h"
41
42
43 #define WHO_MAXREPLIES 500
44
45
46 /* 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 static void
56 do_who(struct Client *source_p, struct Client *target_p,
57 const char *name, const char *op_flags)
58 {
59 char status[IRCD_BUFSIZE] = "";
60
61 if (HasUMode(source_p, UMODE_OPER))
62 snprintf(status, sizeof(status), "%c%s%s%s", target_p->away[0] ? 'G' : 'H',
63 HasUMode(target_p, UMODE_REGISTERED) ? "r" : "",
64 HasUMode(target_p, UMODE_OPER) ? "*" : "", op_flags);
65 else
66 snprintf(status, sizeof(status), "%c%s%s%s", target_p->away[0] ? 'G' : 'H',
67 HasUMode(target_p, UMODE_REGISTERED) ? "r" : "",
68 HasUMode(target_p, UMODE_OPER) &&
69 !HasUMode(target_p, UMODE_HIDDEN) ? "*" : "", op_flags);
70
71 if (ConfigServerHide.hide_servers || IsHidden(target_p->servptr))
72 sendto_one_numeric(source_p, &me, RPL_WHOREPLY,
73 (name) ? (name) : "*",
74 target_p->username, target_p->host,
75 HasUMode(source_p, UMODE_OPER) ? target_p->servptr->name : "*",
76 target_p->name, status,
77 HasUMode(source_p, UMODE_OPER) ? target_p->hopcount : 0, target_p->info);
78 else
79 sendto_one_numeric(source_p, &me, RPL_WHOREPLY,
80 (name) ? (name) : "*", target_p->username,
81 target_p->host, target_p->servptr->name, target_p->name,
82 status, target_p->hopcount, target_p->info);
83 }
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 who_common_channel(struct Client *source_p, struct Channel *chptr, char *mask,
98 int server_oper, unsigned int *maxmatches)
99 {
100 dlink_node *ptr = NULL;
101
102 DLINK_FOREACH(ptr, chptr->members.head)
103 {
104 struct Client *target_p = ((struct Membership *)ptr->data)->client_p;
105
106 if (!HasUMode(target_p, UMODE_INVISIBLE) || HasFlag(target_p, FLAGS_MARK))
107 continue;
108
109 if (server_oper)
110 if (!HasUMode(target_p, UMODE_OPER) ||
111 (HasUMode(target_p, UMODE_HIDDEN) && !HasUMode(source_p, UMODE_OPER)))
112 continue;
113
114 AddFlag(target_p, FLAGS_MARK);
115
116 if ((mask == NULL) ||
117 !match(mask, target_p->name) || !match(mask, target_p->username) ||
118 !match(mask, target_p->host) ||
119 ((!ConfigServerHide.hide_servers || HasUMode(source_p, UMODE_OPER)) &&
120 !match(mask, target_p->servptr->name)) ||
121 !match(mask, target_p->info))
122 {
123 do_who(source_p, target_p, NULL, "");
124
125 if (*maxmatches > 0)
126 {
127 if (--(*maxmatches) == 0)
128 {
129 sendto_one_numeric(source_p, &me, ERR_WHOLIMEXCEED, WHO_MAXREPLIES, "WHO");
130 return;
131 }
132 }
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 dlink_node *ptr = NULL;
150 unsigned int maxmatches = WHO_MAXREPLIES;
151 static time_t last_used = 0;
152
153 if (!HasUMode(source_p, UMODE_OPER))
154 {
155 if ((last_used + ConfigGeneral.pace_wait) > CurrentTime)
156 {
157 sendto_one_numeric(source_p, &me, RPL_LOAD2HI);
158 return;
159 }
160
161 last_used = CurrentTime;
162 }
163
164 /* First, list all matching invisible clients on common channels */
165 DLINK_FOREACH(ptr, source_p->channel.head)
166 {
167 struct Channel *chptr = ((struct Membership *)ptr->data)->chptr;
168 who_common_channel(source_p, chptr, mask, server_oper, &maxmatches);
169 }
170
171 /* Second, list all matching visible clients */
172 DLINK_FOREACH(ptr, global_client_list.head)
173 {
174 struct Client *target_p = ptr->data;
175
176 if (!IsClient(target_p))
177 continue;
178
179 if (HasUMode(target_p, UMODE_INVISIBLE))
180 {
181 DelFlag(target_p, FLAGS_MARK);
182 continue;
183 }
184
185 if (server_oper)
186 if (!HasUMode(target_p, UMODE_OPER) ||
187 (HasUMode(target_p, UMODE_HIDDEN) && !HasUMode(source_p, UMODE_OPER)))
188 continue;
189
190 if (!mask ||
191 !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 {
195 do_who(source_p, target_p, NULL, "");
196
197 if (maxmatches > 0)
198 {
199 if (--maxmatches == 0)
200 {
201 sendto_one_numeric(source_p, &me, ERR_WHOLIMEXCEED, WHO_MAXREPLIES, "WHO");
202 return;
203 }
204 }
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 int member, int server_oper)
223 {
224 dlink_node *ptr = NULL;
225
226 DLINK_FOREACH(ptr, chptr->members.head)
227 {
228 struct Membership *ms = ptr->data;
229 struct Client *target_p = ms->client_p;
230
231 if (member || !HasUMode(target_p, UMODE_INVISIBLE))
232 {
233 if (server_oper)
234 if (!HasUMode(target_p, UMODE_OPER) ||
235 (HasUMode(target_p, UMODE_HIDDEN) && !HasUMode(source_p, UMODE_OPER)))
236 continue;
237 do_who(source_p, target_p, chptr->name, get_member_status(ms, !!HasCap(source_p, CAP_MULTI_PREFIX)));
238 }
239 }
240 }
241
242 /*! \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 static int
255 m_who(struct Client *source_p, int parc, char *parv[])
256 {
257 struct Client *target_p = NULL;
258 struct Channel *chptr = NULL;
259 char *mask = parv[1];
260 dlink_node *ptr = NULL;
261 int server_oper = parc > 2 ? (*parv[2] == 'o') : 0; /* Show OPERS only */
262
263 /* 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 sendto_one_numeric(source_p, &me, RPL_ENDOFWHO, "*");
268 return 0;
269 }
270
271 /* Mask isn't NULL at this point. repeat after me... -db */
272 collapse(mask);
273
274 /* '/who #some_channel' */
275 if (IsChanPrefix(*mask))
276 {
277 /* List all users on a given channel */
278 if ((chptr = hash_find_channel(mask)))
279 {
280 if (IsMember(source_p, chptr) || HasUMode(source_p, UMODE_ADMIN))
281 do_who_on_channel(source_p, chptr, 1, server_oper);
282 else if (!SecretChannel(chptr))
283 do_who_on_channel(source_p, chptr, 0, server_oper);
284 }
285
286 sendto_one_numeric(source_p, &me, RPL_ENDOFWHO, mask);
287 return 0;
288 }
289
290 /* '/who nick' */
291 if (((target_p = hash_find_client(mask))) &&
292 IsClient(target_p) && (!server_oper || HasUMode(target_p, UMODE_OPER)))
293 {
294 DLINK_FOREACH(ptr, target_p->channel.head)
295 {
296 chptr = ((struct Membership *)ptr->data)->chptr;
297 if (PubChannel(chptr) || IsMember(source_p, chptr))
298 break;
299 }
300
301 if (ptr)
302 do_who(source_p, target_p, chptr->name,
303 get_member_status(ptr->data, !!HasCap(source_p, CAP_MULTI_PREFIX)));
304 else
305 do_who(source_p, target_p, NULL, "");
306
307 sendto_one_numeric(source_p, &me, RPL_ENDOFWHO, mask);
308 return 0;
309 }
310
311 /* '/who *' */
312 if (!strcmp(mask, "*"))
313 {
314 if ((ptr = source_p->channel.head))
315 {
316 chptr = ((struct Membership *)ptr->data)->chptr;
317 do_who_on_channel(source_p, chptr, 1, server_oper);
318 }
319
320 sendto_one_numeric(source_p, &me, RPL_ENDOFWHO, "*");
321 return 0;
322 }
323
324 /* '/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 sendto_one_numeric(source_p, &me, RPL_ENDOFWHO, mask);
332 return 0;
333 }
334
335 static struct Message who_msgtab =
336 {
337 "WHO", NULL, 0, 0, 2, MAXPARA, MFLG_SLOW, 0,
338 { m_unregistered, m_who, m_ignore, m_ignore, m_who, m_ignore }
339 };
340
341 static void
342 module_init(void)
343 {
344 mod_add_cmd(&who_msgtab);
345 }
346
347 static void
348 module_exit(void)
349 {
350 mod_del_cmd(&who_msgtab);
351 }
352
353 struct module module_entry =
354 {
355 .node = { NULL, NULL, NULL },
356 .name = NULL,
357 .version = "$Revision$",
358 .handle = NULL,
359 .modinit = module_init,
360 .modexit = module_exit,
361 .flags = 0
362 };

Properties

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