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