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