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