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