anope- supernets anope source code & configuration |
git clone git://git.acid.vegas/anope.git |
Log | Files | Refs | Archive | README |
unreal.cpp (41304B)
1 /* Unreal IRCD 3.2.x 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 #include "modules/sasl.h" 15 16 class UnrealIRCdProto : public IRCDProto 17 { 18 public: 19 UnrealIRCdProto(Module *creator) : IRCDProto(creator, "UnrealIRCd 3.2.x") 20 { 21 DefaultPseudoclientModes = "+Soiq"; 22 CanSVSNick = true; 23 CanSVSJoin = true; 24 CanSetVHost = true; 25 CanSetVIdent = true; 26 CanSNLine = true; 27 CanSQLine = true; 28 CanSZLine = true; 29 CanSVSHold = true; 30 CanSVSO = true; 31 MaxModes = 12; 32 } 33 34 private: 35 /* SVSNOOP */ 36 void SendSVSNOOP(const Server *server, bool set) anope_override 37 { 38 UplinkSocket::Message() << "SVSNOOP " << server->GetName() << " " << (set ? "+" : "-"); 39 } 40 41 void SendAkillDel(const XLine *x) anope_override 42 { 43 if (x->IsRegex() || x->HasNickOrReal()) 44 return; 45 46 /* ZLine if we can instead */ 47 if (x->GetUser() == "*") 48 { 49 cidr a(x->GetHost()); 50 if (a.valid()) 51 { 52 IRCD->SendSZLineDel(x); 53 return; 54 } 55 } 56 57 UplinkSocket::Message() << "TKL - G " << x->GetUser() << " " << x->GetHost() << " " << x->by; 58 } 59 60 void SendTopic(const MessageSource &source, Channel *c) anope_override 61 { 62 UplinkSocket::Message(source) << "TOPIC " << c->name << " " << c->topic_setter << " " << c->topic_ts << " :" << c->topic; 63 } 64 65 void SendGlobalNotice(BotInfo *bi, const Server *dest, const Anope::string &msg) anope_override 66 { 67 UplinkSocket::Message(bi) << "NOTICE $" << dest->GetName() << " :" << msg; 68 } 69 70 void SendGlobalPrivmsg(BotInfo *bi, const Server *dest, const Anope::string &msg) anope_override 71 { 72 UplinkSocket::Message(bi) << "PRIVMSG $" << dest->GetName() << " :" << msg; 73 } 74 75 void SendVhostDel(User *u) anope_override 76 { 77 BotInfo *HostServ = Config->GetClient("HostServ"); 78 u->RemoveMode(HostServ, "CLOAK"); 79 u->RemoveMode(HostServ, "VHOST"); 80 ModeManager::ProcessModes(); 81 u->SetMode(HostServ, "CLOAK"); 82 } 83 84 void SendAkill(User *u, XLine *x) anope_override 85 { 86 if (x->IsRegex() || x->HasNickOrReal()) 87 { 88 if (!u) 89 { 90 /* No user (this akill was just added), and contains nick and/or realname. Find users that match and ban them */ 91 for (user_map::const_iterator it = UserListByNick.begin(); it != UserListByNick.end(); ++it) 92 if (x->manager->Check(it->second, x)) 93 this->SendAkill(it->second, x); 94 return; 95 } 96 97 const XLine *old = x; 98 99 if (old->manager->HasEntry("*@" + u->host)) 100 return; 101 102 /* We can't akill x as it has a nick and/or realname included, so create a new akill for *@host */ 103 XLine *xline = new XLine("*@" + u->host, old->by, old->expires, old->reason, old->id); 104 old->manager->AddXLine(xline); 105 x = xline; 106 107 Log(Config->GetClient("OperServ"), "akill") << "AKILL: Added an akill for " << x->mask << " because " << u->GetMask() << "#" << u->realname << " matches " << old->mask; 108 } 109 110 /* ZLine if we can instead */ 111 if (x->GetUser() == "*") 112 { 113 cidr a(x->GetHost()); 114 if (a.valid()) 115 { 116 IRCD->SendSZLine(u, x); 117 return; 118 } 119 } 120 121 // Calculate the time left before this would expire, capping it at 2 days 122 time_t timeleft = x->expires - Anope::CurTime; 123 if (timeleft > 172800 || !x->expires) 124 timeleft = 172800; 125 UplinkSocket::Message() << "TKL + G " << x->GetUser() << " " << x->GetHost() << " " << x->by << " " << Anope::CurTime + timeleft << " " << x->created << " :" << x->GetReason(); 126 } 127 128 void SendSVSKillInternal(const MessageSource &source, User *user, const Anope::string &buf) anope_override 129 { 130 UplinkSocket::Message(source) << "SVSKILL " << user->nick << " :" << buf; 131 user->KillInternal(source, buf); 132 } 133 134 void SendModeInternal(const MessageSource &source, User *u, const Anope::string &buf) anope_override 135 { 136 UplinkSocket::Message(source) << "SVS2MODE " << u->nick <<" " << buf; 137 } 138 139 void SendClientIntroduction(User *u) anope_override 140 { 141 Anope::string modes = "+" + u->GetModes(); 142 UplinkSocket::Message() << "NICK " << u->nick << " 1 " << u->timestamp << " " << u->GetIdent() << " " << u->host << " " << u->server->GetName() << " 0 " << modes << " " << u->host << " * :" << u->realname; 143 } 144 145 /* SERVER name hop descript */ 146 /* Unreal 3.2 actually sends some info about itself in the descript area */ 147 void SendServer(const Server *server) anope_override 148 { 149 if (!server->GetSID().empty() && server == Me) 150 UplinkSocket::Message() << "SERVER " << server->GetName() << " " << server->GetHops() << " :U0-*-" << server->GetSID() << " " << server->GetDescription(); 151 else 152 UplinkSocket::Message() << "SERVER " << server->GetName() << " " << server->GetHops() << " :" << server->GetDescription(); 153 } 154 155 /* JOIN */ 156 void SendJoin(User *user, Channel *c, const ChannelStatus *status) anope_override 157 { 158 UplinkSocket::Message(Me) << "SJOIN " << c->creation_time << " " << c->name << " :" << user->nick; 159 if (status) 160 { 161 /* First save the channel status incase uc->Status == status */ 162 ChannelStatus cs = *status; 163 /* If the user is internally on the channel with flags, kill them so that 164 * the stacker will allow this. 165 */ 166 ChanUserContainer *uc = c->FindUser(user); 167 if (uc != NULL) 168 uc->status.Clear(); 169 170 BotInfo *setter = BotInfo::Find(user->GetUID()); 171 for (size_t i = 0; i < cs.Modes().length(); ++i) 172 c->SetMode(setter, ModeManager::FindChannelModeByChar(cs.Modes()[i]), user->GetUID(), false); 173 174 if (uc != NULL) 175 uc->status = cs; 176 } 177 } 178 179 /* unsqline 180 */ 181 void SendSQLineDel(const XLine *x) anope_override 182 { 183 UplinkSocket::Message() << "UNSQLINE " << x->mask; 184 } 185 186 /* SQLINE */ 187 /* 188 ** - Unreal will translate this to TKL for us 189 ** 190 */ 191 void SendSQLine(User *, const XLine *x) anope_override 192 { 193 UplinkSocket::Message() << "SQLINE " << x->mask << " :" << x->GetReason(); 194 } 195 196 /* 197 ** svso 198 ** parv[0] = sender prefix 199 ** parv[1] = nick 200 ** parv[2] = options 201 */ 202 void SendSVSO(BotInfo *source, const Anope::string &nick, const Anope::string &flag) anope_override 203 { 204 UplinkSocket::Message(source) << "SVSO " << nick << " " << flag; 205 } 206 207 /* Functions that use serval cmd functions */ 208 209 void SendVhost(User *u, const Anope::string &vIdent, const Anope::string &vhost) anope_override 210 { 211 if (!vIdent.empty()) 212 UplinkSocket::Message(Me) << "CHGIDENT " << u->nick << " " << vIdent; 213 if (!vhost.empty()) 214 UplinkSocket::Message(Me) << "CHGHOST " << u->nick << " " << vhost; 215 } 216 217 void SendConnect() anope_override 218 { 219 /* 220 NICKv2 = Nick Version 2 221 VHP = Sends hidden host 222 UMODE2 = sends UMODE2 on user modes 223 NICKIP = Sends IP on NICK 224 TOKEN = Use tokens to talk 225 SJ3 = Supports SJOIN 226 NOQUIT = No Quit 227 TKLEXT = Extended TKL we don't use it but best to have it 228 SJB64 = Base64 encoded time stamps 229 ESVID = Allows storing account names as services stamp 230 MLOCK = Supports the MLOCK server command 231 VL = Version Info 232 NS = Config->Numeric Server 233 */ 234 Anope::string protoctl = "NICKv2 VHP UMODE2 NICKIP SJOIN SJOIN2 SJ3 NOQUIT TKLEXT ESVID MLOCK VL"; 235 if (!Me->GetSID().empty()) 236 protoctl += " VL"; 237 UplinkSocket::Message() << "PROTOCTL " << protoctl; 238 UplinkSocket::Message() << "PASS :" << Config->Uplinks[Anope::CurrentUplink].password; 239 SendServer(Me); 240 } 241 242 /* SVSHOLD - set */ 243 void SendSVSHold(const Anope::string &nick, time_t t) anope_override 244 { 245 UplinkSocket::Message() << "TKL + Q H " << nick << " " << Me->GetName() << " " << Anope::CurTime + t << " " << Anope::CurTime << " :Being held for registered user"; 246 } 247 248 /* SVSHOLD - release */ 249 void SendSVSHoldDel(const Anope::string &nick) anope_override 250 { 251 UplinkSocket::Message() << "TKL - Q * " << nick << " " << Me->GetName(); 252 } 253 254 /* UNSGLINE */ 255 /* 256 * SVSNLINE - :realname mask 257 */ 258 void SendSGLineDel(const XLine *x) anope_override 259 { 260 UplinkSocket::Message() << "SVSNLINE - :" << x->mask; 261 } 262 263 /* UNSZLINE */ 264 void SendSZLineDel(const XLine *x) anope_override 265 { 266 UplinkSocket::Message() << "TKL - Z * " << x->GetHost() << " " << x->by; 267 } 268 269 /* SZLINE */ 270 void SendSZLine(User *, const XLine *x) anope_override 271 { 272 // Calculate the time left before this would expire, capping it at 2 days 273 time_t timeleft = x->expires - Anope::CurTime; 274 if (timeleft > 172800 || !x->expires) 275 timeleft = 172800; 276 UplinkSocket::Message() << "TKL + Z * " << x->GetHost() << " " << x->by << " " << Anope::CurTime + timeleft << " " << x->created << " :" << x->GetReason(); 277 } 278 279 /* SGLINE */ 280 /* 281 * SVSNLINE + reason_where_is_space :realname mask with spaces 282 */ 283 void SendSGLine(User *, const XLine *x) anope_override 284 { 285 Anope::string edited_reason = x->GetReason(); 286 edited_reason = edited_reason.replace_all_cs(" ", "_"); 287 UplinkSocket::Message() << "SVSNLINE + " << edited_reason << " :" << x->mask; 288 } 289 290 /* svsjoin 291 parv[0] - sender 292 parv[1] - nick to make join 293 parv[2] - channel to join 294 parv[3] - (optional) channel key(s) 295 */ 296 /* In older Unreal SVSJOIN and SVSNLINE tokens were mixed so SVSJOIN and SVSNLINE are broken 297 when coming from a none TOKEN'd server 298 */ 299 void SendSVSJoin(const MessageSource &source, User *user, const Anope::string &chan, const Anope::string ¶m) anope_override 300 { 301 if (!param.empty()) 302 UplinkSocket::Message(source) << "SVSJOIN " << user->GetUID() << " " << chan << " :" << param; 303 else 304 UplinkSocket::Message(source) << "SVSJOIN " << user->GetUID() << " " << chan; 305 } 306 307 void SendSVSPart(const MessageSource &source, User *user, const Anope::string &chan, const Anope::string ¶m) anope_override 308 { 309 if (!param.empty()) 310 UplinkSocket::Message(source) << "SVSPART " << user->GetUID() << " " << chan << " :" << param; 311 else 312 UplinkSocket::Message(source) << "SVSPART " << user->GetUID() << " " << chan; 313 } 314 315 void SendSWhois(const MessageSource &source, const Anope::string &who, const Anope::string &mask) anope_override 316 { 317 UplinkSocket::Message(source) << "SWHOIS " << who << " :" << mask; 318 } 319 320 void SendEOB() anope_override 321 { 322 UplinkSocket::Message(Me) << "EOS"; 323 } 324 325 bool IsNickValid(const Anope::string &nick) anope_override 326 { 327 if (nick.equals_ci("ircd") || nick.equals_ci("irc")) 328 return false; 329 330 return IRCDProto::IsNickValid(nick); 331 } 332 333 bool IsChannelValid(const Anope::string &chan) anope_override 334 { 335 if (chan.find(':') != Anope::string::npos) 336 return false; 337 338 return IRCDProto::IsChannelValid(chan); 339 } 340 341 bool IsExtbanValid(const Anope::string &mask) anope_override 342 { 343 return mask.length() >= 4 && mask[0] == '~' && mask[2] == ':'; 344 } 345 346 void SendLogin(User *u, NickAlias *na) anope_override 347 { 348 /* 3.2.10.4+ treats users logged in with accounts as fully registered, even if -r, so we can not set this here. Just use the timestamp. */ 349 if (Servers::Capab.count("ESVID") > 0 && !na->nc->HasExt("UNCONFIRMED")) 350 IRCD->SendMode(Config->GetClient("NickServ"), u, "+d %s", na->nc->display.c_str()); 351 else 352 IRCD->SendMode(Config->GetClient("NickServ"), u, "+d %d", u->signon); 353 } 354 355 void SendLogout(User *u) anope_override 356 { 357 IRCD->SendMode(Config->GetClient("NickServ"), u, "+d 0"); 358 } 359 360 void SendChannel(Channel *c) anope_override 361 { 362 /* Unreal does not support updating a channels TS without actually joining a user, 363 * so we will join and part us now 364 */ 365 BotInfo *bi = c->ci->WhoSends(); 366 if (!bi) 367 ; 368 else if (c->FindUser(bi) == NULL) 369 { 370 bi->Join(c); 371 bi->Part(c); 372 } 373 else 374 { 375 bi->Part(c); 376 bi->Join(c); 377 } 378 } 379 380 void SendSASLMessage(const SASL::Message &message) anope_override 381 { 382 size_t p = message.target.find('!'); 383 if (p == Anope::string::npos) 384 return; 385 386 UplinkSocket::Message(BotInfo::Find(message.source)) << "SASL " << message.target.substr(0, p) << " " << message.target << " " << message.type << " " << message.data << (message.ext.empty() ? "" : " " + message.ext); 387 } 388 389 void SendSVSLogin(const Anope::string &uid, const Anope::string &acc, const Anope::string &vident, const Anope::string &vhost) anope_override 390 { 391 size_t p = uid.find('!'); 392 if (p == Anope::string::npos) 393 return; 394 UplinkSocket::Message(Me) << "SVSLOGIN " << uid.substr(0, p) << " " << uid << " " << acc; 395 } 396 397 bool IsIdentValid(const Anope::string &ident) anope_override 398 { 399 if (ident.empty() || ident.length() > Config->GetBlock("networkinfo")->Get<unsigned>("userlen")) 400 return false; 401 402 for (unsigned i = 0; i < ident.length(); ++i) 403 { 404 const char &c = ident[i]; 405 406 if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '.' || c == '-') 407 continue; 408 409 if (c == '-' || c == '.' || c == '_') 410 continue; 411 412 return false; 413 } 414 415 return true; 416 } 417 }; 418 419 class UnrealExtBan : public ChannelModeVirtual<ChannelModeList> 420 { 421 char ext; 422 423 public: 424 UnrealExtBan(const Anope::string &mname, const Anope::string &basename, char extban) : ChannelModeVirtual<ChannelModeList>(mname, basename) 425 , ext(extban) 426 { 427 } 428 429 ChannelMode *Wrap(Anope::string ¶m) anope_override 430 { 431 param = "~" + Anope::string(ext) + ":" + param; 432 return ChannelModeVirtual<ChannelModeList>::Wrap(param); 433 } 434 435 ChannelMode *Unwrap(ChannelMode *cm, Anope::string ¶m) anope_override 436 { 437 if (cm->type != MODE_LIST || param.length() < 4 || param[0] != '~' || param[1] != ext || param[2] != ':') 438 return cm; 439 440 param = param.substr(3); 441 return this; 442 } 443 }; 444 445 namespace UnrealExtban 446 { 447 class ChannelMatcher : public UnrealExtBan 448 { 449 public: 450 ChannelMatcher(const Anope::string &mname, const Anope::string &mbase, char c) : UnrealExtBan(mname, mbase, c) 451 { 452 } 453 454 bool Matches(User *u, const Entry *e) anope_override 455 { 456 const Anope::string &mask = e->GetMask(); 457 Anope::string channel = mask.substr(3); 458 459 ChannelMode *cm = NULL; 460 if (channel[0] != '#') 461 { 462 char modeChar = ModeManager::GetStatusChar(channel[0]); 463 channel.erase(channel.begin()); 464 cm = ModeManager::FindChannelModeByChar(modeChar); 465 if (cm != NULL && cm->type != MODE_STATUS) 466 cm = NULL; 467 } 468 469 Channel *c = Channel::Find(channel); 470 if (c != NULL) 471 { 472 ChanUserContainer *uc = c->FindUser(u); 473 if (uc != NULL) 474 if (cm == NULL || uc->status.HasMode(cm->mchar)) 475 return true; 476 } 477 478 return false; 479 } 480 }; 481 482 class EntryMatcher : public UnrealExtBan 483 { 484 public: 485 EntryMatcher(const Anope::string &mname, const Anope::string &mbase, char c) : UnrealExtBan(mname, mbase, c) 486 { 487 } 488 489 bool Matches(User *u, const Entry *e) anope_override 490 { 491 const Anope::string &mask = e->GetMask(); 492 Anope::string real_mask = mask.substr(3); 493 494 return Entry(this->name, real_mask).Matches(u); 495 } 496 }; 497 498 class RealnameMatcher : public UnrealExtBan 499 { 500 public: 501 RealnameMatcher(const Anope::string &mname, const Anope::string &mbase, char c) : UnrealExtBan(mname, mbase, c) 502 { 503 } 504 505 bool Matches(User *u, const Entry *e) anope_override 506 { 507 const Anope::string &mask = e->GetMask(); 508 Anope::string real_mask = mask.substr(3); 509 510 return Anope::Match(u->realname, real_mask); 511 } 512 }; 513 514 class RegisteredMatcher : public UnrealExtBan 515 { 516 public: 517 RegisteredMatcher(const Anope::string &mname, const Anope::string &mbase, char c) : UnrealExtBan(mname, mbase, c) 518 { 519 } 520 521 bool Matches(User *u, const Entry *e) anope_override 522 { 523 const Anope::string &mask = e->GetMask(); 524 return u->HasMode("REGISTERED") && mask.equals_ci(u->nick); 525 } 526 }; 527 528 class AccountMatcher : public UnrealExtBan 529 { 530 public: 531 AccountMatcher(const Anope::string &mname, const Anope::string &mbase, char c) : UnrealExtBan(mname, mbase, c) 532 { 533 } 534 535 bool Matches(User *u, const Entry *e) anope_override 536 { 537 const Anope::string &mask = e->GetMask(); 538 Anope::string real_mask = mask.substr(3); 539 540 return u->Account() && Anope::Match(u->Account()->display, real_mask); 541 } 542 }; 543 } 544 545 class ChannelModeFlood : public ChannelModeParam 546 { 547 public: 548 ChannelModeFlood(char modeChar, bool minusNoArg) : ChannelModeParam("FLOOD", modeChar, minusNoArg) { } 549 550 /* Borrowed part of this check from UnrealIRCd */ 551 bool IsValid(Anope::string &value) const anope_override 552 { 553 if (value.empty()) 554 return false; 555 try 556 { 557 Anope::string rest; 558 if (value[0] != ':' && convertTo<unsigned>(value[0] == '*' ? value.substr(1) : value, rest, false) > 0 && rest[0] == ':' && rest.length() > 1 && convertTo<unsigned>(rest.substr(1), rest, false) > 0 && rest.empty()) 559 return true; 560 } 561 catch (const ConvertException &) { } 562 563 /* '['<number><1 letter>[optional: '#'+1 letter],[next..]']'':'<number> */ 564 size_t end_bracket = value.find(']', 1); 565 if (end_bracket == Anope::string::npos) 566 return false; 567 Anope::string xbuf = value.substr(0, end_bracket); 568 if (value[end_bracket + 1] != ':') 569 return false; 570 commasepstream args(xbuf.substr(1)); 571 Anope::string arg; 572 while (args.GetToken(arg)) 573 { 574 /* <number><1 letter>[optional: '#'+1 letter] */ 575 size_t p = 0; 576 while (p < arg.length() && isdigit(arg[p])) 577 ++p; 578 if (p == arg.length() || !(arg[p] == 'c' || arg[p] == 'j' || arg[p] == 'k' || arg[p] == 'm' || arg[p] == 'n' || arg[p] == 't')) 579 continue; /* continue instead of break for forward compatibility. */ 580 try 581 { 582 int v = arg.substr(0, p).is_number_only() ? convertTo<int>(arg.substr(0, p)) : 0; 583 if (v < 1 || v > 999) 584 return false; 585 } 586 catch (const ConvertException &) 587 { 588 return false; 589 } 590 } 591 592 return true; 593 } 594 }; 595 596 class ChannelModeUnrealSSL : public ChannelMode 597 { 598 public: 599 ChannelModeUnrealSSL(const Anope::string &n, char c) : ChannelMode(n, c) 600 { 601 } 602 603 bool CanSet(User *u) const anope_override 604 { 605 return false; 606 } 607 }; 608 609 struct IRCDMessageCapab : Message::Capab 610 { 611 IRCDMessageCapab(Module *creator) : Message::Capab(creator, "PROTOCTL") { } 612 613 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 614 { 615 for (unsigned i = 0; i < params.size(); ++i) 616 { 617 Anope::string capab = params[i]; 618 619 if (capab.find("CHANMODES") != Anope::string::npos) 620 { 621 Anope::string modes(capab.begin() + 10, capab.end()); 622 commasepstream sep(modes); 623 Anope::string modebuf; 624 625 sep.GetToken(modebuf); 626 for (size_t t = 0, end = modebuf.length(); t < end; ++t) 627 { 628 switch (modebuf[t]) 629 { 630 case 'b': 631 ModeManager::AddChannelMode(new ChannelModeList("BAN", 'b')); 632 633 ModeManager::AddChannelMode(new UnrealExtban::ChannelMatcher("CHANNELBAN", "BAN", 'c')); 634 ModeManager::AddChannelMode(new UnrealExtban::EntryMatcher("JOINBAN", "BAN", 'j')); 635 ModeManager::AddChannelMode(new UnrealExtban::EntryMatcher("NONICKBAN", "BAN", 'n')); 636 ModeManager::AddChannelMode(new UnrealExtban::EntryMatcher("QUIET", "BAN", 'q')); 637 ModeManager::AddChannelMode(new UnrealExtban::RealnameMatcher("REALNAMEBAN", "BAN", 'r')); 638 ModeManager::AddChannelMode(new UnrealExtban::RegisteredMatcher("REGISTEREDBAN", "BAN", 'R')); 639 ModeManager::AddChannelMode(new UnrealExtban::AccountMatcher("ACCOUNTBAN", "BAN", 'a')); 640 continue; 641 case 'e': 642 ModeManager::AddChannelMode(new ChannelModeList("EXCEPT", 'e')); 643 continue; 644 case 'I': 645 ModeManager::AddChannelMode(new ChannelModeList("INVITEOVERRIDE", 'I')); 646 continue; 647 default: 648 ModeManager::AddChannelMode(new ChannelModeList("", modebuf[t])); 649 } 650 } 651 652 sep.GetToken(modebuf); 653 for (size_t t = 0, end = modebuf.length(); t < end; ++t) 654 { 655 switch (modebuf[t]) 656 { 657 case 'k': 658 ModeManager::AddChannelMode(new ChannelModeKey('k')); 659 continue; 660 case 'f': 661 ModeManager::AddChannelMode(new ChannelModeFlood('f', false)); 662 continue; 663 case 'L': 664 ModeManager::AddChannelMode(new ChannelModeParam("REDIRECT", 'L')); 665 continue; 666 default: 667 ModeManager::AddChannelMode(new ChannelModeParam("", modebuf[t])); 668 } 669 } 670 671 sep.GetToken(modebuf); 672 for (size_t t = 0, end = modebuf.length(); t < end; ++t) 673 { 674 switch (modebuf[t]) 675 { 676 case 'l': 677 ModeManager::AddChannelMode(new ChannelModeParam("LIMIT", 'l', true)); 678 continue; 679 case 'j': 680 ModeManager::AddChannelMode(new ChannelModeParam("JOINFLOOD", 'j', true)); 681 continue; 682 default: 683 ModeManager::AddChannelMode(new ChannelModeParam("", modebuf[t], true)); 684 } 685 } 686 687 sep.GetToken(modebuf); 688 for (size_t t = 0, end = modebuf.length(); t < end; ++t) 689 { 690 switch (modebuf[t]) 691 { 692 case 'p': 693 ModeManager::AddChannelMode(new ChannelMode("PRIVATE", 'p')); 694 continue; 695 case 's': 696 ModeManager::AddChannelMode(new ChannelMode("SECRET", 's')); 697 continue; 698 case 'm': 699 ModeManager::AddChannelMode(new ChannelMode("MODERATED", 'm')); 700 continue; 701 case 'n': 702 ModeManager::AddChannelMode(new ChannelMode("NOEXTERNAL", 'n')); 703 continue; 704 case 't': 705 ModeManager::AddChannelMode(new ChannelMode("TOPIC", 't')); 706 continue; 707 case 'i': 708 ModeManager::AddChannelMode(new ChannelMode("INVITE", 'i')); 709 continue; 710 case 'r': 711 ModeManager::AddChannelMode(new ChannelModeNoone("REGISTERED", 'r')); 712 continue; 713 case 'R': 714 ModeManager::AddChannelMode(new ChannelMode("REGISTEREDONLY", 'R')); 715 continue; 716 case 'c': 717 ModeManager::AddChannelMode(new ChannelMode("BLOCKCOLOR", 'c')); 718 continue; 719 case 'O': 720 ModeManager::AddChannelMode(new ChannelModeOperOnly("OPERONLY", 'O')); 721 continue; 722 case 'A': 723 ModeManager::AddChannelMode(new ChannelModeOperOnly("ADMINONLY", 'A')); 724 continue; 725 case 'Q': 726 ModeManager::AddChannelMode(new ChannelMode("NOKICK", 'Q')); 727 continue; 728 case 'K': 729 ModeManager::AddChannelMode(new ChannelMode("NOKNOCK", 'K')); 730 continue; 731 case 'V': 732 ModeManager::AddChannelMode(new ChannelMode("NOINVITE", 'V')); 733 continue; 734 case 'C': 735 ModeManager::AddChannelMode(new ChannelMode("NOCTCP", 'C')); 736 continue; 737 case 'u': 738 ModeManager::AddChannelMode(new ChannelMode("AUDITORIUM", 'u')); 739 continue; 740 case 'z': 741 ModeManager::AddChannelMode(new ChannelMode("SSL", 'z')); 742 continue; 743 case 'N': 744 ModeManager::AddChannelMode(new ChannelMode("NONICK", 'N')); 745 continue; 746 case 'S': 747 ModeManager::AddChannelMode(new ChannelMode("STRIPCOLOR", 'S')); 748 continue; 749 case 'M': 750 ModeManager::AddChannelMode(new ChannelMode("REGMODERATED", 'M')); 751 continue; 752 case 'T': 753 ModeManager::AddChannelMode(new ChannelMode("NONOTICE", 'T')); 754 continue; 755 case 'G': 756 ModeManager::AddChannelMode(new ChannelMode("CENSOR", 'G')); 757 continue; 758 case 'Z': 759 ModeManager::AddChannelMode(new ChannelModeUnrealSSL("", 'Z')); 760 continue; 761 default: 762 ModeManager::AddChannelMode(new ChannelMode("", modebuf[t])); 763 } 764 } 765 } 766 } 767 768 Message::Capab::Run(source, params); 769 } 770 }; 771 772 struct IRCDMessageChgHost : IRCDMessage 773 { 774 IRCDMessageChgHost(Module *creator) : IRCDMessage(creator, "CHGHOST", 2) { } 775 776 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 777 { 778 User *u = User::Find(params[0]); 779 if (u) 780 u->SetDisplayedHost(params[1]); 781 } 782 }; 783 784 struct IRCDMessageChgIdent : IRCDMessage 785 { 786 IRCDMessageChgIdent(Module *creator) : IRCDMessage(creator, "CHGIDENT", 2) { } 787 788 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 789 { 790 User *u = User::Find(params[0]); 791 if (u) 792 u->SetVIdent(params[1]); 793 } 794 }; 795 796 struct IRCDMessageChgName : IRCDMessage 797 { 798 IRCDMessageChgName(Module *creator) : IRCDMessage(creator, "CHGNAME", 2) { } 799 800 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 801 { 802 User *u = User::Find(params[0]); 803 if (u) 804 u->SetRealname(params[1]); 805 } 806 }; 807 808 struct IRCDMessageMode : IRCDMessage 809 { 810 IRCDMessageMode(Module *creator, const Anope::string &mname) : IRCDMessage(creator, mname, 2) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); } 811 812 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 813 { 814 bool server_source = source.GetServer() != NULL; 815 Anope::string modes = params[1]; 816 for (unsigned i = 2; i < params.size() - (server_source ? 1 : 0); ++i) 817 modes += " " + params[i]; 818 819 if (IRCD->IsChannelValid(params[0])) 820 { 821 Channel *c = Channel::Find(params[0]); 822 time_t ts = 0; 823 824 try 825 { 826 if (server_source) 827 ts = convertTo<time_t>(params[params.size() - 1]); 828 } 829 catch (const ConvertException &) { } 830 831 if (c) 832 c->SetModesInternal(source, modes, ts); 833 } 834 else 835 { 836 User *u = User::Find(params[0]); 837 if (u) 838 u->SetModesInternal(source, "%s", params[1].c_str()); 839 } 840 } 841 }; 842 843 /* netinfo 844 * argv[0] = max global count 845 * argv[1] = time of end sync 846 * argv[2] = unreal protocol using (numeric) 847 * argv[3] = cloak-crc (> u2302) 848 * argv[4] = free(**) 849 * argv[5] = free(**) 850 * argv[6] = free(**) 851 * argv[7] = ircnet 852 */ 853 struct IRCDMessageNetInfo : IRCDMessage 854 { 855 IRCDMessageNetInfo(Module *creator) : IRCDMessage(creator, "NETINFO", 8) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); } 856 857 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 858 { 859 UplinkSocket::Message() << "NETINFO " << MaxUserCount << " " << Anope::CurTime << " " << convertTo<int>(params[2]) << " " << params[3] << " 0 0 0 :" << params[7]; 860 } 861 }; 862 863 struct IRCDMessageNick : IRCDMessage 864 { 865 IRCDMessageNick(Module *creator) : IRCDMessage(creator, "NICK", 2) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); } 866 867 /* 868 ** NICK - new 869 ** source = NULL 870 ** parv[0] = nickname 871 ** parv[1] = hopcount 872 ** parv[2] = timestamp 873 ** parv[3] = username 874 ** parv[4] = hostname 875 ** parv[5] = servername 876 ** parv[6] = servicestamp 877 ** parv[7] = umodes 878 ** parv[8] = virthost, * if none 879 ** parv[9] = ip 880 ** parv[10] = info 881 ** 882 ** NICK - change 883 ** source = oldnick 884 ** parv[0] = new nickname 885 ** parv[1] = hopcount 886 */ 887 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 888 { 889 if (params.size() == 11) 890 { 891 Anope::string ip; 892 if (params[9] != "*") 893 { 894 Anope::string decoded_ip; 895 Anope::B64Decode(params[9], decoded_ip); 896 897 sockaddrs ip_addr; 898 ip_addr.ntop(params[9].length() == 8 ? AF_INET : AF_INET6, decoded_ip.c_str()); 899 ip = ip_addr.addr(); 900 } 901 902 Anope::string vhost = params[8]; 903 if (vhost.equals_cs("*")) 904 vhost.clear(); 905 906 time_t user_ts = params[2].is_pos_number_only() ? convertTo<time_t>(params[2]) : Anope::CurTime; 907 908 Server *s = Server::Find(params[5]); 909 if (s == NULL) 910 { 911 Log(LOG_DEBUG) << "User " << params[0] << " introduced from nonexistent server " << params[5] << "?"; 912 return; 913 } 914 915 NickAlias *na = NULL; 916 917 if (params[6] == "0") 918 ; 919 else if (params[6].is_pos_number_only()) 920 { 921 if (convertTo<time_t>(params[6]) == user_ts) 922 na = NickAlias::Find(params[0]); 923 } 924 else 925 { 926 na = NickAlias::Find(params[6]); 927 } 928 929 User::OnIntroduce(params[0], params[3], params[4], vhost, ip, s, params[10], user_ts, params[7], "", na ? *na->nc : NULL); 930 } 931 else 932 { 933 User *u = source.GetUser(); 934 if (u) 935 u->ChangeNick(params[0]); 936 } 937 } 938 }; 939 940 /** This is here because: 941 * 942 * If we had three servers, A, B & C linked like so: A<->B<->C 943 * If Anope is linked to A and B splits from A and then reconnects 944 * B introduces itself, introduces C, sends EOS for C, introduces Bs clients 945 * introduces Cs clients, sends EOS for B. This causes all of Cs clients to be introduced 946 * with their server "not syncing". We now send a PING immediately when receiving a new server 947 * and then finish sync once we get a pong back from that server. 948 */ 949 struct IRCDMessagePong : IRCDMessage 950 { 951 IRCDMessagePong(Module *creator) : IRCDMessage(creator, "PONG", 0) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); SetFlag(IRCDMESSAGE_REQUIRE_SERVER); } 952 953 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 954 { 955 if (!source.GetServer()->IsSynced()) 956 source.GetServer()->Sync(false); 957 } 958 }; 959 960 struct IRCDMessageSASL : IRCDMessage 961 { 962 IRCDMessageSASL(Module *creator) : IRCDMessage(creator, "SASL", 4) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); SetFlag(IRCDMESSAGE_REQUIRE_SERVER); } 963 964 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 965 { 966 size_t p = params[1].find('!'); 967 if (!SASL::sasl || p == Anope::string::npos) 968 return; 969 970 SASL::Message m; 971 m.source = params[1]; 972 m.target = params[0]; 973 m.type = params[2]; 974 m.data = params[3]; 975 m.ext = params.size() > 4 ? params[4] : ""; 976 977 SASL::sasl->ProcessMessage(m); 978 } 979 }; 980 981 struct IRCDMessageSDesc : IRCDMessage 982 { 983 IRCDMessageSDesc(Module *creator) : IRCDMessage(creator, "SDESC", 1) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); } 984 985 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 986 { 987 source.GetServer()->SetDescription(params[0]); 988 } 989 }; 990 991 struct IRCDMessageSetHost : IRCDMessage 992 { 993 IRCDMessageSetHost(Module *creator) : IRCDMessage(creator, "SETHOST", 1) { SetFlag(IRCDMESSAGE_REQUIRE_USER); } 994 995 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 996 { 997 User *u = source.GetUser(); 998 999 /* When a user sets +x we receive the new host and then the mode change */ 1000 if (u->HasMode("CLOAK")) 1001 u->SetDisplayedHost(params[0]); 1002 else 1003 u->SetCloakedHost(params[0]); 1004 } 1005 }; 1006 1007 struct IRCDMessageSetIdent : IRCDMessage 1008 { 1009 IRCDMessageSetIdent(Module *creator) : IRCDMessage(creator, "SETIDENT", 1) { SetFlag(IRCDMESSAGE_REQUIRE_USER); } 1010 1011 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1012 { 1013 User *u = source.GetUser(); 1014 u->SetVIdent(params[0]); 1015 } 1016 }; 1017 1018 struct IRCDMessageSetName : IRCDMessage 1019 { 1020 IRCDMessageSetName(Module *creator) : IRCDMessage(creator, "SETNAME", 1) { SetFlag(IRCDMESSAGE_REQUIRE_USER); } 1021 1022 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1023 { 1024 User *u = source.GetUser(); 1025 u->SetRealname(params[0]); 1026 } 1027 }; 1028 1029 struct IRCDMessageServer : IRCDMessage 1030 { 1031 IRCDMessageServer(Module *creator) : IRCDMessage(creator, "SERVER", 3) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); } 1032 1033 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1034 { 1035 unsigned int hops = Anope::string(params[1]).is_pos_number_only() ? convertTo<unsigned>(params[1]) : 0; 1036 1037 if (params[1].equals_cs("1")) 1038 { 1039 Anope::string desc; 1040 spacesepstream(params[2]).GetTokenRemainder(desc, 1); 1041 1042 new Server(source.GetServer() == NULL ? Me : source.GetServer(), params[0], hops, desc); 1043 } 1044 else 1045 new Server(source.GetServer(), params[0], hops, params[2]); 1046 1047 IRCD->SendPing(Me->GetName(), params[0]); 1048 } 1049 }; 1050 1051 struct IRCDMessageSJoin : IRCDMessage 1052 { 1053 IRCDMessageSJoin(Module *creator) : IRCDMessage(creator, "SJOIN", 3) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); SetFlag(IRCDMESSAGE_SOFT_LIMIT); } 1054 1055 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1056 { 1057 Anope::string modes; 1058 if (params.size() >= 4) 1059 for (unsigned i = 2; i < params.size() - 1; ++i) 1060 modes += " " + params[i]; 1061 if (!modes.empty()) 1062 modes.erase(modes.begin()); 1063 1064 std::list<Anope::string> bans, excepts, invites; 1065 std::list<Message::Join::SJoinUser> users; 1066 1067 spacesepstream sep(params[params.size() - 1]); 1068 Anope::string buf; 1069 while (sep.GetToken(buf)) 1070 { 1071 /* Ban */ 1072 if (buf[0] == '&') 1073 { 1074 buf.erase(buf.begin()); 1075 bans.push_back(buf); 1076 } 1077 /* Except */ 1078 else if (buf[0] == '"') 1079 { 1080 buf.erase(buf.begin()); 1081 excepts.push_back(buf); 1082 } 1083 /* Invex */ 1084 else if (buf[0] == '\'') 1085 { 1086 buf.erase(buf.begin()); 1087 invites.push_back(buf); 1088 } 1089 else 1090 { 1091 Message::Join::SJoinUser sju; 1092 1093 /* Get prefixes from the nick */ 1094 for (char ch; (ch = ModeManager::GetStatusChar(buf[0]));) 1095 { 1096 sju.first.AddMode(ch); 1097 buf.erase(buf.begin()); 1098 } 1099 1100 sju.second = User::Find(buf); 1101 if (!sju.second) 1102 { 1103 Log(LOG_DEBUG) << "SJOIN for nonexistent user " << buf << " on " << params[1]; 1104 continue; 1105 } 1106 1107 users.push_back(sju); 1108 } 1109 } 1110 1111 time_t ts = Anope::string(params[0]).is_pos_number_only() ? convertTo<time_t>(params[0]) : Anope::CurTime; 1112 Message::Join::SJoin(source, params[1], ts, modes, users); 1113 1114 if (!bans.empty() || !excepts.empty() || !invites.empty()) 1115 { 1116 Channel *c = Channel::Find(params[1]); 1117 1118 if (!c || c->creation_time != ts) 1119 return; 1120 1121 ChannelMode *ban = ModeManager::FindChannelModeByName("BAN"), 1122 *except = ModeManager::FindChannelModeByName("EXCEPT"), 1123 *invex = ModeManager::FindChannelModeByName("INVITEOVERRIDE"); 1124 1125 if (ban) 1126 for (std::list<Anope::string>::iterator it = bans.begin(), it_end = bans.end(); it != it_end; ++it) 1127 c->SetModeInternal(source, ban, *it); 1128 if (except) 1129 for (std::list<Anope::string>::iterator it = excepts.begin(), it_end = excepts.end(); it != it_end; ++it) 1130 c->SetModeInternal(source, except, *it); 1131 if (invex) 1132 for (std::list<Anope::string>::iterator it = invites.begin(), it_end = invites.end(); it != it_end; ++it) 1133 c->SetModeInternal(source, invex, *it); 1134 } 1135 } 1136 }; 1137 1138 struct IRCDMessageTopic : IRCDMessage 1139 { 1140 IRCDMessageTopic(Module *creator) : IRCDMessage(creator, "TOPIC", 4) { } 1141 1142 /* 1143 ** source = sender prefix 1144 ** parv[0] = channel name 1145 ** parv[1] = topic nickname 1146 ** parv[2] = topic time 1147 ** parv[3] = topic text 1148 */ 1149 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1150 { 1151 Channel *c = Channel::Find(params[0]); 1152 if (c) 1153 c->ChangeTopicInternal(source.GetUser(), params[1], params[3], Anope::string(params[2]).is_pos_number_only() ? convertTo<time_t>(params[2]) : Anope::CurTime); 1154 } 1155 }; 1156 1157 1158 struct IRCDMessageUmode2 : IRCDMessage 1159 { 1160 IRCDMessageUmode2(Module *creator) : IRCDMessage(creator, "UMODE2", 1) { SetFlag(IRCDMESSAGE_REQUIRE_USER); } 1161 1162 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1163 { 1164 source.GetUser()->SetModesInternal(source, "%s", params[0].c_str()); 1165 } 1166 }; 1167 1168 class ProtoUnreal : public Module 1169 { 1170 UnrealIRCdProto ircd_proto; 1171 1172 /* Core message handlers */ 1173 Message::Away message_away; 1174 Message::Error message_error; 1175 Message::Invite message_invite; 1176 Message::Join message_join; 1177 Message::Kick message_kick; 1178 Message::Kill message_kill, message_svskill; 1179 Message::MOTD message_motd; 1180 Message::Notice message_notice; 1181 Message::Part message_part; 1182 Message::Ping message_ping; 1183 Message::Privmsg message_privmsg; 1184 Message::Quit message_quit; 1185 Message::SQuit message_squit; 1186 Message::Stats message_stats; 1187 Message::Time message_time; 1188 Message::Version message_version; 1189 Message::Whois message_whois; 1190 1191 /* Our message handlers */ 1192 IRCDMessageCapab message_capab; 1193 IRCDMessageChgHost message_chghost; 1194 IRCDMessageChgIdent message_chgident; 1195 IRCDMessageChgName message_chgname; 1196 IRCDMessageMode message_mode, message_svsmode, message_svs2mode; 1197 IRCDMessageNetInfo message_netinfo; 1198 IRCDMessageNick message_nick; 1199 IRCDMessagePong message_pong; 1200 IRCDMessageSASL message_sasl; 1201 IRCDMessageSDesc message_sdesc; 1202 IRCDMessageSetHost message_sethost; 1203 IRCDMessageSetIdent message_setident; 1204 IRCDMessageSetName message_setname; 1205 IRCDMessageServer message_server; 1206 IRCDMessageSJoin message_sjoin; 1207 IRCDMessageTopic message_topic; 1208 IRCDMessageUmode2 message_umode2; 1209 1210 bool use_server_side_mlock; 1211 1212 void AddModes() 1213 { 1214 ModeManager::AddChannelMode(new ChannelModeStatus("VOICE", 'v', '+', 0)); 1215 ModeManager::AddChannelMode(new ChannelModeStatus("HALFOP", 'h', '%', 1)); 1216 ModeManager::AddChannelMode(new ChannelModeStatus("OP", 'o', '@', 2)); 1217 /* Unreal sends +q as * and +a as ~ */ 1218 ModeManager::AddChannelMode(new ChannelModeStatus("PROTECT", 'a', '~', 3)); 1219 ModeManager::AddChannelMode(new ChannelModeStatus("OWNER", 'q', '*', 4)); 1220 1221 /* Add user modes */ 1222 ModeManager::AddUserMode(new UserModeOperOnly("SERV_ADMIN", 'A')); 1223 ModeManager::AddUserMode(new UserMode("BOT", 'B')); 1224 ModeManager::AddUserMode(new UserModeOperOnly("CO_ADMIN", 'C')); 1225 ModeManager::AddUserMode(new UserMode("CENSOR", 'G')); 1226 ModeManager::AddUserMode(new UserModeOperOnly("HIDEOPER", 'H')); 1227 ModeManager::AddUserMode(new UserModeOperOnly("HIDEIDLE", 'I')); 1228 ModeManager::AddUserMode(new UserModeOperOnly("NETADMIN", 'N')); 1229 ModeManager::AddUserMode(new UserMode("REGPRIV", 'R')); 1230 ModeManager::AddUserMode(new UserModeOperOnly("PROTECTED", 'S')); 1231 ModeManager::AddUserMode(new UserMode("NOCTCP", 'T')); 1232 ModeManager::AddUserMode(new UserMode("WEBTV", 'V')); 1233 ModeManager::AddUserMode(new UserModeOperOnly("WHOIS", 'W')); 1234 ModeManager::AddUserMode(new UserModeOperOnly("ADMIN", 'a')); 1235 ModeManager::AddUserMode(new UserMode("DEAF", 'd')); 1236 ModeManager::AddUserMode(new UserModeOperOnly("GLOBOPS", 'g')); 1237 ModeManager::AddUserMode(new UserModeOperOnly("HELPOP", 'h')); 1238 ModeManager::AddUserMode(new UserMode("INVIS", 'i')); 1239 ModeManager::AddUserMode(new UserModeOperOnly("OPER", 'o')); 1240 ModeManager::AddUserMode(new UserMode("PRIV", 'p')); 1241 ModeManager::AddUserMode(new UserModeOperOnly("GOD", 'q')); 1242 ModeManager::AddUserMode(new UserModeNoone("REGISTERED", 'r')); 1243 ModeManager::AddUserMode(new UserModeOperOnly("SNOMASK", 's')); 1244 ModeManager::AddUserMode(new UserModeNoone("VHOST", 't')); 1245 ModeManager::AddUserMode(new UserMode("WALLOPS", 'w')); 1246 ModeManager::AddUserMode(new UserMode("CLOAK", 'x')); 1247 ModeManager::AddUserMode(new UserModeNoone("SSL", 'z')); 1248 } 1249 1250 public: 1251 ProtoUnreal(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, PROTOCOL | VENDOR), 1252 ircd_proto(this), 1253 message_away(this), message_error(this), message_invite(this), message_join(this), message_kick(this), 1254 message_kill(this), message_svskill(this, "SVSKILL"), message_motd(this), message_notice(this), message_part(this), message_ping(this), 1255 message_privmsg(this), message_quit(this), message_squit(this), message_stats(this), message_time(this), 1256 message_version(this), message_whois(this), 1257 1258 message_capab(this), message_chghost(this), message_chgident(this), message_chgname(this), message_mode(this, "MODE"), 1259 message_svsmode(this, "SVSMODE"), message_svs2mode(this, "SVS2MODE"), message_netinfo(this), message_nick(this), message_pong(this), 1260 message_sasl(this), message_sdesc(this), message_sethost(this), message_setident(this), message_setname(this), message_server(this), 1261 message_sjoin(this), message_topic(this), message_umode2(this) 1262 { 1263 1264 this->AddModes(); 1265 } 1266 1267 void Prioritize() anope_override 1268 { 1269 ModuleManager::SetPriority(this, PRIORITY_FIRST); 1270 } 1271 1272 void OnReload(Configuration::Conf *conf) anope_override 1273 { 1274 use_server_side_mlock = conf->GetModule(this)->Get<bool>("use_server_side_mlock"); 1275 } 1276 1277 void OnUserNickChange(User *u, const Anope::string &) anope_override 1278 { 1279 u->RemoveModeInternal(Me, ModeManager::FindUserModeByName("REGISTERED")); 1280 if (Servers::Capab.count("ESVID") == 0) 1281 IRCD->SendLogout(u); 1282 } 1283 1284 void OnChannelSync(Channel *c) anope_override 1285 { 1286 if (!c->ci) 1287 return; 1288 1289 ModeLocks *modelocks = c->ci->GetExt<ModeLocks>("modelocks"); 1290 if (use_server_side_mlock && Servers::Capab.count("MLOCK") > 0 && modelocks) 1291 { 1292 Anope::string modes = modelocks->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", ""); 1293 UplinkSocket::Message(Me) << "MLOCK " << static_cast<long>(c->creation_time) << " " << c->ci->name << " " << modes; 1294 } 1295 } 1296 1297 void OnChanRegistered(ChannelInfo *ci) anope_override 1298 { 1299 ModeLocks *modelocks = ci->GetExt<ModeLocks>("modelocks"); 1300 if (!ci->c || !use_server_side_mlock || !modelocks || !Servers::Capab.count("MLOCK")) 1301 return; 1302 Anope::string modes = modelocks->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", ""); 1303 UplinkSocket::Message(Me) << "MLOCK " << static_cast<long>(ci->c->creation_time) << " " << ci->name << " " << modes; 1304 } 1305 1306 void OnDelChan(ChannelInfo *ci) anope_override 1307 { 1308 if (!ci->c || !use_server_side_mlock || !Servers::Capab.count("MLOCK")) 1309 return; 1310 UplinkSocket::Message(Me) << "MLOCK " << static_cast<long>(ci->c->creation_time) << " " << ci->name << " :"; 1311 } 1312 1313 EventReturn OnMLock(ChannelInfo *ci, ModeLock *lock) anope_override 1314 { 1315 ModeLocks *modelocks = ci->GetExt<ModeLocks>("modelocks"); 1316 ChannelMode *cm = ModeManager::FindChannelModeByName(lock->name); 1317 if (use_server_side_mlock && cm && modelocks && ci->c && (cm->type == MODE_REGULAR || cm->type == MODE_PARAM) && Servers::Capab.count("MLOCK") > 0) 1318 { 1319 Anope::string modes = modelocks->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", "") + cm->mchar; 1320 UplinkSocket::Message(Me) << "MLOCK " << static_cast<long>(ci->c->creation_time) << " " << ci->name << " " << modes; 1321 } 1322 1323 return EVENT_CONTINUE; 1324 } 1325 1326 EventReturn OnUnMLock(ChannelInfo *ci, ModeLock *lock) anope_override 1327 { 1328 ModeLocks *modelocks = ci->GetExt<ModeLocks>("modelocks"); 1329 ChannelMode *cm = ModeManager::FindChannelModeByName(lock->name); 1330 if (use_server_side_mlock && cm && modelocks && ci->c && (cm->type == MODE_REGULAR || cm->type == MODE_PARAM) && Servers::Capab.count("MLOCK") > 0) 1331 { 1332 Anope::string modes = modelocks->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", "").replace_all_cs(cm->mchar, ""); 1333 UplinkSocket::Message(Me) << "MLOCK " << static_cast<long>(ci->c->creation_time) << " " << ci->name << " " << modes; 1334 } 1335 1336 return EVENT_CONTINUE; 1337 } 1338 }; 1339 1340 MODULE_INIT(ProtoUnreal)