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