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