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.
32 #include "ircd_chattr.h"
33 #include "ircd_policy.h"
34 #include "ircd_reply.h"
35 #include "ircd_snprintf.h"
36 #include "ircd_string.h"
41 #include "querycmds.h"
48 #include "sprintf_irc.h"
57 #include <arpa/inet.h> /* inet_ntoa */
66 * The function that actually prints out the WHO reply for a client found
68 void do_who(struct Client* sptr, struct Client* acptr, struct Channel* repchan,
69 int fields, char* qrt)
72 struct Channel *chptr = repchan;
74 static char buf1[512];
75 /* NOTE: with current fields list and sizes this _cannot_ overrun,
76 and also the message finally sent shouldn't ever be truncated */
81 /* If we don't have a channel and we need one... try to find it,
82 unless the listing is for a channel service, we already know
83 that there are no common channels, thus use PubChannel and not
85 if (!chptr && (!fields || (fields & (WHO_FIELD_CHA | WHO_FIELD_FLA))) &&
86 !IsChannelService(acptr))
88 struct Membership* chan;
89 for (chan = cli_user(acptr)->channel; chan && !chptr; chan = chan->next_channel)
90 if (PubChannel(chan->channel) &&
91 (acptr == sptr || !IsZombie(chan)))
92 chptr = chan->channel;
95 /* Place the fields one by one in the buffer and send it
96 note that fields == NULL means "default query" */
98 if (fields & WHO_FIELD_QTY) /* Query type */
104 while ((*qrt) && (*(p1++) = *(qrt++)));
107 if (!fields || (fields & WHO_FIELD_CHA))
111 if ((p2 = (chptr ? chptr->chname : NULL)))
112 while ((*p2) && (*(p1++) = *(p2++)));
117 if (!fields || (fields & WHO_FIELD_UID))
119 char *p2 = cli_user(acptr)->username;
121 while ((*p2) && (*(p1++) = *(p2++)));
124 if (fields & WHO_FIELD_NIP)
126 const char* p2 = ircd_ntoa((const char*) &(cli_ip(acptr)));
128 while ((*p2) && (*(p1++) = *(p2++)));
131 if (!fields || (fields & WHO_FIELD_HOS))
133 char *p2 = cli_user(acptr)->host;
135 while ((*p2) && (*(p1++) = *(p2++)));
138 if (!fields || (fields & WHO_FIELD_SER))
140 char *p2 = cli_name(cli_user(acptr)->server);
142 while ((*p2) && (*(p1++) = *(p2++)));
145 if (!fields || (fields & WHO_FIELD_NIC))
147 char *p2 = cli_name(acptr);
149 while ((*p2) && (*(p1++) = *(p2++)));
152 if (!fields || (fields & WHO_FIELD_FLA))
155 if (cli_user(acptr)->away)
159 if (IsAnOper(acptr) &&
160 (HasPriv(acptr, PRIV_DISPLAY) || HasPriv(sptr, PRIV_SEE_OPERS)))
163 /* If you specified flags then we assume you know how to parse
164 * multiple channel status flags, as this is currently the only
165 * way to know if someone has @'s *and* is +'d.
167 if (chptr && is_chan_op(acptr, chptr))
169 if (chptr && has_voice(acptr, chptr))
171 if (chptr && is_zombie(acptr, chptr))
175 if (chptr && is_chan_op(acptr, chptr))
177 else if (chptr && has_voice(acptr, chptr))
179 else if (chptr && is_zombie(acptr, chptr))
186 if (IsInvisible(acptr))
188 if (SendWallops(acptr))
190 if (SendDebug(acptr))
195 if (!fields || (fields & WHO_FIELD_DIS))
199 *p1++ = ':'; /* Place colon here for default reply */
200 #ifdef HEAD_IN_SAND_WHO_HOPCOUNT
201 strcat(p1, sptr == acptr ? "0" : "3");
204 p1 = sprintf_irc(p1, "%d", cli_hopcount(acptr));
208 if (fields & WHO_FIELD_IDL)
212 p1 = sprintf_irc(p1, "%d", CurrentTime - cli_user(acptr)->last);
219 if (!fields || (fields & WHO_FIELD_REN))
221 char *p2 = cli_info(acptr);
224 *p1++ = ':'; /* Place colon here for special reply */
225 while ((*p2) && (*(p1++) = *(p2++)));
228 /* The first char will always be an useless blank and we
229 need to terminate buf1 */
232 send_reply(sptr, fields ? RPL_WHOSPCRPL : RPL_WHOREPLY, ++p1);
236 count_users(char *mask)
238 struct Client *acptr;
240 char namebuf[USERLEN + HOSTLEN + 2];
241 char ipbuf[USERLEN + 16 + 2];
243 for (acptr = GlobalClientList; acptr; acptr = cli_next(acptr)) {
247 ircd_snprintf(0, namebuf, sizeof(namebuf), "%s@%s",
248 cli_user(acptr)->username, cli_user(acptr)->host);
249 ircd_snprintf(0, ipbuf, sizeof(ipbuf), "%s@%s", cli_user(acptr)->username,
250 ircd_ntoa((const char *) &(cli_ip(acptr))));
252 if (!match(mask, namebuf) || !match(mask, ipbuf))