]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/cmd_who.cpp
Better way even than suggested.
[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 CmdResult cmd_who::Handle (const char** parameters, int pcnt, userrec *user)
95 {
96         /*
97          * XXX - RFC says:
98          *   The <name> passed to WHO is matched against users' host, server, real
99          *   name and nickname
100          * Currently, we support WHO #chan, WHO nick, WHO 0, WHO *, and the addition of a 'o' flag, as per RFC.
101          */
102
103         /* WHO options */
104         bool opt_viewopersonly = false;
105         bool opt_showrealhost = false;
106         bool opt_unlimit = false;
107         bool opt_realname = false;
108         bool opt_mode = false;
109
110         chanrec *ch = NULL;
111         std::vector<std::string> whoresults;
112         std::string initial = "352 " + std::string(user->nick) + " ";
113
114         const char* matchtext = NULL;
115
116         /* Change '0' into '*' so the wildcard matcher can grok it */
117         matchtext = parameters[0];
118         if (!strcmp(matchtext,"0"))
119                 matchtext = "*";
120
121         if (pcnt > 1)
122         {
123                 /* parse flags */
124                 const char *iter = parameters[1];
125
126                 while (*iter)
127                 {
128                         switch (*iter)
129                         {
130                                 case 'o':
131                                         opt_viewopersonly = true;
132                                 break;
133                                 case 'h':
134                                         if (*user->oper)
135                                                 opt_showrealhost = true;
136                                 break;
137                                 case 'u':
138                                         if (*user->oper)
139                                                 opt_unlimit = true;
140                                 break;
141                                 case 'r':
142                                         opt_realname = true;
143                                 break;
144                                 case 'm':
145                                         opt_mode = true;
146                                 break;
147                         }
148
149                         *iter++;
150                 }
151         }
152
153
154         /* who on a channel? */
155         ch = ServerInstance->FindChan(matchtext);
156
157         if ((ch) && (CanView(ch,user)))
158         {
159                 /* who on a channel. */
160                 CUList *cu = ch->GetUsers();
161
162                 for (CUList::iterator i = cu->begin(); i != cu->end(); i++)
163                 {
164                         /* opers only, please */
165                         if (opt_viewopersonly && !*(i->second)->oper)
166                                 continue;
167
168                         /* XXX - code duplication; this could be more efficient -- w00t */
169                         std::string wholine = initial;
170
171                         wholine = wholine + ch->name + " " + i->second->ident + " " + (opt_showrealhost ? i->second->host : i->second->dhost) + " " + 
172                                         i->second->server + " " + i->second->nick + " ";
173
174                         /* away? */
175                         if (*(i->second)->awaymsg)
176                         {
177                                 wholine.append("G");
178                         }
179                         else
180                         {
181                                 wholine.append("H");
182                         }
183
184                         /* oper? */
185                         if (*(i->second)->oper)
186                         {
187                                 wholine.append("*");
188                         }
189
190                         wholine = wholine + ch->GetPrefixChar(i->second) + " :0 " + i->second->fullname;
191                         whoresults.push_back(wholine);
192                 }
193         }
194         else
195         {
196                 /* Match against wildcard of nick, server or host */
197
198                 if (opt_viewopersonly)
199                 {
200                         /* Showing only opers */
201                         for (std::vector<userrec*>::iterator i = ServerInstance->all_opers.begin(); i != ServerInstance->all_opers.end(); i++)
202                         {
203                                 userrec* oper = *i;
204
205                                 if (whomatch(oper, matchtext, opt_realname, opt_showrealhost, opt_mode))
206                                 {
207                                         std::string wholine = initial;
208         
209                                         wholine = wholine + getlastchanname(oper) + " " + oper->ident + " " + (opt_showrealhost ? oper->host : oper->dhost) + " " + 
210                                                         oper->server + " " + oper->nick + " ";
211
212                                         ch = ServerInstance->FindChan(getlastchanname(oper));
213
214                                         /* away? */
215                                         if (*oper->awaymsg)
216                                         {
217                                                 wholine.append("G");
218                                         }
219                                         else
220                                         {
221                                                 wholine.append("H");
222                                         }
223         
224                                         /* oper? */
225                                         if (*oper->oper)
226                                         {
227                                                 wholine.append("*");
228                                         }
229         
230                                         wholine = wholine + (ch ? ch->GetPrefixChar(oper) : "") + " :0 " + oper->fullname;
231                                         whoresults.push_back(wholine);
232                                 }
233                         }
234                 }
235                 else
236                 {
237                         for (user_hash::iterator i = ServerInstance->clientlist->begin(); i != ServerInstance->clientlist->end(); i++)
238                         {
239                                 if (whomatch(i->second, matchtext, opt_realname, opt_showrealhost, opt_mode))
240                                 {
241                                         std::string wholine = initial;
242         
243                                         wholine = wholine + getlastchanname(i->second) + " " + i->second->ident + " " + (opt_showrealhost ? i->second->host : i->second->dhost) + " " + 
244                                                 i->second->server + " " + i->second->nick + " ";
245         
246                                         ch = ServerInstance->FindChan(getlastchanname(i->second));
247
248                                         /* away? */
249                                         if (*(i->second)->awaymsg)
250                                         {
251                                                 wholine.append("G");
252                                         }
253                                         else
254                                         {
255                                                 wholine.append("H");
256                                         }
257
258                                         /* oper? */
259                                         if (*(i->second)->oper)
260                                         {
261                                                 wholine.append("*");
262                                         }
263
264                                         wholine = wholine + (ch ? ch->GetPrefixChar(i->second) : "") + " :0 " + i->second->fullname;
265                                         whoresults.push_back(wholine);
266                                 }
267                         }
268                 }
269         }
270         /* Send the results out */
271         if ((whoresults.size() < (size_t)ServerInstance->Config->MaxWhoResults) && (!opt_unlimit))
272         {
273                 for (std::vector<std::string>::const_iterator n = whoresults.begin(); n != whoresults.end(); n++)
274                         user->WriteServ(*n);
275                 user->WriteServ("315 %s %s :End of /WHO list.",user->nick, *parameters[0] ? parameters[0] : "*");
276                 return CMD_SUCCESS;
277         }
278         else
279         {
280                 /* BZZT! Too many results. */
281                 user->WriteServ("315 %s %s :Too many results",user->nick, parameters[0]);
282                 return CMD_FAILURE;
283         }
284 }