]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/cmd_who.cpp
Fix slightly broken oper checks on +i
[user/henk/code/inspircd.git] / src / cmd_who.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
6  * See: http://www.inspircd.org/wiki/index.php/Credits
7  *
8  * This program is free but copyrighted software; see
9  *          the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */
13
14 #include "configreader.h"
15 #include "users.h"
16 #include "modules.h"
17 #include "wildcard.h"
18 #include "commands/cmd_who.h"
19
20 /* get the last 'visible' chan of a user */
21 static char *getlastchanname(userrec *u)
22 {
23         UCListIter i = u->chans.begin();
24         if (i != u->chans.end())
25         {
26                 if (!i->first->IsModeSet('s'))
27                         return i->first->name;
28         }
29
30         return "*";
31 }
32
33 bool cmd_who::whomatch(userrec* user, const char* matchtext)
34 {
35         bool realhost = false;
36         bool realname = false;
37         bool positive = true;
38         bool metadata = false;
39         bool ident = false;
40         bool away = false;
41         bool port = false;
42         char* dummy = NULL;
43
44         if (user->registered != REG_ALL)
45                 return false;
46
47         if (opt_mode)
48         {
49                 for (const char* n = matchtext; *n; n++)
50                 {
51                         if (*n == '+')
52                         {
53                                 positive = true;
54                                 continue;
55                         }
56                         else if (*n == '-')
57                         {
58                                 positive = false;
59                                 continue;
60                         }
61                         if (user->IsModeSet(*n) != positive)
62                                 return false;
63                 }
64                 return true;
65         }
66         else
67         {
68
69                 if (opt_metadata)
70                         metadata = user->GetExt(matchtext, dummy);
71                 else
72                 {
73                         if (opt_realname)
74                                 realname = match(user->fullname, matchtext);
75                         else
76                         {
77                                 if (opt_showrealhost)
78                                         realhost = match(user->host, matchtext);
79                                 else
80                                 {
81                                         if (opt_ident)
82                                                 ident = match(user->ident, matchtext);
83                                         else
84                                         {
85                                                 if (opt_port)
86                                                         port = (user->GetPort() == ConvToInt(matchtext));
87                                                 else
88                                                 {
89                                                         if (opt_away)
90                                                                 away = match(user->awaymsg, matchtext);
91                                                 }
92                                         }
93                                 }
94                         }
95                 }
96                 return ((port) || (away) || (ident) || (metadata) || (realname) || (realhost) || (match(user->dhost, matchtext)) || (match(user->nick, matchtext)) || (match(user->server, matchtext)));
97         }
98 }
99
100
101
102 extern "C" command_t* init_command(InspIRCd* Instance)
103 {
104         return new cmd_who(Instance);
105 }
106
107 bool cmd_who::CanView(chanrec* chan, userrec* user)
108 {
109         if (!user || !chan)
110                 return false;
111
112         /* Execute items in fastest-to-execute first order */
113
114         /* Opers see all */
115         if (*user->oper)
116                 return true;
117         else if (!chan->IsModeSet('s') && !chan->IsModeSet('p'))
118                 return true;
119         else if (chan->HasUser(user))
120                 return true;
121
122         return false;
123 }
124
125 void cmd_who::SendWhoLine(userrec* user, const std::string &initial, chanrec* ch, userrec* u, std::vector<std::string> &whoresults)
126 {
127         std::string lcn = getlastchanname(u);
128         chanrec* chlast = ServerInstance->FindChan(lcn);
129
130         /* Not visible to this user */
131         if (u->Visibility && !u->Visibility->VisibleTo(user))
132                 return;
133
134         std::string wholine =   initial + (ch ? ch->name : lcn) + " " + u->ident + " " + (opt_showrealhost ? u->host : u->dhost) + " " +
135                                 ((*ServerInstance->Config->HideWhoisServer && !*user->oper) ? ServerInstance->Config->HideWhoisServer : u->server) +
136                                 " " + u->nick + " ";
137
138         /* away? */
139         if (*u->awaymsg)
140         {
141                 wholine.append("G");
142         }
143         else
144         {
145                 wholine.append("H");
146         }
147
148         /* oper? */
149         if (*u->oper)
150         {
151                 wholine.append("*");
152         }
153
154         wholine = wholine + (ch ? ch->GetPrefixChar(u) : (chlast ? chlast->GetPrefixChar(u) : "")) + " :0 " + u->fullname;
155         whoresults.push_back(wholine);
156 }
157
158 CmdResult cmd_who::Handle (const char** parameters, int pcnt, userrec *user)
159 {
160         /*
161          * XXX - RFC says:
162          *   The <name> passed to WHO is matched against users' host, server, real
163          *   name and nickname
164          * Currently, we support WHO #chan, WHO nick, WHO 0, WHO *, and the addition of a 'o' flag, as per RFC.
165          */
166
167         /* WHO options */
168         opt_viewopersonly = false;
169         opt_showrealhost = false;
170         opt_unlimit = false;
171         opt_realname = false;
172         opt_mode = false;
173         opt_ident = false;
174         opt_metadata = false;
175         opt_port = false;
176         opt_away = false;
177
178         chanrec *ch = NULL;
179         std::vector<std::string> whoresults;
180         std::string initial = "352 " + std::string(user->nick) + " ";
181
182         const char* matchtext = NULL;
183
184         /* Change '0' into '*' so the wildcard matcher can grok it */
185         matchtext = parameters[0];
186         if (!strcmp(matchtext,"0"))
187                 matchtext = "*";
188
189         if (pcnt > 1)
190         {
191                 /* parse flags */
192                 const char *iter = parameters[1];
193
194                 while (*iter)
195                 {
196                         switch (*iter)
197                         {
198                                 case 'o':
199                                         opt_viewopersonly = true;
200                                 break;
201                                 case 'h':
202                                         if (*user->oper)
203                                                 opt_showrealhost = true;
204                                 break;
205                                 case 'u':
206                                         if (*user->oper)
207                                                 opt_unlimit = true;
208                                 break;
209                                 case 'r':
210                                         opt_realname = true;
211                                 break;
212                                 case 'm':
213                                         opt_mode = true;
214                                 break;
215                                 case 'M':
216                                         opt_metadata = true;
217                                 break;
218                                 case 'i':
219                                         opt_ident = true;
220                                 break;
221                                 case 'p':
222                                         opt_port = true;
223                                 break;
224                                 case 'a':
225                                         opt_away = true;
226                                 break;
227                         }
228
229                         *iter++;
230                 }
231         }
232
233
234         /* who on a channel? */
235         ch = ServerInstance->FindChan(matchtext);
236
237         if (ch)
238         {
239                 if (CanView(ch,user))
240                 {
241                         bool inside = ch->HasUser(user);
242         
243                         /* who on a channel. */
244                         CUList *cu = ch->GetUsers();
245         
246                         for (CUList::iterator i = cu->begin(); i != cu->end(); i++)
247                         {
248                                 /* opers only, please */
249                                 if (opt_viewopersonly && !IS_OPER(i->second))
250                                         continue;
251         
252                                 /* If we're not inside the channel, hide +i users */
253                                 if (i->second->IsModeSet('i') && !inside)
254                                         continue;
255         
256                                 SendWhoLine(user, initial, ch, i->second, whoresults);
257                         }
258                 }
259         }
260         else
261         {
262                 /* Match against wildcard of nick, server or host */
263
264                 if (opt_viewopersonly)
265                 {
266                         /* Showing only opers */
267                         for (std::vector<userrec*>::iterator i = ServerInstance->all_opers.begin(); i != ServerInstance->all_opers.end(); i++)
268                         {
269                                 userrec* oper = *i;
270
271                                 if (whomatch(oper, matchtext))
272                                 {
273                                         if ((!oper->IsModeSet('i')) && (!IS_OPER(user)))
274                                                 continue;
275
276                                         SendWhoLine(user, initial, NULL, oper, whoresults);
277                                 }
278                         }
279                 }
280                 else
281                 {
282                         for (user_hash::iterator i = ServerInstance->clientlist->begin(); i != ServerInstance->clientlist->end(); i++)
283                         {
284                                 if (whomatch(i->second, matchtext))
285                                 {
286                                         if ((i->second->IsModeSet('i')) && (!IS_OPER(user)))
287                                                 continue;
288
289                                         SendWhoLine(user, initial, NULL, i->second, whoresults);
290                                 }
291                         }
292                 }
293         }
294         /* Send the results out */
295         if ((whoresults.size() <= (size_t)ServerInstance->Config->MaxWhoResults) || opt_unlimit)
296         {
297                 for (std::vector<std::string>::const_iterator n = whoresults.begin(); n != whoresults.end(); n++)
298                         user->WriteServ(*n);
299                 user->WriteServ("315 %s %s :End of /WHO list.",user->nick, *parameters[0] ? parameters[0] : "*");
300                 return CMD_SUCCESS;
301         }
302         else
303         {
304                 /* BZZT! Too many results. */
305                 user->WriteServ("315 %s %s :Too many results",user->nick, parameters[0]);
306                 return CMD_FAILURE;
307         }
308 }