ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/modules/m_who.c
Revision: 2691
Committed: Tue Dec 17 18:55:59 2013 UTC (10 years, 3 months ago) by michael
Content type: text/x-csrc
File size: 10143 byte(s)
Log Message:
- Avoid magically sized temporary buffers

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 michael 1011
25 adx 30 #include "stdinc.h"
26 michael 1011 #include "list.h"
27 adx 30 #include "client.h"
28     #include "channel.h"
29     #include "channel_mode.h"
30     #include "hash.h"
31     #include "ircd.h"
32     #include "numeric.h"
33     #include "s_serv.h"
34     #include "send.h"
35     #include "irc_string.h"
36 michael 1309 #include "conf.h"
37 adx 30 #include "parse.h"
38     #include "modules.h"
39    
40    
41 michael 2088 /* do_who()
42     *
43     * inputs - pointer to client requesting who
44     * - pointer to client to do who on
45     * - The reported name
46     * - channel flags
47     * output - NONE
48     * side effects - do a who on given person
49     */
50 adx 30 static void
51 michael 2088 do_who(struct Client *source_p, struct Client *target_p,
52     const char *chname, const char *op_flags)
53 adx 30 {
54 michael 2691 char status[IRCD_BUFSIZE];
55 adx 30
56 michael 2088 if (HasUMode(source_p, UMODE_OPER))
57 michael 2549 snprintf(status, sizeof(status), "%c%s%s%s", target_p->away[0] ? 'G' : 'H',
58     HasUMode(target_p, UMODE_REGISTERED) ? "r" : "",
59 michael 2088 HasUMode(target_p, UMODE_OPER) ? "*" : "", op_flags);
60     else
61 michael 2549 snprintf(status, sizeof(status), "%c%s%s%s", target_p->away[0] ? 'G' : 'H',
62     HasUMode(target_p, UMODE_REGISTERED) ? "r" : "",
63 michael 2088 HasUMode(target_p, UMODE_OPER) &&
64     !HasUMode(target_p, UMODE_HIDDEN) ? "*" : "", op_flags);
65 adx 30
66 michael 2088 if (ConfigServerHide.hide_servers)
67     sendto_one(source_p, form_str(RPL_WHOREPLY), me.name, source_p->name,
68     (chname) ? (chname) : "*",
69     target_p->username, target_p->host,
70     HasUMode(source_p, UMODE_OPER) ? target_p->servptr->name : "*",
71     target_p->name, status, 0, target_p->info);
72 adx 30 else
73 michael 2088 sendto_one(source_p, form_str(RPL_WHOREPLY), me.name, source_p->name,
74     (chname) ? (chname) : "*", target_p->username,
75     target_p->host, target_p->servptr->name, target_p->name,
76     status, target_p->hopcount, target_p->info);
77 adx 30 }
78    
79     /* who_common_channel
80     * inputs - pointer to client requesting who
81     * - pointer to channel member chain.
82     * - char * mask to match
83     * - int if oper on a server or not
84     * - pointer to int maxmatches
85     * output - NONE
86     * side effects - lists matching clients on specified channel,
87     * marks matched clients.
88     *
89     */
90     static void
91     who_common_channel(struct Client *source_p, struct Channel *chptr,
92     char *mask, int server_oper, int *maxmatches)
93     {
94 michael 1295 dlink_node *ptr = NULL;
95 adx 30
96     DLINK_FOREACH(ptr, chptr->members.head)
97     {
98 michael 1295 struct Client *target_p = ((struct Membership *)ptr->data)->client_p;
99 adx 30
100 michael 1219 if (!HasUMode(target_p, UMODE_INVISIBLE) || HasFlag(target_p, FLAGS_MARK))
101 adx 30 continue;
102    
103 michael 1295 if (server_oper)
104     if (!HasUMode(target_p, UMODE_OPER) ||
105     (HasUMode(target_p, UMODE_HIDDEN) && !HasUMode(source_p, UMODE_OPER)))
106     continue;
107 adx 30
108 michael 1219 AddFlag(target_p, FLAGS_MARK);
109 adx 30
110     assert(target_p->servptr != NULL);
111    
112     if ((mask == NULL) ||
113 michael 1652 !match(mask, target_p->name) || !match(mask, target_p->username) ||
114     !match(mask, target_p->host) ||
115 michael 1219 ((!ConfigServerHide.hide_servers || HasUMode(source_p, UMODE_OPER)) &&
116 michael 1652 !match(mask, target_p->servptr->name)) ||
117     !match(mask, target_p->info))
118 adx 30 {
119     do_who(source_p, target_p, NULL, "");
120    
121     if (*maxmatches > 0)
122     {
123 adx 268 if (--(*maxmatches) == 0)
124     return;
125 adx 30 }
126     }
127     }
128     }
129    
130     /* who_global()
131     *
132     * inputs - pointer to client requesting who
133     * - char * mask to match
134     * - int if oper on a server or not
135     * output - NONE
136     * side effects - do a global scan of all clients looking for match
137     * this is slightly expensive on EFnet ...
138     */
139     static void
140     who_global(struct Client *source_p, char *mask, int server_oper)
141     {
142     struct Channel *chptr;
143     struct Client *target_p;
144 michael 2091 dlink_node *lp = NULL, *gcptr = NULL;
145 adx 30 int maxmatches = 500;
146 michael 1230 static time_t last_used = 0;
147 adx 30
148 michael 1219 if (!HasUMode(source_p, UMODE_OPER))
149 adx 268 {
150     if ((last_used + ConfigFileEntry.pace_wait) > CurrentTime)
151     {
152     /* safe enough to give this on a local connect only */
153 michael 1834 sendto_one(source_p, form_str(RPL_LOAD2HI), me.name, source_p->name);
154 adx 268 return;
155     }
156 michael 980
157     last_used = CurrentTime;
158 adx 268 }
159    
160 adx 30 /* first, list all matching invisible clients on common channels */
161 michael 2091 DLINK_FOREACH(lp, source_p->channel.head)
162 adx 30 {
163     chptr = ((struct Membership *)lp->data)->chptr;
164     who_common_channel(source_p, chptr, mask, server_oper, &maxmatches);
165     }
166    
167     /* second, list all matching visible clients */
168 michael 2091 DLINK_FOREACH(gcptr, global_client_list.head)
169 adx 30 {
170     target_p = gcptr->data;
171    
172     if (!IsClient(target_p))
173     continue;
174    
175 michael 1219 if (HasUMode(target_p, UMODE_INVISIBLE))
176 adx 30 {
177 michael 1219 DelFlag(target_p, FLAGS_MARK);
178 adx 30 continue;
179     }
180    
181 michael 1295 if (server_oper)
182     if (!HasUMode(target_p, UMODE_OPER) ||
183     (HasUMode(target_p, UMODE_HIDDEN) && !HasUMode(source_p, UMODE_OPER)))
184     continue;
185 adx 30
186     assert(target_p->servptr != NULL);
187    
188     if (!mask ||
189 michael 1652 !match(mask, target_p->name) || !match(mask, target_p->username) ||
190     !match(mask, target_p->host) || !match(mask, target_p->servptr->name) ||
191     !match(mask, target_p->info))
192 adx 30 {
193     do_who(source_p, target_p, NULL, "");
194    
195     if (maxmatches > 0)
196     {
197     if (--maxmatches == 0)
198 adx 268 return;
199 adx 30 }
200     }
201     }
202     }
203    
204     /* do_who_on_channel()
205     *
206     * inputs - pointer to client requesting who
207     * - pointer to channel to do who on
208     * - The "real name" of this channel
209     * - int if source_p is a server oper or not
210     * - int if client is member or not
211     * - int server_op flag
212     * output - NONE
213     * side effects - do a who on given channel
214     */
215     static void
216     do_who_on_channel(struct Client *source_p, struct Channel *chptr,
217     const char *chname, int member, int server_oper)
218     {
219 michael 2091 dlink_node *ptr = NULL;
220 adx 30
221 michael 2091 DLINK_FOREACH(ptr, chptr->members.head)
222 adx 30 {
223 michael 2088 struct Membership *ms = ptr->data;
224     struct Client *target_p = ms->client_p;
225 adx 30
226 michael 1219 if (member || !HasUMode(target_p, UMODE_INVISIBLE))
227 adx 30 {
228 michael 1295 if (server_oper)
229     if (!HasUMode(target_p, UMODE_OPER) ||
230     (HasUMode(target_p, UMODE_HIDDEN) && !HasUMode(source_p, UMODE_OPER)))
231     continue;
232 michael 1146 do_who(source_p, target_p, chname, get_member_status(ms, !!HasCap(source_p, CAP_MULTI_PREFIX)));
233 adx 30 }
234     }
235     }
236    
237 michael 2088 /*
238     ** m_who
239     ** parv[0] = sender prefix
240     ** parv[1] = nickname mask list
241     ** parv[2] = additional selection flag, only 'o' for now.
242     */
243 adx 30 static void
244 michael 2088 m_who(struct Client *client_p, struct Client *source_p,
245     int parc, char *parv[])
246 adx 30 {
247 michael 2088 struct Client *target_p = NULL;
248     struct Channel *chptr = NULL;
249     char *mask = parv[1];
250     dlink_node *lp = NULL;
251     int server_oper = parc > 2 ? (*parv[2] == 'o') : 0; /* Show OPERS only */
252 adx 30
253 michael 2088 /* See if mask is there, collapse it or return if not there */
254     if (EmptyString(mask))
255     {
256     who_global(source_p, mask, server_oper);
257     sendto_one(source_p, form_str(RPL_ENDOFWHO),
258     me.name, source_p->name, "*");
259     return;
260     }
261 adx 30
262 michael 2088 /* mask isn't NULL at this point. repeat after me... -db */
263     collapse(mask);
264    
265     /* '/who #some_channel' */
266     if (IsChanPrefix(*mask))
267 adx 30 {
268 michael 2088 /* List all users on a given channel */
269     if ((chptr = hash_find_channel(mask)) != NULL)
270     {
271     if (IsMember(source_p, chptr))
272     do_who_on_channel(source_p, chptr, chptr->chname, 1, server_oper);
273     else if (!SecretChannel(chptr))
274     do_who_on_channel(source_p, chptr, chptr->chname, 0, server_oper);
275     }
276    
277     sendto_one(source_p, form_str(RPL_ENDOFWHO),
278     me.name, source_p->name, mask);
279     return;
280 adx 30 }
281 michael 2088
282     /* '/who nick' */
283     if (((target_p = hash_find_client(mask)) != NULL) &&
284     IsClient(target_p) && (!server_oper || HasUMode(target_p, UMODE_OPER)))
285     {
286     DLINK_FOREACH(lp, target_p->channel.head)
287     {
288     chptr = ((struct Membership *) lp->data)->chptr;
289     if (PubChannel(chptr) || IsMember(source_p, chptr))
290     break;
291     }
292    
293     if (lp != NULL)
294     do_who(source_p, target_p, chptr->chname,
295     get_member_status(lp->data, !!HasCap(source_p, CAP_MULTI_PREFIX)));
296     else
297     do_who(source_p, target_p, NULL, "");
298    
299     sendto_one(source_p, form_str(RPL_ENDOFWHO),
300     me.name, source_p->name, mask);
301     return;
302     }
303    
304 michael 2091 /* '/who *' */
305     if (!strcmp(mask, "*"))
306     {
307     if ((lp = source_p->channel.head) != NULL)
308     {
309     struct Channel *mychannel = ((struct Membership *)lp->data)->chptr;
310     do_who_on_channel(source_p, mychannel, mychannel->chname, 1,
311     server_oper);
312     }
313    
314     sendto_one(source_p, form_str(RPL_ENDOFWHO),
315     me.name, source_p->name, "*");
316     return;
317     }
318    
319 michael 2088 /* '/who 0' */
320     if (!strcmp(mask, "0"))
321     who_global(source_p, NULL, server_oper);
322     else
323     who_global(source_p, mask, server_oper);
324    
325     /* Wasn't a nick, wasn't a channel, wasn't a '*' so ... */
326     sendto_one(source_p, form_str(RPL_ENDOFWHO),
327     me.name, source_p->name, mask);
328 adx 30 }
329 michael 1230
330     static struct Message who_msgtab = {
331     "WHO", 0, 0, 2, MAXPARA, MFLG_SLOW, 0,
332     {m_unregistered, m_who, m_ignore, m_ignore, m_who, m_ignore}
333     };
334    
335     static void
336     module_init(void)
337     {
338     mod_add_cmd(&who_msgtab);
339     }
340    
341     static void
342     module_exit(void)
343     {
344     mod_del_cmd(&who_msgtab);
345     }
346    
347     struct module module_entry = {
348     .node = { NULL, NULL, NULL },
349     .name = NULL,
350     .version = "$Revision$",
351     .handle = NULL,
352     .modinit = module_init,
353     .modexit = module_exit,
354     .flags = 0
355     };

Properties

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