/[svn]/ircd-hybrid/trunk/modules/m_who.c
ViewVC logotype

Contents of /ircd-hybrid/trunk/modules/m_who.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2691 - (show annotations)
Tue Dec 17 18:55:59 2013 UTC (8 years, 8 months ago) by michael
File MIME type: text/x-chdr
File size: 10143 byte(s)
- Avoid magically sized temporary buffers

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[IRCD_BUFSIZE];
55
56 if (HasUMode(source_p, UMODE_OPER))
57 snprintf(status, sizeof(status), "%c%s%s%s", target_p->away[0] ? 'G' : 'H',
58 HasUMode(target_p, UMODE_REGISTERED) ? "r" : "",
59 HasUMode(target_p, UMODE_OPER) ? "*" : "", op_flags);
60 else
61 snprintf(status, sizeof(status), "%c%s%s%s", target_p->away[0] ? 'G' : 'H',
62 HasUMode(target_p, UMODE_REGISTERED) ? "r" : "",
63 HasUMode(target_p, UMODE_OPER) &&
64 !HasUMode(target_p, UMODE_HIDDEN) ? "*" : "", op_flags);
65
66 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 else
73 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 }
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 dlink_node *ptr = NULL;
95
96 DLINK_FOREACH(ptr, chptr->members.head)
97 {
98 struct Client *target_p = ((struct Membership *)ptr->data)->client_p;
99
100 if (!HasUMode(target_p, UMODE_INVISIBLE) || HasFlag(target_p, FLAGS_MARK))
101 continue;
102
103 if (server_oper)
104 if (!HasUMode(target_p, UMODE_OPER) ||
105 (HasUMode(target_p, UMODE_HIDDEN) && !HasUMode(source_p, UMODE_OPER)))
106 continue;
107
108 AddFlag(target_p, FLAGS_MARK);
109
110 assert(target_p->servptr != NULL);
111
112 if ((mask == NULL) ||
113 !match(mask, target_p->name) || !match(mask, target_p->username) ||
114 !match(mask, target_p->host) ||
115 ((!ConfigServerHide.hide_servers || HasUMode(source_p, UMODE_OPER)) &&
116 !match(mask, target_p->servptr->name)) ||
117 !match(mask, target_p->info))
118 {
119 do_who(source_p, target_p, NULL, "");
120
121 if (*maxmatches > 0)
122 {
123 if (--(*maxmatches) == 0)
124 return;
125 }
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 dlink_node *lp = NULL, *gcptr = NULL;
145 int maxmatches = 500;
146 static time_t last_used = 0;
147
148 if (!HasUMode(source_p, UMODE_OPER))
149 {
150 if ((last_used + ConfigFileEntry.pace_wait) > CurrentTime)
151 {
152 /* safe enough to give this on a local connect only */
153 sendto_one(source_p, form_str(RPL_LOAD2HI), me.name, source_p->name);
154 return;
155 }
156
157 last_used = CurrentTime;
158 }
159
160 /* first, list all matching invisible clients on common channels */
161 DLINK_FOREACH(lp, source_p->channel.head)
162 {
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 DLINK_FOREACH(gcptr, global_client_list.head)
169 {
170 target_p = gcptr->data;
171
172 if (!IsClient(target_p))
173 continue;
174
175 if (HasUMode(target_p, UMODE_INVISIBLE))
176 {
177 DelFlag(target_p, FLAGS_MARK);
178 continue;
179 }
180
181 if (server_oper)
182 if (!HasUMode(target_p, UMODE_OPER) ||
183 (HasUMode(target_p, UMODE_HIDDEN) && !HasUMode(source_p, UMODE_OPER)))
184 continue;
185
186 assert(target_p->servptr != NULL);
187
188 if (!mask ||
189 !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 {
193 do_who(source_p, target_p, NULL, "");
194
195 if (maxmatches > 0)
196 {
197 if (--maxmatches == 0)
198 return;
199 }
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 dlink_node *ptr = NULL;
220
221 DLINK_FOREACH(ptr, chptr->members.head)
222 {
223 struct Membership *ms = ptr->data;
224 struct Client *target_p = ms->client_p;
225
226 if (member || !HasUMode(target_p, UMODE_INVISIBLE))
227 {
228 if (server_oper)
229 if (!HasUMode(target_p, UMODE_OPER) ||
230 (HasUMode(target_p, UMODE_HIDDEN) && !HasUMode(source_p, UMODE_OPER)))
231 continue;
232 do_who(source_p, target_p, chname, get_member_status(ms, !!HasCap(source_p, CAP_MULTI_PREFIX)));
233 }
234 }
235 }
236
237 /*
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 static void
244 m_who(struct Client *client_p, struct Client *source_p,
245 int parc, char *parv[])
246 {
247 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
253 /* 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
262 /* mask isn't NULL at this point. repeat after me... -db */
263 collapse(mask);
264
265 /* '/who #some_channel' */
266 if (IsChanPrefix(*mask))
267 {
268 /* 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 }
281
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 /* '/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 /* '/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 }
329
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

svnadmin@ircd-hybrid.org
ViewVC Help
Powered by ViewVC 1.1.28