inspircd12.cpp

Go to the documentation of this file.
00001 /* inspircd 1.2 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 class ChannelModeFlood : public ChannelModeParam
00017 {
00018  public:
00019         ChannelModeFlood(char modeChar, bool minusNoArg) : ChannelModeParam("FLOOD", modeChar, minusNoArg) { }
00020 
00021         bool IsValid(const Anope::string &value) const anope_override
00022         {
00023                 try
00024                 {
00025                         Anope::string rest;
00026                         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())
00027                                 return true;
00028                 }
00029                 catch (const ConvertException &) { }
00030 
00031                 return false;
00032         }
00033 };
00034 
00035 class InspIRCd12Proto : public IRCDProto
00036 {
00037  private:
00038         void SendSVSKillInternal(const BotInfo *source, User *user, const Anope::string &buf) anope_override
00039         {
00040                 IRCDProto::SendSVSKillInternal(source, user, buf);
00041                 user->KillInternal(source ? source->nick : Me->GetName(), buf);
00042         }
00043 
00044         void SendChgIdentInternal(const Anope::string &nick, const Anope::string &vIdent)
00045         {
00046                 if (!Servers::Capab.count("CHGIDENT"))
00047                         Log() << "CHGIDENT not loaded!";
00048                 else
00049                         UplinkSocket::Message(HostServ) << "CHGIDENT " << nick << " " << vIdent;
00050         }
00051 
00052         void SendChgHostInternal(const Anope::string &nick, const Anope::string &vhost)
00053         {
00054                 if (!Servers::Capab.count("CHGHOST"))
00055                         Log() << "CHGHOST not loaded!";
00056                 else
00057                         UplinkSocket::Message(Me) << "CHGHOST " << nick << " " << vhost;
00058         }
00059 
00060         void SendAddLine(const Anope::string &xtype, const Anope::string &mask, time_t duration, const Anope::string &addedby, const Anope::string &reason)
00061         {
00062                 UplinkSocket::Message(Me) << "ADDLINE " << xtype << " " << mask << " " << addedby << " " << Anope::CurTime << " " << duration << " :" << reason;
00063         }
00064 
00065         void SendDelLine(const Anope::string &xtype, const Anope::string &mask)
00066         {
00067                 UplinkSocket::Message(Me) << "DELLINE " << xtype << " " << mask;
00068         }
00069 
00070  public:
00071         InspIRCd12Proto(Module *creator) : IRCDProto(creator, "InspIRCd 1.2")
00072         {
00073                 DefaultPseudoclientModes = "+I";
00074                 CanSVSNick = true;
00075                 CanSVSJoin = true;
00076                 CanSetVHost = true;
00077                 CanSetVIdent = true;
00078                 CanSQLine = true;
00079                 CanSZLine = true;
00080                 CanSVSHold = true;
00081                 CanCertFP = true;
00082                 RequiresID = true;
00083                 MaxModes = 20;
00084         }
00085 
00086         void SendGlobalNotice(const BotInfo *bi, const Server *dest, const Anope::string &msg) anope_override
00087         {
00088                 UplinkSocket::Message(bi) << "NOTICE $" << dest->GetName() << " :" << msg;
00089         }
00090 
00091         void SendGlobalPrivmsg(const BotInfo *bi, const Server *dest, const Anope::string &msg) anope_override
00092         {
00093                 UplinkSocket::Message(bi) << "PRIVMSG $" << dest->GetName() << " :" << msg;
00094         }
00095 
00096         void SendAkillDel(const XLine *x) anope_override
00097         {
00098                 /* InspIRCd may support regex bans */
00099                 if (x->IsRegex() && Servers::Capab.count("RLINE"))
00100                 {
00101                         Anope::string mask = x->mask;
00102                         size_t h = x->mask.find('#');
00103                         if (h != Anope::string::npos)
00104                                 mask = mask.replace(h, 1, ' ');
00105                         SendDelLine("R", mask);
00106                         return;
00107                 }
00108                 else if (x->IsRegex() || x->HasNickOrReal())
00109                         return;
00110 
00111                 SendDelLine("G", x->mask);
00112         }
00113 
00114         void SendTopic(BotInfo *whosets, Channel *c) anope_override
00115         {
00116                 if (Servers::Capab.count("SVSTOPIC"))
00117                 {
00118                         UplinkSocket::Message(c->ci->WhoSends()) << "SVSTOPIC " << c->name << " " << c->topic_ts << " " << c->topic_setter << " :" << c->topic;
00119                 }
00120                 else
00121                 {
00122                         /* If the last time a topic was set is after the TS we want for this topic we must bump this topic's timestamp to now */
00123                         time_t ts = c->topic_ts;
00124                         if (c->topic_time > ts)
00125                                 ts = Anope::CurTime;
00126                         /* But don't modify c->topic_ts, it should remain set to the real TS we want as ci->last_topic_time pulls from it */
00127                         UplinkSocket::Message(whosets) << "FTOPIC " << c->name << " " << ts << " " << c->topic_setter << " :" << c->topic;
00128                 }
00129         }
00130 
00131         void SendVhostDel(User *u) anope_override
00132         {
00133                 if (u->HasMode("CLOAK"))
00134                         this->SendChgHostInternal(u->nick, u->chost);
00135                 else
00136                         this->SendChgHostInternal(u->nick, u->host);
00137 
00138                 if (Servers::Capab.count("CHGIDENT") && u->GetIdent() != u->GetVIdent())
00139                         this->SendChgIdentInternal(u->nick, u->GetIdent());
00140         }
00141 
00142         void SendAkill(User *u, XLine *x) anope_override
00143         {
00144                 // Calculate the time left before this would expire, capping it at 2 days
00145                 time_t timeleft = x->expires - Anope::CurTime;
00146                 if (timeleft > 172800 || !x->expires)
00147                         timeleft = 172800;
00148 
00149                 /* InspIRCd may support regex bans, if they do we can send this and forget about it */
00150                 if (x->IsRegex() && Servers::Capab.count("RLINE"))
00151                 {
00152                         Anope::string mask = x->mask;
00153                         size_t h = x->mask.find('#');
00154                         if (h != Anope::string::npos)
00155                                 mask = mask.replace(h, 1, ' ');
00156                         SendAddLine("R", mask, timeleft, x->by, x->GetReason());
00157                         return;
00158                 }
00159                 else if (x->IsRegex() || x->HasNickOrReal())
00160                 {
00161                         if (!u)
00162                         {
00163                                 /* No user (this akill was just added), and contains nick and/or realname. Find users that match and ban them */
00164                                 for (user_map::const_iterator it = UserListByNick.begin(); it != UserListByNick.end(); ++it)
00165                                         if (x->manager->Check(it->second, x))
00166                                                 this->SendAkill(it->second, x);
00167                                 return;
00168                         }
00169 
00170                         const XLine *old = x;
00171 
00172                         if (old->manager->HasEntry("*@" + u->host))
00173                                 return;
00174 
00175                         /* We can't akill x as it has a nick and/or realname included, so create a new akill for *@host */
00176                         x = new XLine("*@" + u->host, old->by, old->expires, old->reason, old->id);
00177                         old->manager->AddXLine(x);
00178 
00179                         Log(OperServ, "akill") << "AKILL: Added an akill for " << x->mask << " because " << u->GetMask() << "#" << u->realname << " matches " << old->mask;
00180                 }
00181 
00182                 /* ZLine if we can instead */
00183                 try
00184                 {
00185                         if (x->GetUser() == "*")
00186                         {
00187                                 sockaddrs(x->GetHost());
00188                                 IRCD->SendSZLine(u, x);
00189                                 return;
00190                         }
00191                 }
00192                 catch (const SocketException &) { }
00193                 SendAddLine("G", x->GetUser() + "@" + x->GetHost(), timeleft, x->by, x->GetReason());
00194         }
00195 
00196         void SendNumericInternal(int numeric, const Anope::string &dest, const Anope::string &buf) anope_override
00197         {
00198                 UplinkSocket::Message() << "PUSH " << dest << " ::" << Me->GetName() << " " << numeric << " " << dest << " " << buf;
00199         }
00200 
00201         void SendModeInternal(const BotInfo *source, const Channel *dest, const Anope::string &buf) anope_override
00202         {
00203                 UplinkSocket::Message(source) << "FMODE " << dest->name << " " << dest->creation_time << " " << buf;
00204         }
00205 
00206         void SendModeInternal(const BotInfo *bi, const User *u, const Anope::string &buf) anope_override
00207         {
00208                 UplinkSocket::Message(bi) << "MODE " << u->GetUID() << " " << buf;
00209         }
00210 
00211         void SendClientIntroduction(const User *u) anope_override
00212         {
00213                 Anope::string modes = "+" + u->GetModes();
00214                 UplinkSocket::Message(Me) << "UID " << u->GetUID() << " " << u->timestamp << " " << u->nick << " " << u->host << " " << u->host << " " << u->GetIdent() << " 0.0.0.0 " << u->timestamp << " " << modes << " :" << u->realname;
00215         }
00216 
00217         /* SERVER services-dev.chatspike.net password 0 :Description here */
00218         void SendServer(const Server *server) anope_override
00219         {
00220                 UplinkSocket::Message() << "SERVER " << server->GetName() << " " << Config->Uplinks[Anope::CurrentUplink]->password << " " << server->GetHops() << " " << server->GetSID() << " :" << server->GetDescription();
00221         }
00222 
00223         /* JOIN */
00224         void SendJoin(const User *user, Channel *c, const ChannelStatus *status) anope_override
00225         {
00226                 UplinkSocket::Message(Me) << "FJOIN " << c->name << " " << c->creation_time << " +" << c->GetModes(true, true) << " :," << user->GetUID();
00227                 /* Note that we can send this with the FJOIN but choose not to
00228                  * because the mode stacker will handle this and probably will
00229                  * merge these modes with +nrt and other mlocked modes
00230                  */
00231                 if (status)
00232                 {
00233                         /* First save the channel status incase uc->Status == status */
00234                         ChannelStatus cs = *status;
00235                         /* If the user is internally on the channel with flags, kill them so that
00236                          * the stacker will allow this.
00237                          */
00238                         ChanUserContainer *uc = c->FindUser(user);
00239                         if (uc != NULL)
00240                                 uc->status.modes.clear();
00241 
00242                         BotInfo *setter = BotInfo::Find(user->nick);
00243                         for (unsigned i = 0; i < ModeManager::ChannelModes.size(); ++i)
00244                         {
00245                                 ChannelMode *cm = ModeManager::ChannelModes[i];
00246 
00247                                 if (cs.modes.count(cm->name) || cs.modes.count(cm->mchar))
00248                                 {
00249                                         c->SetMode(setter, ModeManager::ChannelModes[i], user->GetUID(), false);
00250                                         cs.modes.insert(cm->name);
00251                                 }
00252                         }
00253                 }
00254         }
00255 
00256         /* UNSQLINE */
00257         void SendSQLineDel(const XLine *x) anope_override
00258         {
00259                 SendDelLine("Q", x->mask);
00260         }
00261 
00262         /* SQLINE */
00263         void SendSQLine(User *, const XLine *x) anope_override
00264         {
00265                 // Calculate the time left before this would expire, capping it at 2 days
00266                 time_t timeleft = x->expires - Anope::CurTime;
00267                 if (timeleft > 172800 || !x->expires)
00268                         timeleft = 172800;
00269                 SendAddLine("Q", x->mask, timeleft, x->by, x->GetReason());
00270         }
00271 
00272         /* Functions that use serval cmd functions */
00273 
00274         void SendVhost(User *u, const Anope::string &vIdent, const Anope::string &vhost) anope_override
00275         {
00276                 if (!vIdent.empty())
00277                         this->SendChgIdentInternal(u->nick, vIdent);
00278                 if (!vhost.empty())
00279                         this->SendChgHostInternal(u->nick, vhost);
00280         }
00281 
00282         void SendConnect() anope_override
00283         {
00284                 SendServer(Me);
00285                 UplinkSocket::Message(Me) << "BURST";
00286                 Module *enc = ModuleManager::FindFirstOf(ENCRYPTION);
00287                 UplinkSocket::Message(Me) << "VERSION :Anope-" << Anope::Version() << " " << Config->ServerName << " :" << IRCD->GetProtocolName() << " - (" << (enc ? enc->name : "none") << ") -- " << Anope::VersionBuildString();
00288         }
00289 
00290         /* SVSHOLD - set */
00291         void SendSVSHold(const Anope::string &nick) anope_override
00292         {
00293                 UplinkSocket::Message(NickServ) << "SVSHOLD " << nick << " " << Config->NSReleaseTimeout << " :Being held for registered user";
00294         }
00295 
00296         /* SVSHOLD - release */
00297         void SendSVSHoldDel(const Anope::string &nick) anope_override
00298         {
00299                 UplinkSocket::Message(NickServ) << "SVSHOLD " << nick;
00300         }
00301 
00302         /* UNSZLINE */
00303         void SendSZLineDel(const XLine *x) anope_override
00304         {
00305                 SendDelLine("Z", x->GetHost());
00306         }
00307 
00308         /* SZLINE */
00309         void SendSZLine(User *, const XLine *x) anope_override
00310         {
00311                 // Calculate the time left before this would expire, capping it at 2 days
00312                 time_t timeleft = x->expires - Anope::CurTime;
00313                 if (timeleft > 172800 || !x->expires)
00314                         timeleft = 172800;
00315                 SendAddLine("Z", x->GetHost(), timeleft, x->by, x->GetReason());
00316         }
00317 
00318         void SendSVSJoin(const BotInfo *source, const User *u, const Anope::string &chan, const Anope::string &) anope_override
00319         {
00320                 UplinkSocket::Message(source) << "SVSJOIN " << u->GetUID() << " " << chan;
00321         }
00322 
00323         void SendSVSPart(const BotInfo *source, const User *u, const Anope::string &chan, const Anope::string &param) anope_override
00324         {
00325                 if (!param.empty())
00326                         UplinkSocket::Message(source) << "SVSPART " << u->GetUID() << " " << chan << " :" << param;
00327                 else
00328                         UplinkSocket::Message(source) << "SVSPART " << u->GetUID() << " " << chan;
00329         }
00330 
00331         void SendSWhois(const BotInfo *, const Anope::string &who, const Anope::string &mask) anope_override
00332         {
00333                 User *u = User::Find(who);
00334 
00335                 UplinkSocket::Message(Me) << "METADATA " << u->GetUID() << " swhois :" << mask;
00336         }
00337 
00338         void SendBOB() anope_override
00339         {
00340                 UplinkSocket::Message(Me) << "BURST " << Anope::CurTime;
00341         }
00342 
00343         void SendEOB() anope_override
00344         {
00345                 UplinkSocket::Message(Me) << "ENDBURST";
00346         }
00347 
00348         void SendGlobopsInternal(const BotInfo *source, const Anope::string &buf)
00349         {
00350                 if (Servers::Capab.count("GLOBOPS"))
00351                         UplinkSocket::Message(source) << "SNONOTICE g :" << buf;
00352                 else
00353                         UplinkSocket::Message(source) << "SNONOTICE A :" << buf;
00354         }
00355 
00356         void SendLogin(User *u) anope_override
00357         {
00358                 if (!u->Account() || u->Account()->HasExt("UNCONFIRMED"))
00359                         return;
00360 
00361                 UplinkSocket::Message(Me) << "METADATA " << u->GetUID() << " accountname :" << u->Account()->display;
00362         }
00363 
00364         void SendLogout(User *u) anope_override
00365         {
00366                 UplinkSocket::Message(Me) << "METADATA " << u->GetUID() << " accountname :";
00367         }
00368 
00369         void SendChannel(Channel *c) anope_override
00370         {
00371                 UplinkSocket::Message(Me) << "FJOIN " << c->name << " " << c->creation_time << " +" << c->GetModes(true, true) << " :";
00372         }
00373 
00374         void SendOper(User *u) anope_override
00375         {
00376         }
00377 
00378         bool IsExtbanValid(const Anope::string &mask) anope_override
00379         {
00380                 return mask.length() >= 3 && mask[1] == ':';
00381         }
00382 };
00383 
00384 class InspIRCdExtBan : public ChannelModeList
00385 {
00386  public:
00387         InspIRCdExtBan(const Anope::string &mname, char modeChar) : ChannelModeList(mname, modeChar) { }
00388 
00389         bool Matches(const User *u, const Entry *e) anope_override
00390         {
00391                 const Anope::string &mask = e->GetMask();
00392 
00393                 if (mask.find("m:") == 0 || mask.find("N:") == 0)
00394                 {
00395                         Anope::string real_mask = mask.substr(2);
00396 
00397                         Entry en(this->name, real_mask);
00398                         if (en.Matches(u))
00399                                 return true;
00400                 }
00401                 else if (mask.find("j:") == 0)
00402                 {
00403                         Anope::string real_mask = mask.substr(2);
00404 
00405                         Channel *c = Channel::Find(real_mask);
00406                         if (c != NULL && c->FindUser(u) != NULL)
00407                                 return true;
00408                 }
00409                 else if (mask.find("M:") == 0 || mask.find("R:") == 0)
00410                 {
00411                         Anope::string real_mask = mask.substr(2);
00412 
00413                         if (u->IsIdentified() && real_mask.equals_ci(u->Account()->display))
00414                                 return true;
00415                 }
00416                 else if (mask.find("r:") == 0)
00417                 {
00418                         Anope::string real_mask = mask.substr(2);
00419 
00420                         if (Anope::Match(u->realname, real_mask))
00421                                 return true;
00422                 }
00423                 else if (mask.find("s:") == 0)
00424                 {
00425                         Anope::string real_mask = mask.substr(2);
00426 
00427                         if (Anope::Match(u->server->GetName(), real_mask))
00428                                 return true;
00429                 }
00430 
00431                 return false;
00432         }
00433 };
00434 
00435 struct IRCDMessageCapab : Message::Capab
00436 {
00437         IRCDMessageCapab(Module *creator) : Message::Capab(creator, "CAPAB") { SetFlag(IRCDMESSAGE_SOFT_LIMIT); }
00438 
00439         void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
00440         {
00441                 if (params[0].equals_cs("START"))
00442                 {
00443                         /* reset CAPAB */
00444                         Servers::Capab.clear();
00445                         Servers::Capab.insert("NOQUIT");
00446                         IRCD->CanSVSHold = false;
00447                 }
00448                 else if (params[0].equals_cs("MODULES") && params.size() > 1)
00449                 {
00450                         if (params[1].find("m_globops.so") != Anope::string::npos)
00451                                 Servers::Capab.insert("GLOBOPS");
00452                         if (params[1].find("m_services_account.so") != Anope::string::npos)
00453                                 Servers::Capab.insert("SERVICES");
00454                         if (params[1].find("m_svshold.so") != Anope::string::npos)
00455                                 IRCD->CanSVSHold = true;
00456                         if (params[1].find("m_chghost.so") != Anope::string::npos)
00457                                 Servers::Capab.insert("CHGHOST");
00458                         if (params[1].find("m_chgident.so") != Anope::string::npos)
00459                                 Servers::Capab.insert("CHGIDENT");
00460                         if (params[1].find("m_hidechans.so") != Anope::string::npos)
00461                                 Servers::Capab.insert("HIDECHANS");
00462                         if (params[1].find("m_servprotect.so") != Anope::string::npos)
00463                                 IRCD->DefaultPseudoclientModes = "+Ik";
00464                         if (params[1].find("m_rline.so") != Anope::string::npos)
00465                                 Servers::Capab.insert("RLINE");
00466                 }
00467                 else if (params[0].equals_cs("CAPABILITIES") && params.size() > 1)
00468                 {
00469                         spacesepstream ssep(params[1]);
00470                         Anope::string capab;
00471                         while (ssep.GetToken(capab))
00472                         {
00473                                 if (capab.find("CHANMODES") != Anope::string::npos)
00474                                 {
00475                                         Anope::string modes(capab.begin() + 10, capab.end());
00476                                         commasepstream sep(modes);
00477                                         Anope::string modebuf;
00478 
00479                                         sep.GetToken(modebuf);
00480                                         for (size_t t = 0, end = modebuf.length(); t < end; ++t)
00481                                         {
00482                                                 switch (modebuf[t])
00483                                                 {
00484                                                         case 'b':
00485                                                                 ModeManager::AddChannelMode(new InspIRCdExtBan("BAN", 'b'));
00486                                                                 continue;
00487                                                         case 'e':
00488                                                                 ModeManager::AddChannelMode(new InspIRCdExtBan("EXCEPT", 'e'));
00489                                                                 continue;
00490                                                         case 'I':
00491                                                                 ModeManager::AddChannelMode(new InspIRCdExtBan("INVITEOVERRIDE", 'I'));
00492                                                                 continue;
00493                                                         /* InspIRCd sends q and a here if they have no prefixes */
00494                                                         case 'q':
00495                                                                 ModeManager::AddChannelMode(new ChannelModeStatus("OWNER", 'q', '@'));
00496                                                                 continue;
00497                                                         case 'a':
00498                                                                 ModeManager::AddChannelMode(new ChannelModeStatus("PROTECT" , 'a', '@'));
00499                                                                 continue;
00500                                                         default:
00501                                                                 ModeManager::AddChannelMode(new ChannelModeList("END", modebuf[t]));
00502                                                 }
00503                                         }
00504 
00505                                         sep.GetToken(modebuf);
00506                                         for (size_t t = 0, end = modebuf.length(); t < end; ++t)
00507                                         {
00508                                                 switch (modebuf[t])
00509                                                 {
00510                                                         case 'k':
00511                                                                 ModeManager::AddChannelMode(new ChannelModeKey('k'));
00512                                                                 continue;
00513                                                         default:
00514                                                                 ModeManager::AddChannelMode(new ChannelModeParam("END", modebuf[t]));
00515                                                 }
00516                                         }
00517 
00518                                         sep.GetToken(modebuf);
00519                                         for (size_t t = 0, end = modebuf.length(); t < end; ++t)
00520                                         {
00521                                                 switch (modebuf[t])
00522                                                 {
00523                                                         case 'F':
00524                                                                 ModeManager::AddChannelMode(new ChannelModeParam("NICKFLOOD", 'F', true));
00525                                                                 continue;
00526                                                         case 'J':
00527                                                                 ModeManager::AddChannelMode(new ChannelModeParam("NOREJOIN", 'J', true));
00528                                                                 continue;
00529                                                         case 'L':
00530                                                                 ModeManager::AddChannelMode(new ChannelModeParam("REDIRECT", 'L', true));
00531                                                                 continue;
00532                                                         case 'f':
00533                                                                 ModeManager::AddChannelMode(new ChannelModeFlood('f', true));
00534                                                                 continue;
00535                                                         case 'j':
00536                                                                 ModeManager::AddChannelMode(new ChannelModeParam("JOINFLOOD", 'j', true));
00537                                                                 continue;
00538                                                         case 'l':
00539                                                                 ModeManager::AddChannelMode(new ChannelModeParam("LIMIT", 'l', true));
00540                                                                 continue;
00541                                                         default:
00542                                                                 ModeManager::AddChannelMode(new ChannelModeParam("END", modebuf[t], true));
00543                                                 }
00544                                         }
00545 
00546                                         sep.GetToken(modebuf);
00547                                         for (size_t t = 0, end = modebuf.length(); t < end; ++t)
00548                                         {
00549                                                 switch (modebuf[t])
00550                                                 {
00551                                                         case 'A':
00552                                                                 ModeManager::AddChannelMode(new ChannelMode("ALLINVITE", 'A'));
00553                                                                 continue;
00554                                                         case 'B':
00555                                                                 ModeManager::AddChannelMode(new ChannelMode("BLOCKCAPS", 'B'));
00556                                                                 continue;
00557                                                         case 'C':
00558                                                                 ModeManager::AddChannelMode(new ChannelMode("NOCTCP", 'C'));
00559                                                                 continue;
00560                                                         case 'D':
00561                                                                 ModeManager::AddChannelMode(new ChannelMode("DELAYEDJOIN", 'D'));
00562                                                                 continue;
00563                                                         case 'G':
00564                                                                 ModeManager::AddChannelMode(new ChannelMode("FILTER", 'G'));
00565                                                                 continue;
00566                                                         case 'K':
00567                                                                 ModeManager::AddChannelMode(new ChannelMode("NOKNOCK", 'K'));
00568                                                                 continue;
00569                                                         case 'M':
00570                                                                 ModeManager::AddChannelMode(new ChannelMode("REGMODERATED", 'M'));
00571                                                                 continue;
00572                                                         case 'N':
00573                                                                 ModeManager::AddChannelMode(new ChannelMode("NONICK", 'N'));
00574                                                                 continue;
00575                                                         case 'O':
00576                                                                 ModeManager::AddChannelMode(new ChannelModeOper('O'));
00577                                                                 continue;
00578                                                         case 'P':
00579                                                                 ModeManager::AddChannelMode(new ChannelMode("PERM", 'P'));
00580                                                                 continue;
00581                                                         case 'Q':
00582                                                                 ModeManager::AddChannelMode(new ChannelMode("NOKICK", 'Q'));
00583                                                                 continue;
00584                                                         case 'R':
00585                                                                 ModeManager::AddChannelMode(new ChannelMode("REGISTEREDONLY", 'R'));
00586                                                                 continue;
00587                                                         case 'S':
00588                                                                 ModeManager::AddChannelMode(new ChannelMode("STRIPCOLOR", 'S'));
00589                                                                 continue;
00590                                                         case 'T':
00591                                                                 ModeManager::AddChannelMode(new ChannelMode("NONOTICE", 'T'));
00592                                                                 continue;
00593                                                         case 'c':
00594                                                                 ModeManager::AddChannelMode(new ChannelMode("BLOCKCOLOR", 'c'));
00595                                                                 continue;
00596                                                         case 'i':
00597                                                                 ModeManager::AddChannelMode(new ChannelMode("INVITE", 'i'));
00598                                                                 continue;
00599                                                         case 'm':
00600                                                                 ModeManager::AddChannelMode(new ChannelMode("MODERATED", 'm'));
00601                                                                 continue;
00602                                                         case 'n':
00603                                                                 ModeManager::AddChannelMode(new ChannelMode("NOEXTERNAL", 'n'));
00604                                                                 continue;
00605                                                         case 'p':
00606                                                                 ModeManager::AddChannelMode(new ChannelMode("PRIVATE", 'p'));
00607                                                                 continue;
00608                                                         case 'r':
00609                                                                 ModeManager::AddChannelMode(new ChannelModeRegistered('r'));
00610                                                                 continue;
00611                                                         case 's':
00612                                                                 ModeManager::AddChannelMode(new ChannelMode("SECRET", 's'));
00613                                                                 continue;
00614                                                         case 't':
00615                                                                 ModeManager::AddChannelMode(new ChannelMode("TOPIC", 't'));
00616                                                                 continue;
00617                                                         case 'u':
00618                                                                 ModeManager::AddChannelMode(new ChannelMode("AUDITORIUM", 'u'));
00619                                                                 continue;
00620                                                         case 'z':
00621                                                                 ModeManager::AddChannelMode(new ChannelMode("SSL", 'z'));
00622                                                                 continue;
00623                                                         default:
00624                                                                 ModeManager::AddChannelMode(new ChannelMode("END", modebuf[t]));
00625                                                 }
00626                                         }
00627                                 }
00628                                 else if (capab.find("USERMODES") != Anope::string::npos)
00629                                 {
00630                                         Anope::string modes(capab.begin() + 10, capab.end());
00631                                         commasepstream sep(modes);
00632                                         Anope::string modebuf;
00633 
00634                                         while (sep.GetToken(modebuf))
00635                                         {
00636                                                 for (size_t t = 0, end = modebuf.length(); t < end; ++t)
00637                                                 {
00638                                                         switch (modebuf[t])
00639                                                         {
00640                                                                 case 'h':
00641                                                                         ModeManager::AddUserMode(new UserMode("HELPOP", 'h'));
00642                                                                         continue;
00643                                                                 case 'B':
00644                                                                         ModeManager::AddUserMode(new UserMode("BOT", 'B'));
00645                                                                         continue;
00646                                                                 case 'G':
00647                                                                         ModeManager::AddUserMode(new UserMode("FILTER", 'G'));
00648                                                                         continue;
00649                                                                 case 'H':
00650                                                                         ModeManager::AddUserMode(new UserMode("HIDEOPER", 'H'));
00651                                                                         continue;
00652                                                                 case 'I':
00653                                                                         ModeManager::AddUserMode(new UserMode("PRIV", 'I'));
00654                                                                         continue;
00655                                                                 case 'Q':
00656                                                                         ModeManager::AddUserMode(new UserMode("HIDDEN", 'Q'));
00657                                                                         continue;
00658                                                                 case 'R':
00659                                                                         ModeManager::AddUserMode(new UserMode("REGPRIV", 'R'));
00660                                                                         continue;
00661                                                                 case 'S':
00662                                                                         ModeManager::AddUserMode(new UserMode("STRIPCOLOR", 'S'));
00663                                                                         continue;
00664                                                                 case 'W':
00665                                                                         ModeManager::AddUserMode(new UserMode("WHOIS", 'W'));
00666                                                                         continue;
00667                                                                 case 'c':
00668                                                                         ModeManager::AddUserMode(new UserMode("COMMONCHANS", 'c'));
00669                                                                         continue;
00670                                                                 case 'g':
00671                                                                         ModeManager::AddUserMode(new UserMode("CALLERID", 'g'));
00672                                                                         continue;
00673                                                                 case 'i':
00674                                                                         ModeManager::AddUserMode(new UserMode("INVIS", 'i'));
00675                                                                         continue;
00676                                                                 case 'k':
00677                                                                         ModeManager::AddUserMode(new UserMode("PROTECTED", 'k'));
00678                                                                         continue;
00679                                                                 case 'o':
00680                                                                         ModeManager::AddUserMode(new UserMode("OPER", 'o'));
00681                                                                         continue;
00682                                                                 case 'r':
00683                                                                         ModeManager::AddUserMode(new UserMode("REGISTERED", 'r'));
00684                                                                         continue;
00685                                                                 case 'w':
00686                                                                         ModeManager::AddUserMode(new UserMode("WALLOPS", 'w'));
00687                                                                         continue;
00688                                                                 case 'x':
00689                                                                         ModeManager::AddUserMode(new UserMode("CLOAK", 'x'));
00690                                                                         continue;
00691                                                                 case 'd':
00692                                                                         ModeManager::AddUserMode(new UserMode("DEAF", 'd'));
00693                                                                         continue;
00694                                                                 default:
00695                                                                         ModeManager::AddUserMode(new UserMode("END", modebuf[t]));
00696                                                         }
00697                                                 }
00698                                         }
00699                                 }
00700                                 else if (capab.find("PREFIX=(") != Anope::string::npos)
00701                                 {
00702                                         Anope::string modes(capab.begin() + 8, capab.begin() + capab.find(')'));
00703                                         Anope::string chars(capab.begin() + capab.find(')') + 1, capab.end());
00704                                         unsigned short level = modes.length() - 1;
00705 
00706                                         for (size_t t = 0, end = modes.length(); t < end; ++t)
00707                                         {
00708                                                 switch (modes[t])
00709                                                 {
00710                                                         case 'q':
00711                                                                 ModeManager::AddChannelMode(new ChannelModeStatus("OWNER", 'q', chars[t], level--));
00712                                                                 continue;
00713                                                         case 'a':
00714                                                                 ModeManager::AddChannelMode(new ChannelModeStatus("PROTECT", 'a', chars[t], level--));
00715                                                                 continue;
00716                                                         case 'o':
00717                                                                 ModeManager::AddChannelMode(new ChannelModeStatus("OP", 'o', chars[t], level--));
00718                                                                 continue;
00719                                                         case 'h':
00720                                                                 ModeManager::AddChannelMode(new ChannelModeStatus("HALFOP", 'h', chars[t], level--));
00721                                                                 continue;
00722                                                         case 'v':
00723                                                                 ModeManager::AddChannelMode(new ChannelModeStatus("VOICE", 'v', chars[t], level--));
00724                                                                 continue;
00725                                                         default:
00726                                                                 ModeManager::AddChannelMode(new ChannelModeStatus("END", modes[t], chars[t], level--));
00727                                                 }
00728                                         }
00729                                 }
00730                                 else if (capab.find("MAXMODES=") != Anope::string::npos)
00731                                 {
00732                                         Anope::string maxmodes(capab.begin() + 9, capab.end());
00733                                         IRCD->MaxModes = maxmodes.is_pos_number_only() ? convertTo<unsigned>(maxmodes) : 3;
00734                                 }
00735                         }
00736                 }
00737                 else if (params[0].equals_cs("END"))
00738                 {
00739                         if (!Servers::Capab.count("GLOBOPS"))
00740                         {
00741                                 UplinkSocket::Message() << "ERROR :m_globops is not loaded. This is required by Anope";
00742                                 Anope::QuitReason = "Remote server does not have the m_globops module loaded, and this is required.";
00743                                 Anope::Quitting = true;
00744                                 return;
00745                         }
00746                         if (!Servers::Capab.count("SERVICES"))
00747                         {
00748                                 UplinkSocket::Message() << "ERROR :m_services_account.so is not loaded. This is required by Anope";
00749                                 Anope::QuitReason = "ERROR: Remote server does not have the m_services_account module loaded, and this is required.";
00750                                 Anope::Quitting = true;
00751                                 return;
00752                         }
00753                         if (!Servers::Capab.count("HIDECHANS"))
00754                         {
00755                                 UplinkSocket::Message() << "ERROR :m_hidechans.so is not loaded. This is required by Anope";
00756                                 Anope::QuitReason = "ERROR: Remote server does not have the m_hidechans module loaded, and this is required.";
00757                                 Anope::Quitting = true;
00758                                 return;
00759                         }
00760                         if (!IRCD->CanSVSHold)
00761                                 Log() << "SVSHOLD missing, Usage disabled until module is loaded.";
00762                         if (!Servers::Capab.count("CHGHOST"))
00763                                 Log() << "CHGHOST missing, Usage disabled until module is loaded.";
00764                         if (!Servers::Capab.count("CHGIDENT"))
00765                                 Log() << "CHGIDENT missing, Usage disabled until module is loaded.";
00766                 }
00767 
00768                 Message::Capab::Run(source, params);
00769         }
00770 };
00771 
00772 struct IRCDMessageChgIdent : IRCDMessage
00773 {
00774         IRCDMessageChgIdent(Module *creator) : IRCDMessage(creator, "CHGIDENT", 2) { }
00775 
00776         void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
00777         {
00778                 User *u = User::Find(params[0]);
00779                 if (u)
00780                         u->SetIdent(params[1]);
00781         }
00782 };
00783 
00784 struct IRCDMessageChgName : IRCDMessage
00785 {
00786         IRCDMessageChgName(Module *creator, const Anope::string &n) : IRCDMessage(creator, n, 1) { SetFlag(IRCDMESSAGE_REQUIRE_USER); }
00787 
00788         void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
00789         {
00790                 source.GetUser()->SetRealname(params[0]);
00791         }
00792 };
00793 
00794 struct IRCDMessageEndburst : IRCDMessage
00795 {
00796         IRCDMessageEndburst(Module *creator) : IRCDMessage(creator, "ENDBURST", 0) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); }
00797 
00798         void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
00799         {
00800                 Server *s = source.GetServer();
00801 
00802                 Log(LOG_DEBUG) << "Processed ENDBURST for " << s->GetName();
00803 
00804                 s->Sync(true);
00805         }
00806 };
00807 
00808 struct IRCDMessageFHost : IRCDMessage
00809 {
00810         IRCDMessageFHost(Module *creator, const Anope::string &n) : IRCDMessage(creator, n, 1) { SetFlag(IRCDMESSAGE_REQUIRE_USER); }
00811 
00812         void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
00813         {
00814                 source.GetUser()->SetDisplayedHost(params[0]);
00815         }
00816 };
00817 
00818 struct IRCDMessageFJoin : IRCDMessage
00819 {
00820         IRCDMessageFJoin(Module *creator) : IRCDMessage(creator, "FJOIN", 2) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); SetFlag(IRCDMESSAGE_SOFT_LIMIT); }
00821 
00822         void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
00823         {
00824                 Anope::string modes;
00825                 if (params.size() >= 3)
00826                 {
00827                         for (unsigned i = 2; i < params.size() - 1; ++i)
00828                                 modes += " " + params[i];
00829                         if (!modes.empty())
00830                                 modes.erase(modes.begin());
00831                 }
00832 
00833                 std::list<Message::Join::SJoinUser> users;
00834 
00835                 spacesepstream sep(params[params.size() - 1]);
00836                 Anope::string buf;
00837                 while (sep.GetToken(buf))
00838                 {
00839                         Message::Join::SJoinUser sju;
00840 
00841                         /* Loop through prefixes and find modes for them */
00842                         for (char c;  (c = buf[0]) != ',';)
00843                         {
00844                                 buf.erase(buf.begin());
00845                                 ChannelMode *cm = ModeManager::FindChannelModeByChar(c);
00846                                 if (!cm)
00847                                 {
00848                                         Log() << "Received unknown mode prefix " << c << " in FJOIN string";
00849                                         continue;
00850                                 }
00851 
00852                                 sju.first.modes.insert(cm->name);
00853                         }
00854                         /* Erase the , */
00855                         buf.erase(buf.begin());
00856 
00857                         sju.second = User::Find(buf);
00858                         if (!sju.second)
00859                         {
00860                                 Log(LOG_DEBUG) << "FJOIN for nonexistant user " << buf << " on " << params[0];
00861                                 continue;
00862                         }
00863 
00864                         users.push_back(sju);
00865                 }
00866 
00867                 time_t ts = Anope::string(params[1]).is_pos_number_only() ? convertTo<time_t>(params[1]) : Anope::CurTime;
00868                 Message::Join::SJoin(source, params[0], ts, modes, users);
00869         }
00870 };
00871 
00872 struct IRCDMessageFMode : IRCDMessage
00873 {
00874         IRCDMessageFMode(Module *creator) : IRCDMessage(creator, "FMODE", 3) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); }
00875 
00876         void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
00877         {
00878                 /* :source FMODE #test 12345678 +nto foo */
00879 
00880                 Anope::string modes = params[2];
00881                 for (unsigned n = 3; n < params.size(); ++n)
00882                         modes += " " + params[n];
00883 
00884                 Channel *c = Channel::Find(params[0]);
00885                 time_t ts;
00886 
00887                 try
00888                 {
00889                         ts = convertTo<time_t>(params[1]);
00890                 }
00891                 catch (const ConvertException &)
00892                 {
00893                         ts = 0;
00894                 }
00895 
00896                 if (c)
00897                         c->SetModesInternal(source, modes, ts);
00898         }
00899 };
00900 
00901 struct IRCDMessageFTopic : IRCDMessage
00902 {
00903         IRCDMessageFTopic(Module *creator) : IRCDMessage(creator, "FTOPIC", 4) { }
00904 
00905         void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
00906         {
00907                 /* :source FTOPIC channel topicts setby :topic */
00908 
00909                 Channel *c = Channel::Find(params[0]);
00910                 if (c)
00911                         c->ChangeTopicInternal(params[2], params[3], Anope::string(params[1]).is_pos_number_only() ? convertTo<time_t>(params[1]) : Anope::CurTime);
00912         }
00913 };
00914 
00915 struct IRCDMessageIdle : IRCDMessage
00916 {
00917         IRCDMessageIdle(Module *creator) : IRCDMessage(creator, "IDLE", 1) { }
00918 
00919         void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
00920         {
00921                 const BotInfo *bi = BotInfo::Find(params[0]);
00922                 if (bi)
00923                         UplinkSocket::Message(bi) << "IDLE " << source.GetSource() << " " << Anope::StartTime << " " << (Anope::CurTime - bi->lastmsg);
00924         }
00925 };
00926 
00927 /*
00928  *   source     = numeric of the sending server
00929  *   params[0]  = uuid
00930  *   params[1]  = metadata name
00931  *   params[2]  = data
00932  */
00933 struct IRCDMessageMetadata : IRCDMessage
00934 {
00935         IRCDMessageMetadata(Module *creator) : IRCDMessage(creator, "METADATA", 3) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); }
00936 
00937         void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
00938         {
00939                 if (isdigit(params[0][0]))
00940                 {
00941                         if (params[1].equals_cs("accountname"))
00942                         {
00943                                 User *u = User::Find(params[0]);
00944                                 NickCore *nc = NickCore::Find(params[2]);
00945                                 if (u && nc)
00946                                 {
00947                                         u->Login(nc);
00948 
00949                                         const NickAlias *user_na = NickAlias::Find(u->nick);
00950                                         if (!Config->NoNicknameOwnership && user_na && user_na->nc == nc && user_na->nc->HasExt("UNCONFIRMED") == false)
00951                                                 u->SetMode(NickServ, "REGISTERED");
00952 
00953                                         /* Sometimes a user connects, we send them the usual "this nickname is registered" mess (if
00954                                          * their server isn't syncing) and then we receive this.. so tell them about it.
00955                                          */
00956                                         if (u->server->IsSynced() && NickServ)
00957                                                 u->SendMessage(NickServ, _("You have been logged in as \002%s\002."), nc->display.c_str());
00958                                 }
00959                         }
00960 
00961                         /*
00962                          *   possible incoming ssl_cert messages:
00963                          *   Received: :409 METADATA 409AAAAAA ssl_cert :vTrSe c38070ce96e41cc144ed6590a68d45a6 <...> <...>
00964                          *   Received: :409 METADATA 409AAAAAC ssl_cert :vTrSE Could not get peer certificate: error:00000000:lib(0):func(0):reason(0)
00965                          */
00966                         else if (params[1].equals_cs("ssl_cert"))
00967                         {
00968                                 User *u = User::Find(params[0]);
00969                                 if (!u)
00970                                         return;
00971                                 std::string data = params[2].c_str();
00972                                 size_t pos1 = data.find(' ') + 1;
00973                                 size_t pos2 = data.find(' ', pos1);
00974                                 if ((pos2 - pos1) >= 32) // inspircd supports md5 and sha1 fingerprint hashes -> size 32 or 40 bytes.
00975                                 {
00976                                         u->fingerprint = data.substr(pos1, pos2 - pos1);
00977                                         FOREACH_MOD(I_OnFingerprint, OnFingerprint(u));
00978                                 }
00979                         }
00980                 }
00981                 else if (params[0][0] == '#')
00982                 {
00983                 }
00984                 else if (params[0] == "*")
00985                 {
00986                         // Wed Oct  3 15:40:27 2012: S[14] O :20D METADATA * modules :-m_svstopic.so
00987 
00988                         if (params[1].equals_cs("modules") && !params[2].empty())
00989                         {
00990                                 // only interested when it comes from our uplink
00991                                 Server* server = source.GetServer();
00992                                 if (!server || server->GetUplink() != Me)
00993                                         return;
00994 
00995                                 bool plus = (params[2][0] == '+');
00996                                 if (!plus && params[2][0] != '-')
00997                                         return;
00998 
00999                                 bool required = false;
01000                                 Anope::string capab, module = params[2].substr(1);
01001 
01002                                 if (module.equals_cs("m_services_account.so"))
01003                                         required = true;
01004                                 else if (module.equals_cs("m_hidechans.so"))
01005                                         required = true;
01006                                 else if (module.equals_cs("m_chghost.so"))
01007                                         capab = "CHGHOST";
01008                                 else if (module.equals_cs("m_chgident.so"))
01009                                         capab = "CHGIDENT";
01010                                 else if (module.equals_cs("m_svshold.so"))
01011                                         capab = "SVSHOLD";
01012                                 else if (module.equals_cs("m_rline.so"))
01013                                         capab = "RLINE";
01014                                 else if (module.equals_cs("m_topiclock.so"))
01015                                         capab = "TOPICLOCK";
01016                                 else
01017                                         return;
01018 
01019                                 if (required)
01020                                 {
01021                                         if (!plus)
01022                                                 Log() << "Warning: InspIRCd unloaded module " << module << ", Anope won't function correctly without it";
01023                                 }
01024                                 else
01025                                 {
01026                                         if (plus)
01027                                                 Servers::Capab.insert(capab);
01028                                         else
01029                                                 Servers::Capab.erase(capab);
01030 
01031                                         Log() << "InspIRCd " << (plus ? "loaded" : "unloaded") << " module " << module << ", adjusted functionality";
01032                                 }
01033 
01034                         }
01035                 }
01036         }
01037 };
01038 
01039 struct IRCDMessageMode : IRCDMessage
01040 {
01041         IRCDMessageMode(Module *creator) : IRCDMessage(creator, "MODE", 2) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); }
01042 
01043         void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
01044         {
01045                 if (IRCD->IsChannelValid(params[0]))
01046                 {
01047                         Channel *c = Channel::Find(params[0]);
01048 
01049                         Anope::string modes = params[1];
01050                         for (unsigned n = 2; n < params.size(); ++n)
01051                                 modes += " " + params[n];
01052 
01053                         if (c)
01054                                 c->SetModesInternal(source, modes);
01055                 }
01056                 else
01057                 {
01058                         /* InspIRCd lets opers change another
01059                            users modes, we have to kludge this
01060                            as it slightly breaks RFC1459
01061                          */
01062                         User *u = source.GetUser();
01063                         // This can happen with server-origin modes.
01064                         if (!u)
01065                                 u = User::Find(params[0]);
01066                         // if it's still null, drop it like fire.
01067                         // most likely situation was that server introduced a nick which we subsequently akilled
01068                         if (u)
01069                                 u->SetModesInternal("%s", params[1].c_str());
01070                 }
01071         }
01072 };
01073 
01074 struct IRCDMessageNick : IRCDMessage
01075 {
01076         IRCDMessageNick(Module *creator) : IRCDMessage(creator, "NICK", 2) { SetFlag(IRCDMESSAGE_REQUIRE_USER); }
01077 
01078         void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
01079         {
01080                 source.GetUser()->ChangeNick(params[0]);
01081         }
01082 };
01083 
01084 struct IRCDMessageOperType : IRCDMessage
01085 {
01086         IRCDMessageOperType(Module *creator) : IRCDMessage(creator, "OPERTYPE", 0) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); SetFlag(IRCDMESSAGE_REQUIRE_USER); }
01087 
01088         void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
01089         {
01090                 /* opertype is equivalent to mode +o because servers
01091                    dont do this directly */
01092                 User *u = source.GetUser();
01093                 if (!u->HasMode("OPER"))
01094                         u->SetModesInternal("+o");
01095         }
01096 };
01097 
01098 struct IRCDMessageRSQuit : IRCDMessage
01099 {
01100         IRCDMessageRSQuit(Module *creator) : IRCDMessage(creator, "RSQUIT", 1) { }
01101 
01102         void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
01103         {
01104                 Server *s = Server::Find(params[0]);
01105                 if (!s)
01106                         return;
01107 
01108                 /* On InspIRCd we must send a SQUIT when we recieve RSQUIT for a server we have juped */
01109                 if (s->IsJuped())
01110                         UplinkSocket::Message(Me) << "SQUIT " << s->GetSID() << " :" << (params.size() > 1 ? params[1].c_str() : "");
01111 
01112                 s->Delete(s->GetName() + " " + s->GetUplink()->GetName());
01113         }
01114 };
01115 
01116 struct IRCDMessageSetIdent : IRCDMessage
01117 {
01118         IRCDMessageSetIdent(Module *creator) : IRCDMessage(creator, "SETIDENT", 0) { SetFlag(IRCDMESSAGE_REQUIRE_USER); }
01119 
01120         void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
01121         {
01122                 source.GetUser()->SetIdent(params[0]);
01123         }
01124 };
01125 
01126 struct IRCDMessageServer : IRCDMessage
01127 {
01128         IRCDMessageServer(Module *creator) : IRCDMessage(creator, "SERVER", 5) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); }
01129 
01130         /*
01131          * [Nov 04 00:08:46.308435 2009] debug: Received: SERVER irc.inspircd.com pass 0 964 :Testnet Central!
01132          * 0: name
01133          * 1: pass
01134          * 2: hops
01135          * 3: numeric
01136          * 4: desc
01137          */
01138         void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
01139         {
01140                 unsigned int hops = Anope::string(params[2]).is_pos_number_only() ? convertTo<unsigned>(params[2]) : 0;
01141                 new Server(source.GetServer() == NULL ? Me : source.GetServer(), params[0], hops, params[4], params[3]);
01142         }
01143 };
01144 
01145 struct IRCDMessageTime : IRCDMessage
01146 {
01147         IRCDMessageTime(Module *creator) : IRCDMessage(creator, "TIME", 2) { }
01148 
01149         void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
01150         {
01151                 UplinkSocket::Message(Me) << "TIME " << source.GetSource() << " " << params[1] << " " << Anope::CurTime;
01152         }
01153 };
01154 
01155 struct IRCDMessageUID : IRCDMessage
01156 {
01157         IRCDMessageUID(Module *creator) : IRCDMessage(creator, "UID", 8) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); SetFlag(IRCDMESSAGE_SOFT_LIMIT); }
01158 
01159         /*
01160          * [Nov 03 22:09:58.176252 2009] debug: Received: :964 UID 964AAAAAC 1225746297 w00t2 localhost testnet.user w00t 127.0.0.1 1225746302 +iosw +ACGJKLNOQcdfgjklnoqtx :Robin Burchell <w00t@inspircd.org>
01161          * 0: uid
01162          * 1: ts
01163          * 2: nick
01164          * 3: host
01165          * 4: dhost
01166          * 5: ident
01167          * 6: ip
01168          * 7: signon
01169          * 8+: modes and params -- IMPORTANT, some modes (e.g. +s) may have parameters. So don't assume a fixed position of realname!
01170          * last: realname
01171          */
01172         void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
01173         {
01174                 time_t ts = convertTo<time_t>(params[1]);
01175 
01176                 Anope::string modes = params[8];
01177                 for (unsigned i = 9; i < params.size() - 1; ++i)
01178                         modes += " " + params[i];
01179 
01180                 new User(params[2], params[5], params[3], params[4], params[6], source.GetServer(), params[params.size() - 1], ts, modes, params[0]);
01181         }
01182 };
01183 
01184 class ProtoInspIRCd : public Module
01185 {
01186         InspIRCd12Proto ircd_proto;
01187 
01188         /* Core message handlers */
01189         Message::Away message_away;
01190         Message::Error message_error;
01191         Message::Join message_join;
01192         Message::Kick message_kick;
01193         Message::Kill message_kill;
01194         Message::MOTD message_motd;
01195         Message::Part message_part;
01196         Message::Ping message_ping;
01197         Message::Privmsg message_privmsg;
01198         Message::Quit message_quit;
01199         Message::SQuit message_squit;
01200         Message::Stats message_stats;
01201         Message::Topic message_topic;
01202         Message::Version message_version;
01203 
01204         /* Our message handlers */
01205         IRCDMessageChgIdent message_chgident;
01206         IRCDMessageChgName message_setname, message_chgname;
01207         IRCDMessageCapab message_capab;
01208         IRCDMessageEndburst message_endburst;
01209         IRCDMessageFHost message_fhost, message_sethost;
01210         IRCDMessageFJoin message_fjoin;
01211         IRCDMessageFMode message_fmode;
01212         IRCDMessageFTopic message_ftopic;
01213         IRCDMessageIdle message_idle;
01214         IRCDMessageMetadata message_metadata;
01215         IRCDMessageMode message_mode;
01216         IRCDMessageNick message_nick;
01217         IRCDMessageOperType message_opertype;
01218         IRCDMessageRSQuit message_rsquit;
01219         IRCDMessageSetIdent message_setident;
01220         IRCDMessageServer message_server;
01221         IRCDMessageTime message_time;
01222         IRCDMessageUID message_uid;
01223 
01224  public:
01225         ProtoInspIRCd(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, PROTOCOL),
01226                 ircd_proto(this),
01227                 message_away(this), message_error(this), message_join(this), message_kick(this), message_kill(this),
01228                 message_motd(this), message_part(this), message_ping(this), message_privmsg(this), message_quit(this),
01229                 message_squit(this), message_stats(this), message_topic(this), message_version(this),
01230 
01231                 message_chgident(this), message_setname(this, "SETNAME"), message_chgname(this, "FNAME"), message_capab(this), message_endburst(this),
01232                 message_fhost(this, "FHOST"), message_sethost(this, "SETHOST"), message_fjoin(this), message_fmode(this), message_ftopic(this),
01233                 message_idle(this), message_metadata(this), message_mode(this), message_nick(this), message_opertype(this), message_rsquit(this),
01234                 message_setident(this), message_server(this), message_time(this), message_uid(this)
01235         {
01236                 this->SetAuthor("Anope");
01237 
01238                 Implementation i[] = { I_OnUserNickChange };
01239                 ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation));
01240 
01241                 Servers::Capab.insert("NOQUIT");
01242 
01243                 if (Config->Numeric.empty())
01244                 {
01245                         Anope::string numeric = Servers::TS6_SID_Retrieve();
01246                         Me->SetSID(numeric);
01247                         Config->Numeric = numeric;
01248                 }
01249 
01250                 for (botinfo_map::iterator it = BotListByNick->begin(), it_end = BotListByNick->end(); it != it_end; ++it)
01251                         it->second->GenerateUID();
01252         }
01253 
01254         void OnUserNickChange(User *u, const Anope::string &) anope_override
01255         {
01256                 /* InspIRCd 1.2 doesn't set -r on nick change, remove -r here. Note that if we have to set +r later
01257                  * this will cancel out this -r, resulting in no mode changes.
01258                  */
01259                 u->RemoveMode(NickServ, "REGISTERED");
01260         }
01261 };
01262 
01263 MODULE_INIT(ProtoInspIRCd)