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 (12 years, 3 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

# 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
25 #include "stdinc.h"
26 #include "list.h"
27 #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 #include "conf.h"
37 #include "parse.h"
38 #include "modules.h"
39
40
41 /* 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 static void
51 do_who(struct Client *source_p, struct Client *target_p,
52 const char *chname, const char *op_flags)
53 {
54 char status[7]; /* G*@%+\0 */
55
56 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
64 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 else
71 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 }
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 dlink_node *ptr = NULL;
93
94 DLINK_FOREACH(ptr, chptr->members.head)
95 {
96 struct Client *target_p = ((struct Membership *)ptr->data)->client_p;
97
98 if (!HasUMode(target_p, UMODE_INVISIBLE) || HasFlag(target_p, FLAGS_MARK))
99 continue;
100
101 if (server_oper)
102 if (!HasUMode(target_p, UMODE_OPER) ||
103 (HasUMode(target_p, UMODE_HIDDEN) && !HasUMode(source_p, UMODE_OPER)))
104 continue;
105
106 AddFlag(target_p, FLAGS_MARK);
107
108 assert(target_p->servptr != NULL);
109
110 if ((mask == NULL) ||
111 !match(mask, target_p->name) || !match(mask, target_p->username) ||
112 !match(mask, target_p->host) ||
113 ((!ConfigServerHide.hide_servers || HasUMode(source_p, UMODE_OPER)) &&
114 !match(mask, target_p->servptr->name)) ||
115 !match(mask, target_p->info))
116 {
117 do_who(source_p, target_p, NULL, "");
118
119 if (*maxmatches > 0)
120 {
121 if (--(*maxmatches) == 0)
122 return;
123 }
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 dlink_node *lp = NULL, *gcptr = NULL;
143 int maxmatches = 500;
144 static time_t last_used = 0;
145
146 if (!HasUMode(source_p, UMODE_OPER))
147 {
148 if ((last_used + ConfigFileEntry.pace_wait) > CurrentTime)
149 {
150 /* safe enough to give this on a local connect only */
151 sendto_one(source_p, form_str(RPL_LOAD2HI), me.name, source_p->name);
152 return;
153 }
154
155 last_used = CurrentTime;
156 }
157
158 /* first, list all matching invisible clients on common channels */
159 DLINK_FOREACH(lp, source_p->channel.head)
160 {
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 DLINK_FOREACH(gcptr, global_client_list.head)
167 {
168 target_p = gcptr->data;
169
170 if (!IsClient(target_p))
171 continue;
172
173 if (HasUMode(target_p, UMODE_INVISIBLE))
174 {
175 DelFlag(target_p, FLAGS_MARK);
176 continue;
177 }
178
179 if (server_oper)
180 if (!HasUMode(target_p, UMODE_OPER) ||
181 (HasUMode(target_p, UMODE_HIDDEN) && !HasUMode(source_p, UMODE_OPER)))
182 continue;
183
184 assert(target_p->servptr != NULL);
185
186 if (!mask ||
187 !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 {
191 do_who(source_p, target_p, NULL, "");
192
193 if (maxmatches > 0)
194 {
195 if (--maxmatches == 0)
196 return;
197 }
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 dlink_node *ptr = NULL;
218
219 DLINK_FOREACH(ptr, chptr->members.head)
220 {
221 struct Membership *ms = ptr->data;
222 struct Client *target_p = ms->client_p;
223
224 if (member || !HasUMode(target_p, UMODE_INVISIBLE))
225 {
226 if (server_oper)
227 if (!HasUMode(target_p, UMODE_OPER) ||
228 (HasUMode(target_p, UMODE_HIDDEN) && !HasUMode(source_p, UMODE_OPER)))
229 continue;
230 do_who(source_p, target_p, chname, get_member_status(ms, !!HasCap(source_p, CAP_MULTI_PREFIX)));
231 }
232 }
233 }
234
235 /*
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 static void
242 m_who(struct Client *client_p, struct Client *source_p,
243 int parc, char *parv[])
244 {
245 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
251 /* 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
260 /* mask isn't NULL at this point. repeat after me... -db */
261 collapse(mask);
262
263 /* '/who #some_channel' */
264 if (IsChanPrefix(*mask))
265 {
266 /* 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 }
279
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 /* '/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 /* '/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 }
327
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