]>
jfr.im git - irc/quakenet/snircd.git/blob - ircd/whocmds.c
2 * IRC - Internet Relay Chat, ircd/s_user.c (formerly ircd/s_msg.c)
3 * Copyright (C) 1990 Jarkko Oikarinen and
4 * University of Oulu, Computing Center
6 * See file AUTHORS in IRC package for additional names of
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 1, or (at your option)
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., 675 Mass Ave, Cambridge, MA 02139, USA.
24 * @brief Support functions for /WHO-like commands.
25 * @version $Id: whocmds.c,v 1.25.2.1 2006/11/04 21:35:28 entrope Exp $
34 #include "ircd_chattr.h"
35 #include "ircd_features.h"
36 #include "ircd_reply.h"
37 #include "ircd_snprintf.h"
38 #include "ircd_string.h"
43 #include "querycmds.h"
64 /** Send a WHO reply to a client who asked.
65 * @param[in] sptr Client who is searching for other users.
66 * @param[in] acptr Client who may be shown to \a sptr.
67 * @param[in] repchan Shared channel that provides visibility.
68 * @param[in] fields Bitmask of WHO_FIELD_* values, indicating what to show.
69 * @param[in] qrt Query type string (ignored unless \a fields & WHO_FIELD_QTY).
71 void do_who(struct Client
* sptr
, struct Client
* acptr
, struct Channel
* repchan
,
72 int fields
, char* qrt
)
75 struct Membership
*chan
= 0;
77 static char buf1
[512];
78 /* NOTE: with current fields list and sizes this _cannot_ overrun,
79 and also the message finally sent shouldn't ever be truncated */
84 /* If we don't have a channel and we need one... try to find it,
85 unless the listing is for a channel service, we already know
86 that there are no common channels, thus use PubChannel and not
90 chan
= find_channel_member(acptr
, repchan
);
92 else if ((!fields
|| (fields
& (WHO_FIELD_CHA
| WHO_FIELD_FLA
)))
93 && !IsChannelService(acptr
) && !IsNoChan(acptr
))
95 for (chan
= cli_user(acptr
)->channel
; chan
; chan
= chan
->next_channel
)
96 if (PubChannel(chan
->channel
) &&
97 (acptr
== sptr
|| !IsZombie(chan
)))
101 /* Place the fields one by one in the buffer and send it
102 note that fields == NULL means "default query" */
104 if (fields
& WHO_FIELD_QTY
) /* Query type */
110 while ((*qrt
) && (*(p1
++) = *(qrt
++)));
113 if (!fields
|| (fields
& WHO_FIELD_CHA
))
117 if ((p2
= (chan
? chan
->channel
->chname
: NULL
)))
118 while ((*p2
) && (*(p1
++) = *(p2
++)));
123 if (!fields
|| (fields
& WHO_FIELD_UID
))
125 char *p2
= cli_user(acptr
)->username
;
127 while ((*p2
) && (*(p1
++) = *(p2
++)));
130 if (fields
& WHO_FIELD_NIP
)
132 const char* p2
= (HasHiddenHost(acptr
) || HasSetHost(acptr
)) && !IsAnOper(sptr
) ?
133 feature_str(FEAT_HIDDEN_IP
) :
134 ircd_ntoa(&cli_ip(acptr
));
136 while ((*p2
) && (*(p1
++) = *(p2
++)));
139 if (!fields
|| (fields
& WHO_FIELD_HOS
))
141 char *p2
= cli_user(acptr
)->host
;
143 while ((*p2
) && (*(p1
++) = *(p2
++)));
146 if (!fields
|| (fields
& WHO_FIELD_SER
))
148 const char *p2
= (feature_bool(FEAT_HIS_WHO_SERVERNAME
) && !IsAnOper(sptr
)) ?
149 feature_str(FEAT_HIS_SERVERNAME
) :
150 cli_name(cli_user(acptr
)->server
);
152 while ((*p2
) && (*(p1
++) = *(p2
++)));
155 if (!fields
|| (fields
& WHO_FIELD_NIC
))
157 char *p2
= cli_name(acptr
);
159 while ((*p2
) && (*(p1
++) = *(p2
++)));
162 if (!fields
|| (fields
& WHO_FIELD_FLA
))
165 if (cli_user(acptr
)->away
)
169 if SeeOper(sptr
,acptr
)
172 /* No flags possible for the channel, so skip them all. */
175 /* If you specified flags then we assume you know how to parse
176 * multiple channel status flags, as this is currently the only
177 * way to know if someone has @'s *and* is +'d.
185 if (IsDelayedJoin(chan
))
191 else if (HasVoice(chan
))
193 else if (IsZombie(chan
))
195 else if (IsDelayedJoin(chan
))
202 if (IsInvisible(acptr
))
204 if (SendWallops(acptr
))
206 if (SendDebug(acptr
))
208 if (HasSetHost(acptr
))
211 if (HasHiddenHost(acptr
))
215 if (!fields
|| (fields
& WHO_FIELD_DIS
))
219 *p1
++ = ':'; /* Place colon here for default reply */
220 if (feature_bool(FEAT_HIS_WHO_HOPCOUNT
) && !IsAnOper(sptr
))
221 *p1
++ = (sptr
== acptr
) ? '0' : '3';
223 /* three digit hopcount maximum */
224 p1
+= ircd_snprintf(0, p1
, 3, "%d", cli_hopcount(acptr
));
227 if (fields
& WHO_FIELD_IDL
)
231 (IsAnOper(sptr
) || !feature_bool(FEAT_HIS_WHO_SERVERNAME
) ||
233 p1
+= ircd_snprintf(0, p1
, 11, "%d",
234 CurrentTime
- cli_user(acptr
)->last
);
239 if (fields
& WHO_FIELD_ACC
)
241 char *p2
= cli_user(acptr
)->account
;
244 while ((*p2
) && (*(p1
++) = *(p2
++)));
249 if (fields
& WHO_FIELD_OPL
)
251 if (!chan
|| !IsChanOp(chan
))
258 int vis_level
= MAXOPLEVEL
;
259 if ((IsGlobalChannel(chan
->channel
->chname
) ? IsOper(sptr
) : IsAnOper(sptr
))
260 || is_chan_op(sptr
, chan
->channel
))
261 vis_level
= OpLevel(chan
);
262 p1
+= ircd_snprintf(0, p1
, 5, " %d", vis_level
);
266 if (!fields
|| (fields
& WHO_FIELD_REN
))
268 char *p2
= cli_info(acptr
);
271 *p1
++ = ':'; /* Place colon here for special reply */
272 while ((*p2
) && (*(p1
++) = *(p2
++)));
275 /* The first char will always be an useless blank and we
276 need to terminate buf1 */
279 send_reply(sptr
, fields
? RPL_WHOSPCRPL
: RPL_WHOREPLY
, ++p1
);
282 /** Count number of users who match \a mask.
283 * @param[in] mask user\@host or user\@ip mask to check.
284 * @return Count of matching users.
287 count_users(char *mask
)
289 struct Client
*acptr
;
291 char namebuf
[NICKLEN
+ USERLEN
+ HOSTLEN
+ 3];
292 char ipbuf
[NICKLEN
+ USERLEN
+ 16 + 3];
294 for (acptr
= GlobalClientList
; acptr
; acptr
= cli_next(acptr
)) {
298 ircd_snprintf(0, namebuf
, sizeof(namebuf
), "%s!%s@%s", cli_name(acptr
),
299 cli_user(acptr
)->username
, cli_user(acptr
)->host
);
300 ircd_snprintf(0, ipbuf
, sizeof(ipbuf
), "%s!%s@%s", cli_name(acptr
),
301 cli_user(acptr
)->username
, ircd_ntoa(&(cli_ip(acptr
))));
303 if (!match(mask
, namebuf
) || !match(mask
, ipbuf
))