Author: Alex Badea <vampire@p16.pub.ro> (by way of Kev <klmitch@mit.edu>)
[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  * $Id$
24  */
25 #include "config.h"
26
27 #include "whocmds.h"
28 #include "channel.h"
29 #include "client.h"
30 #include "hash.h"
31 #include "ircd.h"
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"
37 #include "list.h"
38 #include "match.h"
39 #include "numeric.h"
40 #include "numnicks.h"
41 #include "querycmds.h"
42 #include "random.h"
43 #include "s_bsd.h"
44 #include "s_conf.h"
45 #include "s_misc.h"
46 #include "s_user.h"
47 #include "send.h"
48 #include "struct.h"
49 #include "support.h"
50 #include "sys.h"
51 #include "userload.h"
52 #include "version.h"
53 #include "whowas.h"
54 #include "msg.h"
55
56 #include <arpa/inet.h>        /* inet_ntoa */
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 /*
65  * The function that actually prints out the WHO reply for a client found
66  */
67 void do_who(struct Client* sptr, struct Client* acptr, struct Channel* repchan,
68             int fields, char* qrt)
69 {
70   char *p1;
71   struct Channel *chptr = repchan;
72
73   static char buf1[512];
74   /* NOTE: with current fields list and sizes this _cannot_ overrun, 
75      and also the message finally sent shouldn't ever be truncated */
76
77   p1 = buf1;
78   buf1[1] = '\0';
79
80   /* If we don't have a channel and we need one... try to find it,
81      unless the listing is for a channel service, we already know
82      that there are no common channels, thus use PubChannel and not
83      SeeChannel */
84   if (!chptr && (!fields || (fields & (WHO_FIELD_CHA | WHO_FIELD_FLA))) &&
85       !IsChannelService(acptr))
86   {
87     struct Membership* chan;
88     for (chan = cli_user(acptr)->channel; chan && !chptr; chan = chan->next_channel)
89       if (PubChannel(chan->channel) &&
90           (acptr == sptr || !IsZombie(chan)))
91         chptr = chan->channel;
92   }
93
94   /* Place the fields one by one in the buffer and send it
95      note that fields == NULL means "default query" */
96
97   if (fields & WHO_FIELD_QTY)   /* Query type */
98   {
99     *(p1++) = ' ';
100     if (BadPtr(qrt))
101       *(p1++) = '0';
102     else
103       while ((*qrt) && (*(p1++) = *(qrt++)));
104   }
105
106   if (!fields || (fields & WHO_FIELD_CHA))
107   {
108     char *p2;
109     *(p1++) = ' ';
110     if ((p2 = (chptr ? chptr->chname : NULL)))
111       while ((*p2) && (*(p1++) = *(p2++)));
112     else
113       *(p1++) = '*';
114   }
115
116   if (!fields || (fields & WHO_FIELD_UID))
117   {
118     char *p2 = cli_user(acptr)->username;
119     *(p1++) = ' ';
120     while ((*p2) && (*(p1++) = *(p2++)));
121   }
122
123   if (fields & WHO_FIELD_NIP)
124   {
125     const char* p2 = HasHiddenHost(acptr) && !IsAnOper(sptr) ?
126       feature_str(FEAT_HIDDEN_IP) :
127       ircd_ntoa((const char*) &(cli_ip(acptr)));
128     *(p1++) = ' ';
129     while ((*p2) && (*(p1++) = *(p2++)));
130   }
131
132   if (!fields || (fields & WHO_FIELD_HOS))
133   {
134     char *p2 = cli_user(acptr)->host;
135     *(p1++) = ' ';
136     while ((*p2) && (*(p1++) = *(p2++)));
137   }
138
139   if (!fields || (fields & WHO_FIELD_SER))
140   {
141     char *p2;
142 #ifdef HEAD_IN_SAND_WHO_SERVERNAME
143     if (IsAnOper(sptr))
144 #endif
145       p2 = cli_name(cli_user(acptr)->server);
146 #ifdef HEAD_IN_SAND_WHO_SERVERNAME
147     else
148       p2 = HEAD_IN_SAND_SERVERNAME;
149 #endif
150     *(p1++) = ' ';
151     while ((*p2) && (*(p1++) = *(p2++)));
152   }
153
154   if (!fields || (fields & WHO_FIELD_NIC))
155   {
156     char *p2 = cli_name(acptr);
157     *(p1++) = ' ';
158     while ((*p2) && (*(p1++) = *(p2++)));
159   }
160
161   if (!fields || (fields & WHO_FIELD_FLA))
162   {
163     *(p1++) = ' ';
164     if (cli_user(acptr)->away)
165       *(p1++) = 'G';
166     else
167       *(p1++) = 'H';
168     if (IsAnOper(acptr) &&
169         (HasPriv(acptr, PRIV_DISPLAY) || HasPriv(sptr, PRIV_SEE_OPERS)))
170       *(p1++) = '*';
171     if (fields) {
172       /* If you specified flags then we assume you know how to parse
173        * multiple channel status flags, as this is currently the only
174        * way to know if someone has @'s *and* is +'d.
175        */
176       if (chptr && is_chan_op(acptr, chptr))
177         *(p1++) = '@';
178       if (chptr && has_voice(acptr, chptr))
179         *(p1++) = '+';
180       if (chptr && is_zombie(acptr, chptr))
181         *(p1++) = '!';
182     }
183     else {
184       if (chptr && is_chan_op(acptr, chptr))
185         *(p1++) = '@';
186       else if (chptr && has_voice(acptr, chptr))
187         *(p1++) = '+';
188       else if (chptr && is_zombie(acptr, chptr))
189         *(p1++) = '!';
190     }
191     if (IsDeaf(acptr))
192       *(p1++) = 'd';
193     if (IsAnOper(sptr))
194     {
195       if (IsInvisible(acptr))
196         *(p1++) = 'i';
197       if (SendWallops(acptr))
198         *(p1++) = 'w';
199       if (SendDebug(acptr))
200         *(p1++) = 'g';
201     }
202     if (HasHiddenHost(acptr))
203       *(p1++) = 'x';
204   }
205
206   if (!fields || (fields & WHO_FIELD_DIS))
207   {
208     *p1++ = ' ';
209     if (!fields)
210       *p1++ = ':';              /* Place colon here for default reply */
211 #ifdef HEAD_IN_SAND_WHO_HOPCOUNT
212     *p1++ = (sptr == acptr) ? '0' : '3';
213 #else
214     /* three digit hopcount maximum */
215     p1 += ircd_snprintf(0, p1, 3, "%d", cli_hopcount(acptr));
216 #endif
217   }
218
219   if (fields & WHO_FIELD_IDL)
220   {
221     *p1++ = ' ';
222     if (MyUser(acptr)) {
223             p1 += ircd_snprintf(0, p1, 11, "%d",
224                                 CurrentTime - cli_user(acptr)->last);
225     }    
226     else {
227             *p1++ = '0';
228     }
229   }
230
231   if (!fields || (fields & WHO_FIELD_REN))
232   {
233     char *p2 = cli_info(acptr);
234     *p1++ = ' ';
235     if (fields)
236       *p1++ = ':';              /* Place colon here for special reply */
237     while ((*p2) && (*(p1++) = *(p2++)));
238   }
239
240   /* The first char will always be an useless blank and we 
241      need to terminate buf1 */
242   *p1 = '\0';
243   p1 = buf1;
244   send_reply(sptr, fields ? RPL_WHOSPCRPL : RPL_WHOREPLY, ++p1);
245 }
246
247 int
248 count_users(char *mask)
249 {
250   struct Client *acptr;
251   int count = 0;
252   char namebuf[USERLEN + HOSTLEN + 2];
253   char ipbuf[USERLEN + 16 + 2];
254
255   for (acptr = GlobalClientList; acptr; acptr = cli_next(acptr)) {
256     if (!IsUser(acptr))
257       continue;
258
259     ircd_snprintf(0, namebuf, sizeof(namebuf), "%s@%s",
260                   cli_user(acptr)->username, cli_user(acptr)->host);
261     ircd_snprintf(0, ipbuf, sizeof(ipbuf), "%s@%s", cli_user(acptr)->username,
262                   ircd_ntoa((const char *) &(cli_ip(acptr))));
263
264     if (!match(mask, namebuf) || !match(mask, ipbuf))
265       count++;
266   }
267
268   return count;
269 }