]>
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 2005/09/27 03:59:55 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
89 chan
= find_channel_member(acptr
, repchan
);
90 else if ((!fields
|| (fields
& (WHO_FIELD_CHA
| WHO_FIELD_FLA
)))
91 && !IsChannelService(acptr
) && !IsNoChan(acptr
))
93 for (chan
= cli_user(acptr
)->channel
; chan
; chan
= chan
->next_channel
)
94 if (PubChannel(chan
->channel
) &&
95 (acptr
== sptr
|| !IsZombie(chan
)))
99 /* Place the fields one by one in the buffer and send it
100 note that fields == NULL means "default query" */
102 if (fields
& WHO_FIELD_QTY
) /* Query type */
108 while ((*qrt
) && (*(p1
++) = *(qrt
++)));
111 if (!fields
|| (fields
& WHO_FIELD_CHA
))
115 if ((p2
= (chan
? chan
->channel
->chname
: NULL
)))
116 while ((*p2
) && (*(p1
++) = *(p2
++)));
121 if (!fields
|| (fields
& WHO_FIELD_UID
))
123 char *p2
= cli_user(acptr
)->username
;
125 while ((*p2
) && (*(p1
++) = *(p2
++)));
128 if (fields
& WHO_FIELD_NIP
)
130 const char* p2
= (HasHiddenHost(acptr
) || HasSetHost(acptr
)) && !IsAnOper(sptr
) ?
131 feature_str(FEAT_HIDDEN_IP
) :
132 ircd_ntoa(&cli_ip(acptr
));
134 while ((*p2
) && (*(p1
++) = *(p2
++)));
137 if (!fields
|| (fields
& WHO_FIELD_HOS
))
139 char *p2
= cli_user(acptr
)->host
;
141 while ((*p2
) && (*(p1
++) = *(p2
++)));
144 if (!fields
|| (fields
& WHO_FIELD_SER
))
146 const char *p2
= (feature_bool(FEAT_HIS_WHO_SERVERNAME
) && !IsAnOper(sptr
)) ?
147 feature_str(FEAT_HIS_SERVERNAME
) :
148 cli_name(cli_user(acptr
)->server
);
150 while ((*p2
) && (*(p1
++) = *(p2
++)));
153 if (!fields
|| (fields
& WHO_FIELD_NIC
))
155 char *p2
= cli_name(acptr
);
157 while ((*p2
) && (*(p1
++) = *(p2
++)));
160 if (!fields
|| (fields
& WHO_FIELD_FLA
))
163 if (cli_user(acptr
)->away
)
167 if SeeOper(sptr
,acptr
)
170 /* No flags possible for the channel, so skip them all. */
173 /* If you specified flags then we assume you know how to parse
174 * multiple channel status flags, as this is currently the only
175 * way to know if someone has @'s *and* is +'d.
183 if (IsDelayedJoin(chan
))
189 else if (HasVoice(chan
))
191 else if (IsZombie(chan
))
193 else if (IsDelayedJoin(chan
))
200 if (IsInvisible(acptr
))
202 if (SendWallops(acptr
))
204 if (SendDebug(acptr
))
206 if (HasSetHost(acptr
))
209 if (HasHiddenHost(acptr
))
213 if (!fields
|| (fields
& WHO_FIELD_DIS
))
217 *p1
++ = ':'; /* Place colon here for default reply */
218 if (feature_bool(FEAT_HIS_WHO_HOPCOUNT
) && !IsAnOper(sptr
))
219 *p1
++ = (sptr
== acptr
) ? '0' : '3';
221 /* three digit hopcount maximum */
222 p1
+= ircd_snprintf(0, p1
, 3, "%d", cli_hopcount(acptr
));
225 if (fields
& WHO_FIELD_IDL
)
229 (IsAnOper(sptr
) || !feature_bool(FEAT_HIS_WHO_SERVERNAME
) ||
231 p1
+= ircd_snprintf(0, p1
, 11, "%d",
232 CurrentTime
- cli_user(acptr
)->last
);
237 if (fields
& WHO_FIELD_ACC
)
239 char *p2
= cli_user(acptr
)->account
;
242 while ((*p2
) && (*(p1
++) = *(p2
++)));
247 if (!fields
|| (fields
& WHO_FIELD_REN
))
249 char *p2
= cli_info(acptr
);
252 *p1
++ = ':'; /* Place colon here for special reply */
253 while ((*p2
) && (*(p1
++) = *(p2
++)));
256 /* The first char will always be an useless blank and we
257 need to terminate buf1 */
260 send_reply(sptr
, fields
? RPL_WHOSPCRPL
: RPL_WHOREPLY
, ++p1
);
263 /** Count number of users who match \a mask.
264 * @param[in] mask user\@host or user\@ip mask to check.
265 * @return Count of matching users.
268 count_users(char *mask
)
270 struct Client
*acptr
;
272 char namebuf
[NICKLEN
+ USERLEN
+ HOSTLEN
+ 3];
273 char ipbuf
[USERLEN
+ 16 + 2];
275 for (acptr
= GlobalClientList
; acptr
; acptr
= cli_next(acptr
)) {
279 ircd_snprintf(0, namebuf
, sizeof(namebuf
), "%s!%s@%s", cli_name(acptr
),
280 cli_user(acptr
)->username
, cli_user(acptr
)->host
);
281 ircd_snprintf(0, ipbuf
, sizeof(ipbuf
), "%s!%s@%s", cli_name(acptr
),
282 cli_user(acptr
)->username
, ircd_ntoa(&(cli_ip(acptr
))));
284 if (!match(mask
, namebuf
) || !match(mask
, ipbuf
))