anope- supernets anope source code & configuration |
git clone git://git.acid.vegas/anope.git |
Log | Files | Refs | Archive | README |
inspircd20.cpp (39170B)
1 /* InspIRCd 2.0 functions 2 * 3 * (C) 2003-2022 Anope Team 4 * Contact us at team@anope.org 5 * 6 * Please read COPYING and README for further details. 7 * 8 * Based on the original code of Epona by Lara. 9 * Based on the original code of Services by Andy Church. 10 */ 11 12 #include "module.h" 13 #include "modules/cs_mode.h" 14 15 static unsigned int spanningtree_proto_ver = 0; 16 17 static ServiceReference<IRCDProto> insp12("IRCDProto", "inspircd12"); 18 19 class InspIRCd20Proto : public IRCDProto 20 { 21 public: 22 InspIRCd20Proto(Module *creator) : IRCDProto(creator, "InspIRCd 2.0") 23 { 24 DefaultPseudoclientModes = "+I"; 25 CanSVSNick = true; 26 CanSVSJoin = true; 27 CanSetVHost = true; 28 CanSetVIdent = true; 29 CanSQLine = true; 30 CanSZLine = true; 31 CanSVSHold = true; 32 CanCertFP = true; 33 RequiresID = true; 34 MaxModes = 20; 35 } 36 37 void SendConnect() anope_override 38 { 39 UplinkSocket::Message() << "CAPAB START 1202"; 40 UplinkSocket::Message() << "CAPAB CAPABILITIES :PROTOCOL=1202"; 41 UplinkSocket::Message() << "CAPAB END"; 42 insp12->SendConnect(); 43 } 44 45 void SendSASLMechanisms(std::vector<Anope::string> &mechanisms) anope_override 46 { 47 Anope::string mechlist; 48 for (unsigned i = 0; i < mechanisms.size(); ++i) 49 mechlist += "," + mechanisms[i]; 50 51 UplinkSocket::Message(Me) << "METADATA * saslmechlist :" << (mechanisms.empty() ? "" : mechlist.substr(1)); 52 } 53 54 void SendSVSKillInternal(const MessageSource &source, User *user, const Anope::string &buf) anope_override { insp12->SendSVSKillInternal(source, user, buf); } 55 void SendGlobalNotice(BotInfo *bi, const Server *dest, const Anope::string &msg) anope_override { insp12->SendGlobalNotice(bi, dest, msg); } 56 void SendGlobalPrivmsg(BotInfo *bi, const Server *dest, const Anope::string &msg) anope_override { insp12->SendGlobalPrivmsg(bi, dest, msg); } 57 void SendAkillDel(const XLine *x) anope_override { insp12->SendAkillDel(x); } 58 void SendTopic(const MessageSource &whosets, Channel *c) anope_override { insp12->SendTopic(whosets, c); }; 59 void SendVhostDel(User *u) anope_override { insp12->SendVhostDel(u); } 60 void SendAkill(User *u, XLine *x) anope_override { insp12->SendAkill(u, x); } 61 void SendNumericInternal(int numeric, const Anope::string &dest, const Anope::string &buf) anope_override { insp12->SendNumericInternal(numeric, dest, buf); } 62 void SendModeInternal(const MessageSource &source, const Channel *dest, const Anope::string &buf) anope_override { insp12->SendModeInternal(source, dest, buf); } 63 void SendClientIntroduction(User *u) anope_override { insp12->SendClientIntroduction(u); } 64 void SendServer(const Server *server) anope_override { insp12->SendServer(server); } 65 void SendSquit(Server *s, const Anope::string &message) anope_override { insp12->SendSquit(s, message); } 66 void SendJoin(User *user, Channel *c, const ChannelStatus *status) anope_override { insp12->SendJoin(user, c, status); } 67 void SendSQLineDel(const XLine *x) anope_override { insp12->SendSQLineDel(x); } 68 void SendSQLine(User *u, const XLine *x) anope_override { insp12->SendSQLine(u, x); } 69 void SendVhost(User *u, const Anope::string &vident, const Anope::string &vhost) anope_override { insp12->SendVhost(u, vident, vhost); } 70 void SendSVSHold(const Anope::string &nick, time_t t) anope_override { insp12->SendSVSHold(nick, t); } 71 void SendSVSHoldDel(const Anope::string &nick) anope_override { insp12->SendSVSHoldDel(nick); } 72 void SendSZLineDel(const XLine *x) anope_override { insp12->SendSZLineDel(x); } 73 void SendSZLine(User *u, const XLine *x) anope_override { insp12->SendSZLine(u, x); } 74 void SendSVSJoin(const MessageSource &source, User *u, const Anope::string &chan, const Anope::string &other) anope_override { insp12->SendSVSJoin(source, u, chan, other); } 75 void SendSVSPart(const MessageSource &source, User *u, const Anope::string &chan, const Anope::string ¶m) anope_override { insp12->SendSVSPart(source, u, chan, param); } 76 void SendSWhois(const MessageSource &bi, const Anope::string &who, const Anope::string &mask) anope_override { insp12->SendSWhois(bi, who, mask); } 77 void SendBOB() anope_override { insp12->SendBOB(); } 78 void SendEOB() anope_override { insp12->SendEOB(); } 79 void SendGlobopsInternal(const MessageSource &source, const Anope::string &buf) { insp12->SendGlobopsInternal(source, buf); } 80 void SendLogin(User *u, NickAlias *na) anope_override { insp12->SendLogin(u, na); } 81 void SendLogout(User *u) anope_override { insp12->SendLogout(u); } 82 void SendChannel(Channel *c) anope_override { insp12->SendChannel(c); } 83 void SendSASLMessage(const SASL::Message &message) anope_override { insp12->SendSASLMessage(message); } 84 void SendSVSLogin(const Anope::string &uid, const Anope::string &acc, const Anope::string &vident, const Anope::string &vhost) anope_override { insp12->SendSVSLogin(uid, acc, vident, vhost); } 85 bool IsExtbanValid(const Anope::string &mask) anope_override { return insp12->IsExtbanValid(mask); } 86 bool IsIdentValid(const Anope::string &ident) anope_override { return insp12->IsIdentValid(ident); } 87 }; 88 89 class InspIRCdAutoOpMode : public ChannelModeList 90 { 91 public: 92 InspIRCdAutoOpMode(char mode) : ChannelModeList("AUTOOP", mode) 93 { 94 } 95 96 bool IsValid(Anope::string &mask) const anope_override 97 { 98 // We can not validate this because we don't know about the 99 // privileges of the setter so just reject attempts to set it. 100 return false; 101 } 102 }; 103 104 class InspIRCdExtBan : public ChannelModeVirtual<ChannelModeList> 105 { 106 char ext; 107 108 public: 109 InspIRCdExtBan(const Anope::string &mname, const Anope::string &basename, char extban) : ChannelModeVirtual<ChannelModeList>(mname, basename) 110 , ext(extban) 111 { 112 } 113 114 ChannelMode *Wrap(Anope::string ¶m) anope_override 115 { 116 param = Anope::string(ext) + ":" + param; 117 return ChannelModeVirtual<ChannelModeList>::Wrap(param); 118 } 119 120 ChannelMode *Unwrap(ChannelMode *cm, Anope::string ¶m) anope_override 121 { 122 if (cm->type != MODE_LIST || param.length() < 3 || param[0] != ext || param[1] != ':') 123 return cm; 124 125 param = param.substr(2); 126 return this; 127 } 128 }; 129 130 namespace InspIRCdExtban 131 { 132 class EntryMatcher : public InspIRCdExtBan 133 { 134 public: 135 EntryMatcher(const Anope::string &mname, const Anope::string &mbase, char c) : InspIRCdExtBan(mname, mbase, c) 136 { 137 } 138 139 bool Matches(User *u, const Entry *e) anope_override 140 { 141 const Anope::string &mask = e->GetMask(); 142 Anope::string real_mask = mask.substr(3); 143 144 return Entry(this->name, real_mask).Matches(u); 145 } 146 }; 147 148 class ChannelMatcher : public InspIRCdExtBan 149 { 150 public: 151 ChannelMatcher(const Anope::string &mname, const Anope::string &mbase, char c) : InspIRCdExtBan(mname, mbase, c) 152 { 153 } 154 155 bool Matches(User *u, const Entry *e) anope_override 156 { 157 const Anope::string &mask = e->GetMask(); 158 159 Anope::string channel = mask.substr(3); 160 161 ChannelMode *cm = NULL; 162 if (channel[0] != '#') 163 { 164 char modeChar = ModeManager::GetStatusChar(channel[0]); 165 channel.erase(channel.begin()); 166 cm = ModeManager::FindChannelModeByChar(modeChar); 167 if (cm != NULL && cm->type != MODE_STATUS) 168 cm = NULL; 169 } 170 171 Channel *c = Channel::Find(channel); 172 if (c != NULL) 173 { 174 ChanUserContainer *uc = c->FindUser(u); 175 if (uc != NULL) 176 if (cm == NULL || uc->status.HasMode(cm->mchar)) 177 return true; 178 } 179 180 return false; 181 } 182 }; 183 184 class AccountMatcher : public InspIRCdExtBan 185 { 186 public: 187 AccountMatcher(const Anope::string &mname, const Anope::string &mbase, char c) : InspIRCdExtBan(mname, mbase, c) 188 { 189 } 190 191 bool Matches(User *u, const Entry *e) anope_override 192 { 193 const Anope::string &mask = e->GetMask(); 194 Anope::string real_mask = mask.substr(2); 195 196 return u->IsIdentified() && real_mask.equals_ci(u->Account()->display); 197 } 198 }; 199 200 class RealnameMatcher : public InspIRCdExtBan 201 { 202 public: 203 RealnameMatcher(const Anope::string &mname, const Anope::string &mbase, char c) : InspIRCdExtBan(mname, mbase, c) 204 { 205 } 206 207 bool Matches(User *u, const Entry *e) anope_override 208 { 209 const Anope::string &mask = e->GetMask(); 210 Anope::string real_mask = mask.substr(2); 211 return Anope::Match(u->realname, real_mask); 212 } 213 }; 214 215 class ServerMatcher : public InspIRCdExtBan 216 { 217 public: 218 ServerMatcher(const Anope::string &mname, const Anope::string &mbase, char c) : InspIRCdExtBan(mname, mbase, c) 219 { 220 } 221 222 bool Matches(User *u, const Entry *e) anope_override 223 { 224 const Anope::string &mask = e->GetMask(); 225 Anope::string real_mask = mask.substr(2); 226 return Anope::Match(u->server->GetName(), real_mask); 227 } 228 }; 229 230 class FingerprintMatcher : public InspIRCdExtBan 231 { 232 public: 233 FingerprintMatcher(const Anope::string &mname, const Anope::string &mbase, char c) : InspIRCdExtBan(mname, mbase, c) 234 { 235 } 236 237 bool Matches(User *u, const Entry *e) anope_override 238 { 239 const Anope::string &mask = e->GetMask(); 240 Anope::string real_mask = mask.substr(2); 241 return !u->fingerprint.empty() && Anope::Match(u->fingerprint, real_mask); 242 } 243 }; 244 245 class UnidentifiedMatcher : public InspIRCdExtBan 246 { 247 public: 248 UnidentifiedMatcher(const Anope::string &mname, const Anope::string &mbase, char c) : InspIRCdExtBan(mname, mbase, c) 249 { 250 } 251 252 bool Matches(User *u, const Entry *e) anope_override 253 { 254 const Anope::string &mask = e->GetMask(); 255 Anope::string real_mask = mask.substr(2); 256 return !u->Account() && Entry("BAN", real_mask).Matches(u); 257 } 258 }; 259 } 260 261 class ColonDelimitedParamMode : public ChannelModeParam 262 { 263 public: 264 ColonDelimitedParamMode(const Anope::string &modename, char modeChar) : ChannelModeParam(modename, modeChar, true) { } 265 266 bool IsValid(Anope::string &value) const anope_override 267 { 268 return IsValid(value, false); 269 } 270 271 bool IsValid(const Anope::string &value, bool historymode) const 272 { 273 if (value.empty()) 274 return false; // empty param is never valid 275 276 Anope::string::size_type pos = value.find(':'); 277 if ((pos == Anope::string::npos) || (pos == 0)) 278 return false; // no ':' or it's the first char, both are invalid 279 280 Anope::string rest; 281 try 282 { 283 if (convertTo<int>(value, rest, false) <= 0) 284 return false; // negative numbers and zero are invalid 285 286 rest = rest.substr(1); 287 int n; 288 if (historymode) 289 { 290 // For the history mode, the part after the ':' is a duration and it 291 // can be in the user friendly "1d3h20m" format, make sure we accept that 292 n = Anope::DoTime(rest); 293 } 294 else 295 n = convertTo<int>(rest); 296 297 if (n <= 0) 298 return false; 299 } 300 catch (const ConvertException &e) 301 { 302 // conversion error, invalid 303 return false; 304 } 305 306 return true; 307 } 308 }; 309 310 class SimpleNumberParamMode : public ChannelModeParam 311 { 312 public: 313 SimpleNumberParamMode(const Anope::string &modename, char modeChar) : ChannelModeParam(modename, modeChar, true) { } 314 315 bool IsValid(Anope::string &value) const anope_override 316 { 317 if (value.empty()) 318 return false; // empty param is never valid 319 320 try 321 { 322 if (convertTo<int>(value) <= 0) 323 return false; 324 } 325 catch (const ConvertException &e) 326 { 327 // conversion error, invalid 328 return false; 329 } 330 331 return true; 332 } 333 }; 334 335 class ChannelModeFlood : public ColonDelimitedParamMode 336 { 337 public: 338 ChannelModeFlood(char modeChar) : ColonDelimitedParamMode("FLOOD", modeChar) { } 339 340 bool IsValid(Anope::string &value) const anope_override 341 { 342 // The parameter of this mode is a bit different, it may begin with a '*', 343 // ignore it if that's the case 344 Anope::string v = value[0] == '*' ? value.substr(1) : value; 345 return ((!value.empty()) && (ColonDelimitedParamMode::IsValid(v))); 346 } 347 }; 348 349 class ChannelModeHistory : public ColonDelimitedParamMode 350 { 351 public: 352 ChannelModeHistory(char modeChar) : ColonDelimitedParamMode("HISTORY", modeChar) { } 353 354 bool IsValid(Anope::string &value) const anope_override 355 { 356 return (ColonDelimitedParamMode::IsValid(value, true)); 357 } 358 }; 359 360 class ChannelModeRedirect : public ChannelModeParam 361 { 362 public: 363 ChannelModeRedirect(char modeChar) : ChannelModeParam("REDIRECT", modeChar, true) { } 364 365 bool IsValid(Anope::string &value) const anope_override 366 { 367 // The parameter of this mode is a channel, and channel names start with '#' 368 return ((!value.empty()) && (value[0] == '#')); 369 } 370 }; 371 372 struct IRCDMessageAway : Message::Away 373 { 374 IRCDMessageAway(Module *creator) : Message::Away(creator, "AWAY") { SetFlag(IRCDMESSAGE_REQUIRE_USER); } 375 376 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 377 { 378 std::vector<Anope::string> newparams(params); 379 if (newparams.size() > 1) 380 newparams.erase(newparams.begin()); 381 382 Message::Away::Run(source, newparams); 383 } 384 }; 385 386 struct IRCDMessageCapab : Message::Capab 387 { 388 std::map<char, Anope::string> chmodes, umodes; 389 390 IRCDMessageCapab(Module *creator) : Message::Capab(creator, "CAPAB") { SetFlag(IRCDMESSAGE_SOFT_LIMIT); } 391 392 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 393 { 394 if (params[0].equals_cs("START")) 395 { 396 if (params.size() >= 2) 397 spanningtree_proto_ver = (Anope::string(params[1]).is_pos_number_only() ? convertTo<unsigned>(params[1]) : 0); 398 399 if (spanningtree_proto_ver < 1202) 400 { 401 UplinkSocket::Message() << "ERROR :Protocol mismatch, no or invalid protocol version given in CAPAB START"; 402 Anope::QuitReason = "Protocol mismatch, no or invalid protocol version given in CAPAB START"; 403 Anope::Quitting = true; 404 return; 405 } 406 407 /* reset CAPAB */ 408 chmodes.clear(); 409 umodes.clear(); 410 Servers::Capab.insert("SERVERS"); 411 Servers::Capab.insert("TOPICLOCK"); 412 IRCD->CanSVSHold = false; 413 IRCD->DefaultPseudoclientModes = "+I"; 414 } 415 else if (params[0].equals_cs("CHANMODES") && params.size() > 1) 416 { 417 spacesepstream ssep(params[1]); 418 Anope::string capab; 419 420 while (ssep.GetToken(capab)) 421 { 422 Anope::string modename = capab.substr(0, capab.find('=')); 423 Anope::string modechar = capab.substr(capab.find('=') + 1); 424 ChannelMode *cm = NULL; 425 426 if (modename.equals_cs("admin")) 427 cm = new ChannelModeStatus("PROTECT", modechar.length() > 1 ? modechar[1] : modechar[0], modechar.length() > 1 ? modechar[0] : 0, 3); 428 else if (modename.equals_cs("allowinvite")) 429 { 430 cm = new ChannelMode("ALLINVITE", modechar[0]); 431 ModeManager::AddChannelMode(new InspIRCdExtban::EntryMatcher("INVITEBAN", "BAN", 'A')); 432 } 433 else if (modename.equals_cs("auditorium")) 434 cm = new ChannelMode("AUDITORIUM", modechar[0]); 435 else if (modename.equals_cs("autoop")) 436 cm = new InspIRCdAutoOpMode(modechar[0]); 437 else if (modename.equals_cs("ban")) 438 cm = new ChannelModeList("BAN", modechar[0]); 439 else if (modename.equals_cs("banexception")) 440 cm = new ChannelModeList("EXCEPT", modechar[0]); 441 else if (modename.equals_cs("blockcaps")) 442 { 443 cm = new ChannelMode("BLOCKCAPS", modechar[0]); 444 ModeManager::AddChannelMode(new InspIRCdExtban::EntryMatcher("BLOCKCAPSBAN", "BAN", 'B')); 445 } 446 else if (modename.equals_cs("blockcolor")) 447 { 448 cm = new ChannelMode("BLOCKCOLOR", modechar[0]); 449 ModeManager::AddChannelMode(new InspIRCdExtban::EntryMatcher("BLOCKCOLORBAN", "BAN", 'c')); 450 } 451 else if (modename.equals_cs("c_registered")) 452 cm = new ChannelModeNoone("REGISTERED", modechar[0]); 453 else if (modename.equals_cs("censor")) 454 cm = new ChannelMode("CENSOR", modechar[0]); 455 else if (modename.equals_cs("delayjoin")) 456 cm = new ChannelMode("DELAYEDJOIN", modechar[0]); 457 else if (modename.equals_cs("delaymsg")) 458 cm = new SimpleNumberParamMode("DELAYMSG", modechar[0]); 459 else if (modename.equals_cs("filter")) 460 cm = new ChannelModeList("FILTER", modechar[0]); 461 else if (modename.equals_cs("flood")) 462 cm = new ChannelModeFlood(modechar[0]); 463 else if (modename.equals_cs("founder")) 464 cm = new ChannelModeStatus("OWNER", modechar.length() > 1 ? modechar[1] : modechar[0], modechar.length() > 1 ? modechar[0] : 0, 4); 465 else if (modename.equals_cs("halfop")) 466 cm = new ChannelModeStatus("HALFOP", modechar.length() > 1 ? modechar[1] : modechar[0], modechar.length() > 1 ? modechar[0] : 0, 1); 467 else if (modename.equals_cs("history")) 468 cm = new ChannelModeHistory(modechar[0]); 469 else if (modename.equals_cs("invex")) 470 cm = new ChannelModeList("INVITEOVERRIDE", modechar[0]); 471 else if (modename.equals_cs("inviteonly")) 472 cm = new ChannelMode("INVITE", modechar[0]); 473 else if (modename.equals_cs("joinflood")) 474 cm = new ColonDelimitedParamMode("JOINFLOOD", modechar[0]); 475 else if (modename.equals_cs("key")) 476 cm = new ChannelModeKey(modechar[0]); 477 else if (modename.equals_cs("kicknorejoin")) 478 cm = new SimpleNumberParamMode("NOREJOIN", modechar[0]); 479 else if (modename.equals_cs("limit")) 480 cm = new ChannelModeParam("LIMIT", modechar[0], true); 481 else if (modename.equals_cs("moderated")) 482 cm = new ChannelMode("MODERATED", modechar[0]); 483 else if (modename.equals_cs("nickflood")) 484 cm = new ColonDelimitedParamMode("NICKFLOOD", modechar[0]); 485 else if (modename.equals_cs("noctcp")) 486 { 487 cm = new ChannelMode("NOCTCP", modechar[0]); 488 ModeManager::AddChannelMode(new InspIRCdExtban::EntryMatcher("NOCTCPBAN", "BAN", 'C')); 489 } 490 else if (modename.equals_cs("noextmsg")) 491 cm = new ChannelMode("NOEXTERNAL", modechar[0]); 492 else if (modename.equals_cs("nokick")) 493 { 494 cm = new ChannelMode("NOKICK", modechar[0]); 495 ModeManager::AddChannelMode(new InspIRCdExtban::EntryMatcher("NOKICKBAN", "BAN", 'Q')); 496 } 497 else if (modename.equals_cs("noknock")) 498 cm = new ChannelMode("NOKNOCK", modechar[0]); 499 else if (modename.equals_cs("nonick")) 500 { 501 cm = new ChannelMode("NONICK", modechar[0]); 502 ModeManager::AddChannelMode(new InspIRCdExtban::EntryMatcher("NONICKBAN", "BAN", 'N')); 503 } 504 else if (modename.equals_cs("nonotice")) 505 { 506 cm = new ChannelMode("NONOTICE", modechar[0]); 507 ModeManager::AddChannelMode(new InspIRCdExtban::EntryMatcher("NONOTICEBAN", "BAN", 'T')); 508 } 509 else if (modename.equals_cs("official-join")) 510 cm = new ChannelModeStatus("OFFICIALJOIN", modechar.length() > 1 ? modechar[1] : modechar[0], modechar.length() > 1 ? modechar[0] : 0, 2); 511 else if (modename.equals_cs("op")) 512 cm = new ChannelModeStatus("OP", modechar.length() > 1 ? modechar[1] : modechar[0], modechar.length() > 1 ? modechar[0] : 0, 2); 513 else if (modename.equals_cs("operonly")) 514 cm = new ChannelModeOperOnly("OPERONLY", modechar[0]); 515 else if (modename.equals_cs("operprefix")) 516 cm = new ChannelModeStatus("OPERPREFIX", modechar.length() > 1 ? modechar[1] : modechar[0], modechar.length() > 1 ? modechar[0] : 0, 2); 517 else if (modename.equals_cs("permanent")) 518 cm = new ChannelMode("PERM", modechar[0]); 519 else if (modename.equals_cs("private")) 520 cm = new ChannelMode("PRIVATE", modechar[0]); 521 else if (modename.equals_cs("redirect")) 522 cm = new ChannelModeRedirect(modechar[0]); 523 else if (modename.equals_cs("reginvite")) 524 cm = new ChannelMode("REGISTEREDONLY", modechar[0]); 525 else if (modename.equals_cs("regmoderated")) 526 cm = new ChannelMode("REGMODERATED", modechar[0]); 527 else if (modename.equals_cs("secret")) 528 cm = new ChannelMode("SECRET", modechar[0]); 529 else if (modename.equals_cs("sslonly")) 530 { 531 cm = new ChannelMode("SSL", modechar[0]); 532 ModeManager::AddChannelMode(new InspIRCdExtban::FingerprintMatcher("SSLBAN", "BAN", 'z')); 533 } 534 else if (modename.equals_cs("stripcolor")) 535 { 536 cm = new ChannelMode("STRIPCOLOR", modechar[0]); 537 ModeManager::AddChannelMode(new InspIRCdExtban::EntryMatcher("STRIPCOLORBAN", "BAN", 'S')); 538 } 539 else if (modename.equals_cs("topiclock")) 540 cm = new ChannelMode("TOPIC", modechar[0]); 541 else if (modename.equals_cs("voice")) 542 cm = new ChannelModeStatus("VOICE", modechar.length() > 1 ? modechar[1] : modechar[0], modechar.length() > 1 ? modechar[0] : 0, 0); 543 /* Unknown status mode, (customprefix) - add it */ 544 else if (modechar.length() == 2) 545 cm = new ChannelModeStatus(modename.upper(), modechar[1], modechar[0], -1); 546 /* Unknown non status mode, add it to our list for later */ 547 else 548 chmodes[modechar[0]] = modename.upper(); 549 550 if (cm) 551 ModeManager::AddChannelMode(cm); 552 } 553 } 554 if (params[0].equals_cs("USERMODES") && params.size() > 1) 555 { 556 spacesepstream ssep(params[1]); 557 Anope::string capab; 558 559 while (ssep.GetToken(capab)) 560 { 561 Anope::string modename = capab.substr(0, capab.find('=')); 562 Anope::string modechar = capab.substr(capab.find('=') + 1); 563 UserMode *um = NULL; 564 565 if (modename.equals_cs("bot")) 566 { 567 um = new UserMode("BOT", modechar[0]); 568 IRCD->DefaultPseudoclientModes += modechar; 569 } 570 else if (modename.equals_cs("callerid")) 571 um = new UserMode("CALLERID", modechar[0]); 572 else if (modename.equals_cs("cloak")) 573 um = new UserMode("CLOAK", modechar[0]); 574 else if (modename.equals_cs("deaf")) 575 um = new UserMode("DEAF", modechar[0]); 576 else if (modename.equals_cs("deaf_commonchan")) 577 um = new UserMode("COMMONCHANS", modechar[0]); 578 else if (modename.equals_cs("helpop")) 579 um = new UserModeOperOnly("HELPOP", modechar[0]); 580 else if (modename.equals_cs("hidechans")) 581 um = new UserMode("PRIV", modechar[0]); 582 else if (modename.equals_cs("hideoper")) 583 um = new UserModeOperOnly("HIDEOPER", modechar[0]); 584 else if (modename.equals_cs("invisible")) 585 um = new UserMode("INVIS", modechar[0]); 586 else if (modename.equals_cs("invis-oper")) 587 um = new UserModeOperOnly("INVISIBLE_OPER", modechar[0]); 588 else if (modename.equals_cs("oper")) 589 um = new UserModeOperOnly("OPER", modechar[0]); 590 else if (modename.equals_cs("regdeaf")) 591 um = new UserMode("REGPRIV", modechar[0]); 592 else if (modename.equals_cs("servprotect")) 593 { 594 um = new UserModeNoone("PROTECTED", modechar[0]); 595 IRCD->DefaultPseudoclientModes += modechar; 596 } 597 else if (modename.equals_cs("showwhois")) 598 um = new UserMode("WHOIS", modechar[0]); 599 else if (modename.equals_cs("u_censor")) 600 um = new UserMode("CENSOR", modechar[0]); 601 else if (modename.equals_cs("u_registered")) 602 um = new UserModeNoone("REGISTERED", modechar[0]); 603 else if (modename.equals_cs("u_stripcolor")) 604 um = new UserMode("STRIPCOLOR", modechar[0]); 605 else if (modename.equals_cs("wallops")) 606 um = new UserMode("WALLOPS", modechar[0]); 607 else 608 umodes[modechar[0]] = modename.upper(); 609 610 if (um) 611 ModeManager::AddUserMode(um); 612 } 613 } 614 else if (params[0].equals_cs("MODULES") && params.size() > 1) 615 { 616 spacesepstream ssep(params[1]); 617 Anope::string module; 618 619 while (ssep.GetToken(module)) 620 { 621 if (module.equals_cs("m_svshold.so")) 622 IRCD->CanSVSHold = true; 623 else if (module.find("m_rline.so") == 0) 624 { 625 Servers::Capab.insert("RLINE"); 626 const Anope::string ®exengine = Config->GetBlock("options")->Get<const Anope::string>("regexengine"); 627 if (!regexengine.empty() && module.length() > 11 && regexengine != module.substr(11)) 628 Log() << "Warning: InspIRCd is using regex engine " << module.substr(11) << ", but we have " << regexengine << ". This may cause inconsistencies."; 629 } 630 else if (module.equals_cs("m_topiclock.so")) 631 Servers::Capab.insert("TOPICLOCK"); 632 } 633 } 634 else if (params[0].equals_cs("MODSUPPORT") && params.size() > 1) 635 { 636 spacesepstream ssep(params[1]); 637 Anope::string module; 638 639 while (ssep.GetToken(module)) 640 { 641 if (module.equals_cs("m_services_account.so")) 642 { 643 Servers::Capab.insert("SERVICES"); 644 ModeManager::AddChannelMode(new InspIRCdExtban::AccountMatcher("ACCOUNTBAN", "BAN", 'R')); 645 ModeManager::AddChannelMode(new InspIRCdExtban::UnidentifiedMatcher("UNREGISTEREDBAN", "BAN", 'U')); 646 } 647 else if (module.equals_cs("m_chghost.so")) 648 Servers::Capab.insert("CHGHOST"); 649 else if (module.equals_cs("m_chgident.so")) 650 Servers::Capab.insert("CHGIDENT"); 651 else if (module == "m_channelban.so") 652 ModeManager::AddChannelMode(new InspIRCdExtban::ChannelMatcher("CHANNELBAN", "BAN", 'j')); 653 else if (module == "m_gecosban.so") 654 ModeManager::AddChannelMode(new InspIRCdExtban::RealnameMatcher("REALNAMEBAN", "BAN", 'r')); 655 else if (module == "m_nopartmessage.so") 656 ModeManager::AddChannelMode(new InspIRCdExtban::EntryMatcher("PARTMESSAGEBAN", "BAN", 'p')); 657 else if (module == "m_serverban.so") 658 ModeManager::AddChannelMode(new InspIRCdExtban::ServerMatcher("SERVERBAN", "BAN", 's')); 659 else if (module == "m_muteban.so") 660 ModeManager::AddChannelMode(new InspIRCdExtban::EntryMatcher("QUIET", "BAN", 'm')); 661 } 662 } 663 else if (params[0].equals_cs("CAPABILITIES") && params.size() > 1) 664 { 665 spacesepstream ssep(params[1]); 666 Anope::string capab; 667 while (ssep.GetToken(capab)) 668 { 669 if (capab.find("CHANMODES") != Anope::string::npos) 670 { 671 Anope::string modes(capab.begin() + 10, capab.end()); 672 commasepstream sep(modes, true); 673 Anope::string modebuf; 674 675 sep.GetToken(modebuf); 676 for (size_t t = 0, end = modebuf.length(); t < end; ++t) 677 { 678 if (ModeManager::FindChannelModeByChar(modebuf[t])) 679 continue; 680 ModeManager::AddChannelMode(new ChannelModeList(chmodes[modebuf[t]], modebuf[t])); 681 } 682 683 sep.GetToken(modebuf); 684 for (size_t t = 0, end = modebuf.length(); t < end; ++t) 685 { 686 if (ModeManager::FindChannelModeByChar(modebuf[t])) 687 continue; 688 ModeManager::AddChannelMode(new ChannelModeParam(chmodes[modebuf[t]], modebuf[t])); 689 } 690 691 sep.GetToken(modebuf); 692 for (size_t t = 0, end = modebuf.length(); t < end; ++t) 693 { 694 if (ModeManager::FindChannelModeByChar(modebuf[t])) 695 continue; 696 ModeManager::AddChannelMode(new ChannelModeParam(chmodes[modebuf[t]], modebuf[t], true)); 697 } 698 699 sep.GetToken(modebuf); 700 for (size_t t = 0, end = modebuf.length(); t < end; ++t) 701 { 702 if (ModeManager::FindChannelModeByChar(modebuf[t])) 703 continue; 704 ModeManager::AddChannelMode(new ChannelMode(chmodes[modebuf[t]], modebuf[t])); 705 } 706 } 707 else if (capab.find("USERMODES") != Anope::string::npos) 708 { 709 Anope::string modes(capab.begin() + 10, capab.end()); 710 commasepstream sep(modes, true); 711 Anope::string modebuf; 712 713 sep.GetToken(modebuf); 714 sep.GetToken(modebuf); 715 716 if (sep.GetToken(modebuf)) 717 for (size_t t = 0, end = modebuf.length(); t < end; ++t) 718 ModeManager::AddUserMode(new UserModeParam(umodes[modebuf[t]], modebuf[t])); 719 720 if (sep.GetToken(modebuf)) 721 for (size_t t = 0, end = modebuf.length(); t < end; ++t) 722 ModeManager::AddUserMode(new UserMode(umodes[modebuf[t]], modebuf[t])); 723 } 724 else if (capab.find("MAXMODES=") != Anope::string::npos) 725 { 726 Anope::string maxmodes(capab.begin() + 9, capab.end()); 727 IRCD->MaxModes = maxmodes.is_pos_number_only() ? convertTo<unsigned>(maxmodes) : 3; 728 } 729 else if (capab.find("PREFIX=") != Anope::string::npos) 730 { 731 Anope::string modes(capab.begin() + 8, capab.begin() + capab.find(')')); 732 Anope::string chars(capab.begin() + capab.find(')') + 1, capab.end()); 733 short level = modes.length() - 1; 734 735 for (size_t t = 0, end = modes.length(); t < end; ++t) 736 { 737 ChannelMode *cm = ModeManager::FindChannelModeByChar(modes[t]); 738 if (cm == NULL || cm->type != MODE_STATUS) 739 { 740 Log() << "CAPAB PREFIX gave unknown channel status mode " << modes[t]; 741 continue; 742 } 743 744 ChannelModeStatus *cms = anope_dynamic_static_cast<ChannelModeStatus *>(cm); 745 cms->level = level--; 746 747 Log(LOG_DEBUG) << cms->name << " is now level " << cms->level; 748 } 749 750 ModeManager::RebuildStatusModes(); 751 } 752 else if (capab == "GLOBOPS=1") 753 Servers::Capab.insert("GLOBOPS"); 754 } 755 } 756 else if (params[0].equals_cs("END")) 757 { 758 if (!Servers::Capab.count("SERVICES")) 759 { 760 UplinkSocket::Message() << "ERROR :m_services_account.so is not loaded. This is required by Anope"; 761 Anope::QuitReason = "ERROR: Remote server does not have the m_services_account module loaded, and this is required."; 762 Anope::Quitting = true; 763 return; 764 } 765 if (!ModeManager::FindUserModeByName("PRIV")) 766 { 767 UplinkSocket::Message() << "ERROR :m_hidechans.so is not loaded. This is required by Anope"; 768 Anope::QuitReason = "ERROR: Remote server does not have the m_hidechans module loaded, and this is required."; 769 Anope::Quitting = true; 770 return; 771 } 772 if (!IRCD->CanSVSHold) 773 Log() << "SVSHOLD missing, Usage disabled until module is loaded."; 774 if (!Servers::Capab.count("CHGHOST")) 775 Log() << "CHGHOST missing, Usage disabled until module is loaded."; 776 if (!Servers::Capab.count("CHGIDENT")) 777 Log() << "CHGIDENT missing, Usage disabled until module is loaded."; 778 779 chmodes.clear(); 780 umodes.clear(); 781 } 782 783 Message::Capab::Run(source, params); 784 } 785 }; 786 787 struct IRCDMessageEncap : IRCDMessage 788 { 789 ServiceReference<IRCDMessage> insp12_encap; 790 791 IRCDMessageEncap(Module *creator) : IRCDMessage(creator, "ENCAP", 4), insp12_encap("IRCDMessage", "inspircd12/encap") { SetFlag(IRCDMESSAGE_SOFT_LIMIT); } 792 793 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 794 { 795 if (!Anope::Match(Me->GetSID(), params[0]) && !Anope::Match(Me->GetName(), params[0])) 796 return; 797 798 if (params[1] == "CHGIDENT") 799 { 800 User *u = User::Find(params[2]); 801 if (!u || u->server != Me) 802 return; 803 804 u->SetIdent(params[3]); 805 UplinkSocket::Message(u) << "FIDENT :" << params[3]; 806 } 807 else if (params[1] == "CHGHOST") 808 { 809 User *u = User::Find(params[2]); 810 if (!u || u->server != Me) 811 return; 812 813 u->SetDisplayedHost(params[3]); 814 UplinkSocket::Message(u) << "FHOST :" << params[3]; 815 } 816 else if (params[1] == "CHGNAME") 817 { 818 User *u = User::Find(params[2]); 819 if (!u || u->server != Me) 820 return; 821 822 u->SetRealname(params[3]); 823 UplinkSocket::Message(u) << "FNAME :" << params[3]; 824 } 825 826 if (insp12_encap) 827 insp12_encap->Run(source, params); 828 } 829 }; 830 831 struct IRCDMessageFHost : IRCDMessage 832 { 833 IRCDMessageFHost(Module *creator) : IRCDMessage(creator, "FHOST", 1) { SetFlag(IRCDMESSAGE_REQUIRE_USER); } 834 835 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 836 { 837 User *u = source.GetUser(); 838 if (u->HasMode("CLOAK")) 839 u->RemoveModeInternal(source, ModeManager::FindUserModeByName("CLOAK")); 840 u->SetDisplayedHost(params[0]); 841 } 842 }; 843 844 struct IRCDMessageFIdent : IRCDMessage 845 { 846 IRCDMessageFIdent(Module *creator) : IRCDMessage(creator, "FIDENT", 1) { SetFlag(IRCDMESSAGE_REQUIRE_USER); } 847 848 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 849 { 850 source.GetUser()->SetIdent(params[0]); 851 } 852 }; 853 854 struct IRCDMessageSave : IRCDMessage 855 { 856 time_t last_collide; 857 858 IRCDMessageSave(Module *creator) : IRCDMessage(creator, "SAVE", 2), last_collide(0) { } 859 860 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 861 { 862 User *targ = User::Find(params[0]); 863 time_t ts; 864 865 try 866 { 867 ts = convertTo<time_t>(params[1]); 868 } 869 catch (const ConvertException &) 870 { 871 return; 872 } 873 874 if (!targ || targ->timestamp != ts) 875 return; 876 877 BotInfo *bi; 878 if (targ->server == Me && (bi = dynamic_cast<BotInfo *>(targ))) 879 { 880 if (last_collide == Anope::CurTime) 881 { 882 Anope::QuitReason = "Nick collision fight on " + targ->nick; 883 Anope::Quitting = true; 884 return; 885 } 886 887 IRCD->SendKill(Me, targ->nick, "Nick collision"); 888 IRCD->SendNickChange(targ, targ->nick); 889 last_collide = Anope::CurTime; 890 } 891 else 892 targ->ChangeNick(targ->GetUID()); 893 } 894 }; 895 896 class IRCDMessageMetadata : IRCDMessage 897 { 898 ServiceReference<IRCDMessage> insp12_metadata; 899 const bool &do_topiclock; 900 const bool &do_mlock; 901 902 public: 903 IRCDMessageMetadata(Module *creator, const bool &handle_topiclock, const bool &handle_mlock) : IRCDMessage(creator, "METADATA", 3), insp12_metadata("IRCDMessage", "inspircd12/metadata"), do_topiclock(handle_topiclock), do_mlock(handle_mlock) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); } 904 905 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 906 { 907 // We deliberately ignore non-bursting servers to avoid pseudoserver fights 908 if ((params[0][0] == '#') && (!source.GetServer()->IsSynced())) 909 { 910 Channel *c = Channel::Find(params[0]); 911 if (c && c->ci) 912 { 913 if ((do_mlock) && (params[1] == "mlock")) 914 { 915 ModeLocks *modelocks = c->ci->GetExt<ModeLocks>("modelocks"); 916 Anope::string modes; 917 if (modelocks) 918 modes = modelocks->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", ""); 919 920 // Mode lock string is not what we say it is? 921 if (modes != params[2]) 922 UplinkSocket::Message(Me) << "METADATA " << c->name << " mlock :" << modes; 923 } 924 else if ((do_topiclock) && (params[1] == "topiclock")) 925 { 926 bool mystate = c->ci->HasExt("TOPICLOCK"); 927 bool serverstate = (params[2] == "1"); 928 if (mystate != serverstate) 929 UplinkSocket::Message(Me) << "METADATA " << c->name << " topiclock :" << (mystate ? "1" : ""); 930 } 931 } 932 } 933 934 if (insp12_metadata) 935 insp12_metadata->Run(source, params); 936 } 937 }; 938 939 class ProtoInspIRCd20 : public Module 940 { 941 Module *m_insp12; 942 943 InspIRCd20Proto ircd_proto; 944 945 /* Core message handlers */ 946 Message::Error message_error; 947 Message::Invite message_invite; 948 Message::Join message_join; 949 Message::Kick message_kick; 950 Message::Kill message_kill; 951 Message::MOTD message_motd; 952 Message::Notice message_notice; 953 Message::Part message_part; 954 Message::Ping message_ping; 955 Message::Privmsg message_privmsg; 956 Message::Quit message_quit; 957 Message::Stats message_stats; 958 Message::Topic message_topic; 959 960 /* InspIRCd 1.2 message handlers */ 961 ServiceAlias message_endburst, message_fjoin, message_fmode, 962 message_ftopic, message_idle, message_mode, 963 message_nick, message_opertype, message_rsquit, message_server, 964 message_squit, message_time, message_uid; 965 966 /* Our message handlers */ 967 IRCDMessageAway message_away; 968 IRCDMessageCapab message_capab; 969 IRCDMessageEncap message_encap; 970 IRCDMessageFHost message_fhost; 971 IRCDMessageFIdent message_fident; 972 IRCDMessageMetadata message_metadata; 973 IRCDMessageSave message_save; 974 975 bool use_server_side_topiclock, use_server_side_mlock; 976 977 void SendChannelMetadata(Channel *c, const Anope::string &metadataname, const Anope::string &value) 978 { 979 UplinkSocket::Message(Me) << "METADATA " << c->name << " " << metadataname << " :" << value; 980 } 981 982 public: 983 ProtoInspIRCd20(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, PROTOCOL | VENDOR), 984 ircd_proto(this), 985 message_error(this), message_invite(this), message_join(this), message_kick(this), message_kill(this), 986 message_motd(this), message_notice(this), message_part(this), message_ping(this), message_privmsg(this), 987 message_quit(this), message_stats(this), message_topic(this), 988 989 message_endburst("IRCDMessage", "inspircd20/endburst", "inspircd12/endburst"), 990 message_fjoin("IRCDMessage", "inspircd20/fjoin", "inspircd12/fjoin"), 991 message_fmode("IRCDMessage", "inspircd20/fmode", "inspircd12/fmode"), 992 message_ftopic("IRCDMessage", "inspircd20/ftopic", "inspircd12/ftopic"), 993 message_idle("IRCDMessage", "inspircd20/idle", "inspircd12/idle"), 994 message_mode("IRCDMessage", "inspircd20/mode", "inspircd12/mode"), 995 message_nick("IRCDMessage", "inspircd20/nick", "inspircd12/nick"), 996 message_opertype("IRCDMessage", "inspircd20/opertype", "inspircd12/opertype"), 997 message_rsquit("IRCDMessage", "inspircd20/rsquit", "inspircd12/rsquit"), 998 message_server("IRCDMessage", "inspircd20/server", "inspircd12/server"), 999 message_squit("IRCDMessage", "inspircd20/squit", "inspircd12/squit"), 1000 message_time("IRCDMessage", "inspircd20/time", "inspircd12/time"), 1001 message_uid("IRCDMessage", "inspircd20/uid", "inspircd12/uid"), 1002 1003 message_away(this), message_capab(this), message_encap(this), message_fhost(this), message_fident(this), 1004 message_metadata(this, use_server_side_topiclock, use_server_side_mlock), message_save(this) 1005 { 1006 1007 if (ModuleManager::LoadModule("inspircd12", User::Find(creator)) != MOD_ERR_OK) 1008 throw ModuleException("Unable to load inspircd12"); 1009 m_insp12 = ModuleManager::FindModule("inspircd12"); 1010 if (!m_insp12) 1011 throw ModuleException("Unable to find inspircd12"); 1012 if (!insp12) 1013 throw ModuleException("No protocol interface for insp12"); 1014 ModuleManager::DetachAll(m_insp12); 1015 1016 } 1017 1018 ~ProtoInspIRCd20() 1019 { 1020 m_insp12 = ModuleManager::FindModule("inspircd12"); 1021 ModuleManager::UnloadModule(m_insp12, NULL); 1022 } 1023 1024 void OnReload(Configuration::Conf *conf) anope_override 1025 { 1026 use_server_side_topiclock = conf->GetModule(this)->Get<bool>("use_server_side_topiclock"); 1027 use_server_side_mlock = conf->GetModule(this)->Get<bool>("use_server_side_mlock"); 1028 } 1029 1030 void OnUserNickChange(User *u, const Anope::string &) anope_override 1031 { 1032 u->RemoveModeInternal(Me, ModeManager::FindUserModeByName("REGISTERED")); 1033 } 1034 1035 void OnChannelSync(Channel *c) anope_override 1036 { 1037 if (c->ci) 1038 this->OnChanRegistered(c->ci); 1039 } 1040 1041 void OnChanRegistered(ChannelInfo *ci) anope_override 1042 { 1043 ModeLocks *modelocks = ci->GetExt<ModeLocks>("modelocks"); 1044 if (use_server_side_mlock && ci->c && modelocks && !modelocks->GetMLockAsString(false).empty()) 1045 { 1046 Anope::string modes = modelocks->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", ""); 1047 SendChannelMetadata(ci->c, "mlock", modes); 1048 } 1049 1050 if (use_server_side_topiclock && Servers::Capab.count("TOPICLOCK") && ci->c) 1051 { 1052 if (ci->HasExt("TOPICLOCK")) 1053 SendChannelMetadata(ci->c, "topiclock", "1"); 1054 } 1055 } 1056 1057 void OnDelChan(ChannelInfo *ci) anope_override 1058 { 1059 if (use_server_side_mlock && ci->c) 1060 SendChannelMetadata(ci->c, "mlock", ""); 1061 1062 if (use_server_side_topiclock && Servers::Capab.count("TOPICLOCK") && ci->c) 1063 SendChannelMetadata(ci->c, "topiclock", ""); 1064 } 1065 1066 EventReturn OnMLock(ChannelInfo *ci, ModeLock *lock) anope_override 1067 { 1068 ModeLocks *modelocks = ci->GetExt<ModeLocks>("modelocks"); 1069 ChannelMode *cm = ModeManager::FindChannelModeByName(lock->name); 1070 if (use_server_side_mlock && cm && ci->c && modelocks && (cm->type == MODE_REGULAR || cm->type == MODE_PARAM)) 1071 { 1072 Anope::string modes = modelocks->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", "") + cm->mchar; 1073 SendChannelMetadata(ci->c, "mlock", modes); 1074 } 1075 1076 return EVENT_CONTINUE; 1077 } 1078 1079 EventReturn OnUnMLock(ChannelInfo *ci, ModeLock *lock) anope_override 1080 { 1081 ModeLocks *modelocks = ci->GetExt<ModeLocks>("modelocks"); 1082 ChannelMode *cm = ModeManager::FindChannelModeByName(lock->name); 1083 if (use_server_side_mlock && cm && ci->c && modelocks && (cm->type == MODE_REGULAR || cm->type == MODE_PARAM)) 1084 { 1085 Anope::string modes = modelocks->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", "").replace_all_cs(cm->mchar, ""); 1086 SendChannelMetadata(ci->c, "mlock", modes); 1087 } 1088 1089 return EVENT_CONTINUE; 1090 } 1091 1092 EventReturn OnSetChannelOption(CommandSource &source, Command *cmd, ChannelInfo *ci, const Anope::string &setting) anope_override 1093 { 1094 if (cmd->name == "chanserv/topic" && ci->c) 1095 { 1096 if (setting == "topiclock on") 1097 SendChannelMetadata(ci->c, "topiclock", "1"); 1098 else if (setting == "topiclock off") 1099 SendChannelMetadata(ci->c, "topiclock", "0"); 1100 } 1101 1102 return EVENT_CONTINUE; 1103 } 1104 }; 1105 1106 MODULE_INIT(ProtoInspIRCd20)