inspircd-ts6.h

Go to the documentation of this file.
00001 /* Inspircd 1.2+ generic TS6 functions
00002  *
00003  * (C) 2003-2012 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 class ChannelModeFlood : public ChannelModeParam
00013 {
00014  public:
00015         ChannelModeFlood(char modeChar, bool minusNoArg) : ChannelModeParam(CMODE_FLOOD, modeChar, minusNoArg) { }
00016 
00017         bool IsValid(const Anope::string &value) const anope_override
00018         {
00019                 try
00020                 {
00021                         Anope::string rest;
00022                         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())
00023                                 return true;
00024                 }
00025                 catch (const ConvertException &) { }
00026 
00027                 return false;
00028         }
00029 };
00030 
00031 class InspIRCdTS6Proto : public IRCDProto
00032 {
00033  private:
00034         void SendChgIdentInternal(const Anope::string &nick, const Anope::string &vIdent)
00035         {
00036                 if (!has_chgidentmod)
00037                         Log() << "CHGIDENT not loaded!";
00038                 else
00039                         UplinkSocket::Message(findbot(Config->HostServ)) << "CHGIDENT " << nick << " " << vIdent;
00040         }
00041 
00042         void SendChgHostInternal(const Anope::string &nick, const Anope::string &vhost)
00043         {
00044                 if (!has_chghostmod)
00045                         Log() << "CHGHOST not loaded!";
00046                 else
00047                         UplinkSocket::Message(Me) << "CHGHOST " << nick << " " << vhost;
00048         }
00049 
00050         void SendAddLine(const Anope::string &type, const Anope::string &mask, time_t duration, const Anope::string &addedby, const Anope::string &reason)
00051         {
00052                 UplinkSocket::Message(Me) << "ADDLINE " << type << " " << mask << " " << addedby << " " << Anope::CurTime << " " << duration << " :" << reason;
00053         }
00054 
00055         void SendDelLine(const Anope::string &type, const Anope::string &mask)
00056         {
00057                 UplinkSocket::Message(Me) << "DELLINE " << type << " " << mask;
00058         }
00059 
00060  protected:
00061         InspIRCdTS6Proto(const Anope::string &name) : IRCDProto(name)
00062         {
00063                 DefaultPseudoclientModes = "+I";
00064                 CanSVSNick = true;
00065                 CanSetVHost = true;
00066                 CanSetVIdent = true;
00067                 CanSQLine = true;
00068                 CanSZLine = true;
00069                 CanSVSHold = true;
00070                 CanCertFP = true;
00071                 RequiresID = true;
00072                 MaxModes = 20;
00073         }
00074 
00075         void SendGlobalNotice(const BotInfo *bi, const Server *dest, const Anope::string &msg) anope_override
00076         {
00077                 UplinkSocket::Message(bi) << "NOTICE $" << dest->GetName() << " :" << msg;
00078         }
00079 
00080         void SendGlobalPrivmsg(const BotInfo *bi, const Server *dest, const Anope::string &msg) anope_override
00081         {
00082                 UplinkSocket::Message(bi) << "PRIVMSG $" << dest->GetName() << " :" << msg;
00083         }
00084 
00085         void SendAkillDel(const XLine *x) anope_override
00086         {
00087                 /* InspIRCd may support regex bans */
00088                 if (x->IsRegex() && has_rlinemod)
00089                 {
00090                         Anope::string mask = x->Mask;
00091                         size_t h = x->Mask.find('#');
00092                         if (h != Anope::string::npos)
00093                                 mask = mask.replace(h, 1, ' ');
00094                         SendDelLine("R", mask);
00095                         return;
00096                 }
00097                 else if (x->IsRegex() || x->HasNickOrReal())
00098                         return;
00099 
00100                 SendDelLine("G", x->Mask);
00101         }
00102 
00103         void SendTopic(BotInfo *whosets, Channel *c) anope_override
00104         {
00105                 if (has_svstopic_topiclock)
00106                 {
00107                         UplinkSocket::Message(c->ci->WhoSends()) << "SVSTOPIC " << c->name << " " << c->topic_ts << " " << c->topic_setter << " :" << c->topic;
00108                 }
00109                 else
00110                 {
00111                         /* 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 */
00112                         time_t ts = c->topic_ts;
00113                         if (c->topic_time > ts)
00114                                 ts = Anope::CurTime;
00115                         /* 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 */
00116                         UplinkSocket::Message(whosets) << "FTOPIC " << c->name << " " << ts << " " << c->topic_setter << " :" << c->topic;
00117                 }
00118         }
00119 
00120         void SendVhostDel(User *u) anope_override
00121         {
00122                 if (u->HasMode(UMODE_CLOAK))
00123                         this->SendChgHostInternal(u->nick, u->chost);
00124                 else
00125                         this->SendChgHostInternal(u->nick, u->host);
00126 
00127                 if (has_chgidentmod && u->GetIdent() != u->GetVIdent())
00128                         this->SendChgIdentInternal(u->nick, u->GetIdent());
00129         }
00130 
00131         void SendAkill(User *u, XLine *x) anope_override
00132         {
00133                 // Calculate the time left before this would expire, capping it at 2 days
00134                 time_t timeleft = x->Expires - Anope::CurTime;
00135                 if (timeleft > 172800 || !x->Expires)
00136                         timeleft = 172800;
00137 
00138                 const BotInfo *bi = findbot(Config->OperServ);
00139                 /* InspIRCd may support regex bans, if they do we can send this and forget about it */
00140                 if (x->IsRegex() && has_rlinemod)
00141                 {
00142                         Anope::string mask = x->Mask;
00143                         size_t h = x->Mask.find('#');
00144                         if (h != Anope::string::npos)
00145                                 mask = mask.replace(h, 1, ' ');
00146                         SendAddLine("R", mask, timeleft, x->By, x->GetReason());
00147                         return;
00148                 }
00149                 else if (x->IsRegex() || x->HasNickOrReal())
00150                 {
00151                         if (!u)
00152                         {
00153                                 /* No user (this akill was just added), and contains nick and/or realname. Find users that match and ban them */
00154                                 for (user_map::const_iterator it = UserListByNick.begin(); it != UserListByNick.end(); ++it)
00155                                         if (x->manager->Check(it->second, x))
00156                                                 this->SendAkill(it->second, x);
00157                                 return;
00158                         }
00159 
00160                         const XLine *old = x;
00161 
00162                         if (old->manager->HasEntry("*@" + u->host))
00163                                 return;
00164 
00165                         /* We can't akill x as it has a nick and/or realname included, so create a new akill for *@host */
00166                         x = new XLine("*@" + u->host, old->By, old->Expires, old->Reason, old->UID);
00167                         old->manager->AddXLine(x);
00168 
00169                         Log(bi, "akill") << "AKILL: Added an akill for " << x->Mask << " because " << u->GetMask() << "#" << u->realname << " matches " << old->Mask;
00170                 }
00171 
00172                 /* ZLine if we can instead */
00173                 try
00174                 {
00175                         if (x->GetUser() == "*")
00176                         {
00177                                 sockaddrs(x->GetHost());
00178                                 ircdproto->SendSZLine(u, x);
00179                                 return;
00180                         }
00181                 }
00182                 catch (const SocketException &) { }
00183                 SendAddLine("G", x->GetUser() + "@" + x->GetHost(), timeleft, x->By, x->GetReason());
00184         }
00185 
00186         void SendNumericInternal(int numeric, const Anope::string &dest, const Anope::string &buf) anope_override
00187         {
00188                 UplinkSocket::Message() << "PUSH " << dest << " ::" << Me->GetName() << " " << numeric << " " << dest << " " << buf;
00189         }
00190 
00191         void SendModeInternal(const BotInfo *source, const Channel *dest, const Anope::string &buf) anope_override
00192         {
00193                 UplinkSocket::Message(source) << "FMODE " << dest->name << " " << dest->creation_time << " " << buf;
00194         }
00195 
00196         void SendModeInternal(const BotInfo *bi, const User *u, const Anope::string &buf) anope_override
00197         {
00198                 UplinkSocket::Message(bi) << "MODE " << u->GetUID() << " " << buf;
00199         }
00200 
00201         void SendClientIntroduction(const User *u) anope_override
00202         {
00203                 Anope::string modes = "+" + u->GetModes();
00204                 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;
00205         }
00206 
00207         /* SERVER services-dev.chatspike.net password 0 :Description here */
00208         void SendServer(const Server *server) anope_override
00209         {
00210                 UplinkSocket::Message() << "SERVER " << server->GetName() << " " << Config->Uplinks[CurrentUplink]->password << " " << server->GetHops() << " " << server->GetSID() << " :" << server->GetDescription();
00211         }
00212 
00213         /* JOIN */
00214         void SendJoin(const User *user, Channel *c, const ChannelStatus *status) anope_override
00215         {
00216                 UplinkSocket::Message(Me) << "FJOIN " << c->name << " " << c->creation_time << " +" << c->GetModes(true, true) << " :," << user->GetUID();
00217                 /* Note that we can send this with the FJOIN but choose not to
00218                  * because the mode stacker will handle this and probably will
00219                  * merge these modes with +nrt and other mlocked modes
00220                  */
00221                 if (status)
00222                 {
00223                         /* First save the channel status incase uc->Status == status */
00224                         ChannelStatus cs = *status;
00225                         /* If the user is internally on the channel with flags, kill them so that
00226                          * the stacker will allow this.
00227                          */
00228                         UserContainer *uc = c->FindUser(user);
00229                         if (uc != NULL)
00230                                 uc->Status->ClearFlags();
00231 
00232                         BotInfo *setter = findbot(user->nick);
00233                         for (unsigned i = 0; i < ModeManager::ChannelModes.size(); ++i)
00234                                 if (cs.HasFlag(ModeManager::ChannelModes[i]->Name))
00235                                         c->SetMode(setter, ModeManager::ChannelModes[i], user->GetUID(), false);
00236                 }
00237         }
00238 
00239         /* UNSQLINE */
00240         void SendSQLineDel(const XLine *x) anope_override
00241         {
00242                 SendDelLine("Q", x->Mask);
00243         }
00244 
00245         /* SQLINE */
00246         void SendSQLine(User *, const XLine *x) anope_override
00247         {
00248                 // Calculate the time left before this would expire, capping it at 2 days
00249                 time_t timeleft = x->Expires - Anope::CurTime;
00250                 if (timeleft > 172800 || !x->Expires)
00251                         timeleft = 172800;
00252                 SendAddLine("Q", x->Mask, timeleft, x->By, x->GetReason());
00253         }
00254 
00255         /* Functions that use serval cmd functions */
00256 
00257         void SendVhost(User *u, const Anope::string &vIdent, const Anope::string &vhost) anope_override
00258         {
00259                 if (!vIdent.empty())
00260                         this->SendChgIdentInternal(u->nick, vIdent);
00261                 if (!vhost.empty())
00262                         this->SendChgHostInternal(u->nick, vhost);
00263         }
00264 
00265         void SendConnect() anope_override
00266         {
00267                 SendServer(Me);
00268                 UplinkSocket::Message(Me) << "BURST";
00269                 Module *enc = ModuleManager::FindFirstOf(ENCRYPTION);
00270                 UplinkSocket::Message(Me) << "VERSION :Anope-" << Anope::Version() << " " << Config->ServerName << " :" << ircdproto->GetProtocolName() << " - (" << (enc ? enc->name : "unknown") << ") -- " << Anope::VersionBuildString();
00271         }
00272 
00273         /* SVSHOLD - set */
00274         void SendSVSHold(const Anope::string &nick) anope_override
00275         {
00276                 const BotInfo *bi = findbot(Config->NickServ);
00277                 if (bi)
00278                         UplinkSocket::Message(bi) << "SVSHOLD " << nick << " " << Config->NSReleaseTimeout << " :Being held for registered user";
00279         }
00280 
00281         /* SVSHOLD - release */
00282         void SendSVSHoldDel(const Anope::string &nick) anope_override
00283         {
00284                 const BotInfo *bi = findbot(Config->NickServ);
00285                 if (bi)
00286                         UplinkSocket::Message(bi) << "SVSHOLD " << nick;
00287         }
00288 
00289         /* UNSZLINE */
00290         void SendSZLineDel(const XLine *x) anope_override
00291         {
00292                 SendDelLine("Z", x->GetHost());
00293         }
00294 
00295         /* SZLINE */
00296         void SendSZLine(User *, const XLine *x) anope_override
00297         {
00298                 // Calculate the time left before this would expire, capping it at 2 days
00299                 time_t timeleft = x->Expires - Anope::CurTime;
00300                 if (timeleft > 172800 || !x->Expires)
00301                         timeleft = 172800;
00302                 SendAddLine("Z", x->GetHost(), timeleft, x->By, x->GetReason());
00303         }
00304 
00305         void SendSVSJoin(const BotInfo *source, const Anope::string &nick, const Anope::string &chan, const Anope::string &) anope_override
00306         {
00307                 User *u = finduser(nick);
00308                 UplinkSocket::Message(source) << "SVSJOIN " << u->GetUID() << " " << chan;
00309         }
00310 
00311         void SendSWhois(const BotInfo *, const Anope::string &who, const Anope::string &mask) anope_override
00312         {
00313                 User *u = finduser(who);
00314 
00315                 UplinkSocket::Message(Me) << "METADATA " << u->GetUID() << " swhois :" << mask;
00316         }
00317 
00318         void SendBOB() anope_override
00319         {
00320                 UplinkSocket::Message(Me) << "BURST " << Anope::CurTime;
00321         }
00322 
00323         void SendEOB() anope_override
00324         {
00325                 UplinkSocket::Message(Me) << "ENDBURST";
00326         }
00327 
00328         void SendGlobopsInternal(const BotInfo *source, const Anope::string &buf)
00329         {
00330                 if (has_globopsmod)
00331                         UplinkSocket::Message(source) << "SNONOTICE g :" << buf;
00332                 else
00333                         UplinkSocket::Message(source) << "SNONOTICE A :" << buf;
00334         }
00335 
00336         void SendLogin(User *u) anope_override
00337         {
00338                 if (!u->Account() || u->Account()->HasFlag(NI_UNCONFIRMED))
00339                         return;
00340 
00341                 UplinkSocket::Message(Me) << "METADATA " << u->GetUID() << " accountname :" << u->Account()->display;
00342         }
00343 
00344         void SendLogout(User *u) anope_override
00345         {
00346                 UplinkSocket::Message(Me) << "METADATA " << u->GetUID() << " accountname :";
00347         }
00348 
00349         void SendChannel(Channel *c) anope_override
00350         {
00351                 UplinkSocket::Message(Me) << "FJOIN " << c->name << " " << c->creation_time << " +" << c->GetModes(true, true) << " :";
00352         }
00353 
00354         bool IsNickValid(const Anope::string &nick) anope_override
00355         {
00356                 /* InspIRCd, like TS6, uses UIDs on collision, so... */
00357                 if (isdigit(nick[0]))
00358                         return false;
00359 
00360                 return true;
00361         }
00362 
00363         void SendOper(User *u) anope_override
00364         {
00365         }
00366 };
00367 
00368 struct IRCDMessageEndburst : IRCDMessage
00369 {
00370         IRCDMessageEndburst() : IRCDMessage("ENDBURST", 0) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); }
00371 
00372         bool Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
00373         {
00374                 Server *s = source.GetServer();
00375 
00376                 Log(LOG_DEBUG) << "Processed ENDBURST for " << s->GetName();
00377 
00378                 s->Sync(true);
00379                 return true;
00380         }
00381 };
00382 
00383 struct IRCDMessageFHost : IRCDMessage
00384 {
00385         IRCDMessageFHost(const Anope::string &n) : IRCDMessage(n, 1) { SetFlag(IRCDMESSAGE_REQUIRE_USER); }
00386 
00387         bool Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
00388         {
00389                 source.GetUser()->SetDisplayedHost(params[0]);
00390                 return true;
00391         }
00392 };
00393 
00394 struct IRCDMessageFJoin : IRCDMessage
00395 {
00396         IRCDMessageFJoin() : IRCDMessage("FJOIN", 2) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); SetFlag(IRCDMESSAGE_SOFT_LIMIT); }
00397 
00398         bool Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
00399         {
00400                 Channel *c = findchan(params[0]);
00401                 time_t ts = Anope::string(params[1]).is_pos_number_only() ? convertTo<time_t>(params[1]) : 0;
00402                 bool keep_their_modes = true;
00403 
00404                 if (!c)
00405                 {
00406                         c = new Channel(params[0], ts);
00407                         c->SetFlag(CH_SYNCING);
00408                 }
00409                 /* Our creation time is newer than what the server gave us */
00410                 else if (c->creation_time > ts)
00411                 {
00412                         c->creation_time = ts;
00413                         c->Reset();
00414                 }
00415                 /* Their TS is newer than ours, our modes > theirs, unset their modes if need be */
00416                 else if (ts > c->creation_time)
00417                         keep_their_modes = false;
00418 
00419                 /* If we need to keep their modes, and this FJOIN string contains modes */
00420                 if (keep_their_modes && params.size() >= 3)
00421                 {
00422                         Anope::string modes;
00423                         for (unsigned i = 2; i < params.size() - 1; ++i)
00424                                 modes += " " + params[i];
00425                         if (!modes.empty())
00426                                 modes.erase(modes.begin());
00427                         /* Set the modes internally */
00428                         c->SetModesInternal(source, modes);
00429                 }
00430 
00431                 spacesepstream sep(params[params.size() - 1]);
00432                 Anope::string buf;
00433                 while (sep.GetToken(buf))
00434                 {
00435                         std::list<ChannelMode *> Status;
00436 
00437                         /* Loop through prefixes and find modes for them */
00438                         while (buf[0] != ',')
00439                         {
00440                                 ChannelMode *cm = ModeManager::FindChannelModeByChar(buf[0]);
00441                                 if (!cm)
00442                                 {
00443                                         Log() << "Received unknown mode prefix " << buf[0] << " in FJOIN string";
00444                                         buf.erase(buf.begin());
00445                                         continue;
00446                                 }
00447 
00448                                 buf.erase(buf.begin());
00449                                 if (keep_their_modes)
00450                                         Status.push_back(cm);
00451                         }
00452                         buf.erase(buf.begin());
00453 
00454                         User *u = finduser(buf);
00455                         if (!u)
00456                         {
00457                                 Log(LOG_DEBUG) << "FJOIN for nonexistant user " << buf << " on " << c->name;
00458                                 continue;
00459                         }
00460 
00461                         EventReturn MOD_RESULT;
00462                         FOREACH_RESULT(I_OnPreJoinChannel, OnPreJoinChannel(u, c));
00463 
00464                         /* Add the user to the channel */
00465                         c->JoinUser(u);
00466 
00467                         /* Update their status internally on the channel
00468                          * This will enforce secureops etc on the user
00469                          */
00470                         for (std::list<ChannelMode *>::iterator it = Status.begin(), it_end = Status.end(); it != it_end; ++it)
00471                                 c->SetModeInternal(source, *it, buf);
00472 
00473                         /* Now set whatever modes this user is allowed to have on the channel */
00474                         chan_set_correct_modes(u, c, 1, true);
00475 
00476                         /* Check to see if modules want the user to join, if they do
00477                          * check to see if they are allowed to join (CheckKick will kick/ban them)
00478                          * Don't trigger OnJoinChannel event then as the user will be destroyed
00479                          */
00480                         if (MOD_RESULT != EVENT_STOP && c->ci && c->ci->CheckKick(u))
00481                                 continue;
00482 
00483                         FOREACH_MOD(I_OnJoinChannel, OnJoinChannel(u, c));
00484                 }
00485 
00486                 /* Channel is done syncing */
00487                 if (c->HasFlag(CH_SYNCING))
00488                 {
00489                         /* Unset the syncing flag */
00490                         c->UnsetFlag(CH_SYNCING);
00491                         c->Sync();
00492                 }
00493 
00494                 return true;
00495         }
00496 };
00497 
00498 struct IRCDMessageFMode : IRCDMessage
00499 {
00500         IRCDMessageFMode() : IRCDMessage("FMODE", 3) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); }
00501 
00502         bool Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
00503         {
00504                 /* :source FMODE #test 12345678 +nto foo */
00505 
00506                 Anope::string modes = params[2];
00507                 for (unsigned n = 3; n < params.size(); ++n)
00508                         modes += " " + params[n];
00509 
00510                 Channel *c = findchan(params[0]);
00511                 time_t ts;
00512 
00513                 try
00514                 {
00515                         ts = convertTo<time_t>(params[1]);
00516                 }
00517                 catch (const ConvertException &)
00518                 {
00519                         ts = 0;
00520                 }
00521 
00522                 if (c)
00523                         c->SetModesInternal(source, modes, ts);
00524 
00525                 return true;
00526         }
00527 };
00528 
00529 struct IRCDMessageFTopic : IRCDMessage
00530 {
00531         IRCDMessageFTopic() : IRCDMessage("FTOPIC", 4) { }
00532 
00533         bool Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
00534         {
00535                 /* :source FTOPIC channel topicts setby :topic */
00536 
00537                 Channel *c = findchan(params[0]);
00538                 if (c)
00539                         c->ChangeTopicInternal(params[2], params[3], Anope::string(params[1]).is_pos_number_only() ? convertTo<time_t>(params[1]) : Anope::CurTime);
00540 
00541                 return true;
00542         }
00543 };
00544 
00545 struct IRCDMessageIdle : IRCDMessage
00546 {
00547         IRCDMessageIdle() : IRCDMessage("IDLE", 1) { }
00548 
00549         bool Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
00550         {
00551                 const BotInfo *bi = findbot(params[0]);
00552                 if (bi)
00553                         UplinkSocket::Message(bi) << "IDLE " << source.GetSource() << " " << start_time << " " << (Anope::CurTime - bi->lastmsg);
00554                 return true;
00555         }
00556 };
00557 
00558 /*
00559  *   source     = numeric of the sending server
00560  *   params[0]  = uuid
00561  *   params[1]  = metadata name
00562  *   params[2]  = data
00563  */
00564 struct IRCDMessageMetadata : IRCDMessage
00565 {
00566         IRCDMessageMetadata() : IRCDMessage("METADATA", 3) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); }
00567 
00568         bool Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
00569         {
00570                 if (isdigit(params[0][0]))
00571                 {
00572                         if (params[1].equals_cs("accountname"))
00573                         {
00574                                 User *u = finduser(params[0]);
00575                                 NickCore *nc = findcore(params[2]);
00576                                 if (u && nc)
00577                                 {
00578                                         u->Login(nc);
00579 
00580                                         const BotInfo *bi = findbot(Config->NickServ);
00581                                         const NickAlias *user_na = findnick(u->nick);
00582                                         if (!Config->NoNicknameOwnership && nickserv && user_na && user_na->nc == nc && user_na->nc->HasFlag(NI_UNCONFIRMED) == false)
00583                                                 u->SetMode(bi, UMODE_REGISTERED);
00584 
00585                                         /* Sometimes a user connects, we send them the usual "this nickname is registered" mess (if
00586                                          * their server isn't syncing) and then we receive this.. so tell them about it.
00587                                          */
00588                                         if (u->server->IsSynced() && bi)
00589                                                 u->SendMessage(bi, _("You have been logged in as \2%s\2."), nc->display.c_str());
00590                                 }
00591                         }
00592 
00593                         /*
00594                          *   possible incoming ssl_cert messages:
00595                          *   Received: :409 METADATA 409AAAAAA ssl_cert :vTrSe c38070ce96e41cc144ed6590a68d45a6 <...> <...>
00596                          *   Received: :409 METADATA 409AAAAAC ssl_cert :vTrSE Could not get peer certificate: error:00000000:lib(0):func(0):reason(0)
00597                          */
00598                         else if (params[1].equals_cs("ssl_cert"))
00599                         {
00600                                 User *u = finduser(params[0]);
00601                                 if (!u)
00602                                         return true;
00603                                 std::string data = params[2].c_str();
00604                                 size_t pos1 = data.find(' ') + 1;
00605                                 size_t pos2 = data.find(' ', pos1);
00606                                 if ((pos2 - pos1) >= 32) // inspircd supports md5 and sha1 fingerprint hashes -> size 32 or 40 bytes.
00607                                 {
00608                                         u->fingerprint = data.substr(pos1, pos2 - pos1);
00609                                         FOREACH_MOD(I_OnFingerprint, OnFingerprint(u));
00610                                 }
00611                         }
00612                 }
00613                 else if (params[0][0] == '#')
00614                 {
00615                 }
00616                 else if (params[0] == "*")
00617                 {
00618                         // Wed Oct  3 15:40:27 2012: S[14] O :20D METADATA * modules :-m_svstopic.so
00619 
00620                         if (params[1].equals_cs("modules") && !params[2].empty())
00621                         {
00622                                 // only interested when it comes from our uplink
00623                                 Server* server = source.GetServer();
00624                                 if (!server || server->GetUplink() != Me)
00625                                         return true;
00626 
00627                                 bool plus = (params[2][0] == '+');
00628                                 if (!plus && params[2][0] != '-')
00629                                         return true;
00630 
00631                                 bool required = false;
00632                                 Anope::string module = params[2].substr(1);
00633 
00634                                 if (module.equals_cs("m_services_account.so"))
00635                                         required = true;
00636                                 else if (module.equals_cs("m_hidechans.so"))
00637                                         required = true;
00638                                 else if (module.equals_cs("m_chghost.so"))
00639                                         has_chghostmod = plus;
00640                                 else if (module.equals_cs("m_chgident.so"))
00641                                         has_chgidentmod = plus;
00642                                 else if (module.equals_cs("m_svshold.so"))
00643                                         ircdproto->CanSVSHold = plus;
00644                                 else if (module.equals_cs("m_rline.so"))
00645                                         has_rlinemod = plus;
00646                                 else if (module.equals_cs("m_topiclock.so"))
00647                                         has_svstopic_topiclock = plus;
00648                                 else
00649                                         return true;
00650 
00651                                 if (required)
00652                                 {
00653                                         if (!plus)
00654                                                 Log() << "Warning: InspIRCd unloaded module " << module << ", Anope won't function correctly without it";
00655                                 }
00656                                 else
00657                                 {
00658                                         Log() << "InspIRCd " << (plus ? "loaded" : "unloaded") << " module " << module << ", adjusted functionality";
00659                                 }
00660 
00661                         }
00662                 }
00663 
00664                 return true;
00665         }
00666 };
00667 
00668 struct IRCDMessageMode : IRCDMessage
00669 {
00670         IRCDMessageMode() : IRCDMessage("MODE", 2) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); }
00671 
00672         bool Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
00673         {
00674                 if (ircdproto->IsChannelValid(params[0]))
00675                 {
00676                         Channel *c = findchan(params[0]);
00677 
00678                         Anope::string modes = params[1];
00679                         for (unsigned n = 2; n < params.size(); ++n)
00680                                 modes += " " + params[n];
00681 
00682                         if (c)
00683                                 c->SetModesInternal(source, modes);
00684                 }
00685                 else
00686                 {
00687                         /* InspIRCd lets opers change another
00688                            users modes, we have to kludge this
00689                            as it slightly breaks RFC1459
00690                          */
00691                         User *u = source.GetUser();
00692                         // This can happen with server-origin modes.
00693                         if (!u)
00694                                 u = finduser(params[0]);
00695                         // if it's still null, drop it like fire.
00696                         // most likely situation was that server introduced a nick which we subsequently akilled
00697                         if (u)
00698                                 u->SetModesInternal("%s", params[1].c_str());
00699                 }
00700 
00701                 return true;
00702         }
00703 };
00704 
00705 struct IRCDMessageNick : IRCDMessage
00706 {
00707         IRCDMessageNick() : IRCDMessage("NICK", 2) { SetFlag(IRCDMESSAGE_REQUIRE_USER); }
00708 
00709         bool Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
00710         {
00711                 source.GetUser()->ChangeNick(params[0]);
00712                 return true;
00713         }
00714 };
00715 
00716 struct IRCDMessageOperType : IRCDMessage
00717 {
00718         IRCDMessageOperType() : IRCDMessage("OPERTYPE", 0) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); SetFlag(IRCDMESSAGE_REQUIRE_USER); }
00719 
00720         bool Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
00721         {
00722                 /* opertype is equivalent to mode +o because servers
00723                    dont do this directly */
00724                 User *u = source.GetUser();
00725                 if (!u->HasMode(UMODE_OPER))
00726                         u->SetModesInternal("+o");
00727 
00728                 return true;
00729         }
00730 };
00731 
00732 struct IRCDMessageRSQuit : IRCDMessage
00733 {
00734         IRCDMessageRSQuit() : IRCDMessage("RSQUIT", 1) { }
00735 
00736         bool Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
00737         {
00738                 Server *s = Server::Find(params[0]);
00739                 if (!s)
00740                         return true;
00741 
00742                 /* On InspIRCd we must send a SQUIT when we recieve RSQUIT for a server we have juped */
00743                 if (s->HasFlag(SERVER_JUPED))
00744                         UplinkSocket::Message(Me) << "SQUIT " << s->GetSID() << " :" << (params.size() > 1 ? params[1].c_str() : "");
00745 
00746                 FOREACH_MOD(I_OnServerQuit, OnServerQuit(s));
00747 
00748                 s->Delete(s->GetName() + " " + s->GetUplink()->GetName());
00749 
00750                 return true;
00751         }
00752 };
00753 
00754 struct IRCDMessageServer : IRCDMessage
00755 {
00756         IRCDMessageServer() : IRCDMessage("SERVER", 5) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); }
00757 
00758         /*
00759          * [Nov 04 00:08:46.308435 2009] debug: Received: SERVER irc.inspircd.com pass 0 964 :Testnet Central!
00760          * 0: name
00761          * 1: pass
00762          * 2: hops
00763          * 3: numeric
00764          * 4: desc
00765          */
00766         bool Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
00767         {
00768                 unsigned int hops = Anope::string(params[2]).is_pos_number_only() ? convertTo<unsigned>(params[2]) : 0;
00769                 new Server(source.GetServer() == NULL ? Me : source.GetServer(), params[0], hops, params[4], params[3]);
00770                 return true;
00771         }
00772 };
00773 
00774 struct IRCDMessageTime : IRCDMessage
00775 {
00776         IRCDMessageTime() : IRCDMessage("TIME", 2) { }
00777 
00778         bool Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
00779         {
00780                 UplinkSocket::Message(Me) << "TIME " << source.GetSource() << " " << params[1] << " " << Anope::CurTime;
00781                 return true;
00782         }
00783 };
00784 
00785 struct IRCDMessageUID : IRCDMessage
00786 {
00787         IRCDMessageUID() : IRCDMessage("UID", 8) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); SetFlag(IRCDMESSAGE_SOFT_LIMIT); }
00788 
00789         /*
00790          * [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>
00791          * 0: uid
00792          * 1: ts
00793          * 2: nick
00794          * 3: host
00795          * 4: dhost
00796          * 5: ident
00797          * 6: ip
00798          * 7: signon
00799          * 8+: modes and params -- IMPORTANT, some modes (e.g. +s) may have parameters. So don't assume a fixed position of realname!
00800          * last: realname
00801          */
00802         bool Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
00803         {
00804                 time_t ts = convertTo<time_t>(params[1]);
00805 
00806                 Anope::string modes = params[8];
00807                 for (unsigned i = 9; i < params.size() - 1; ++i)
00808                         modes += " " + params[i];
00809 
00810                 User *u = new User(params[2], params[5], params[3], params[4], params[6], source.GetServer(), params[params.size() - 1], ts, modes, params[0]);
00811                 if (u->server->IsSynced() && nickserv)
00812                         nickserv->Validate(u);
00813 
00814                 return true;
00815         }
00816 };
00817