Author: 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 "whocmds.h"
26 #include "channel.h"
27 #include "client.h"
28 #include "hash.h"
29 #include "ircd.h"
30 #include "ircd_chattr.h"
31 #include "ircd_reply.h"
32 #include "ircd_string.h"
33 #include "list.h"
34 #include "match.h"
35 #include "numeric.h"
36 #include "numnicks.h"
37 #include "querycmds.h"
38 #include "random.h"
39 #include "s_bsd.h"
40 #include "s_conf.h"
41 #include "s_misc.h"
42 #include "s_user.h"
43 #include "send.h"
44 #include "sprintf_irc.h"
45 #include "struct.h"
46 #include "support.h"
47 #include "sys.h"
48 #include "userload.h"
49 #include "version.h"
50 #include "whowas.h"
51 #include "msg.h"
52
53 #include <arpa/inet.h>        /* inet_ntoa */
54 #include <fcntl.h>
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <string.h>
58 #include <sys/stat.h>
59 #include <unistd.h>
60
61 /*
62  * The function that actually prints out the WHO reply for a client found
63  */
64 void do_who(struct Client* sptr, struct Client* acptr, struct Channel* repchan,
65             int fields, char* qrt)
66 {
67   char *p1;
68   struct Channel *chptr = repchan;
69
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 */
73
74   p1 = buf1;
75   buf1[1] = '\0';
76
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
80      SeeChannel */
81   if (!chptr && (!fields || (fields & (WHO_FIELD_CHA | WHO_FIELD_FLA))) &&
82       !IsChannelService(acptr))
83   {
84     struct Membership* chan;
85     for (chan = cli_user(acptr)->channel; chan && !chptr; chan = chan->next_channel)
86       if (PubChannel(chan->channel) &&
87           (acptr == sptr || !IsZombie(chan)))
88         chptr = chan->channel;
89   }
90
91   /* Place the fields one by one in the buffer and send it
92      note that fields == NULL means "default query" */
93
94   if (fields & WHO_FIELD_QTY)   /* Query type */
95   {
96     *(p1++) = ' ';
97     if (BadPtr(qrt))
98       *(p1++) = '0';
99     else
100       while ((*qrt) && (*(p1++) = *(qrt++)));
101   }
102
103   if (!fields || (fields & WHO_FIELD_CHA))
104   {
105     char *p2;
106     *(p1++) = ' ';
107     if ((p2 = (chptr ? chptr->chname : NULL)))
108       while ((*p2) && (*(p1++) = *(p2++)));
109     else
110       *(p1++) = '*';
111   }
112
113   if (!fields || (fields & WHO_FIELD_UID))
114   {
115     char *p2 = cli_user(acptr)->username;
116     *(p1++) = ' ';
117     while ((*p2) && (*(p1++) = *(p2++)));
118   }
119
120   if (fields & WHO_FIELD_NIP)
121   {
122     const char* p2 = ircd_ntoa((const char*) &(cli_ip(acptr)));
123     *(p1++) = ' ';
124     while ((*p2) && (*(p1++) = *(p2++)));
125   }
126
127   if (!fields || (fields & WHO_FIELD_HOS))
128   {
129     char *p2 = cli_user(acptr)->host;
130     *(p1++) = ' ';
131     while ((*p2) && (*(p1++) = *(p2++)));
132   }
133
134   if (!fields || (fields & WHO_FIELD_SER))
135   {
136     char *p2 = cli_name(cli_user(acptr)->server);
137     *(p1++) = ' ';
138     while ((*p2) && (*(p1++) = *(p2++)));
139   }
140
141   if (!fields || (fields & WHO_FIELD_NIC))
142   {
143     char *p2 = cli_name(acptr);
144     *(p1++) = ' ';
145     while ((*p2) && (*(p1++) = *(p2++)));
146   }
147
148   if (!fields || (fields & WHO_FIELD_FLA))
149   {
150     *(p1++) = ' ';
151     if (cli_user(acptr)->away)
152       *(p1++) = 'G';
153     else
154       *(p1++) = 'H';
155     if (IsAnOper(acptr) &&
156         (HasPriv(acptr, PRIV_DISPLAY) || HasPriv(sptr, PRIV_SEE_OPERS)))
157       *(p1++) = '*';
158     if (fields) {
159       /* If you specified flags then we assume you know how to parse
160        * multiple channel status flags, as this is currently the only
161        * way to know if someone has @'s *and* is +'d.
162        */
163       if (chptr && is_chan_op(acptr, chptr))
164         *(p1++) = '@';
165       if (chptr && has_voice(acptr, chptr))
166         *(p1++) = '+';
167       if (chptr && is_zombie(acptr, chptr))
168         *(p1++) = '!';
169     }
170     else {
171       if (chptr && is_chan_op(acptr, chptr))
172         *(p1++) = '@';
173       else if (chptr && has_voice(acptr, chptr))
174         *(p1++) = '+';
175       else if (chptr && is_zombie(acptr, chptr))
176         *(p1++) = '!';
177     }
178     if (IsDeaf(acptr))
179       *(p1++) = 'd';
180     if (IsAnOper(sptr))
181     {
182       if (IsInvisible(acptr))
183         *(p1++) = 'i';
184       if (SendWallops(acptr))
185         *(p1++) = 'w';
186       if (SendDebug(acptr))
187         *(p1++) = 'g';
188     }
189   }
190
191   if (!fields || (fields & WHO_FIELD_DIS))
192   {
193     *p1++ = ' ';
194     if (!fields)
195       *p1++ = ':';              /* Place colon here for default reply */
196     p1 = sprintf_irc(p1, "%d", cli_hopcount(acptr));
197   }
198
199   if (fields & WHO_FIELD_IDL)
200   {
201     *p1++ = ' ';
202     if (MyUser(acptr)) {
203             p1 = sprintf_irc(p1, "%d", CurrentTime - cli_user(acptr)->last);
204     }    
205     else {
206             *p1++ = '0';
207     }
208   }
209
210   if (!fields || (fields & WHO_FIELD_REN))
211   {
212     char *p2 = cli_info(acptr);
213     *p1++ = ' ';
214     if (fields)
215       *p1++ = ':';              /* Place colon here for special reply */
216     while ((*p2) && (*(p1++) = *(p2++)));
217   }
218
219   /* The first char will always be an useless blank and we 
220      need to terminate buf1 */
221   *p1 = '\0';
222   p1 = buf1;
223   send_reply(sptr, fields ? RPL_WHOSPCRPL : RPL_WHOREPLY, ++p1);
224 }
225