]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/cmd_who.cpp
Fix for crash found by potter if you set up two redirects in two channels to forward...
[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         if (*user->oper)
85                 return true;
86         else if (!chan->IsModeSet('s') && !chan->IsModeSet('p'))
87                 return true;
88         else if (chan->HasUser(user))
89                 return true;
90
91         return false;
92 }
93
94 void cmd_who::SendWhoLine(userrec* user, const std::string &initial, chanrec* ch, userrec* u, std::vector<std::string> &whoresults)
95 {
96         std::string lcn = getlastchanname(u);
97         chanrec* chlast = ServerInstance->FindChan(lcn);
98
99         /* Not visible to this user */
100         if (u->Visibility && !u->Visibility->VisibleTo(user))
101                 return;
102
103         std::string wholine =   initial + (ch ? ch->name : lcn) + " " + u->ident + " " + (opt_showrealhost ? u->host : u->dhost) + " " +
104                                 ((*ServerInstance->Config->HideWhoisServer && !*user->oper) ? ServerInstance->Config->HideWhoisServer : u->server) +
105                                 " " + u->nick + " ";
106
107         /* away? */
108         if (*u->awaymsg)
109         {
110                 wholine.append("G");
111         }
112         else
113         {
114                 wholine.append("H");
115         }
116
117         /* oper? */
118         if (*u->oper)
119         {
120                 wholine.append("*");
121         }
122
123         wholine = wholine + (ch ? ch->GetPrefixChar(u) : (chlast ? chlast->GetPrefixChar(u) : "")) + " :0 " + u->fullname;
124         whoresults.push_back(wholine);
125 }
126
127 CmdResult cmd_who::Handle (const char** parameters, int pcnt, userrec *user)
128 {
129         /*
130          * XXX - RFC says:
131          *   The <name> passed to WHO is matched against users' host, server, real
132          *   name and nickname
133          * Currently, we support WHO #chan, WHO nick, WHO 0, WHO *, and the addition of a 'o' flag, as per RFC.
134          */
135
136         /* WHO options */
137         opt_viewopersonly = false;
138         opt_showrealhost = false;
139         opt_unlimit = false;
140         opt_realname = false;
141         opt_mode = false;
142
143         chanrec *ch = NULL;
144         std::vector<std::string> whoresults;
145         std::string initial = "352 " + std::string(user->nick) + " ";
146
147         const char* matchtext = NULL;
148
149         /* Change '0' into '*' so the wildcard matcher can grok it */
150         matchtext = parameters[0];
151         if (!strcmp(matchtext,"0"))
152                 matchtext = "*";
153
154         if (pcnt > 1)
155         {
156                 /* parse flags */
157                 const char *iter = parameters[1];
158
159                 while (*iter)
160                 {
161                         switch (*iter)
162                         {
163                                 case 'o':
164                                         opt_viewopersonly = true;
165                                 break;
166                                 case 'h':
167                                         if (*user->oper)
168                                                 opt_showrealhost = true;
169                                 break;
170                                 case 'u':
171                                         if (*user->oper)
172                                                 opt_unlimit = true;
173                                 break;
174                                 case 'r':
175                                         opt_realname = true;
176                                 break;
177                                 case 'm':
178                                         opt_mode = true;
179                                 break;
180                         }
181
182                         *iter++;
183                 }
184         }
185
186
187         /* who on a channel? */
188         ch = ServerInstance->FindChan(matchtext);
189
190         if ((ch) && (CanView(ch,user)))
191         {
192                 /* who on a channel. */
193                 CUList *cu = ch->GetUsers();
194
195                 for (CUList::iterator i = cu->begin(); i != cu->end(); i++)
196                 {
197                         /* opers only, please */
198                         if (opt_viewopersonly && !*(i->second)->oper)
199                                 continue;
200
201                         SendWhoLine(user, initial, ch, i->second, whoresults);
202                 }
203         }
204         else
205         {
206                 /* Match against wildcard of nick, server or host */
207
208                 if (opt_viewopersonly)
209                 {
210                         /* Showing only opers */
211                         for (std::vector<userrec*>::iterator i = ServerInstance->all_opers.begin(); i != ServerInstance->all_opers.end(); i++)
212                         {
213                                 userrec* oper = *i;
214
215                                 if (whomatch(oper, matchtext, opt_realname, opt_showrealhost, opt_mode))
216                                 {
217                                         SendWhoLine(user, initial, NULL, oper, whoresults);
218                                 }
219                         }
220                 }
221                 else
222                 {
223                         for (user_hash::iterator i = ServerInstance->clientlist->begin(); i != ServerInstance->clientlist->end(); i++)
224                         {
225                                 if (whomatch(i->second, matchtext, opt_realname, opt_showrealhost, opt_mode))
226                                 {
227                                         SendWhoLine(user, initial, NULL, i->second, whoresults);
228                                 }
229                         }
230                 }
231         }
232         /* Send the results out */
233         if ((whoresults.size() < (size_t)ServerInstance->Config->MaxWhoResults) && (!opt_unlimit))
234         {
235                 for (std::vector<std::string>::const_iterator n = whoresults.begin(); n != whoresults.end(); n++)
236                         user->WriteServ(*n);
237                 user->WriteServ("315 %s %s :End of /WHO list.",user->nick, *parameters[0] ? parameters[0] : "*");
238                 return CMD_SUCCESS;
239         }
240         else
241         {
242                 /* BZZT! Too many results. */
243                 user->WriteServ("315 %s %s :Too many results",user->nick, parameters[0]);
244                 return CMD_FAILURE;
245         }
246 }