fixed ssl.c bug when ssl backend returns IO_BLOCKED but IO engine doesn't get informe...
[ircu2.10.12-pk.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 1838 2007-10-30 01:53:33Z entrope $
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) || IsOper(sptr) || sptr == 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) && !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 (IsHalfOp(chan))
182         *(p1++) = '%';
183       if (HasVoice(chan))
184         *(p1++) = '+';
185       if (IsZombie(chan))
186         *(p1++) = '!';
187       if (IsDelayedJoin(chan))
188         *(p1++) = '<';
189     }
190     else {
191       if (IsChanOp(chan))
192         *(p1++) = '@';
193       else if (IsHalfOp(chan))
194         *(p1++) = '%';
195       else if (HasVoice(chan))
196         *(p1++) = '+';
197       else if (IsZombie(chan))
198         *(p1++) = '!';
199       else if (IsDelayedJoin(chan))
200         *(p1++) = '<';
201     }
202     if (IsDeaf(acptr))
203       *(p1++) = 'd';
204     if (IsAnOper(sptr))
205     {
206       if (IsInvisible(acptr))
207         *(p1++) = 'i';
208       if (SendWallops(acptr))
209         *(p1++) = 'w';
210       if (SendDebug(acptr))
211         *(p1++) = 'g';
212     }
213     if (HasHiddenHost(acptr))
214       *(p1++) = 'x';
215   }
216
217   if (!fields || (fields & WHO_FIELD_DIS))
218   {
219     *p1++ = ' ';
220     if (!fields)
221       *p1++ = ':';              /* Place colon here for default reply */
222     if (feature_bool(FEAT_HIS_WHO_HOPCOUNT) && !IsAnOper(sptr))
223       *p1++ = (sptr == acptr) ? '0' : '3';
224     else
225       /* three digit hopcount maximum */
226       p1 += ircd_snprintf(0, p1, 3, "%d", cli_hopcount(acptr));
227   }
228
229   if (fields & WHO_FIELD_IDL)
230   {
231     *p1++ = ' ';
232     if (MyUser(acptr) &&
233         (IsAnOper(sptr) || !feature_bool(FEAT_HIS_WHO_SERVERNAME) ||
234          acptr == sptr))
235       p1 += ircd_snprintf(0, p1, 11, "%d",
236                           CurrentTime - cli_user(acptr)->last);
237     else
238       *p1++ = '0';
239   }
240
241   if (fields & WHO_FIELD_ACC)
242   {
243     char *p2 = cli_user(acptr)->account;
244     *(p1++) = ' ';
245     if (*p2)
246       while ((*p2) && (*(p1++) = *(p2++)));
247     else
248       *(p1++) = '0';
249   }
250
251   if (fields & WHO_FIELD_OPL)
252   {
253       if (!chan || !IsChanOp(chan))
254       {
255         strcpy(p1, " n/a");
256         p1 += 4;
257       }
258       else
259       {
260         int vis_level = MAXOPLEVEL;
261         if ((IsGlobalChannel(chan->channel->chname) ? IsOper(sptr) : IsAnOper(sptr))
262             || is_chan_op(sptr, chan->channel))
263           vis_level = OpLevel(chan);
264         p1 += ircd_snprintf(0, p1, 5, " %d", vis_level);
265       }
266   }
267
268   if (!fields || (fields & WHO_FIELD_REN))
269   {
270     char *p2 = cli_info(acptr);
271     *p1++ = ' ';
272     if (fields)
273       *p1++ = ':';              /* Place colon here for special reply */
274     while ((*p2) && (*(p1++) = *(p2++)));
275   }
276
277   /* The first char will always be an useless blank and we 
278      need to terminate buf1 */
279   *p1 = '\0';
280   p1 = buf1;
281   send_reply(sptr, fields ? RPL_WHOSPCRPL : RPL_WHOREPLY, ++p1);
282 }