inspircd20.cpp

Go to the documentation of this file.
00001 /* Inspircd 2.0 functions
00002  *
00003  * (C) 2003-2013 Anope Team
00004  * Contact us at team@anope.org
00005  *
00006  * Please read COPYING and README for further details.
00007  *
00008  * Based on the original code of Epona by Lara.
00009  * Based on the original code of Services by Andy Church.
00010  */
00011 
00012 /*************************************************************************/
00013 
00014 #include "module.h"
00015 
00016 static unsigned int spanningtree_proto_ver = 0;
00017 
00018 static ServiceReference<IRCDProto> insp12("IRCDProto", "inspircd12");
00019 
00020 class InspIRCd20Proto : public IRCDProto
00021 {
00022  public:
00023         InspIRCd20Proto(Module *creator) : IRCDProto(creator, "InspIRCd 2.0")
00024         {
00025                 DefaultPseudoclientModes = "+I";
00026                 CanSVSNick = true;
00027                 CanSVSJoin = true;
00028                 CanSetVHost = true;
00029                 CanSetVIdent = true;
00030                 CanSQLine = true;
00031                 CanSZLine = true;
00032                 CanSVSHold = true;
00033                 CanCertFP = true;
00034                 RequiresID = true;
00035                 MaxModes = 20;
00036         }
00037 
00038         void SendConnect() anope_override
00039         {
00040                 UplinkSocket::Message() << "CAPAB START 1202";
00041                 UplinkSocket::Message() << "CAPAB CAPABILITIES :PROTOCOL=1202";
00042                 UplinkSocket::Message() << "CAPAB END";
00043                 insp12->SendConnect();
00044         }
00045 
00046         void SendSVSKillInternal(const BotInfo *source, User *user, const Anope::string &buf) anope_override { insp12->SendSVSKillInternal(source, user, buf); }
00047         void SendGlobalNotice(const BotInfo *bi, const Server *dest, const Anope::string &msg) anope_override { insp12->SendGlobalNotice(bi, dest, msg); }
00048         void SendGlobalPrivmsg(const BotInfo *bi, const Server *dest, const Anope::string &msg) anope_override { insp12->SendGlobalPrivmsg(bi, dest, msg); }
00049         void SendAkillDel(const XLine *x) anope_override { insp12->SendAkillDel(x); }
00050         void SendTopic(BotInfo *whosets, Channel *c) anope_override { insp12->SendTopic(whosets, c); };
00051         void SendVhostDel(User *u) anope_override { insp12->SendVhostDel(u); }
00052         void SendAkill(User *u, XLine *x) anope_override { insp12->SendAkill(u, x); }
00053         void SendNumericInternal(int numeric, const Anope::string &dest, const Anope::string &buf) anope_override { insp12->SendNumericInternal(numeric, dest, buf); }
00054         void SendModeInternal(const BotInfo *source, const Channel *dest, const Anope::string &buf) anope_override { insp12->SendModeInternal(source, dest, buf); }
00055         void SendModeInternal(const BotInfo *bi, const User *u, const Anope::string &buf) anope_override { insp12->SendModeInternal(bi, u, buf); }
00056         void SendClientIntroduction(const User *u) anope_override { insp12->SendClientIntroduction(u); }
00057         void SendServer(const Server *server) anope_override { insp12->SendServer(server); }
00058         void SendJoin(const User *user, Channel *c, const ChannelStatus *status) anope_override { insp12->SendJoin(user, c, status); }
00059         void SendSQLineDel(const XLine *x) anope_override { insp12->SendSQLineDel(x); }
00060         void SendSQLine(User *u, const XLine *x) anope_override { insp12->SendSQLine(u, x); }
00061         void SendVhost(User *u, const Anope::string &vident, const Anope::string &vhost) anope_override { insp12->SendVhost(u, vident, vhost); }
00062         void SendSVSHold(const Anope::string &nick) anope_override { insp12->SendSVSHold(nick); }
00063         void SendSVSHoldDel(const Anope::string &nick) anope_override { insp12->SendSVSHoldDel(nick); }
00064         void SendSZLineDel(const XLine *x) anope_override { insp12->SendSZLineDel(x); }
00065         void SendSZLine(User *u, const XLine *x) anope_override { insp12->SendSZLine(u, x); }
00066         void SendSVSJoin(const BotInfo *source, const User *u, const Anope::string &chan, const Anope::string &other) anope_override { insp12->SendSVSJoin(source, u, chan, other); }
00067         void SendSVSPart(const BotInfo *source, const User *u, const Anope::string &chan, const Anope::string &param) anope_override { insp12->SendSVSPart(source, u, chan, param); }
00068         void SendSWhois(const BotInfo *bi, const Anope::string &who, const Anope::string &mask) anope_override { insp12->SendSWhois(bi, who, mask); }
00069         void SendBOB() anope_override { insp12->SendBOB(); }
00070         void SendEOB() anope_override { insp12->SendEOB(); }
00071         void SendGlobopsInternal(const BotInfo *source, const Anope::string &buf) { insp12->SendGlobopsInternal(source, buf); }
00072         void SendLogin(User *u) anope_override { insp12->SendLogin(u); }
00073         void SendLogout(User *u) anope_override { insp12->SendLogout(u); }
00074         void SendChannel(Channel *c) anope_override { insp12->SendChannel(c); }
00075         bool IsExtbanValid(const Anope::string &mask) anope_override { return insp12->IsExtbanValid(mask); }
00076 };
00077 
00078 class InspIRCdExtBan : public ChannelModeList
00079 {
00080  public:
00081         InspIRCdExtBan(const Anope::string &mname, char modeChar) : ChannelModeList(mname, modeChar) { }
00082 
00083         bool Matches(const User *u, const Entry *e) anope_override
00084         {
00085                 const Anope::string &mask = e->GetMask();
00086 
00087                 if (mask.find("m:") == 0 || mask.find("N:") == 0)
00088                 {
00089                         Anope::string real_mask = mask.substr(3);
00090 
00091                         Entry en(this->name, real_mask);
00092                         if (en.Matches(u))
00093                                 return true;
00094                 }
00095                 else if (mask.find("j:") == 0)
00096                 {
00097                         Anope::string channel = mask.substr(3);
00098 
00099                         ChannelMode *cm = NULL;
00100                         if (channel[0] != '#')
00101                         {
00102                                 char modeChar = ModeManager::GetStatusChar(channel[0]);
00103                                 channel.erase(channel.begin());
00104                                 cm = ModeManager::FindChannelModeByChar(modeChar);
00105                                 if (cm != NULL && cm->type != MODE_STATUS)
00106                                         cm = NULL;
00107                         }
00108 
00109                         Channel *c = Channel::Find(channel);
00110                         if (c != NULL)
00111                         {
00112                                 ChanUserContainer *uc = c->FindUser(u);
00113                                 if (uc != NULL)
00114                                         if (cm == NULL || uc->status.modes.count(cm->name))
00115                                                 return true;
00116                         }
00117                 }
00118                 else if (mask.find("R:") == 0)
00119                 {
00120                         Anope::string real_mask = mask.substr(2);
00121 
00122                         if (u->IsIdentified() && real_mask.equals_ci(u->Account()->display))
00123                                 return true;
00124                 }
00125                 else if (mask.find("r:") == 0)
00126                 {
00127                         Anope::string real_mask = mask.substr(2);
00128 
00129                         if (Anope::Match(u->realname, real_mask))
00130                                 return true;
00131                 }
00132                 else if (mask.find("s:") == 0)
00133                 {
00134                         Anope::string real_mask = mask.substr(2);
00135 
00136                         if (Anope::Match(u->server->GetName(), real_mask))
00137                                 return true;
00138                 }
00139                 else if (mask.find("z:") == 0)
00140                 {
00141                         Anope::string real_mask = mask.substr(2);
00142 
00143                         if (Anope::Match(u->fingerprint, real_mask))
00144                                 return true;
00145                 }
00146 
00147                 return false;
00148         }
00149 };
00150 
00151 class ChannelModeFlood : public ChannelModeParam
00152 {
00153  public:
00154         ChannelModeFlood(char modeChar, bool minusNoArg) : ChannelModeParam("FLOOD", modeChar, minusNoArg) { }
00155 
00156         bool IsValid(const Anope::string &value) const anope_override
00157         {
00158                 try
00159                 {
00160                         Anope::string rest;
00161                         if (!value.empty() && value[0] != ':' && convertTo<int>(value[0] == '*' ? value.substr(1) : value, rest, false) > 0 && rest[0] == ':' && rest.length() > 1 && convertTo<int>(rest.substr(1), rest, false) > 0 && rest.empty())
00162                                 return true;
00163                 }
00164                 catch (const ConvertException &) { }
00165 
00166                 return false;
00167         }
00168 };
00169 
00170 struct IRCDMessageCapab : Message::Capab
00171 {
00172         IRCDMessageCapab(Module *creator) : Message::Capab(creator, "CAPAB") { SetFlag(IRCDMESSAGE_SOFT_LIMIT); }
00173 
00174         void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
00175         {
00176                 if (params[0].equals_cs("START"))
00177                 {
00178                         if (params.size() >= 2)
00179                                 spanningtree_proto_ver = (Anope::string(params[1]).is_pos_number_only() ? convertTo<unsigned>(params[1]) : 0);
00180 
00181                         if (spanningtree_proto_ver < 1202)
00182                         {
00183                                 UplinkSocket::Message() << "ERROR :Protocol mismatch, no or invalid protocol version given in CAPAB START";
00184                                 Anope::QuitReason = "Protocol mismatch, no or invalid protocol version given in CAPAB START";
00185                                 Anope::Quitting = true;
00186                                 return;
00187                         }
00188 
00189                         /* reset CAPAB */
00190                         Servers::Capab.insert("SERVERS");
00191                         Servers::Capab.insert("CHGHOST");
00192                         Servers::Capab.insert("CHGIDENT");
00193                         Servers::Capab.insert("TOPICLOCK");
00194                         IRCD->CanSVSHold = false;
00195                 }
00196                 else if (params[0].equals_cs("CHANMODES") && params.size() > 1)
00197                 {
00198                         spacesepstream ssep(params[1]);
00199                         Anope::string capab;
00200 
00201                         while (ssep.GetToken(capab))
00202                         {
00203                                 Anope::string modename = capab.substr(0, capab.find('='));
00204                                 Anope::string modechar = capab.substr(capab.find('=') + 1);
00205                                 ChannelMode *cm = NULL;
00206 
00207                                 if (modename.equals_cs("admin"))
00208                                         cm = new ChannelModeStatus("PROTECT", modechar.length() > 1 ? modechar[1] : modechar[0], modechar.length() > 1 ? modechar[0] : 0);
00209                                 else if (modename.equals_cs("allowinvite"))
00210                                         cm = new ChannelMode("ALLINVITE", modechar[0]);
00211                                 else if (modename.equals_cs("auditorium"))
00212                                         cm = new ChannelMode("AUDITORIUM", modechar[0]);
00213                                 else if (modename.equals_cs("ban"))
00214                                         cm = new InspIRCdExtBan("BAN", modechar[0]);
00215                                 else if (modename.equals_cs("banexception"))
00216                                         cm = new InspIRCdExtBan("EXCEPT", 'e');
00217                                 else if (modename.equals_cs("blockcaps"))
00218                                         cm = new ChannelMode("BLOCKCAPS", modechar[0]);
00219                                 else if (modename.equals_cs("blockcolor"))
00220                                         cm = new ChannelMode("BLOCKCOLOR", modechar[0]);
00221                                 else if (modename.equals_cs("c_registered"))
00222                                         cm = new ChannelModeRegistered(modechar[0]);
00223                                 else if (modename.equals_cs("censor"))
00224                                         cm = new ChannelMode("FILTER", modechar[0]);
00225                                 else if (modename.equals_cs("delayjoin"))
00226                                         cm = new ChannelMode("DELAYEDJOIN", modechar[0]);
00227                                 else if (modename.equals_cs("filter"))
00228                                         cm = new ChannelModeList("FILTER", modechar[0]);
00229                                 else if (modename.equals_cs("flood"))
00230                                         cm = new ChannelModeFlood(modechar[0], true);
00231                                 else if (modename.equals_cs("founder"))
00232                                         cm = new ChannelModeStatus("OWNER", modechar.length() > 1 ? modechar[1] : modechar[0], modechar.length() > 1 ? modechar[0] : 0);
00233                                 else if (modename.equals_cs("halfop"))
00234                                         cm = new ChannelModeStatus("HALFOP", modechar.length() > 1 ? modechar[1] : modechar[0], modechar.length() > 1 ? modechar[0] : 0);
00235                                 else if (modename.equals_cs("invex"))
00236                                         cm = new InspIRCdExtBan("INVITEOVERRIDE", 'I');
00237                                 else if (modename.equals_cs("inviteonly"))
00238                                         cm = new ChannelMode("INVITE", modechar[0]);
00239                                 else if (modename.equals_cs("joinflood"))
00240                                         cm = new ChannelModeParam("JOINFLOOD", modechar[0], true);
00241                                 else if (modename.equals_cs("key"))
00242                                         cm = new ChannelModeKey(modechar[0]);
00243                                 else if (modename.equals_cs("kicknorejoin"))
00244                                         cm = new ChannelModeParam("NOREJOIN", modechar[0], true);
00245                                 else if (modename.equals_cs("limit"))
00246                                         cm = new ChannelModeParam("LIMIT", modechar[0], true);
00247                                 else if (modename.equals_cs("moderated"))
00248                                         cm = new ChannelMode("MODERATED", modechar[0]);
00249                                 else if (modename.equals_cs("nickflood"))
00250                                         cm = new ChannelModeParam("NICKFLOOD", modechar[0], true);
00251                                 else if (modename.equals_cs("noctcp"))
00252                                         cm = new ChannelMode("NOCTCP", modechar[0]);
00253                                 else if (modename.equals_cs("noextmsg"))
00254                                         cm = new ChannelMode("NOEXTERNAL", modechar[0]);
00255                                 else if (modename.equals_cs("nokick"))
00256                                         cm = new ChannelMode("NOKICK", modechar[0]);
00257                                 else if (modename.equals_cs("noknock"))
00258                                         cm = new ChannelMode("NOKNOCK", modechar[0]);
00259                                 else if (modename.equals_cs("nonick"))
00260                                         cm = new ChannelMode("NONICK", modechar[0]);
00261                                 else if (modename.equals_cs("nonotice"))
00262                                         cm = new ChannelMode("NONOTICE", modechar[0]);
00263                                 else if (modename.equals_cs("op"))
00264                                         cm = new ChannelModeStatus("OP", modechar.length() > 1 ? modechar[1] : modechar[0], modechar.length() > 1 ? modechar[0] : 0);
00265                                 else if (modename.equals_cs("operonly"))
00266                                         cm = new ChannelModeOper(modechar[0]);
00267                                 else if (modename.equals_cs("permanent"))
00268                                         cm = new ChannelMode("PERM", modechar[0]);
00269                                 else if (modename.equals_cs("private"))
00270                                         cm = new ChannelMode("PRIVATE", modechar[0]);
00271                                 else if (modename.equals_cs("redirect"))
00272                                         cm = new ChannelModeParam("REDIRECT", modechar[0], true);
00273                                 else if (modename.equals_cs("reginvite"))
00274                                         cm = new ChannelMode("REGISTEREDONLY", modechar[0]);
00275                                 else if (modename.equals_cs("regmoderated"))
00276                                         cm = new ChannelMode("REGMODERATED", modechar[0]);
00277                                 else if (modename.equals_cs("secret"))
00278                                         cm = new ChannelMode("SECRET", modechar[0]);
00279                                 else if (modename.equals_cs("sslonly"))
00280                                         cm = new ChannelMode("SSL", modechar[0]);
00281                                 else if (modename.equals_cs("stripcolor"))
00282                                         cm = new ChannelMode("STRIPCOLOR", modechar[0]);
00283                                 else if (modename.equals_cs("topiclock"))
00284                                         cm = new ChannelMode("TOPIC", modechar[0]);
00285                                 else if (modename.equals_cs("voice"))
00286                                         cm = new ChannelModeStatus("VOICE", modechar.length() > 1 ? modechar[1] : modechar[0], modechar.length() > 1 ? modechar[0] : 0);
00287                                 /* Unknown status mode, (customprefix) - add it */
00288                                 else if (modechar.length() == 2)
00289                                         cm = new ChannelModeStatus("END", modechar[1], modechar[0]);
00290                                 /* else don't do anything here, we will get it in CAPAB CAPABILITIES */
00291 
00292                                 if (cm)
00293                                         ModeManager::AddChannelMode(cm);
00294                                 else
00295                                         Log() << "Unrecognized mode string in CAPAB CHANMODES: " << capab;
00296                         }
00297                 }
00298                 if (params[0].equals_cs("USERMODES") && params.size() > 1)
00299                 {
00300                         spacesepstream ssep(params[1]);
00301                         Anope::string capab;
00302 
00303                         while (ssep.GetToken(capab))
00304                         {
00305                                 Anope::string modename = capab.substr(0, capab.find('='));
00306                                 Anope::string modechar = capab.substr(capab.find('=') + 1);
00307                                 UserMode *um = NULL;
00308 
00309                                 if (modename.equals_cs("bot"))
00310                                         um = new UserMode("BOT", modechar[0]);
00311                                 else if (modename.equals_cs("callerid"))
00312                                         um = new UserMode("CALLERID", modechar[0]);
00313                                 else if (modename.equals_cs("cloak"))
00314                                         um = new UserMode("CLOAK", modechar[0]);
00315                                 else if (modename.equals_cs("deaf"))
00316                                         um = new UserMode("DEAF", modechar[0]);
00317                                 else if (modename.equals_cs("deaf_commonchan"))
00318                                         um = new UserMode("COMMONCHANS", modechar[0]);
00319                                 else if (modename.equals_cs("helpop"))
00320                                         um = new UserMode("HELPOP", modechar[0]);
00321                                 else if (modename.equals_cs("hidechans"))
00322                                         um = new UserMode("PRIV", modechar[0]);
00323                                 else if (modename.equals_cs("hideoper"))
00324                                         um = new UserMode("HIDEOPER", modechar[0]);
00325                                 else if (modename.equals_cs("invisible"))
00326                                         um = new UserMode("INVIS", modechar[0]);
00327                                 else if (modename.equals_cs("invis-oper"))
00328                                         um = new UserMode("INVISIBLE_OPER", modechar[0]);
00329                                 else if (modename.equals_cs("oper"))
00330                                         um = new UserMode("OPER", modechar[0]);
00331                                 else if (modename.equals_cs("regdeaf"))
00332                                         um = new UserMode("REGPRIV", modechar[0]);
00333                                 else if (modename.equals_cs("servprotect"))
00334                                 {
00335                                         um = new UserMode("PROTECTED", modechar[0]);
00336                                         IRCD->DefaultPseudoclientModes += "k";
00337                                 }
00338                                 else if (modename.equals_cs("showwhois"))
00339                                         um = new UserMode("WHOIS", modechar[0]);
00340                                 else if (modename.equals_cs("u_censor"))
00341                                         um = new UserMode("FILTER", modechar[0]);
00342                                 else if (modename.equals_cs("u_registered"))
00343                                         um = new UserMode("REGISTERED", modechar[0]);
00344                                 else if (modename.equals_cs("u_stripcolor"))
00345                                         um = new UserMode("STRIPCOLOR", modechar[0]);
00346                                 else if (modename.equals_cs("wallops"))
00347                                         um = new UserMode("WALLOPS", modechar[0]);
00348 
00349                                 if (um)
00350                                         ModeManager::AddUserMode(um);
00351                                 else
00352                                         Log() << "Unrecognized mode string in CAPAB USERMODES: " << capab;
00353                         }
00354                 }
00355                 else if (params[0].equals_cs("MODULES") && params.size() > 1)
00356                 {
00357                         spacesepstream ssep(params[1]);
00358                         Anope::string module;
00359 
00360                         while (ssep.GetToken(module))
00361                         {
00362                                 if (module.equals_cs("m_svshold.so"))
00363                                         IRCD->CanSVSHold = true;
00364                                 else if (module.find("m_rline.so") == 0)
00365                                 {
00366                                         Servers::Capab.insert("RLINE");
00367                                         if (!Config->RegexEngine.empty() && module.length() > 11 && Config->RegexEngine != module.substr(11))
00368                                                 Log() << "Warning: InspIRCd is using regex engine " << module.substr(11) << ", but we have " << Config->RegexEngine << ". This may cause inconsistencies.";
00369                                 }
00370                                 else if (module.equals_cs("m_topiclock.so"))
00371                                         Servers::Capab.insert("TOPICLOCK");
00372                         }
00373                 }
00374                 else if (params[0].equals_cs("MODSUPPORT") && params.size() > 1)
00375                 {
00376                         spacesepstream ssep(params[1]);
00377                         Anope::string module;
00378 
00379                         while (ssep.GetToken(module))
00380                         {
00381                                 if (module.equals_cs("m_services_account.so"))
00382                                         Servers::Capab.insert("SERVICES");
00383                                 else if (module.equals_cs("m_chghost.so"))
00384                                         Servers::Capab.insert("CHGHOST");
00385                                 else if (module.equals_cs("m_chgident.so"))
00386                                         Servers::Capab.insert("CHGIDENT");
00387                         }
00388                 }
00389                 else if (params[0].equals_cs("CAPABILITIES") && params.size() > 1)
00390                 {
00391                         spacesepstream ssep(params[1]);
00392                         Anope::string capab;
00393                         while (ssep.GetToken(capab))
00394                         {
00395                                 if (capab.find("CHANMODES") != Anope::string::npos)
00396                                 {
00397                                         Anope::string modes(capab.begin() + 10, capab.end());
00398                                         commasepstream sep(modes);
00399                                         Anope::string modebuf;
00400 
00401                                         sep.GetToken(modebuf);
00402                                         for (size_t t = 0, end = modebuf.length(); t < end; ++t)
00403                                         {
00404                                                 if (ModeManager::FindChannelModeByChar(modebuf[t]))
00405                                                         continue;
00406                                                 ModeManager::AddChannelMode(new ChannelModeList("END", modebuf[t]));
00407                                         }
00408 
00409                                         sep.GetToken(modebuf);
00410                                         for (size_t t = 0, end = modebuf.length(); t < end; ++t)
00411                                         {
00412                                                 if (ModeManager::FindChannelModeByChar(modebuf[t]))
00413                                                         continue;
00414                                                 ModeManager::AddChannelMode(new ChannelModeParam("END", modebuf[t]));
00415                                         }
00416 
00417                                         sep.GetToken(modebuf);
00418                                         for (size_t t = 0, end = modebuf.length(); t < end; ++t)
00419                                         {
00420                                                 if (ModeManager::FindChannelModeByChar(modebuf[t]))
00421                                                         continue;
00422                                                 ModeManager::AddChannelMode(new ChannelModeParam("END", true));
00423                                         }
00424 
00425                                         sep.GetToken(modebuf);
00426                                         for (size_t t = 0, end = modebuf.length(); t < end; ++t)
00427                                         {
00428                                                 if (ModeManager::FindChannelModeByChar(modebuf[t]))
00429                                                         continue;
00430                                                 ModeManager::AddChannelMode(new ChannelMode("END", modebuf[t]));
00431                                         }
00432                                 }
00433                                 else if (capab.find("USERMODES") != Anope::string::npos)
00434                                 {
00435                                         Anope::string modes(capab.begin() + 10, capab.end());
00436                                         commasepstream sep(modes);
00437                                         Anope::string modebuf;
00438 
00439                                         sep.GetToken(modebuf);
00440                                         sep.GetToken(modebuf);
00441 
00442                                         if (sep.GetToken(modebuf))
00443                                                 for (size_t t = 0, end = modebuf.length(); t < end; ++t)
00444                                                         ModeManager::AddUserMode(new UserModeParam("END", modebuf[t]));
00445 
00446                                         if (sep.GetToken(modebuf))
00447                                                 for (size_t t = 0, end = modebuf.length(); t < end; ++t)
00448                                                         ModeManager::AddUserMode(new UserMode("END", modebuf[t]));
00449                                 }
00450                                 else if (capab.find("MAXMODES=") != Anope::string::npos)
00451                                 {
00452                                         Anope::string maxmodes(capab.begin() + 9, capab.end());
00453                                         IRCD->MaxModes = maxmodes.is_pos_number_only() ? convertTo<unsigned>(maxmodes) : 3;
00454                                 }
00455                                 else if (capab.find("PREFIX=") != Anope::string::npos)
00456                                 {
00457                                         Anope::string modes(capab.begin() + 8, capab.begin() + capab.find(')'));
00458                                         Anope::string chars(capab.begin() + capab.find(')') + 1, capab.end());
00459                                         short level = modes.length() - 1;
00460 
00461                                         for (size_t t = 0, end = modes.length(); t < end; ++t)
00462                                         {
00463                                                 ChannelMode *cm = ModeManager::FindChannelModeByChar(modes[t]);
00464                                                 if (cm == NULL || cm->type != MODE_STATUS)
00465                                                 {
00466                                                         Log() << "CAPAB PREFIX gave unknown channel status mode " << modes[t];
00467                                                         continue;
00468                                                 }
00469 
00470                                                 ChannelModeStatus *cms = anope_dynamic_static_cast<ChannelModeStatus *>(cm);
00471                                                 cms->level = level--;
00472                                         }
00473                                 }
00474                         }
00475                 }
00476                 else if (params[0].equals_cs("END"))
00477                 {
00478                         if (!Servers::Capab.count("SERVICES"))
00479                         {
00480                                 UplinkSocket::Message() << "ERROR :m_services_account.so is not loaded. This is required by Anope";
00481                                 Anope::QuitReason = "ERROR: Remote server does not have the m_services_account module loaded, and this is required.";
00482                                 Anope::Quitting = true;
00483                                 return;
00484                         }
00485                         if (!ModeManager::FindUserModeByName("PRIV"))
00486                         {
00487                                 UplinkSocket::Message() << "ERROR :m_hidechans.so is not loaded. This is required by Anope";
00488                                 Anope::QuitReason = "ERROR: Remote server does not have the m_hidechans module loaded, and this is required.";
00489                                 Anope::Quitting = true;
00490                                 return;
00491                         }
00492                         if (!IRCD->CanSVSHold)
00493                                 Log() << "SVSHOLD missing, Usage disabled until module is loaded.";
00494                         if (!Servers::Capab.count("CHGHOST"))
00495                                 Log() << "CHGHOST missing, Usage disabled until module is loaded.";
00496                         if (!Servers::Capab.count("CHGIDENT"))
00497                                 Log() << "CHGIDENT missing, Usage disabled until module is loaded.";
00498                         if (!Servers::Capab.count("TOPICLOCK") && Config->UseServerSideTopicLock)
00499                                 Log() << "m_topiclock missing, server side topic locking disabled until module is loaded.";
00500                 }
00501 
00502                 Message::Capab::Run(source, params);
00503         }
00504 };
00505 
00506 struct IRCDMessageEncap : IRCDMessage
00507 {
00508         IRCDMessageEncap(Module *creator) : IRCDMessage(creator, "ENCAP", 4) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); }
00509 
00510         void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
00511         {
00512                 if (Anope::Match(Me->GetSID(), params[0]) == false)
00513                         return;
00514 
00515                 if (params[1] == "CHGIDENT")
00516                 {
00517                         User *u = User::Find(params[2]);
00518                         if (!u || u->server != Me)
00519                                 return;
00520 
00521                         u->SetIdent(params[3]);
00522                         UplinkSocket::Message(u) << "FIDENT " << params[3];
00523                 }
00524                 else if (params[1] == "CHGHOST")
00525                 {
00526                         User *u = User::Find(params[2]);
00527                         if (!u || u->server != Me)
00528                                 return;
00529 
00530                         u->SetDisplayedHost(params[3]);
00531                         UplinkSocket::Message(u) << "FHOST " << params[3];
00532                 }
00533                 else if (params[1] == "CHGNAME")
00534                 {
00535                         User *u = User::Find(params[2]);
00536                         if (!u || u->server != Me)
00537                                 return;
00538 
00539                         u->SetRealname(params[3]);
00540                         UplinkSocket::Message(u) << "FNAME " << params[3];
00541                 }
00542                 else if (Config->NSSASL && params[1] == "SASL" && params.size() == 6)
00543                 {
00544                         class InspIRCDSASLIdentifyRequest : public IdentifyRequest
00545                         {
00546                                 Anope::string uid;
00547 
00548                          public:
00549                                 InspIRCDSASLIdentifyRequest(Module *m, const Anope::string &id, const Anope::string &acc, const Anope::string &pass) : IdentifyRequest(m, acc, pass), uid(id) { }
00550 
00551                                 void OnSuccess() anope_override
00552                                 {
00553                                         UplinkSocket::Message(Me) << "METADATA " << this->uid << " accountname :" << this->GetAccount();
00554                                         UplinkSocket::Message(Me) << "ENCAP " << this->uid.substr(0, 3) << " SASL " << Me->GetSID() << " " << this->uid << " D S";
00555                                 }
00556 
00557                                 void OnFail() anope_override
00558                                 {
00559                                         UplinkSocket::Message(Me) << "ENCAP " << this->uid.substr(0, 3) << " SASL " << Me->GetSID() << " " << this->uid << " " << " D F";
00560 
00561                                         Log(NickServ) << "A user failed to identify for account " << this->GetAccount() << " using SASL";
00562                                 }
00563                         };
00564 
00565                         /*
00566                         Received: :869 ENCAP * SASL 869AAAAAH * S PLAIN
00567                         Sent: :00B ENCAP 869 SASL 00B 869AAAAAH C +
00568                         Received: :869 ENCAP * SASL 869AAAAAH 00B C QWRhbQBBZGFtAG1vbw==
00569                                                                     base64(account\0account\0pass)
00570                         */
00571                         if (params[4] == "S")
00572                         {
00573                                 if (params[5] == "PLAIN")
00574                                         UplinkSocket::Message(Me) << "ENCAP " << params[2].substr(0, 3) << " SASL " << Me->GetSID() << " " << params[2] << " C +";
00575                                 else
00576                                         UplinkSocket::Message(Me) << "ENCAP " << params[2].substr(0, 3) << " SASL " << Me->GetSID() << " " << params[2] << " D F";
00577                         }
00578                         else if (params[4] == "C")
00579                         {
00580                                 Anope::string decoded;
00581                                 Anope::B64Decode(params[5], decoded);
00582 
00583                                 size_t p = decoded.find('\0');
00584                                 if (p == Anope::string::npos)
00585                                         return;
00586                                 decoded = decoded.substr(p + 1);
00587 
00588                                 p = decoded.find('\0');
00589                                 if (p == Anope::string::npos)
00590                                         return;
00591 
00592                                 Anope::string acc = decoded.substr(0, p),
00593                                         pass = decoded.substr(p + 1);
00594 
00595                                 if (acc.empty() || pass.empty())
00596                                         return;
00597 
00598                                 IdentifyRequest *req = new InspIRCDSASLIdentifyRequest(this->owner, params[2], acc, pass);
00599                                 FOREACH_MOD(I_OnCheckAuthentication, OnCheckAuthentication(NULL, req));
00600                                 req->Dispatch();
00601                         }
00602                 }
00603         }
00604 };
00605 
00606 struct IRCDMessageFIdent : IRCDMessage
00607 {
00608         IRCDMessageFIdent(Module *creator) : IRCDMessage(creator, "FIDENT", 1) { SetFlag(IRCDMESSAGE_REQUIRE_USER); }
00609 
00610         void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
00611         {
00612                 source.GetUser()->SetIdent(params[0]);
00613         }
00614 };
00615 
00616 class ProtoInspIRCd : public Module
00617 {
00618         Module *m_insp12;
00619 
00620         InspIRCd20Proto ircd_proto;
00621 
00622         /* Core message handlers */
00623         Message::Away message_away;
00624         Message::Error message_error;
00625         Message::Join message_join;
00626         Message::Kick message_kick;
00627         Message::Kill message_kill;
00628         Message::MOTD message_motd;
00629         Message::Part message_part;
00630         Message::Ping message_ping;
00631         Message::Privmsg message_privmsg;
00632         Message::Quit message_quit;
00633         Message::SQuit message_squit;
00634         Message::Stats message_stats;
00635         Message::Topic message_topic;
00636         Message::Version message_version;
00637 
00638         /* InspIRCd 1.2 message handlers */
00639         ServiceAlias message_endburst, message_fhost, message_fjoin, message_fmode,
00640                                 message_ftopic, message_idle, message_metadata, message_mode,
00641                                 message_nick, message_opertype, message_rsquit, message_server,
00642                                 message_time, message_uid;
00643 
00644         /* Our message handlers */
00645         IRCDMessageCapab message_capab;
00646         IRCDMessageEncap message_encap;
00647         IRCDMessageFIdent message_fident;
00648 
00649         void SendChannelMetadata(Channel *c, const Anope::string &metadataname, const Anope::string &value)
00650         {
00651                 UplinkSocket::Message(Me) << "METADATA " << c->name << " " << metadataname << " :" << value;
00652         }
00653 
00654  public:
00655         ProtoInspIRCd(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, PROTOCOL),
00656                 ircd_proto(this),
00657                 message_away(this), message_error(this), message_join(this), message_kick(this), message_kill(this),
00658                 message_motd(this), message_part(this), message_ping(this), message_privmsg(this), message_quit(this),
00659                 message_squit(this), message_stats(this), message_topic(this), message_version(this),
00660 
00661                 message_endburst("IRCDMessage", "inspircd20/endburst", "inspircd12/endburst"),
00662                 message_fhost("IRCDMessage", "inspircd20/fhost", "inspircd12/fhost"),
00663                 message_fjoin("IRCDMessage", "inspircd20/fjoin", "inspircd12/fjoin"),
00664                 message_fmode("IRCDMessage", "inspircd20/fmode", "inspircd12/fmode"),
00665                 message_ftopic("IRCDMessage", "inspircd20/ftopic", "inspircd12/ftopic"),
00666                 message_idle("IRCDMessage", "inspircd20/idle", "inspircd12/idle"),
00667                 message_metadata("IRCDMessage", "inspircd20/metadata", "inspircd12/metadata"),
00668                 message_mode("IRCDMessage", "inspircd20/mode", "inspircd12/mode"),
00669                 message_nick("IRCDMessage", "inspircd20/nick", "inspircd12/nick"),
00670                 message_opertype("IRCDMessage", "inspircd20/opertype", "inspircd12/opertype"),
00671                 message_rsquit("IRCDMessage", "inspircd20/rsquit", "inspircd12/rsquit"),
00672                 message_server("IRCDMessage", "inspircd20/server", "inspircd12/server"),
00673                 message_time("IRCDMessage", "inspircd20/time", "inspircd12/time"),
00674                 message_uid("IRCDMessage", "inspircd20/uid", "inspircd12/uid"),
00675 
00676                 message_capab(this), message_encap(this), message_fident(this)
00677         {
00678                 this->SetAuthor("Anope");
00679 
00680                 if (ModuleManager::LoadModule("inspircd12", User::Find(creator)) != MOD_ERR_OK)
00681                         throw ModuleException("Unable to load inspircd12");
00682                 m_insp12 = ModuleManager::FindModule("inspircd12");
00683                 if (!m_insp12)
00684                         throw ModuleException("Unable to find inspircd12");
00685                 if (!insp12)
00686                         throw ModuleException("No protocol interface for insp12");
00687                 ModuleManager::DetachAll(m_insp12);
00688 
00689                 Implementation i[] = { I_OnUserNickChange, I_OnChannelCreate, I_OnChanRegistered, I_OnDelChan, I_OnMLock, I_OnUnMLock, I_OnSetChannelOption };
00690                 ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation));
00691         }
00692 
00693         ~ProtoInspIRCd()
00694         {
00695                 ModuleManager::UnloadModule(m_insp12, NULL);
00696         }
00697 
00698         void OnUserNickChange(User *u, const Anope::string &) anope_override
00699         {
00700                 u->RemoveModeInternal(ModeManager::FindUserModeByName("REGISTERED"));
00701         }
00702 
00703         void OnChannelCreate(Channel *c) anope_override
00704         {
00705                 if (c->ci && (Config->UseServerSideMLock || Config->UseServerSideTopicLock))
00706                         this->OnChanRegistered(c->ci);
00707         }
00708 
00709         void OnChanRegistered(ChannelInfo *ci) anope_override
00710         {
00711                 if (Config->UseServerSideMLock && ci->c)
00712                 {
00713                         Anope::string modes = ci->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", "");
00714                         SendChannelMetadata(ci->c, "mlock", modes);
00715                 }
00716 
00717                 if (Config->UseServerSideTopicLock && Servers::Capab.count("TOPICLOCK") && ci->c)
00718                 {
00719                         Anope::string on = ci->HasExt("TOPICLOCK") ? "1" : "";
00720                         SendChannelMetadata(ci->c, "topiclock", on);
00721                 }
00722         }
00723 
00724         void OnDelChan(ChannelInfo *ci) anope_override
00725         {
00726                 if (Config->UseServerSideMLock && ci->c)
00727                         SendChannelMetadata(ci->c, "mlock", "");
00728 
00729                 if (Config->UseServerSideTopicLock && Servers::Capab.count("TOPICLOCK") && ci->c)
00730                         SendChannelMetadata(ci->c, "topiclock", "");
00731         }
00732 
00733         EventReturn OnMLock(ChannelInfo *ci, ModeLock *lock) anope_override
00734         {
00735                 ChannelMode *cm = ModeManager::FindChannelModeByName(lock->name);
00736                 if (cm && ci->c && (cm->type == MODE_REGULAR || cm->type == MODE_PARAM) && Config->UseServerSideMLock)
00737                 {
00738                         Anope::string modes = ci->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", "") + cm->mchar;
00739                         SendChannelMetadata(ci->c, "mlock", modes);
00740                 }
00741 
00742                 return EVENT_CONTINUE;
00743         }
00744 
00745         EventReturn OnUnMLock(ChannelInfo *ci, ModeLock *lock) anope_override
00746         {
00747                 ChannelMode *cm = ModeManager::FindChannelModeByName(lock->name);
00748                 if (cm && ci->c && (cm->type == MODE_REGULAR || cm->type == MODE_PARAM) && Config->UseServerSideMLock)
00749                 {
00750                         Anope::string modes = ci->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", "").replace_all_cs(cm->mchar, "");
00751                         SendChannelMetadata(ci->c, "mlock", modes);
00752                 }
00753 
00754                 return EVENT_CONTINUE;
00755         }
00756 
00757         EventReturn OnSetChannelOption(CommandSource &source, Command *cmd, ChannelInfo *ci, const Anope::string &setting) anope_override
00758         {
00759                 if (cmd->name == "chanserv/set/topiclock" && ci->c)
00760                         SendChannelMetadata(ci->c, "topiclock", setting.equals_ci("ON") ? "1" : "");
00761 
00762                 return EVENT_CONTINUE;
00763         }
00764 };
00765 
00766 MODULE_INIT(ProtoInspIRCd)