The InspIRCd Project
Home | Developers | Wiki | Forums | Bug Tracker | SVN | Download
Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

m_cap.cpp

Go to the documentation of this file.
00001 /*       +------------------------------------+
00002  *       | Inspire Internet Relay Chat Daemon |
00003  *       +------------------------------------+
00004  *
00005  *  InspIRCd: (C) 2002-2008 InspIRCd Development Team
00006  * See: http://www.inspircd.org/wiki/index.php/Credits
00007  *
00008  * This program is free but copyrighted software; see
00009  *            the file COPYING for details.
00010  *
00011  * ---------------------------------------------------
00012  */
00013 
00014 #include "inspircd.h"
00015 #include "m_cap.h"
00016 
00017 /* $ModDesc: Provides the CAP negotiation mechanism seen in ratbox-derived ircds */
00018 
00019 /*
00020 CAP LS
00021 :alfred.staticbox.net CAP * LS :multi-prefix sasl
00022 CAP REQ :multi-prefix
00023 :alfred.staticbox.net CAP * ACK :multi-prefix
00024 CAP CLEAR
00025 :alfred.staticbox.net CAP * ACK :-multi-prefix
00026 CAP REQ :multi-prefix
00027 :alfred.staticbox.net CAP * ACK :multi-prefix
00028 CAP LIST
00029 :alfred.staticbox.net CAP * LIST :multi-prefix
00030 CAP END
00031 */
00032 
00035 class CommandCAP : public Command
00036 {
00037         Module* Creator;
00038  public:
00039         CommandCAP (InspIRCd* Instance, Module* mod) : Command(Instance,"CAP", 0, 1, true), Creator(mod)
00040         {
00041                 this->source = "m_cap.so";
00042         }
00043 
00044         CmdResult Handle (const std::vector<std::string> &parameters, User *user)
00045         {
00046                 irc::string subcommand = parameters[0].c_str();
00047 
00048                 if (subcommand == "REQ")
00049                 {
00050                         CapData Data;
00051 
00052                         Data.type = subcommand;
00053                         Data.user = user;
00054                         Data.creator = this->Creator;
00055 
00056                         if (parameters.size() < 2)
00057                                 return CMD_FAILURE;
00058 
00059                         // tokenize the input into a nice list of requested caps
00060                         std::string param = parameters[1];
00061                         std::string cap_;
00062                         irc::spacesepstream cap_stream(param);
00063 
00064                         while (cap_stream.GetToken(cap_))
00065                         {
00066                                 Data.wanted.push_back(cap_);
00067                         }
00068 
00069                         user->Extend("CAP_REGHOLD");
00070                         Event event((char*) &Data, (Module*)this->Creator, "cap_req");
00071                         event.Send(this->ServerInstance);
00072 
00073                         if (Data.ack.size() > 0)
00074                         {
00075                                 std::string AckResult = irc::stringjoiner(" ", Data.ack, 0, Data.ack.size() - 1).GetJoined();
00076                                 user->WriteServ("CAP * ACK :%s", AckResult.c_str());
00077                         }
00078 
00079                         if (Data.wanted.size() > 0)
00080                         {
00081                                 std::string NakResult = irc::stringjoiner(" ", Data.wanted, 0, Data.wanted.size() - 1).GetJoined();
00082                                 user->WriteServ("CAP * NAK :%s", NakResult.c_str());
00083                         }
00084                 }
00085                 else if (subcommand == "END")
00086                 {
00087                         user->Shrink("CAP_REGHOLD");
00088                 }
00089                 else if ((subcommand == "LS") || (subcommand == "LIST"))
00090                 {
00091                         CapData Data;
00092 
00093                         Data.type = subcommand;
00094                         Data.user = user;
00095                         Data.creator = this->Creator;
00096 
00097                         user->Extend("CAP_REGHOLD");
00098                         Event event((char*) &Data, (Module*)this->Creator, subcommand == "LS" ? "cap_ls" : "cap_list");
00099                         event.Send(this->ServerInstance);
00100 
00101                         std::string Result;
00102                         if (Data.wanted.size() > 0)
00103                                 Result = irc::stringjoiner(" ", Data.wanted, 0, Data.wanted.size() - 1).GetJoined();
00104                         else
00105                                 Result = "";
00106 
00107                         user->WriteServ("CAP * %s :%s", subcommand.c_str(), Result.c_str());
00108                 }
00109                 else if (subcommand == "CLEAR")
00110                 {
00111                         CapData Data;
00112 
00113                         Data.type = subcommand;
00114                         Data.user = user;
00115                         Data.creator = this->Creator;
00116 
00117                         user->Extend("CAP_REGHOLD");
00118                         Event event((char*) &Data, (Module*)this->Creator, "cap_clear");
00119                         event.Send(this->ServerInstance);
00120 
00121                         std::string Result = irc::stringjoiner(" ", Data.ack, 0, Data.ack.size() - 1).GetJoined();
00122                         user->WriteServ("CAP * ACK :%s", Result.c_str());
00123                 }
00124                 else
00125                 {
00126                         user->WriteNumeric(ERR_INVALIDCAPSUBCOMMAND, "* %s :Invalid CAP subcommand", subcommand.c_str());
00127                 }
00128 
00129                 return CMD_FAILURE;
00130         }
00131 };
00132 
00133 class ModuleCAP : public Module
00134 {
00135         CommandCAP* newcommand;
00136  public:
00137         ModuleCAP(InspIRCd* Me)
00138                 : Module(Me)
00139         {
00140                 // Create a new command
00141                 newcommand = new CommandCAP(ServerInstance, this);
00142                 ServerInstance->AddCommand(newcommand);
00143 
00144                 Implementation eventlist[] = { I_OnCheckReady };
00145                 ServerInstance->Modules->Attach(eventlist, this, 1);
00146         }
00147 
00148         virtual bool OnCheckReady(User* user)
00149         {
00150                 /* Users in CAP state get held until CAP END */
00151                 if (user->GetExt("CAP_REGHOLD"))
00152                         return false;
00153 
00154                 return true;
00155         }
00156 
00157         virtual ~ModuleCAP()
00158         {
00159         }
00160 
00161         virtual Version GetVersion()
00162         {
00163                 return Version("$Id: m_cap.cpp 10333 2008-08-28 15:40:16Z w00t $", VF_VENDOR, API_VERSION);
00164         }
00165 };
00166 
00167 MODULE_INIT(ModuleCAP)
00168