]>
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
))
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
) && !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
))
207 if (HasHiddenHost(acptr
))
211 if (!fields
|| (fields
& WHO_FIELD_DIS
))
215 *p1
++ = ':'; /* Place colon here for default reply */
216 if (feature_bool(FEAT_HIS_WHO_HOPCOUNT
) && !IsAnOper(sptr
))
217 *p1
++ = (sptr
== acptr
) ? '0' : '3';
219 /* three digit hopcount maximum */
220 p1
+= ircd_snprintf(0, p1
, 3, "%d", cli_hopcount(acptr
));
223 if (fields
& WHO_FIELD_IDL
)
227 (IsAnOper(sptr
) || !feature_bool(FEAT_HIS_WHO_SERVERNAME
) ||
229 p1
+= ircd_snprintf(0, p1
, 11, "%d",
230 CurrentTime
- cli_user(acptr
)->last
);
235 if (fields
& WHO_FIELD_ACC
)
237 char *p2
= cli_user(acptr
)->account
;
240 while ((*p2
) && (*(p1
++) = *(p2
++)));
245 if (!fields
|| (fields
& WHO_FIELD_REN
))
247 char *p2
= cli_info(acptr
);
250 *p1
++ = ':'; /* Place colon here for special reply */
251 while ((*p2
) && (*(p1
++) = *(p2
++)));
254 /* The first char will always be an useless blank and we
255 need to terminate buf1 */
258 send_reply(sptr
, fields
? RPL_WHOSPCRPL
: RPL_WHOREPLY
, ++p1
);
261 /** Count number of users who match \a mask.
262 * @param[in] mask user\@host or user\@ip mask to check.
263 * @return Count of matching users.
266 count_users(char *mask
)
268 struct Client
*acptr
;
270 char namebuf
[USERLEN
+ HOSTLEN
+ 2];
271 char ipbuf
[USERLEN
+ 16 + 2];
273 for (acptr
= GlobalClientList
; acptr
; acptr
= cli_next(acptr
)) {
277 ircd_snprintf(0, namebuf
, sizeof(namebuf
), "%s@%s",
278 cli_user(acptr
)->username
, cli_user(acptr
)->host
);
279 ircd_snprintf(0, ipbuf
, sizeof(ipbuf
), "%s@%s", cli_user(acptr
)->username
,
280 ircd_ntoa(&cli_ip(acptr
)));
282 if (!match(mask
, namebuf
) || !match(mask
, ipbuf
))