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
24 * $Id: m_who.c 3350 2007-04-02 22:03:08Z jilles $
35 #include "irc_string.h"
36 #include "sprintf_irc.h"
43 #include "s_newconf.h"
45 static int m_who(struct Client
*, struct Client
*, int, const char **);
47 struct Message who_msgtab
= {
48 "WHO", 0, 0, 0, MFLG_SLOW
,
49 {mg_unreg
, {m_who
, 2}, mg_ignore
, mg_ignore
, mg_ignore
, {m_who
, 2}}
52 mapi_clist_av1 who_clist
[] = { &who_msgtab
, NULL
};
53 DECLARE_MODULE_AV1(who
, NULL
, NULL
, who_clist
, NULL
, NULL
, "$Revision: 3350 $");
55 static void do_who_on_channel(struct Client
*source_p
, struct Channel
*chptr
,
56 int server_oper
, int member
);
58 static void who_global(struct Client
*source_p
, const char *mask
, int server_oper
, int operspy
);
60 static void do_who(struct Client
*source_p
,
61 struct Client
*target_p
, const char *chname
, const char *op_flags
);
66 ** parv[0] = sender prefix
67 ** parv[1] = nickname mask list
68 ** parv[2] = additional selection flag, only 'o' for now.
71 m_who(struct Client
*client_p
, struct Client
*source_p
, int parc
, const char *parv
[])
73 static time_t last_used
= 0;
74 struct Client
*target_p
;
75 struct membership
*msptr
;
78 struct Channel
*chptr
= NULL
;
79 int server_oper
= parc
> 2 ? (*parv
[2] == 'o') : 0; /* Show OPERS only */
83 mask
= LOCAL_COPY(parv
[1]);
88 if((*(mask
+ 1) == '\0') && (*mask
== '*'))
90 if(source_p
->user
== NULL
)
93 if((lp
= source_p
->user
->channel
.head
) != NULL
)
96 do_who_on_channel(source_p
, msptr
->chptr
, server_oper
, YES
);
99 sendto_one(source_p
, form_str(RPL_ENDOFWHO
),
100 me
.name
, source_p
->name
, "*");
104 if(IsOperSpy(source_p
) && *mask
== '!')
109 if(EmptyString(mask
))
111 sendto_one(source_p
, form_str(RPL_ENDOFWHO
),
112 me
.name
, source_p
->name
, parv
[1]);
117 /* '/who #some_channel' */
118 if(IsChannelName(mask
))
120 /* List all users on a given channel */
121 chptr
= find_channel(parv
[1] + operspy
);
125 report_operspy(source_p
, "WHO", chptr
->chname
);
127 if(IsMember(source_p
, chptr
) || operspy
)
128 do_who_on_channel(source_p
, chptr
, server_oper
, YES
);
129 else if(!SecretChannel(chptr
))
130 do_who_on_channel(source_p
, chptr
, server_oper
, NO
);
132 sendto_one(source_p
, form_str(RPL_ENDOFWHO
),
133 me
.name
, source_p
->name
, parv
[1] + operspy
);
139 if(((target_p
= find_named_person(mask
)) != NULL
) &&
140 (!server_oper
|| IsOper(target_p
)))
144 isinvis
= IsInvisible(target_p
);
145 RB_DLINK_FOREACH(lp
, target_p
->user
->channel
.head
)
148 chptr
= msptr
->chptr
;
150 member
= IsMember(source_p
, chptr
);
152 if(isinvis
&& !member
)
155 if(member
|| (!isinvis
&& PubChannel(chptr
)))
159 /* if we stopped midlist, lp->data is the membership for
163 do_who(source_p
, target_p
, chptr
->chname
,
164 find_channel_status(lp
->data
, IsCapable(source_p
, CLICAP_MULTI_PREFIX
)));
166 do_who(source_p
, target_p
, NULL
, "");
168 sendto_one(source_p
, form_str(RPL_ENDOFWHO
),
169 me
.name
, source_p
->name
, mask
);
173 if(!IsFloodDone(source_p
))
174 flood_endgrace(source_p
);
176 /* it has to be a global who at this point, limit it */
177 if(!IsOper(source_p
))
179 if((last_used
+ ConfigFileEntry
.pace_wait
) > rb_current_time())
181 sendto_one(source_p
, form_str(RPL_LOAD2HI
),
182 me
.name
, source_p
->name
, "WHO");
183 sendto_one(source_p
, form_str(RPL_ENDOFWHO
),
184 me
.name
, source_p
->name
, "*");
188 last_used
= rb_current_time();
191 /* Note: operspy_dont_care_user_info does not apply to
193 if(IsOperSpy(source_p
) && ConfigFileEntry
.operspy_dont_care_user_info
)
196 /* '/who 0' for a global list. this forces clients to actually
197 * request a full list. I presume its because of too many typos
198 * with "/who" ;) --fl
200 if((*(mask
+ 1) == '\0') && (*mask
== '0'))
201 who_global(source_p
, NULL
, server_oper
, 0);
203 who_global(source_p
, mask
, server_oper
, operspy
);
205 sendto_one(source_p
, form_str(RPL_ENDOFWHO
),
206 me
.name
, source_p
->name
, mask
);
211 /* who_common_channel
212 * inputs - pointer to client requesting who
213 * - pointer to channel member chain.
214 * - char * mask to match
215 * - int if oper on a server or not
216 * - pointer to int maxmatches
218 * side effects - lists matching invisible clients on specified channel,
219 * marks matched clients.
222 who_common_channel(struct Client
*source_p
, struct Channel
*chptr
,
223 const char *mask
, int server_oper
, int *maxmatches
)
225 struct membership
*msptr
;
226 struct Client
*target_p
;
229 RB_DLINK_FOREACH(ptr
, chptr
->members
.head
)
232 target_p
= msptr
->client_p
;
234 if(!IsInvisible(target_p
) || IsMarked(target_p
))
237 if(server_oper
&& !IsOper(target_p
))
245 match(mask
, target_p
->name
) || match(mask
, target_p
->username
) ||
246 match(mask
, target_p
->host
) || match(mask
, target_p
->servptr
->name
) ||
247 (IsOper(source_p
) && match(mask
, target_p
->orighost
)) ||
248 match(mask
, target_p
->info
))
250 do_who(source_p
, target_p
, NULL
, "");
260 * inputs - pointer to client requesting who
261 * - char * mask to match
262 * - int if oper on a server or not
264 * side effects - do a global scan of all clients looking for match
265 * this is slightly expensive on EFnet ...
266 * marks assumed cleared for all clients initially
267 * and will be left cleared on return
270 who_global(struct Client
*source_p
, const char *mask
, int server_oper
, int operspy
)
272 struct membership
*msptr
;
273 struct Client
*target_p
;
274 rb_dlink_node
*lp
, *ptr
;
275 int maxmatches
= 500;
277 /* first, list all matching INvisible clients on common channels
278 * if this is not an operspy who
282 RB_DLINK_FOREACH(lp
, source_p
->user
->channel
.head
)
285 who_common_channel(source_p
, msptr
->chptr
, mask
, server_oper
, &maxmatches
);
288 else if (!ConfigFileEntry
.operspy_dont_care_user_info
)
289 report_operspy(source_p
, "WHO", mask
);
291 /* second, list all matching visible clients and clear all marks
292 * on invisible clients
293 * if this is an operspy who, list all matching clients, no need
296 RB_DLINK_FOREACH(ptr
, global_client_list
.head
)
298 target_p
= ptr
->data
;
299 if(!IsPerson(target_p
))
302 if(IsInvisible(target_p
) && !operspy
)
308 if(server_oper
&& !IsOper(target_p
))
314 match(mask
, target_p
->name
) || match(mask
, target_p
->username
) ||
315 match(mask
, target_p
->host
) || match(mask
, target_p
->servptr
->name
) ||
316 (IsOper(source_p
) && match(mask
, target_p
->orighost
)) ||
317 match(mask
, target_p
->info
))
319 do_who(source_p
, target_p
, NULL
, "");
327 form_str(ERR_TOOMANYMATCHES
),
328 me
.name
, source_p
->name
, "WHO");
334 * inputs - pointer to client requesting who
335 * - pointer to channel to do who on
336 * - The "real name" of this channel
337 * - int if source_p is a server oper or not
338 * - int if client is member or not
340 * side effects - do a who on given channel
343 do_who_on_channel(struct Client
*source_p
, struct Channel
*chptr
,
344 int server_oper
, int member
)
346 struct Client
*target_p
;
347 struct membership
*msptr
;
349 int combine
= IsCapable(source_p
, CLICAP_MULTI_PREFIX
);
351 RB_DLINK_FOREACH(ptr
, chptr
->members
.head
)
354 target_p
= msptr
->client_p
;
356 if(server_oper
&& !IsOper(target_p
))
359 if(member
|| !IsInvisible(target_p
))
360 do_who(source_p
, target_p
, chptr
->chname
,
361 find_channel_status(msptr
, combine
));
368 * inputs - pointer to client requesting who
369 * - pointer to client to do who on
370 * - The reported name
373 * side effects - do a who on given person
377 do_who(struct Client
*source_p
, struct Client
*target_p
, const char *chname
, const char *op_flags
)
381 rb_sprintf(status
, "%c%s%s",
382 target_p
->user
->away
? 'G' : 'H', IsOper(target_p
) ? "*" : "", op_flags
);
384 sendto_one(source_p
, form_str(RPL_WHOREPLY
), me
.name
, source_p
->name
,
385 (chname
) ? (chname
) : "*",
387 target_p
->host
, target_p
->servptr
->name
, target_p
->name
,
389 ConfigServerHide
.flatten_links
? 0 : target_p
->hopcount
,