]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_cap.cpp
Crash fixes from nenolod
[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 char* const* parameters, int pcnt, User *user)
45         {
46                 irc::string subcommand = parameters[0];
47
48                 if (subcommand == "REQ")
49                 {
50                         CapData Data;
51
52                         Data.type = subcommand;
53                         Data.user = user;
54                         Data.creator = this->Creator;
55
56                         if (pcnt < 2)
57                                 return CMD_FAILURE;
58
59                         // tokenize the input into a nice list of requested caps
60                         std::string param = parameters[1];
61                         std::string cap_;
62                         irc::spacesepstream cap_stream(param);
63
64                         while (cap_stream.GetToken(cap_))
65                         {
66                                 Data.wanted.push_back(cap_);
67                         }
68
69                         user->Extend("CAP_REGHOLD");
70                         Event event((char*) &Data, (Module*)this->Creator, "cap_req");
71                         event.Send(this->ServerInstance);
72
73                         if (Data.ack.size() > 0)
74                         {
75                                 std::string AckResult = irc::stringjoiner(" ", Data.ack, 0, Data.ack.size() - 1).GetJoined();
76                                 user->WriteServ("CAP * ACK :%s", AckResult.c_str());
77                         }
78
79                         if (Data.nak.size() > 0)
80                         {
81                                 std::string NakResult = irc::stringjoiner(" ", Data.nak, 0, Data.nak.size() - 1).GetJoined();
82                                 user->WriteServ("CAP * NAK :%s", NakResult.c_str());
83                         }
84                 }
85                 else if (subcommand == "END")
86                 {
87                         user->Shrink("CAP_REGHOLD");
88                 }
89                 else if ((subcommand == "LS") || (subcommand == "LIST"))
90                 {
91                         CapData Data;
92
93                         Data.type = subcommand;
94                         Data.user = user;
95                         Data.creator = this->Creator;
96
97                         user->Extend("CAP_REGHOLD");
98                         Event event((char*) &Data, (Module*)this->Creator, subcommand == "LS" ? "cap_ls" : "cap_list");
99                         event.Send(this->ServerInstance);
100
101                         std::string Result;
102                         if (Data.wanted.size() > 0)
103                                 Result = irc::stringjoiner(" ", Data.wanted, 0, Data.wanted.size() - 1).GetJoined();
104                         else
105                                 Result = "";
106
107                         user->WriteServ("CAP * %s :%s", subcommand.c_str(), Result.c_str());
108                 }
109                 else if (subcommand == "CLEAR")
110                 {
111                         CapData Data;
112
113                         Data.type = subcommand;
114                         Data.user = user;
115                         Data.creator = this->Creator;
116
117                         user->Extend("CAP_REGHOLD");
118                         Event event((char*) &Data, (Module*)this->Creator, "cap_clear");
119                         event.Send(this->ServerInstance);
120
121                         std::string Result = irc::stringjoiner(" ", Data.ack, 0, Data.ack.size() - 1).GetJoined();
122                         user->WriteServ("CAP * ACK :%s", Result.c_str());
123                 }
124                 else
125                 {
126                         user->WriteServ("410 * %s :Invalid CAP subcommand", subcommand.c_str());
127                 }
128
129                 return CMD_FAILURE;
130         }
131 };
132
133 class ModuleCAP : public Module
134 {
135         CommandCAP* newcommand;
136  public:
137         ModuleCAP(InspIRCd* Me)
138                 : Module(Me)
139         {
140                 // Create a new command
141                 newcommand = new CommandCAP(ServerInstance, this);
142                 ServerInstance->AddCommand(newcommand);
143
144                 Implementation eventlist[] = { I_OnCheckReady };
145                 ServerInstance->Modules->Attach(eventlist, this, 1);
146         }
147
148         virtual bool OnCheckReady(User* user)
149         {
150                 /* Users in CAP state get held until CAP END */
151                 if (user->GetExt("CAP_REGHOLD"))
152                         return true;
153
154                 return false;
155         }
156
157         virtual ~ModuleCAP()
158         {
159         }
160
161         virtual Version GetVersion()
162         {
163                 return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);
164         }
165 };
166
167 MODULE_INIT(ModuleCAP)
168