]> jfr.im git - irc/quakenet/snircd.git/blob - ircd/whocmds.c
Update my e-mail address.
[irc/quakenet/snircd.git] / ircd / whocmds.c
1 /*
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
5 *
6 * See file AUTHORS in IRC package for additional names of
7 * the programmers.
8 *
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)
12 * any later version.
13 *
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.
18 *
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.
22 */
23 /** @file
24 * @brief Support functions for /WHO-like commands.
25 * @version $Id: whocmds.c,v 1.25.2.2 2007/03/04 14:55:31 entrope Exp $
26 */
27 #include "config.h"
28
29 #include "whocmds.h"
30 #include "channel.h"
31 #include "client.h"
32 #include "hash.h"
33 #include "ircd.h"
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"
39 #include "list.h"
40 #include "match.h"
41 #include "numeric.h"
42 #include "numnicks.h"
43 #include "querycmds.h"
44 #include "random.h"
45 #include "s_bsd.h"
46 #include "s_conf.h"
47 #include "s_misc.h"
48 #include "s_user.h"
49 #include "send.h"
50 #include "struct.h"
51 #include "sys.h"
52 #include "userload.h"
53 #include "version.h"
54 #include "whowas.h"
55 #include "msg.h"
56
57 #include <fcntl.h>
58 #include <stdio.h>
59 #include <stdlib.h>
60 #include <string.h>
61 #include <sys/stat.h>
62 #include <unistd.h>
63
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).
70 */
71 void do_who(struct Client* sptr, struct Client* acptr, struct Channel* repchan,
72 int fields, char* qrt)
73 {
74 char *p1;
75 struct Membership *chan = 0;
76
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 */
80
81 p1 = buf1;
82 buf1[1] = '\0';
83
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
87 SeeChannel */
88 if (repchan)
89 {
90 chan = find_channel_member(acptr, repchan);
91 }
92 else if ((!fields || (fields & (WHO_FIELD_CHA | WHO_FIELD_FLA)))
93 && !IsChannelService(acptr) && !IsNoChan(acptr))
94 {
95 for (chan = cli_user(acptr)->channel; chan; chan = chan->next_channel)
96 if (PubChannel(chan->channel) &&
97 (acptr == sptr || !IsZombie(chan)))
98 break;
99 }
100
101 /* Place the fields one by one in the buffer and send it
102 note that fields == NULL means "default query" */
103
104 if (fields & WHO_FIELD_QTY) /* Query type */
105 {
106 *(p1++) = ' ';
107 if (BadPtr(qrt))
108 *(p1++) = '0';
109 else
110 while ((*qrt) && (*(p1++) = *(qrt++)));
111 }
112
113 if (!fields || (fields & WHO_FIELD_CHA))
114 {
115 char *p2;
116 *(p1++) = ' ';
117 if ((p2 = (chan ? chan->channel->chname : NULL)))
118 while ((*p2) && (*(p1++) = *(p2++)));
119 else
120 *(p1++) = '*';
121 }
122
123 if (!fields || (fields & WHO_FIELD_UID))
124 {
125 char *p2 = cli_user(acptr)->username;
126 *(p1++) = ' ';
127 while ((*p2) && (*(p1++) = *(p2++)));
128 }
129
130 if (fields & WHO_FIELD_NIP)
131 {
132 const char* p2 = (HasHiddenHost(acptr) || HasSetHost(acptr)) && !IsAnOper(sptr) ?
133 feature_str(FEAT_HIDDEN_IP) :
134 ircd_ntoa(&cli_ip(acptr));
135 *(p1++) = ' ';
136 while ((*p2) && (*(p1++) = *(p2++)));
137 }
138
139 if (!fields || (fields & WHO_FIELD_HOS))
140 {
141 char *p2 = cli_user(acptr)->host;
142 *(p1++) = ' ';
143 while ((*p2) && (*(p1++) = *(p2++)));
144 }
145
146 if (!fields || (fields & WHO_FIELD_SER))
147 {
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);
151 *(p1++) = ' ';
152 while ((*p2) && (*(p1++) = *(p2++)));
153 }
154
155 if (!fields || (fields & WHO_FIELD_NIC))
156 {
157 char *p2 = cli_name(acptr);
158 *(p1++) = ' ';
159 while ((*p2) && (*(p1++) = *(p2++)));
160 }
161
162 if (!fields || (fields & WHO_FIELD_FLA))
163 {
164 *(p1++) = ' ';
165 if (cli_user(acptr)->away)
166 *(p1++) = 'G';
167 else
168 *(p1++) = 'H';
169 if SeeOper(sptr,acptr)
170 *(p1++) = '*';
171 if (!chan) {
172 /* No flags possible for the channel, so skip them all. */
173 }
174 else if (fields) {
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.
178 */
179 if (IsChanOp(chan))
180 *(p1++) = '@';
181 if (HasVoice(chan))
182 *(p1++) = '+';
183 if (IsZombie(chan))
184 *(p1++) = '!';
185 if (IsDelayedJoin(chan))
186 *(p1++) = '<';
187 }
188 else {
189 if (IsChanOp(chan))
190 *(p1++) = '@';
191 else if (HasVoice(chan))
192 *(p1++) = '+';
193 else if (IsZombie(chan))
194 *(p1++) = '!';
195 else if (IsDelayedJoin(chan))
196 *(p1++) = '<';
197 }
198 if (IsDeaf(acptr))
199 *(p1++) = 'd';
200 if (IsAnOper(sptr))
201 {
202 if (IsInvisible(acptr))
203 *(p1++) = 'i';
204 if (SendWallops(acptr))
205 *(p1++) = 'w';
206 if (SendDebug(acptr))
207 *(p1++) = 'g';
208 if (HasSetHost(acptr))
209 *(p1++) = 'h';
210 }
211 if (HasHiddenHost(acptr))
212 *(p1++) = 'x';
213 }
214
215 if (!fields || (fields & WHO_FIELD_DIS))
216 {
217 *p1++ = ' ';
218 if (!fields)
219 *p1++ = ':'; /* Place colon here for default reply */
220 if (feature_bool(FEAT_HIS_WHO_HOPCOUNT) && !IsAnOper(sptr))
221 *p1++ = (sptr == acptr) ? '0' : '3';
222 else
223 /* three digit hopcount maximum */
224 p1 += ircd_snprintf(0, p1, 3, "%d", cli_hopcount(acptr));
225 }
226
227 if (fields & WHO_FIELD_IDL)
228 {
229 *p1++ = ' ';
230 if (MyUser(acptr) &&
231 (IsAnOper(sptr) || !feature_bool(FEAT_HIS_WHO_SERVERNAME) ||
232 acptr == sptr))
233 p1 += ircd_snprintf(0, p1, 11, "%d",
234 CurrentTime - cli_user(acptr)->last);
235 else
236 *p1++ = '0';
237 }
238
239 if (fields & WHO_FIELD_ACC)
240 {
241 char *p2 = cli_user(acptr)->account;
242 *(p1++) = ' ';
243 if (*p2)
244 while ((*p2) && (*(p1++) = *(p2++)));
245 else
246 *(p1++) = '0';
247 }
248
249 if (fields & WHO_FIELD_OPL)
250 {
251 if (!chan || !IsChanOp(chan))
252 {
253 strcpy(p1, " n/a");
254 p1 += 4;
255 }
256 else
257 {
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);
263 }
264 }
265
266 if (!fields || (fields & WHO_FIELD_REN))
267 {
268 char *p2 = cli_info(acptr);
269 *p1++ = ' ';
270 if (fields)
271 *p1++ = ':'; /* Place colon here for special reply */
272 while ((*p2) && (*(p1++) = *(p2++)));
273 }
274
275 /* The first char will always be an useless blank and we
276 need to terminate buf1 */
277 *p1 = '\0';
278 p1 = buf1;
279 send_reply(sptr, fields ? RPL_WHOSPCRPL : RPL_WHOREPLY, ++p1);
280 }
281
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.
285 */
286 int
287 count_users(char *mask)
288 {
289 struct Client *acptr;
290 int count = 0;
291 char namebuf[NICKLEN + USERLEN + HOSTLEN + 3];
292 char ipbuf[NICKLEN + USERLEN + SOCKIPLEN + 3];
293
294 for (acptr = GlobalClientList; acptr; acptr = cli_next(acptr)) {
295 if (!IsUser(acptr))
296 continue;
297
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))));
302
303 if (!match(mask, namebuf) || !match(mask, ipbuf))
304 count++;
305 }
306
307 return count;
308 }