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