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.
30 #include "ircd_chattr.h"
31 #include "ircd_reply.h"
32 #include "ircd_string.h"
37 #include "querycmds.h"
44 #include "sprintf_irc.h"
53 #include <arpa/inet.h> /* inet_ntoa */
62 * The function that actually prints out the WHO reply for a client found
64 void do_who(struct Client* sptr, struct Client* acptr, struct Channel* repchan,
65 int fields, char* qrt)
68 struct Channel *chptr = repchan;
70 static char buf1[512];
71 /* NOTE: with current fields list and sizes this _cannot_ overrun,
72 and also the message finally sent shouldn't ever be truncated */
77 /* If we don't have a channel and we need one... try to find it,
78 unless the listing is for a channel service, we already know
79 that there are no common channels, thus use PubChannel and not
81 if (!chptr && (!fields || (fields & (WHO_FIELD_CHA | WHO_FIELD_FLA))) &&
82 !IsChannelService(acptr))
84 struct Membership* chan;
85 for (chan = acptr->user->channel; chan && !chptr; chan = chan->next_channel)
86 if (PubChannel(chan->channel) &&
87 (acptr == sptr || !IsZombie(chan)))
88 chptr = chan->channel;
91 /* Place the fields one by one in the buffer and send it
92 note that fields == NULL means "default query" */
94 if (fields & WHO_FIELD_QTY) /* Query type */
100 while ((*qrt) && (*(p1++) = *(qrt++)));
103 if (!fields || (fields & WHO_FIELD_CHA))
107 if ((p2 = (chptr ? chptr->chname : NULL)))
108 while ((*p2) && (*(p1++) = *(p2++)));
113 if (!fields || (fields & WHO_FIELD_UID))
115 char *p2 = acptr->user->username;
117 while ((*p2) && (*(p1++) = *(p2++)));
120 if (fields & WHO_FIELD_NIP)
122 const char* p2 = ircd_ntoa((const char*) &acptr->ip);
124 while ((*p2) && (*(p1++) = *(p2++)));
127 if (!fields || (fields & WHO_FIELD_HOS))
129 char *p2 = acptr->user->host;
131 while ((*p2) && (*(p1++) = *(p2++)));
134 if (!fields || (fields & WHO_FIELD_SER))
136 char *p2 = acptr->user->server->name;
138 while ((*p2) && (*(p1++) = *(p2++)));
141 if (!fields || (fields & WHO_FIELD_NIC))
143 char *p2 = acptr->name;
145 while ((*p2) && (*(p1++) = *(p2++)));
148 if (!fields || (fields & WHO_FIELD_FLA))
151 if (acptr->user->away)
158 /* If you specified flags then we assume you know how to parse
159 * multiple channel status flags, as this is currently the only
160 * way to know if someone has @'s *and* is +'d.
162 if (chptr && is_chan_op(acptr, chptr))
164 if (chptr && has_voice(acptr, chptr))
166 if (chptr && is_zombie(acptr, chptr))
170 if (chptr && is_chan_op(acptr, chptr))
172 else if (chptr && has_voice(acptr, chptr))
174 else if (chptr && is_zombie(acptr, chptr))
181 if (IsInvisible(acptr))
183 if (SendWallops(acptr))
185 if (SendDebug(acptr))
190 if (!fields || (fields & WHO_FIELD_DIS))
194 *p1++ = ':'; /* Place colon here for default reply */
195 p1 = sprintf_irc(p1, "%d", acptr->hopcount);
198 if (fields & WHO_FIELD_IDL)
202 p1 = sprintf_irc(p1, "%d", CurrentTime - acptr->user->last);
209 if (!fields || (fields & WHO_FIELD_REN))
211 char *p2 = acptr->info;
214 *p1++ = ':'; /* Place colon here for special reply */
215 while ((*p2) && (*(p1++) = *(p2++)));
218 /* The first char will always be an useless blank and we
219 need to terminate buf1 */
222 send_reply(sptr, fields ? RPL_WHOSPCRPL : RPL_WHOREPLY, ++p1);