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