ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/modules/m_who.c
Revision: 2091
Committed: Sat May 18 18:46:39 2013 UTC (13 years, 4 months ago) by michael
Content type: text/x-csrc
File size: 10018 byte(s)
Log Message:
- m_who.c: replaced several DLINK_FOREACH_SAFE with a simple DLINK_FOREACH

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

Properties

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