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

File Contents

# User Rev Content
1 adx 30 /*
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 knight 31 * $Id$
23 adx 30 */
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 adx 268 static time_t last_used = 0;
45    
46 adx 30 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 knight 31 const char *_version = "$Revision$";
68 adx 30 #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 adx 268 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 adx 30 {
222     do_who(source_p, target_p, NULL, "");
223    
224     if (*maxmatches > 0)
225     {
226 adx 268 if (--(*maxmatches) == 0)
227     return;
228 adx 30 }
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 adx 268 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 adx 30 /* 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 adx 268 match(mask, target_p->host) || match(mask, target_p->servptr->name) ||
295     match(mask, target_p->info))
296 adx 30 {
297     do_who(source_p, target_p, NULL, "");
298    
299     if (maxmatches > 0)
300     {
301     if (--maxmatches == 0)
302 adx 268 return;
303 adx 30 }
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 michael 313 dlink_node *ptr = NULL, *ptr_next = NULL;
324 adx 30 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 adx 268 continue;
336 adx 30 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