]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_cap.cpp
Ignore CAP from clients that have already registered
[user/henk/code/inspircd.git] / src / modules / m_cap.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2008 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 "m_cap.h"
16
17 /* $ModDesc: Provides the CAP negotiation mechanism seen in ratbox-derived ircds */
18
19 /*
20 CAP LS
21 :alfred.staticbox.net CAP * LS :multi-prefix sasl
22 CAP REQ :multi-prefix
23 :alfred.staticbox.net CAP * ACK :multi-prefix 
24 CAP CLEAR
25 :alfred.staticbox.net CAP * ACK :-multi-prefix
26 CAP REQ :multi-prefix
27 :alfred.staticbox.net CAP * ACK :multi-prefix 
28 CAP LIST
29 :alfred.staticbox.net CAP * LIST :multi-prefix
30 CAP END
31 */
32
33 /** Handle /CAP
34  */
35 class CommandCAP : public Command
36 {
37         Module* Creator;
38  public:
39         CommandCAP (InspIRCd* Instance, Module* mod) : Command(Instance,"CAP", 0, 1, true), Creator(mod)
40         {
41                 this->source = "m_cap.so";
42         }
43
44         CmdResult Handle (const std::vector<std::string> &parameters, User *user)
45         {
46                 /* Ignore CAP from registered clients */
47                 if (user->registered == REG_ALL)
48                         return CMD_FAILURE;
49
50                 irc::string subcommand = parameters[0].c_str();
51
52                 if (subcommand == "REQ")
53                 {
54                         CapData Data;
55
56                         Data.type = subcommand;
57                         Data.user = user;
58                         Data.creator = this->Creator;
59
60                         if (parameters.size() < 2)
61                                 return CMD_FAILURE;
62
63                         // tokenize the input into a nice list of requested caps
64                         std::string param = parameters[1];
65                         std::string cap_;
66                         irc::spacesepstream cap_stream(param);
67
68                         while (cap_stream.GetToken(cap_))
69                         {
70                                 Data.wanted.push_back(cap_);
71                         }
72
73                         user->Extend("CAP_REGHOLD");
74                         Event event((char*) &Data, (Module*)this->Creator, "cap_req");
75                         event.Send(this->ServerInstance);
76
77                         if (Data.ack.size() > 0)
78                         {
79                                 std::string AckResult = irc::stringjoiner(" ", Data.ack, 0, Data.ack.size() - 1).GetJoined();
80                                 user->WriteServ("CAP * ACK :%s", AckResult.c_str());
81                         }
82
83                         if (Data.wanted.size() > 0)
84                         {
85                                 std::string NakResult = irc::stringjoiner(" ", Data.wanted, 0, Data.wanted.size() - 1).GetJoined();
86                                 user->WriteServ("CAP * NAK :%s", NakResult.c_str());
87                         }
88                 }
89                 else if (subcommand == "END")
90                 {
91                         user->Shrink("CAP_REGHOLD");
92                 }
93                 else if ((subcommand == "LS") || (subcommand == "LIST"))
94                 {
95                         CapData Data;
96
97                         Data.type = subcommand;
98                         Data.user = user;
99                         Data.creator = this->Creator;
100
101                         user->Extend("CAP_REGHOLD");
102                         Event event((char*) &Data, (Module*)this->Creator, subcommand == "LS" ? "cap_ls" : "cap_list");
103                         event.Send(this->ServerInstance);
104
105                         std::string Result;
106                         if (Data.wanted.size() > 0)
107                                 Result = irc::stringjoiner(" ", Data.wanted, 0, Data.wanted.size() - 1).GetJoined();
108                         else
109                                 Result = "";
110
111                         user->WriteServ("CAP * %s :%s", subcommand.c_str(), Result.c_str());
112                 }
113                 else if (subcommand == "CLEAR")
114                 {
115                         CapData Data;
116
117                         Data.type = subcommand;
118                         Data.user = user;
119                         Data.creator = this->Creator;
120
121                         user->Extend("CAP_REGHOLD");
122                         Event event((char*) &Data, (Module*)this->Creator, "cap_clear");
123                         event.Send(this->ServerInstance);
124
125                         std::string Result = irc::stringjoiner(" ", Data.ack, 0, Data.ack.size() - 1).GetJoined();
126                         user->WriteServ("CAP * ACK :%s", Result.c_str());
127                 }
128                 else
129                 {
130                         user->WriteNumeric(410, "* %s :Invalid CAP subcommand", subcommand.c_str());
131                 }
132
133                 return CMD_FAILURE;
134         }
135 };
136
137 class ModuleCAP : public Module
138 {
139         CommandCAP* newcommand;
140  public:
141         ModuleCAP(InspIRCd* Me)
142                 : Module(Me)
143         {
144                 // Create a new command
145                 newcommand = new CommandCAP(ServerInstance, this);
146                 ServerInstance->AddCommand(newcommand);
147
148                 Implementation eventlist[] = { I_OnCheckReady };
149                 ServerInstance->Modules->Attach(eventlist, this, 1);
150         }
151
152         virtual bool OnCheckReady(User* user)
153         {
154                 /* Users in CAP state get held until CAP END */
155                 if (user->GetExt("CAP_REGHOLD"))
156                         return false;
157
158                 return true;
159         }
160
161         virtual ~ModuleCAP()
162         {
163         }
164
165         virtual Version GetVersion()
166         {
167                 return Version(1, 2, 0, 0, VF_VENDOR, API_VERSION);
168         }
169 };
170
171 MODULE_INIT(ModuleCAP)
172