ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-7.2/modules/m_who.c
Revision: 313
Committed: Fri Dec 23 10:55:47 2005 UTC (18 years, 3 months ago) by michael
Content type: text/x-csrc
File size: 10775 byte(s)
Log Message:
- Don't pace "WHO #somechan" and "WHO *" as this breaks several clients

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3 * m_who.c: Shows who is on a channel.
4 *
5 * Copyright (C) 2002 by the past and present ircd coders, and others.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 * USA
21 *
22 * $Id$
23 */
24 #include "stdinc.h"
25 #include "tools.h"
26 #include "common.h"
27 #include "handlers.h"
28 #include "client.h"
29 #include "channel.h"
30 #include "channel_mode.h"
31 #include "hash.h"
32 #include "ircd.h"
33 #include "numeric.h"
34 #include "s_serv.h"
35 #include "send.h"
36 #include "list.h"
37 #include "irc_string.h"
38 #include "sprintf_irc.h"
39 #include "s_conf.h"
40 #include "msg.h"
41 #include "parse.h"
42 #include "modules.h"
43
44 static time_t last_used = 0;
45
46 static void m_who(struct Client *, struct Client *, int, char **);
47 static void ms_who(struct Client *, struct Client *, int, char **);
48
49 struct Message who_msgtab = {
50 "WHO", 0, 0, 2, 0, MFLG_SLOW, 0,
51 {m_unregistered, m_who, ms_who, m_ignore, m_who, m_ignore}
52 };
53
54 #ifndef STATIC_MODULES
55 void
56 _modinit(void)
57 {
58 mod_add_cmd(&who_msgtab);
59 }
60
61 void
62 _moddeinit(void)
63 {
64 mod_del_cmd(&who_msgtab);
65 }
66
67 const char *_version = "$Revision$";
68 #endif
69
70 static void who_global(struct Client *source_p, char *mask, int server_oper);
71 static void do_who(struct Client *source_p, struct Client *target_p,
72 const char *chname, const char *op_flags);
73 static void do_who_on_channel(struct Client *source_p, struct Channel *chptr,
74 const char *chname, int member, int server_oper);
75
76 /*
77 ** m_who
78 ** parv[0] = sender prefix
79 ** parv[1] = nickname mask list
80 ** parv[2] = additional selection flag, only 'o' for now.
81 */
82 static void
83 m_who(struct Client *client_p, struct Client *source_p,
84 int parc, char *parv[])
85 {
86 struct Client *target_p;
87 char *mask = parv[1];
88 dlink_node *lp;
89 int server_oper = parc > 2 ? (*parv[2] == 'o') : 0; /* Show OPERS only */
90 struct Channel *chptr;
91 const char *from, *to;
92
93 if (IsCapable(source_p->from, CAP_TS6) && HasID(source_p))
94 {
95 from = me.id;
96 to = source_p->id;
97 }
98 else
99 {
100 from = me.name;
101 to = source_p->name;
102 }
103
104 /* See if mask is there, collapse it or return if not there */
105 if (mask == NULL || !*mask)
106 {
107 who_global(source_p, mask, server_oper);
108 sendto_one(source_p, form_str(RPL_ENDOFWHO),
109 from, to, "*");
110 return;
111 }
112
113 /* mask isn't NULL at this point. repeat after me... -db */
114 collapse(mask);
115
116 /* '/who *' */
117 if (mask[0] == '*' && !mask[1])
118 {
119 if ((lp = source_p->channel.head) != NULL)
120 {
121 struct Channel *mychannel = ((struct Membership *)lp->data)->chptr;
122 do_who_on_channel(source_p, mychannel, mychannel->chname, YES,
123 server_oper);
124 }
125
126 sendto_one(source_p, form_str(RPL_ENDOFWHO), from, to, "*");
127 return;
128 }
129
130 /* '/who #some_channel' */
131 if (IsChanPrefix(*mask))
132 {
133 /* List all users on a given channel */
134 if ((chptr = hash_find_channel(mask)) != NULL)
135 {
136 if (IsMember(source_p, chptr))
137 do_who_on_channel(source_p, chptr, chptr->chname, YES, server_oper);
138 else if (!SecretChannel(chptr))
139 do_who_on_channel(source_p, chptr, chptr->chname, NO, server_oper);
140 }
141
142 sendto_one(source_p, form_str(RPL_ENDOFWHO),
143 from, to, mask);
144 return;
145 }
146
147 /* '/who nick' */
148 if (((target_p = find_client(mask)) != NULL) &&
149 IsClient(target_p) && (!server_oper || IsOper(target_p)))
150 {
151 if (IsServer(client_p))
152 client_burst_if_needed(client_p,target_p);
153
154 DLINK_FOREACH(lp, target_p->channel.head)
155 {
156 chptr = ((struct Membership *) lp->data)->chptr;
157 if (PubChannel(chptr) || IsMember(source_p, chptr))
158 break;
159 }
160
161 if (lp != NULL)
162 do_who(source_p, target_p, chptr->chname,
163 get_member_status(lp->data, NO));
164 else
165 do_who(source_p, target_p, NULL, "");
166
167 sendto_one(source_p, form_str(RPL_ENDOFWHO),
168 from, to, mask);
169 return;
170 }
171
172 /* '/who 0' */
173 if (mask[0] == '0' && !mask[1])
174 who_global(source_p, NULL, server_oper);
175 else
176 who_global(source_p, mask, server_oper);
177
178 /* Wasn't a nick, wasn't a channel, wasn't a '*' so ... */
179 sendto_one(source_p, form_str(RPL_ENDOFWHO),
180 from, to, mask);
181 }
182
183 /* who_common_channel
184 * inputs - pointer to client requesting who
185 * - pointer to channel member chain.
186 * - char * mask to match
187 * - int if oper on a server or not
188 * - pointer to int maxmatches
189 * output - NONE
190 * side effects - lists matching clients on specified channel,
191 * marks matched clients.
192 *
193 */
194 static void
195 who_common_channel(struct Client *source_p, struct Channel *chptr,
196 char *mask, int server_oper, int *maxmatches)
197 {
198 dlink_node *ptr;
199 struct Client *target_p;
200
201 DLINK_FOREACH(ptr, chptr->members.head)
202 {
203 target_p = ((struct Membership *)ptr->data)->client_p;
204
205 if (!IsInvisible(target_p) || IsMarked(target_p))
206 continue;
207
208 if (server_oper && !IsOper(target_p))
209 continue;
210
211 SetMark(target_p);
212
213 assert(target_p->servptr != NULL);
214
215 if ((mask == NULL) ||
216 match(mask, target_p->name) || match(mask, target_p->username) ||
217 match(mask, target_p->host) ||
218 ((!ConfigServerHide.hide_servers || IsOper(source_p)) &&
219 match(mask, target_p->servptr->name)) ||
220 match(mask, target_p->info))
221 {
222 do_who(source_p, target_p, NULL, "");
223
224 if (*maxmatches > 0)
225 {
226 if (--(*maxmatches) == 0)
227 return;
228 }
229 }
230 }
231 }
232
233 /* who_global()
234 *
235 * inputs - pointer to client requesting who
236 * - char * mask to match
237 * - int if oper on a server or not
238 * output - NONE
239 * side effects - do a global scan of all clients looking for match
240 * this is slightly expensive on EFnet ...
241 */
242 static void
243 who_global(struct Client *source_p, char *mask, int server_oper)
244 {
245 struct Channel *chptr;
246 struct Client *target_p;
247 dlink_node *lp;
248 dlink_node *lp_next;
249 dlink_node *gcptr;
250 dlink_node *gcptr_next;
251 int maxmatches = 500;
252
253 if (!IsOper(source_p))
254 {
255 if ((last_used + ConfigFileEntry.pace_wait) > CurrentTime)
256 {
257 /* safe enough to give this on a local connect only */
258 sendto_one(source_p, form_str(RPL_LOAD2HI),
259 me.name, source_p->name);
260 return;
261 }
262 else
263 last_used = CurrentTime;
264 }
265
266 /* first, list all matching invisible clients on common channels */
267 DLINK_FOREACH_SAFE(lp, lp_next, source_p->channel.head)
268 {
269 chptr = ((struct Membership *)lp->data)->chptr;
270 who_common_channel(source_p, chptr, mask, server_oper, &maxmatches);
271 }
272
273 /* second, list all matching visible clients */
274 DLINK_FOREACH_SAFE(gcptr, gcptr_next, global_client_list.head)
275 {
276 target_p = gcptr->data;
277
278 if (!IsClient(target_p))
279 continue;
280
281 if (IsInvisible(target_p))
282 {
283 ClearMark(target_p);
284 continue;
285 }
286
287 if (server_oper && !IsOper(target_p))
288 continue;
289
290 assert(target_p->servptr != NULL);
291
292 if (!mask ||
293 match(mask, target_p->name) || match(mask, target_p->username) ||
294 match(mask, target_p->host) || match(mask, target_p->servptr->name) ||
295 match(mask, target_p->info))
296 {
297 do_who(source_p, target_p, NULL, "");
298
299 if (maxmatches > 0)
300 {
301 if (--maxmatches == 0)
302 return;
303 }
304 }
305 }
306 }
307
308 /* do_who_on_channel()
309 *
310 * inputs - pointer to client requesting who
311 * - pointer to channel to do who on
312 * - The "real name" of this channel
313 * - int if source_p is a server oper or not
314 * - int if client is member or not
315 * - int server_op flag
316 * output - NONE
317 * side effects - do a who on given channel
318 */
319 static void
320 do_who_on_channel(struct Client *source_p, struct Channel *chptr,
321 const char *chname, int member, int server_oper)
322 {
323 dlink_node *ptr = NULL, *ptr_next = NULL;
324 struct Client *target_p;
325 struct Membership *ms;
326
327 DLINK_FOREACH_SAFE(ptr, ptr_next, chptr->members.head)
328 {
329 ms = ptr->data;
330 target_p = ms->client_p;
331
332 if (member || !IsInvisible(target_p))
333 {
334 if (server_oper && !IsOper(target_p))
335 continue;
336 do_who(source_p, target_p, chname, get_member_status(ms, NO));
337 }
338 }
339 }
340
341 /* do_who()
342 *
343 * inputs - pointer to client requesting who
344 * - pointer to client to do who on
345 * - The reported name
346 * - channel flags
347 * output - NONE
348 * side effects - do a who on given person
349 */
350 static void
351 do_who(struct Client *source_p, struct Client *target_p,
352 const char *chname, const char *op_flags)
353 {
354 char status[6];
355 const char *from, *to;
356
357 if (IsCapable(source_p->from, CAP_TS6) && HasID(source_p))
358 {
359 from = me.id;
360 to = source_p->id;
361 }
362 else
363 {
364 from = me.name;
365 to = source_p->name;
366 }
367
368 if (IsOper(source_p))
369 ircsprintf(status, "%c%s%s%s",
370 target_p->away ? 'G' : 'H',
371 IsOper(target_p) ? "*" : "", IsCaptured(target_p) ? "#" : "", op_flags);
372 else
373 ircsprintf(status, "%c%s%s", target_p->away ? 'G' : 'H',
374 IsOper(target_p) ? "*" : "", op_flags);
375
376 if (ConfigServerHide.hide_servers)
377 {
378 sendto_one(source_p, form_str(RPL_WHOREPLY), from, to,
379 (chname) ? (chname) : "*",
380 target_p->username, target_p->host,
381 IsOper(source_p) ? target_p->servptr->name : "*",
382 target_p->name, status, 0, target_p->info);
383 }
384 else
385 {
386 sendto_one(source_p, form_str(RPL_WHOREPLY), from, to,
387 (chname) ? (chname) : "*",
388 target_p->username,
389 target_p->host, target_p->servptr->name, target_p->name,
390 status, target_p->hopcount, target_p->info);
391 }
392 }
393
394 /*
395 ** ms_who()
396 ** parv[0] = sender prefix
397 ** parv[1] = nickname mask list
398 ** parv[2] = additional selection flag, only 'o' for now.
399 */
400 static void
401 ms_who(struct Client *client_p, struct Client *source_p,
402 int parc, char *parv[])
403 {
404 /* If its running as a hub, and linked with lazy links
405 * then allow leaf to use normal client m_who()
406 * other wise, ignore it.
407 */
408 if (IsClient(source_p) && ServerInfo.hub &&
409 IsCapable(client_p->from, CAP_LL))
410 m_who(client_p, source_p, parc, parv);
411 }

Properties

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