Remove cruft left behind by removed stats_p_hook.
[seven-1.x.git] / modules / m_who.c
bloba2575f17faa0734c9f3fce17cf005835e63cf478
1 /*
2 * ircd-ratbox: A slightly useful ircd.
3 * m_who.c: Shows who is on a channel.
5 * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
6 * Copyright (C) 1996-2002 Hybrid Development Team
7 * Copyright (C) 2002-2005 ircd-ratbox development team
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 * USA
24 #include "stdinc.h"
25 #include "tools.h"
26 #include "common.h"
27 #include "client.h"
28 #include "channel.h"
29 #include "hash.h"
30 #include "ircd.h"
31 #include "numeric.h"
32 #include "s_serv.h"
33 #include "send.h"
34 #include "irc_string.h"
35 #include "sprintf_irc.h"
36 #include "s_conf.h"
37 #include "s_log.h"
38 #include "msg.h"
39 #include "parse.h"
40 #include "modules.h"
41 #include "packet.h"
42 #include "s_newconf.h"
44 static int m_who(struct Client *, struct Client *, int, const char **);
46 struct Message who_msgtab = {
47 "WHO", 0, 0, 0, MFLG_SLOW,
48 {mg_unreg, {m_who, 2}, mg_ignore, mg_ignore, mg_ignore, {m_who, 2}}
51 mapi_clist_av1 who_clist[] = { &who_msgtab, NULL };
52 DECLARE_MODULE_AV1(who, NULL, NULL, who_clist, NULL, NULL, "$Revision: 111 $");
54 static void do_who_on_channel(struct Client *source_p, struct Channel *chptr,
55 int server_oper, int member);
57 static void who_global(struct Client *source_p, const char *mask, int server_oper, int auspex);
59 static void do_who(struct Client *source_p,
60 struct Client *target_p, const char *chname, const char *op_flags);
64 ** m_who
65 ** parv[0] = sender prefix
66 ** parv[1] = nickname mask list
67 ** parv[2] = additional selection flag, only 'o' for now.
69 static int
70 m_who(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
72 static time_t last_used = 0;
73 struct Client *target_p;
74 struct membership *msptr;
75 char *mask;
76 dlink_node *lp;
77 struct Channel *chptr = NULL;
78 int server_oper = parc > 2 ? (*parv[2] == 'o') : 0; /* Show OPERS only */
79 int member;
80 int auspex = 0;
82 mask = LOCAL_COPY(parv[1]);
84 collapse(mask);
86 /* '/who *' */
87 if((*(mask + 1) == '\0') && (*mask == '*'))
89 if(source_p->user == NULL)
90 return 0;
92 if((lp = source_p->user->channel.head) != NULL)
94 msptr = lp->data;
95 do_who_on_channel(source_p, msptr->chptr, server_oper, YES);
98 sendto_one(source_p, form_str(RPL_ENDOFWHO),
99 me.name, source_p->name, "*");
100 return 0;
103 if(IsAuspex(source_p))
105 auspex = 1;
107 if(EmptyString(mask))
109 sendto_one(source_p, form_str(RPL_ENDOFWHO),
110 me.name, source_p->name, parv[1]);
111 return 0;
115 /* '/who #some_channel' */
116 if(IsChannelName(mask))
118 /* List all users on a given channel */
119 chptr = find_channel(mask);
120 if(chptr != NULL)
122 if(IsMember(source_p, chptr) || auspex)
123 do_who_on_channel(source_p, chptr, server_oper, YES);
124 else if(!SecretChannel(chptr))
125 do_who_on_channel(source_p, chptr, server_oper, NO);
127 sendto_one(source_p, form_str(RPL_ENDOFWHO),
128 me.name, source_p->name, mask);
129 return 0;
132 /* '/who nick' */
134 if(((target_p = find_named_person(mask)) != NULL) &&
135 (!server_oper || IsOper(target_p)))
137 int isinvis = 0;
139 isinvis = IsInvisible(target_p);
140 DLINK_FOREACH(lp, target_p->user->channel.head)
142 msptr = lp->data;
143 chptr = msptr->chptr;
145 member = IsMember(source_p, chptr);
147 if(isinvis && !member)
148 continue;
150 if(member || (!isinvis && PubChannel(chptr)))
151 break;
154 /* if we stopped midlist, lp->data is the membership for
155 * target_p of chptr
157 if(lp != NULL)
158 do_who(source_p, target_p, chptr->chname,
159 find_channel_status(lp->data, IsCapable(source_p, CLICAP_MULTI_PREFIX)));
160 else
161 do_who(source_p, target_p, NULL, "");
163 sendto_one(source_p, form_str(RPL_ENDOFWHO),
164 me.name, source_p->name, mask);
165 return 0;
168 if(!IsFloodDone(source_p))
169 flood_endgrace(source_p);
171 /* it has to be a global who at this point, limit it */
172 if(!IsOper(source_p))
174 if((last_used + ConfigFileEntry.pace_wait) > CurrentTime)
176 sendto_one(source_p, form_str(RPL_LOAD2HI),
177 me.name, source_p->name, "WHO");
178 sendto_one(source_p, form_str(RPL_ENDOFWHO),
179 me.name, source_p->name, "*");
180 return 0;
182 else
183 last_used = CurrentTime;
186 if(IsAuspex(source_p))
187 auspex = 1;
189 /* '/who 0' for a global list. this forces clients to actually
190 * request a full list. I presume its because of too many typos
191 * with "/who" ;) --fl
193 if((*(mask + 1) == '\0') && (*mask == '0'))
194 who_global(source_p, NULL, server_oper, 0);
195 else
196 who_global(source_p, mask, server_oper, auspex);
198 sendto_one(source_p, form_str(RPL_ENDOFWHO),
199 me.name, source_p->name, mask);
201 return 0;
204 /* who_common_channel
205 * inputs - pointer to client requesting who
206 * - pointer to channel member chain.
207 * - char * mask to match
208 * - int if oper on a server or not
209 * - pointer to int maxmatches
210 * output - NONE
211 * side effects - lists matching invisible clients on specified channel,
212 * marks matched clients.
214 static void
215 who_common_channel(struct Client *source_p, struct Channel *chptr,
216 const char *mask, int server_oper, int *maxmatches)
218 struct membership *msptr;
219 struct Client *target_p;
220 dlink_node *ptr;
222 DLINK_FOREACH(ptr, chptr->members.head)
224 msptr = ptr->data;
225 target_p = msptr->client_p;
227 if(!IsInvisible(target_p) || IsMarked(target_p))
228 continue;
230 if(server_oper && !IsOper(target_p))
231 continue;
233 SetMark(target_p);
235 if(*maxmatches > 0)
237 if((mask == NULL) ||
238 match(mask, target_p->name) || match(mask, target_p->username) ||
239 match(mask, target_p->host) || match(mask, target_p->user->server) ||
240 (IsOper(source_p) && match(mask, target_p->orighost)) ||
241 match(mask, target_p->info))
243 do_who(source_p, target_p, NULL, "");
244 --(*maxmatches);
251 * who_global
253 * inputs - pointer to client requesting who
254 * - char * mask to match
255 * - int if oper on a server or not
256 * output - NONE
257 * side effects - do a global scan of all clients looking for match
258 * this is slightly expensive on EFnet ...
259 * marks assumed cleared for all clients initially
260 * and will be left cleared on return
262 static void
263 who_global(struct Client *source_p, const char *mask, int server_oper, int auspex)
265 struct membership *msptr;
266 struct Client *target_p;
267 dlink_node *lp, *ptr;
268 int maxmatches = 500;
270 /* first, list all matching INvisible clients on common channels
271 * if this is not an auspex who
273 if(!auspex)
275 DLINK_FOREACH(lp, source_p->user->channel.head)
277 msptr = lp->data;
278 who_common_channel(source_p, msptr->chptr, mask, server_oper, &maxmatches);
282 /* second, list all matching visible clients and clear all marks
283 * on invisible clients
284 * if this is an auspex who, list all matching clients, no need
285 * to clear marks
287 DLINK_FOREACH(ptr, global_client_list.head)
289 target_p = ptr->data;
290 if(!IsPerson(target_p))
291 continue;
293 if(IsInvisible(target_p) && !auspex)
295 ClearMark(target_p);
296 continue;
299 if(server_oper && !IsOper(target_p))
300 continue;
302 if(maxmatches > 0)
304 if(!mask ||
305 match(mask, target_p->name) || match(mask, target_p->username) ||
306 match(mask, target_p->host) || match(mask, target_p->user->server) ||
307 (IsOper(source_p) && match(mask, target_p->orighost)) ||
308 match(mask, target_p->info))
310 do_who(source_p, target_p, NULL, "");
311 --maxmatches;
316 if (maxmatches <= 0)
317 sendto_one(source_p,
318 form_str(ERR_TOOMANYMATCHES),
319 me.name, source_p->name, "WHO");
323 * do_who_on_channel
325 * inputs - pointer to client requesting who
326 * - pointer to channel to do who on
327 * - The "real name" of this channel
328 * - int if source_p is a server oper or not
329 * - int if client is member or not
330 * output - NONE
331 * side effects - do a who on given channel
333 static void
334 do_who_on_channel(struct Client *source_p, struct Channel *chptr,
335 int server_oper, int member)
337 struct Client *target_p;
338 struct membership *msptr;
339 dlink_node *ptr;
340 int combine = IsCapable(source_p, CLICAP_MULTI_PREFIX);
342 DLINK_FOREACH(ptr, chptr->members.head)
344 msptr = ptr->data;
345 target_p = msptr->client_p;
347 if(server_oper && !IsOper(target_p))
348 continue;
350 if(member || !IsInvisible(target_p))
351 do_who(source_p, target_p, chptr->chname,
352 find_channel_status(msptr, combine));
357 * do_who
359 * inputs - pointer to client requesting who
360 * - pointer to client to do who on
361 * - The reported name
362 * - channel flags
363 * output - NONE
364 * side effects - do a who on given person
367 static void
368 do_who(struct Client *source_p, struct Client *target_p, const char *chname, const char *op_flags)
370 char status[5];
372 ircsprintf(status, "%c%s%s",
373 target_p->user->away ? 'G' : 'H', SeesOper(target_p, source_p) ? "*" : "", op_flags);
375 sendto_one(source_p, form_str(RPL_WHOREPLY), me.name, source_p->name,
376 (chname) ? (chname) : "*",
377 target_p->username,
378 target_p->host, target_p->user->server, target_p->name,
379 status,
380 ConfigServerHide.flatten_links ? 0 : target_p->hopcount,
381 target_p->info);