anope- supernets anope source code & configuration |
git clone git://git.acid.vegas/anope.git |
Log | Files | Refs | Archive | README |
inspircd3.cpp (63524B)
1 /* InspIRCd 3.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 #include "modules/sasl.h" 15 16 typedef std::map<char, unsigned> ListLimits; 17 18 struct SASLUser 19 { 20 Anope::string uid; 21 Anope::string acc; 22 time_t created; 23 }; 24 25 static std::list<SASLUser> saslusers; 26 27 static Anope::string rsquit_server, rsquit_id; 28 29 class InspIRCd3Proto : public IRCDProto 30 { 31 private: 32 void SendChgIdentInternal(const Anope::string &nick, const Anope::string &vIdent) 33 { 34 if (!Servers::Capab.count("CHGIDENT")) 35 Log() << "CHGIDENT not loaded!"; 36 else 37 UplinkSocket::Message(Me) << "CHGIDENT " << nick << " " << vIdent; 38 } 39 40 void SendChgHostInternal(const Anope::string &nick, const Anope::string &vhost) 41 { 42 if (!Servers::Capab.count("CHGHOST")) 43 Log() << "CHGHOST not loaded!"; 44 else 45 UplinkSocket::Message(Me) << "CHGHOST " << nick << " " << vhost; 46 } 47 48 void SendAddLine(const Anope::string &xtype, const Anope::string &mask, time_t duration, const Anope::string &addedby, const Anope::string &reason) 49 { 50 UplinkSocket::Message(Me) << "ADDLINE " << xtype << " " << mask << " " << addedby << " " << Anope::CurTime << " " << duration << " :" << reason; 51 } 52 53 void SendDelLine(const Anope::string &xtype, const Anope::string &mask) 54 { 55 UplinkSocket::Message(Me) << "DELLINE " << xtype << " " << mask; 56 } 57 58 public: 59 PrimitiveExtensibleItem<ListLimits> maxlist; 60 61 InspIRCd3Proto(Module *creator) : IRCDProto(creator, "InspIRCd 3"), maxlist(creator, "maxlist") 62 { 63 DefaultPseudoclientModes = "+oI"; 64 CanSVSNick = true; 65 CanSVSJoin = true; 66 CanSetVHost = true; 67 CanSetVIdent = true; 68 CanSQLine = true; 69 CanSQLineChannel = true; 70 CanSZLine = true; 71 CanSVSHold = true; 72 CanCertFP = true; 73 RequiresID = true; 74 MaxModes = 20; 75 MaxLine = 4096; 76 } 77 78 unsigned GetMaxListFor(Channel *c, ChannelMode *cm) anope_override 79 { 80 ListLimits *limits = maxlist.Get(c); 81 if (limits) 82 { 83 ListLimits::const_iterator limit = limits->find(cm->mchar); 84 if (limit != limits->end()) 85 return limit->second; 86 } 87 88 // Fall back to the config limit if we can't find the mode. 89 return IRCDProto::GetMaxListFor(c, cm); 90 } 91 92 void SendConnect() anope_override 93 { 94 UplinkSocket::Message() << "CAPAB START 1205"; 95 UplinkSocket::Message() << "CAPAB CAPABILITIES :CASEMAPPING=" << Config->GetBlock("options")->Get<const Anope::string>("casemap", "ascii"); 96 UplinkSocket::Message() << "CAPAB END"; 97 UplinkSocket::Message() << "SERVER " << Me->GetName() << " " << Config->Uplinks[Anope::CurrentUplink].password << " 0 " << Me->GetSID() << " :" << Me->GetDescription(); 98 } 99 100 void SendSASLMechanisms(std::vector<Anope::string> &mechanisms) anope_override 101 { 102 Anope::string mechlist; 103 for (unsigned i = 0; i < mechanisms.size(); ++i) 104 mechlist += "," + mechanisms[i]; 105 106 UplinkSocket::Message(Me) << "METADATA * saslmechlist :" << (mechanisms.empty() ? "" : mechlist.substr(1)); 107 } 108 109 void SendSVSKillInternal(const MessageSource &source, User *user, const Anope::string &buf) anope_override 110 { 111 IRCDProto::SendSVSKillInternal(source, user, buf); 112 user->KillInternal(source, buf); 113 } 114 115 void SendGlobalNotice(BotInfo *bi, const Server *dest, const Anope::string &msg) anope_override 116 { 117 UplinkSocket::Message(bi) << "NOTICE $" << dest->GetName() << " :" << msg; 118 } 119 120 void SendGlobalPrivmsg(BotInfo *bi, const Server *dest, const Anope::string &msg) anope_override 121 { 122 UplinkSocket::Message(bi) << "PRIVMSG $" << dest->GetName() << " :" << msg; 123 } 124 125 void SendPong(const Anope::string &servname, const Anope::string &who) anope_override 126 { 127 Server *serv = servname.empty() ? NULL : Server::Find(servname); 128 if (!serv) 129 serv = Me; 130 131 UplinkSocket::Message(serv) << "PONG " << who; 132 } 133 134 void SendAkillDel(const XLine *x) anope_override 135 { 136 { 137 /* InspIRCd may support regex bans 138 * Mask is expected in format: 'n!u@h\sr' and spaces as '\s' 139 * We remove the '//' and replace '#' and any ' ' with '\s' 140 */ 141 if (x->IsRegex() && Servers::Capab.count("RLINE")) 142 { 143 Anope::string mask = x->mask; 144 if (mask.length() >= 2 && mask[0] == '/' && mask[mask.length() - 1] == '/') 145 mask = mask.substr(1, mask.length() - 2); 146 size_t h = mask.find('#'); 147 if (h != Anope::string::npos) 148 { 149 mask = mask.replace(h, 1, "\\s"); 150 mask = mask.replace_all_cs(" ", "\\s"); 151 } 152 SendDelLine("R", mask); 153 return; 154 } 155 else if (x->IsRegex() || x->HasNickOrReal()) 156 return; 157 158 /* ZLine if we can instead */ 159 if (x->GetUser() == "*") 160 { 161 cidr addr(x->GetHost()); 162 if (addr.valid()) 163 { 164 IRCD->SendSZLineDel(x); 165 return; 166 } 167 } 168 169 SendDelLine("G", x->GetUser() + "@" + x->GetHost()); 170 } 171 } 172 173 void SendInvite(const MessageSource &source, const Channel *c, User *u) anope_override 174 { 175 UplinkSocket::Message(source) << "INVITE " << u->GetUID() << " " << c->name << " " << c->creation_time; 176 } 177 178 void SendTopic(const MessageSource &source, Channel *c) anope_override 179 { 180 if (Servers::Capab.count("SVSTOPIC")) 181 { 182 UplinkSocket::Message(c->ci->WhoSends()) << "SVSTOPIC " << c->name << " " << c->topic_ts << " " << c->topic_setter << " :" << c->topic; 183 } 184 else 185 { 186 /* 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 */ 187 time_t ts = c->topic_ts; 188 if (c->topic_time > ts) 189 ts = Anope::CurTime; 190 /* 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 */ 191 UplinkSocket::Message(source) << "FTOPIC " << c->name << " " << c->creation_time << " " << ts << " " << c->topic_setter << " :" << c->topic; 192 } 193 } 194 195 void SendVhostDel(User *u) anope_override 196 { 197 UserMode *um = ModeManager::FindUserModeByName("CLOAK"); 198 199 if (um && !u->HasMode(um->name)) 200 // Just set +x if we can 201 u->SetMode(NULL, um); 202 else 203 // Try to restore cloaked host 204 this->SendChgHostInternal(u->nick, u->chost); 205 } 206 207 void SendAkill(User *u, XLine *x) anope_override 208 { 209 // Calculate the time left before this would expire, capping it at 2 days 210 time_t timeleft = x->expires - Anope::CurTime; 211 if (timeleft > 172800 || !x->expires) 212 timeleft = 172800; 213 214 /* InspIRCd may support regex bans, if they do we can send this and forget about it 215 * Mask is expected in format: 'n!u@h\sr' and spaces as '\s' 216 * We remove the '//' and replace '#' and any ' ' with '\s' 217 */ 218 if (x->IsRegex() && Servers::Capab.count("RLINE")) 219 { 220 Anope::string mask = x->mask; 221 if (mask.length() >= 2 && mask[0] == '/' && mask[mask.length() - 1] == '/') 222 mask = mask.substr(1, mask.length() - 2); 223 size_t h = mask.find('#'); 224 if (h != Anope::string::npos) 225 { 226 mask = mask.replace(h, 1, "\\s"); 227 mask = mask.replace_all_cs(" ", "\\s"); 228 } 229 SendAddLine("R", mask, timeleft, x->by, x->GetReason()); 230 return; 231 } 232 else if (x->IsRegex() || x->HasNickOrReal()) 233 { 234 if (!u) 235 { 236 /* No user (this akill was just added), and contains nick and/or realname. Find users that match and ban them */ 237 for (user_map::const_iterator it = UserListByNick.begin(); it != UserListByNick.end(); ++it) 238 if (x->manager->Check(it->second, x)) 239 this->SendAkill(it->second, x); 240 return; 241 } 242 243 const XLine *old = x; 244 245 if (old->manager->HasEntry("*@" + u->host)) 246 return; 247 248 /* We can't akill x as it has a nick and/or realname included, so create a new akill for *@host */ 249 x = new XLine("*@" + u->host, old->by, old->expires, old->reason, old->id); 250 old->manager->AddXLine(x); 251 252 Log(Config->GetClient("OperServ"), "akill") << "AKILL: Added an akill for " << x->mask << " because " << u->GetMask() << "#" << u->realname << " matches " << old->mask; 253 } 254 255 /* ZLine if we can instead */ 256 if (x->GetUser() == "*") 257 { 258 cidr addr(x->GetHost()); 259 if (addr.valid()) 260 { 261 IRCD->SendSZLine(u, x); 262 return; 263 } 264 } 265 266 SendAddLine("G", x->GetUser() + "@" + x->GetHost(), timeleft, x->by, x->GetReason()); 267 } 268 269 void SendNumericInternal(int numeric, const Anope::string &dest, const Anope::string &buf) anope_override 270 { 271 UplinkSocket::Message() << "NUM " << Me->GetSID() << " " << dest << " " << numeric << " " << buf; 272 } 273 274 void SendModeInternal(const MessageSource &source, const Channel *dest, const Anope::string &buf) anope_override 275 { 276 UplinkSocket::Message(source) << "FMODE " << dest->name << " " << dest->creation_time << " " << buf; 277 } 278 279 void SendClientIntroduction(User *u) anope_override 280 { 281 Anope::string modes = "+" + u->GetModes(); 282 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; 283 if (modes.find('o') != Anope::string::npos) 284 UplinkSocket::Message(u) << "OPERTYPE :service"; 285 } 286 287 void SendServer(const Server *server) anope_override 288 { 289 /* if rsquit is set then we are waiting on a squit */ 290 if (rsquit_id.empty() && rsquit_server.empty()) 291 UplinkSocket::Message() << "SERVER " << server->GetName() << " " << server->GetSID() << " :" << server->GetDescription(); 292 } 293 294 void SendSquit(Server *s, const Anope::string &message) anope_override 295 { 296 if (s != Me) 297 { 298 rsquit_id = s->GetSID(); 299 rsquit_server = s->GetName(); 300 UplinkSocket::Message() << "RSQUIT " << s->GetName() << " :" << message; 301 } 302 else 303 UplinkSocket::Message() << "SQUIT " << s->GetName() << " :" << message; 304 } 305 306 void SendJoin(User *user, Channel *c, const ChannelStatus *status) anope_override 307 { 308 UplinkSocket::Message(Me) << "FJOIN " << c->name << " " << c->creation_time << " +" << c->GetModes(true, true) << " :," << user->GetUID(); 309 /* Note that we can send this with the FJOIN but choose not to 310 * because the mode stacker will handle this and probably will 311 * merge these modes with +nrt and other mlocked modes 312 */ 313 if (status) 314 { 315 /* First save the channel status incase uc->Status == status */ 316 ChannelStatus cs = *status; 317 /* If the user is internally on the channel with flags, kill them so that 318 * the stacker will allow this. 319 */ 320 ChanUserContainer *uc = c->FindUser(user); 321 if (uc != NULL) 322 uc->status.Clear(); 323 324 BotInfo *setter = BotInfo::Find(user->GetUID()); 325 for (size_t i = 0; i < cs.Modes().length(); ++i) 326 c->SetMode(setter, ModeManager::FindChannelModeByChar(cs.Modes()[i]), user->GetUID(), false); 327 328 if (uc != NULL) 329 uc->status = cs; 330 } 331 } 332 333 void SendSQLineDel(const XLine *x) anope_override 334 { 335 if (IRCD->CanSQLineChannel && (x->mask[0] == '#')) 336 SendDelLine("CBAN", x->mask); 337 else 338 SendDelLine("Q", x->mask); 339 } 340 341 void SendSQLine(User *u, const XLine *x) anope_override 342 { 343 // Calculate the time left before this would expire, capping it at 2 days 344 time_t timeleft = x->expires - Anope::CurTime; 345 if (timeleft > 172800 || !x->expires) 346 timeleft = 172800; 347 348 if (IRCD->CanSQLineChannel && (x->mask[0] == '#')) 349 SendAddLine("CBAN", x->mask, timeleft, x->by, x->GetReason()); 350 else 351 SendAddLine("Q", x->mask, timeleft, x->by, x->GetReason()); 352 } 353 354 void SendVhost(User *u, const Anope::string &vIdent, const Anope::string &vhost) anope_override 355 { 356 if (!vIdent.empty()) 357 this->SendChgIdentInternal(u->nick, vIdent); 358 if (!vhost.empty()) 359 this->SendChgHostInternal(u->nick, vhost); 360 } 361 362 void SendSVSHold(const Anope::string &nick, time_t t) anope_override 363 { 364 UplinkSocket::Message(Config->GetClient("NickServ")) << "SVSHOLD " << nick << " " << t << " :Being held for registered user"; 365 } 366 367 void SendSVSHoldDel(const Anope::string &nick) anope_override 368 { 369 UplinkSocket::Message(Config->GetClient("NickServ")) << "SVSHOLD " << nick; 370 } 371 372 void SendSZLineDel(const XLine *x) anope_override 373 { 374 SendDelLine("Z", x->GetHost()); 375 } 376 377 void SendSZLine(User *u, const XLine *x) anope_override 378 { 379 // Calculate the time left before this would expire, capping it at 2 days 380 time_t timeleft = x->expires - Anope::CurTime; 381 if (timeleft > 172800 || !x->expires) 382 timeleft = 172800; 383 SendAddLine("Z", x->GetHost(), timeleft, x->by, x->GetReason()); 384 } 385 386 void SendSVSJoin(const MessageSource &source, User *u, const Anope::string &chan, const Anope::string &other) anope_override 387 { 388 UplinkSocket::Message(source) << "SVSJOIN " << u->GetUID() << " " << chan; 389 } 390 391 void SendSVSPart(const MessageSource &source, User *u, const Anope::string &chan, const Anope::string ¶m) anope_override 392 { 393 if (!param.empty()) 394 UplinkSocket::Message(source) << "SVSPART " << u->GetUID() << " " << chan << " :" << param; 395 else 396 UplinkSocket::Message(source) << "SVSPART " << u->GetUID() << " " << chan; 397 } 398 399 void SendSWhois(const MessageSource &bi, const Anope::string &who, const Anope::string &mask) anope_override 400 { 401 User *u = User::Find(who); 402 403 UplinkSocket::Message(Me) << "METADATA " << u->GetUID() << " swhois :" << mask; 404 } 405 406 void SendBOB() anope_override 407 { 408 UplinkSocket::Message(Me) << "BURST " << Anope::CurTime; 409 Module *enc = ModuleManager::FindFirstOf(ENCRYPTION); 410 UplinkSocket::Message(Me) << "SINFO version :Anope-" << Anope::Version() << " " << Me->GetName() << " :" << IRCD->GetProtocolName() << " - (" << (enc ? enc->name : "none") << ") -- " << Anope::VersionBuildString(); 411 UplinkSocket::Message(Me) << "SINFO fullversion :Anope-" << Anope::Version() << " " << Me->GetName() << " :[" << Me->GetSID() << "] " << IRCD->GetProtocolName() << " - (" << (enc ? enc->name : "none") << ") -- " << Anope::VersionBuildString(); 412 UplinkSocket::Message(Me) << "SINFO rawversion :Anope-" << Anope::VersionShort(); 413 } 414 415 void SendEOB() anope_override 416 { 417 UplinkSocket::Message(Me) << "ENDBURST"; 418 } 419 420 void SendGlobopsInternal(const MessageSource &source, const Anope::string &buf) anope_override 421 { 422 if (Servers::Capab.count("GLOBOPS")) 423 UplinkSocket::Message(source) << "SNONOTICE g :" << buf; 424 else 425 UplinkSocket::Message(source) << "SNONOTICE A :" << buf; 426 } 427 428 void SendLogin(User *u, NickAlias *na) anope_override 429 { 430 /* InspIRCd uses an account to bypass chmode +R, not umode +r, so we can't send this here */ 431 if (na->nc->HasExt("UNCONFIRMED")) 432 return; 433 434 UplinkSocket::Message(Me) << "METADATA " << u->GetUID() << " accountid :" << na->nc->GetId(); 435 UplinkSocket::Message(Me) << "METADATA " << u->GetUID() << " accountname :" << na->nc->display; 436 } 437 438 void SendLogout(User *u) anope_override 439 { 440 UplinkSocket::Message(Me) << "METADATA " << u->GetUID() << " accountid :"; 441 UplinkSocket::Message(Me) << "METADATA " << u->GetUID() << " accountname :"; 442 } 443 444 void SendChannel(Channel *c) anope_override 445 { 446 UplinkSocket::Message(Me) << "FJOIN " << c->name << " " << c->creation_time << " +" << c->GetModes(true, true) << " :"; 447 } 448 449 void SendSASLMessage(const SASL::Message &message) anope_override 450 { 451 UplinkSocket::Message(Me) << "ENCAP " << message.target.substr(0, 3) << " SASL " << message.source << " " << message.target << " " << message.type << " " << message.data << (message.ext.empty() ? "" : (" " + message.ext)); 452 } 453 454 void SendSVSLogin(const Anope::string &uid, const Anope::string &acc, const Anope::string &vident, const Anope::string &vhost) anope_override 455 { 456 // TODO: in 2.1 this function should take a NickAlias instead of strings. 457 NickCore *nc = NickCore::Find(acc); 458 if (!nc) 459 return; 460 461 UplinkSocket::Message(Me) << "METADATA " << uid << " accountid :" << nc->GetId(); 462 UplinkSocket::Message(Me) << "METADATA " << uid << " accountname :" << acc; 463 464 if (!vident.empty()) 465 UplinkSocket::Message(Me) << "ENCAP " << uid.substr(0, 3) << " CHGIDENT " << uid << " " << vident; 466 if (!vhost.empty()) 467 UplinkSocket::Message(Me) << "ENCAP " << uid.substr(0, 3) << " CHGHOST " << uid << " " << vhost; 468 469 SASLUser su; 470 su.uid = uid; 471 su.acc = acc; 472 su.created = Anope::CurTime; 473 474 for (std::list<SASLUser>::iterator it = saslusers.begin(); it != saslusers.end();) 475 { 476 SASLUser &u = *it; 477 478 if (u.created + 30 < Anope::CurTime || u.uid == uid) 479 it = saslusers.erase(it); 480 else 481 ++it; 482 } 483 484 saslusers.push_back(su); 485 } 486 487 bool IsExtbanValid(const Anope::string &mask) anope_override 488 { 489 return mask.length() >= 3 && mask[1] == ':'; 490 } 491 492 bool IsIdentValid(const Anope::string &ident) anope_override 493 { 494 if (ident.empty() || ident.length() > Config->GetBlock("networkinfo")->Get<unsigned>("userlen")) 495 return false; 496 497 for (unsigned i = 0; i < ident.length(); ++i) 498 { 499 const char &c = ident[i]; 500 501 if (c >= 'A' && c <= '}') 502 continue; 503 504 if ((c >= '0' && c <= '9') || c == '-' || c == '.') 505 continue; 506 507 return false; 508 } 509 510 return true; 511 } 512 }; 513 514 class InspIRCdAutoOpMode : public ChannelModeList 515 { 516 public: 517 InspIRCdAutoOpMode(char mode) : ChannelModeList("AUTOOP", mode) 518 { 519 } 520 521 bool IsValid(Anope::string &mask) const anope_override 522 { 523 // We can not validate this because we don't know about the 524 // privileges of the setter so just reject attempts to set it. 525 return false; 526 } 527 }; 528 529 class InspIRCdExtBan : public ChannelModeVirtual<ChannelModeList> 530 { 531 char ext; 532 533 public: 534 InspIRCdExtBan(const Anope::string &mname, const Anope::string &basename, char extban) : ChannelModeVirtual<ChannelModeList>(mname, basename) 535 , ext(extban) 536 { 537 } 538 539 ChannelMode *Wrap(Anope::string ¶m) anope_override 540 { 541 param = Anope::string(ext) + ":" + param; 542 return ChannelModeVirtual<ChannelModeList>::Wrap(param); 543 } 544 545 ChannelMode *Unwrap(ChannelMode *cm, Anope::string ¶m) anope_override 546 { 547 if (cm->type != MODE_LIST || param.length() < 3 || param[0] != ext || param[1] != ':') 548 return cm; 549 550 param = param.substr(2); 551 return this; 552 } 553 }; 554 555 namespace InspIRCdExtban 556 { 557 class EntryMatcher : public InspIRCdExtBan 558 { 559 public: 560 EntryMatcher(const Anope::string &mname, const Anope::string &mbase, char c) : InspIRCdExtBan(mname, mbase, c) 561 { 562 } 563 564 bool Matches(User *u, const Entry *e) anope_override 565 { 566 const Anope::string &mask = e->GetMask(); 567 Anope::string real_mask = mask.substr(3); 568 569 return Entry(this->name, real_mask).Matches(u); 570 } 571 }; 572 573 class ChannelMatcher : public InspIRCdExtBan 574 { 575 public: 576 ChannelMatcher(const Anope::string &mname, const Anope::string &mbase, char c) : InspIRCdExtBan(mname, mbase, c) 577 { 578 } 579 580 bool Matches(User *u, const Entry *e) anope_override 581 { 582 const Anope::string &mask = e->GetMask(); 583 584 Anope::string channel = mask.substr(3); 585 586 ChannelMode *cm = NULL; 587 if (channel[0] != '#') 588 { 589 char modeChar = ModeManager::GetStatusChar(channel[0]); 590 channel.erase(channel.begin()); 591 cm = ModeManager::FindChannelModeByChar(modeChar); 592 if (cm != NULL && cm->type != MODE_STATUS) 593 cm = NULL; 594 } 595 596 Channel *c = Channel::Find(channel); 597 if (c != NULL) 598 { 599 ChanUserContainer *uc = c->FindUser(u); 600 if (uc != NULL) 601 if (cm == NULL || uc->status.HasMode(cm->mchar)) 602 return true; 603 } 604 605 return false; 606 } 607 }; 608 609 class AccountMatcher : public InspIRCdExtBan 610 { 611 public: 612 AccountMatcher(const Anope::string &mname, const Anope::string &mbase, char c) : InspIRCdExtBan(mname, mbase, c) 613 { 614 } 615 616 bool Matches(User *u, const Entry *e) anope_override 617 { 618 const Anope::string &mask = e->GetMask(); 619 Anope::string real_mask = mask.substr(2); 620 621 return u->IsIdentified() && real_mask.equals_ci(u->Account()->display); 622 } 623 }; 624 625 class RealnameMatcher : public InspIRCdExtBan 626 { 627 public: 628 RealnameMatcher(const Anope::string &mname, const Anope::string &mbase, char c) : InspIRCdExtBan(mname, mbase, c) 629 { 630 } 631 632 bool Matches(User *u, const Entry *e) anope_override 633 { 634 const Anope::string &mask = e->GetMask(); 635 Anope::string real_mask = mask.substr(2); 636 return Anope::Match(u->realname, real_mask); 637 } 638 }; 639 640 class ServerMatcher : public InspIRCdExtBan 641 { 642 public: 643 ServerMatcher(const Anope::string &mname, const Anope::string &mbase, char c) : InspIRCdExtBan(mname, mbase, c) 644 { 645 } 646 647 bool Matches(User *u, const Entry *e) anope_override 648 { 649 const Anope::string &mask = e->GetMask(); 650 Anope::string real_mask = mask.substr(2); 651 return Anope::Match(u->server->GetName(), real_mask); 652 } 653 }; 654 655 class FingerprintMatcher : public InspIRCdExtBan 656 { 657 public: 658 FingerprintMatcher(const Anope::string &mname, const Anope::string &mbase, char c) : InspIRCdExtBan(mname, mbase, c) 659 { 660 } 661 662 bool Matches(User *u, const Entry *e) anope_override 663 { 664 const Anope::string &mask = e->GetMask(); 665 Anope::string real_mask = mask.substr(2); 666 return !u->fingerprint.empty() && Anope::Match(u->fingerprint, real_mask); 667 } 668 }; 669 670 class UnidentifiedMatcher : public InspIRCdExtBan 671 { 672 public: 673 UnidentifiedMatcher(const Anope::string &mname, const Anope::string &mbase, char c) : InspIRCdExtBan(mname, mbase, c) 674 { 675 } 676 677 bool Matches(User *u, const Entry *e) anope_override 678 { 679 const Anope::string &mask = e->GetMask(); 680 Anope::string real_mask = mask.substr(2); 681 return !u->Account() && Entry("BAN", real_mask).Matches(u); 682 } 683 }; 684 } 685 686 class ColonDelimitedParamMode : public ChannelModeParam 687 { 688 public: 689 ColonDelimitedParamMode(const Anope::string &modename, char modeChar) : ChannelModeParam(modename, modeChar, true) { } 690 691 bool IsValid(Anope::string &value) const anope_override 692 { 693 return IsValid(value, false); 694 } 695 696 bool IsValid(const Anope::string &value, bool historymode) const 697 { 698 if (value.empty()) 699 return false; // empty param is never valid 700 701 Anope::string::size_type pos = value.find(':'); 702 if ((pos == Anope::string::npos) || (pos == 0)) 703 return false; // no ':' or it's the first char, both are invalid 704 705 Anope::string rest; 706 try 707 { 708 if (convertTo<int>(value, rest, false) <= 0) 709 return false; // negative numbers and zero are invalid 710 711 rest = rest.substr(1); 712 int n; 713 if (historymode) 714 { 715 // For the history mode, the part after the ':' is a duration and it 716 // can be in the user friendly "1d3h20m" format, make sure we accept that 717 n = Anope::DoTime(rest); 718 } 719 else 720 n = convertTo<int>(rest); 721 722 if (n <= 0) 723 return false; 724 } 725 catch (const ConvertException &e) 726 { 727 // conversion error, invalid 728 return false; 729 } 730 731 return true; 732 } 733 }; 734 735 class SimpleNumberParamMode : public ChannelModeParam 736 { 737 public: 738 SimpleNumberParamMode(const Anope::string &modename, char modeChar) : ChannelModeParam(modename, modeChar, true) { } 739 740 bool IsValid(Anope::string &value) const anope_override 741 { 742 if (value.empty()) 743 return false; // empty param is never valid 744 745 try 746 { 747 if (convertTo<int>(value) <= 0) 748 return false; 749 } 750 catch (const ConvertException &e) 751 { 752 // conversion error, invalid 753 return false; 754 } 755 756 return true; 757 } 758 }; 759 760 class ChannelModeFlood : public ColonDelimitedParamMode 761 { 762 public: 763 ChannelModeFlood(char modeChar) : ColonDelimitedParamMode("FLOOD", modeChar) { } 764 765 bool IsValid(Anope::string &value) const anope_override 766 { 767 // The parameter of this mode is a bit different, it may begin with a '*', 768 // ignore it if that's the case 769 Anope::string v = value[0] == '*' ? value.substr(1) : value; 770 return ((!value.empty()) && (ColonDelimitedParamMode::IsValid(v))); 771 } 772 }; 773 774 class ChannelModeHistory : public ColonDelimitedParamMode 775 { 776 public: 777 ChannelModeHistory(char modeChar) : ColonDelimitedParamMode("HISTORY", modeChar) { } 778 779 bool IsValid(Anope::string &value) const anope_override 780 { 781 return (ColonDelimitedParamMode::IsValid(value, true)); 782 } 783 }; 784 785 class ChannelModeRedirect : public ChannelModeParam 786 { 787 public: 788 ChannelModeRedirect(char modeChar) : ChannelModeParam("REDIRECT", modeChar, true) { } 789 790 bool IsValid(Anope::string &value) const anope_override 791 { 792 // The parameter of this mode is a channel, and channel names start with '#' 793 return ((!value.empty()) && (value[0] == '#')); 794 } 795 }; 796 797 struct IRCDMessageAway : Message::Away 798 { 799 IRCDMessageAway(Module *creator) : Message::Away(creator, "AWAY") { SetFlag(IRCDMESSAGE_REQUIRE_USER); } 800 801 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 802 { 803 std::vector<Anope::string> newparams(params); 804 if (newparams.size() > 1) 805 newparams.erase(newparams.begin()); 806 807 Message::Away::Run(source, newparams); 808 } 809 }; 810 811 struct IRCDMessageCapab : Message::Capab 812 { 813 struct ModeInfo 814 { 815 // The letter assigned to the mode (e.g. o). 816 char letter; 817 818 // If a prefix mode then the rank of the prefix. 819 unsigned level; 820 821 // The name of the mode. 822 Anope::string name; 823 824 // If a prefix mode then the symbol associated with the prefix. 825 char symbol; 826 827 // The type of mode. 828 Anope::string type; 829 830 ModeInfo() : letter(0), level(0), symbol(0) { } 831 }; 832 833 static bool ParseMode(const Anope::string& token, ModeInfo& mode) 834 { 835 // list:ban=b param-set:limit=l param:key=k prefix:30000:op=@o simple:noextmsg=n 836 // A C A C A C A B C A C 837 Anope::string::size_type a = token.find(':'); 838 if (a == Anope::string::npos) 839 return false; 840 841 // If the mode is a prefix mode then it also has a rank. 842 mode.type = token.substr(0, a); 843 if (mode.type == "prefix") 844 { 845 Anope::string::size_type b = token.find(':', a + 1); 846 if (b == Anope::string::npos) 847 return false; 848 849 const Anope::string modelevel = token.substr(a + 1, b - a - 1); 850 mode.level = modelevel.is_pos_number_only() ? convertTo<unsigned>(modelevel) : 0; 851 a = b; 852 } 853 854 Anope::string::size_type c = token.find('=', a + 1); 855 if (c == Anope::string::npos) 856 return false; 857 858 mode.name = token.substr(a + 1, c - a - 1); 859 switch (token.length() - c) 860 { 861 case 2: 862 mode.letter = token[c + 1]; 863 break; 864 case 3: 865 mode.symbol = token[c + 1]; 866 mode.letter = token[c + 2]; 867 break; 868 default: 869 return false; 870 } 871 872 Log(LOG_DEBUG) << "Parsed mode: " << "type=" << mode.type << " name=" << mode.name << " level=" 873 << mode.level << " symbol=" << mode.symbol << " letter=" << mode.letter; 874 return true; 875 } 876 877 IRCDMessageCapab(Module *creator) : Message::Capab(creator, "CAPAB") { SetFlag(IRCDMESSAGE_SOFT_LIMIT); } 878 879 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 880 { 881 if (params[0].equals_cs("START")) 882 { 883 unsigned int spanningtree_proto_ver = 0; 884 if (params.size() >= 2) 885 spanningtree_proto_ver = params[1].is_pos_number_only() ? convertTo<unsigned>(params[1]) : 0; 886 887 if (spanningtree_proto_ver < 1205) 888 { 889 UplinkSocket::Message() << "ERROR :Protocol mismatch, no or invalid protocol version given in CAPAB START"; 890 Anope::QuitReason = "Protocol mismatch, no or invalid protocol version given in CAPAB START"; 891 Anope::Quitting = true; 892 return; 893 } 894 895 /* reset CAPAB */ 896 Servers::Capab.insert("SERVERS"); 897 Servers::Capab.insert("TOPICLOCK"); 898 IRCD->CanSQLineChannel = false; 899 IRCD->CanSVSHold = false; 900 IRCD->DefaultPseudoclientModes = "+oI"; 901 } 902 else if (params[0].equals_cs("CHANMODES") && params.size() > 1) 903 { 904 spacesepstream ssep(params[1]); 905 Anope::string capab; 906 907 while (ssep.GetToken(capab)) 908 { 909 ModeInfo mode; 910 if (!ParseMode(capab, mode)) 911 continue; 912 913 ChannelMode *cm = NULL; 914 if (mode.name.equals_cs("admin")) 915 cm = new ChannelModeStatus("PROTECT", mode.letter, mode.symbol, mode.level); 916 else if (mode.name.equals_cs("allowinvite")) 917 { 918 cm = new ChannelMode("ALLINVITE", mode.letter); 919 ModeManager::AddChannelMode(new InspIRCdExtban::EntryMatcher("INVITEBAN", "BAN", 'A')); 920 } 921 else if (mode.name.equals_cs("auditorium")) 922 cm = new ChannelMode("AUDITORIUM", mode.letter); 923 else if (mode.name.equals_cs("autoop")) 924 cm = new InspIRCdAutoOpMode(mode.letter); 925 else if (mode.name.equals_cs("ban")) 926 cm = new ChannelModeList("BAN", mode.letter); 927 else if (mode.name.equals_cs("banexception")) 928 cm = new ChannelModeList("EXCEPT", mode.letter); 929 else if (mode.name.equals_cs("blockcaps")) 930 { 931 cm = new ChannelMode("BLOCKCAPS", mode.letter); 932 ModeManager::AddChannelMode(new InspIRCdExtban::EntryMatcher("BLOCKCAPSBAN", "BAN", 'B')); 933 } 934 else if (mode.name.equals_cs("blockcolor")) 935 { 936 cm = new ChannelMode("BLOCKCOLOR", mode.letter); 937 ModeManager::AddChannelMode(new InspIRCdExtban::EntryMatcher("BLOCKCOLORBAN", "BAN", 'c')); 938 } 939 else if (mode.name.equals_cs("c_registered")) 940 cm = new ChannelModeNoone("REGISTERED", mode.letter); 941 else if (mode.name.equals_cs("censor")) 942 cm = new ChannelMode("CENSOR", mode.letter); 943 else if (mode.name.equals_cs("delayjoin")) 944 cm = new ChannelMode("DELAYEDJOIN", mode.letter); 945 else if (mode.name.equals_cs("delaymsg")) 946 cm = new SimpleNumberParamMode("DELAYMSG", mode.letter); 947 else if (mode.name.equals_cs("filter")) 948 cm = new ChannelModeList("FILTER", mode.letter); 949 else if (mode.name.equals_cs("flood")) 950 cm = new ChannelModeFlood(mode.letter); 951 else if (mode.name.equals_cs("founder")) 952 cm = new ChannelModeStatus("OWNER", mode.letter, mode.symbol, mode.level); 953 else if (mode.name.equals_cs("halfop")) 954 cm = new ChannelModeStatus("HALFOP", mode.letter, mode.symbol, mode.level); 955 else if (mode.name.equals_cs("history")) 956 cm = new ChannelModeHistory(mode.letter); 957 else if (mode.name.equals_cs("invex")) 958 cm = new ChannelModeList("INVITEOVERRIDE", mode.letter); 959 else if (mode.name.equals_cs("inviteonly")) 960 cm = new ChannelMode("INVITE", mode.letter); 961 else if (mode.name.equals_cs("joinflood")) 962 cm = new ColonDelimitedParamMode("JOINFLOOD", mode.letter); 963 else if (mode.name.equals_cs("key")) 964 cm = new ChannelModeKey(mode.letter); 965 else if (mode.name.equals_cs("kicknorejoin")) 966 cm = new SimpleNumberParamMode("NOREJOIN", mode.letter); 967 else if (mode.name.equals_cs("limit")) 968 cm = new ChannelModeParam("LIMIT", mode.letter, true); 969 else if (mode.name.equals_cs("moderated")) 970 cm = new ChannelMode("MODERATED", mode.letter); 971 else if (mode.name.equals_cs("nickflood")) 972 cm = new ColonDelimitedParamMode("NICKFLOOD", mode.letter); 973 else if (mode.name.equals_cs("noctcp")) 974 { 975 cm = new ChannelMode("NOCTCP", mode.letter); 976 ModeManager::AddChannelMode(new InspIRCdExtban::EntryMatcher("NOCTCPBAN", "BAN", 'C')); 977 } 978 else if (mode.name.equals_cs("noextmsg")) 979 cm = new ChannelMode("NOEXTERNAL", mode.letter); 980 else if (mode.name.equals_cs("nokick")) 981 { 982 cm = new ChannelMode("NOKICK", mode.letter); 983 ModeManager::AddChannelMode(new InspIRCdExtban::EntryMatcher("NOKICKBAN", "BAN", 'Q')); 984 } 985 else if (mode.name.equals_cs("noknock")) 986 cm = new ChannelMode("NOKNOCK", mode.letter); 987 else if (mode.name.equals_cs("nonick")) 988 { 989 cm = new ChannelMode("NONICK", mode.letter); 990 ModeManager::AddChannelMode(new InspIRCdExtban::EntryMatcher("NONICKBAN", "BAN", 'N')); 991 } 992 else if (mode.name.equals_cs("nonotice")) 993 { 994 cm = new ChannelMode("NONOTICE", mode.letter); 995 ModeManager::AddChannelMode(new InspIRCdExtban::EntryMatcher("NONOTICEBAN", "BAN", 'T')); 996 } 997 else if (mode.name.equals_cs("official-join")) 998 cm = new ChannelModeStatus("OFFICIALJOIN", mode.letter, mode.symbol, mode.level); 999 else if (mode.name.equals_cs("op")) 1000 cm = new ChannelModeStatus("OP", mode.letter, mode.symbol, mode.level); 1001 else if (mode.name.equals_cs("operonly")) 1002 cm = new ChannelModeOperOnly("OPERONLY", mode.letter); 1003 else if (mode.name.equals_cs("operprefix")) 1004 cm = new ChannelModeStatus("OPERPREFIX", mode.letter, mode.symbol, mode.level); 1005 else if (mode.name.equals_cs("permanent")) 1006 cm = new ChannelMode("PERM", mode.letter); 1007 else if (mode.name.equals_cs("private")) 1008 cm = new ChannelMode("PRIVATE", mode.letter); 1009 else if (mode.name.equals_cs("redirect")) 1010 cm = new ChannelModeRedirect(mode.letter); 1011 else if (mode.name.equals_cs("reginvite")) 1012 cm = new ChannelMode("REGISTEREDONLY", mode.letter); 1013 else if (mode.name.equals_cs("regmoderated")) 1014 cm = new ChannelMode("REGMODERATED", mode.letter); 1015 else if (mode.name.equals_cs("secret")) 1016 cm = new ChannelMode("SECRET", mode.letter); 1017 else if (mode.name.equals_cs("sslonly")) 1018 { 1019 cm = new ChannelMode("SSL", mode.letter); 1020 ModeManager::AddChannelMode(new InspIRCdExtban::FingerprintMatcher("SSLBAN", "BAN", 'z')); 1021 } 1022 else if (mode.name.equals_cs("stripcolor")) 1023 { 1024 cm = new ChannelMode("STRIPCOLOR", mode.letter); 1025 ModeManager::AddChannelMode(new InspIRCdExtban::EntryMatcher("STRIPCOLORBAN", "BAN", 'S')); 1026 } 1027 else if (mode.name.equals_cs("topiclock")) 1028 cm = new ChannelMode("TOPIC", mode.letter); 1029 else if (mode.name.equals_cs("voice")) 1030 cm = new ChannelModeStatus("VOICE", mode.letter, mode.symbol, mode.level); 1031 1032 // Handle unknown modes. 1033 else if (mode.type.equals_cs("list")) 1034 cm = new ChannelModeList(mode.name.upper(), mode.letter); 1035 else if (mode.type.equals_cs("param-set")) 1036 cm = new ChannelModeParam(mode.name.upper(), mode.letter, true); 1037 else if (mode.type.equals_cs("param")) 1038 cm = new ChannelModeParam(mode.name.upper(), mode.letter, false); 1039 else if (mode.type.equals_cs("prefix")) 1040 cm = new ChannelModeStatus(mode.name.upper(), mode.letter, mode.symbol, mode.level); 1041 else if (mode.type.equals_cs("simple")) 1042 cm = new ChannelMode(mode.name.upper(), mode.letter); 1043 else 1044 Log(LOG_DEBUG) << "Unknown channel mode: " << capab; 1045 1046 if (cm) 1047 ModeManager::AddChannelMode(cm); 1048 } 1049 } 1050 if (params[0].equals_cs("USERMODES") && params.size() > 1) 1051 { 1052 spacesepstream ssep(params[1]); 1053 Anope::string capab; 1054 1055 while (ssep.GetToken(capab)) 1056 { 1057 ModeInfo mode; 1058 if (!ParseMode(capab, mode)) 1059 continue; 1060 1061 UserMode *um = NULL; 1062 if (mode.name.equals_cs("bot")) 1063 { 1064 um = new UserMode("BOT", mode.letter); 1065 IRCD->DefaultPseudoclientModes += mode.letter; 1066 } 1067 else if (mode.name.equals_cs("callerid")) 1068 um = new UserMode("CALLERID", mode.letter); 1069 else if (mode.name.equals_cs("cloak")) 1070 um = new UserMode("CLOAK", mode.letter); 1071 else if (mode.name.equals_cs("deaf")) 1072 um = new UserMode("DEAF", mode.letter); 1073 else if (mode.name.equals_cs("deaf_commonchan")) 1074 um = new UserMode("COMMONCHANS", mode.letter); 1075 else if (mode.name.equals_cs("helpop")) 1076 um = new UserModeOperOnly("HELPOP", mode.letter); 1077 else if (mode.name.equals_cs("hidechans")) 1078 um = new UserMode("PRIV", mode.letter); 1079 else if (mode.name.equals_cs("hideoper")) 1080 um = new UserModeOperOnly("HIDEOPER", mode.letter); 1081 else if (mode.name.equals_cs("invisible")) 1082 um = new UserMode("INVIS", mode.letter); 1083 else if (mode.name.equals_cs("invis-oper")) 1084 um = new UserModeOperOnly("INVISIBLE_OPER", mode.letter); 1085 else if (mode.name.equals_cs("oper")) 1086 um = new UserModeOperOnly("OPER", mode.letter); 1087 else if (mode.name.equals_cs("regdeaf")) 1088 um = new UserMode("REGPRIV", mode.letter); 1089 else if (mode.name.equals_cs("servprotect")) 1090 { 1091 um = new UserModeNoone("PROTECTED", mode.letter); 1092 IRCD->DefaultPseudoclientModes += mode.letter; 1093 } 1094 else if (mode.name.equals_cs("showwhois")) 1095 um = new UserMode("WHOIS", mode.letter); 1096 else if (mode.name.equals_cs("u_censor")) 1097 um = new UserMode("CENSOR", mode.letter); 1098 else if (mode.name.equals_cs("u_registered")) 1099 um = new UserModeNoone("REGISTERED", mode.letter); 1100 else if (mode.name.equals_cs("u_stripcolor")) 1101 um = new UserMode("STRIPCOLOR", mode.letter); 1102 else if (mode.name.equals_cs("wallops")) 1103 um = new UserMode("WALLOPS", mode.letter); 1104 1105 // Handle unknown modes. 1106 else if (mode.type.equals_cs("param-set")) 1107 um = new UserModeParam(mode.name.upper(), mode.letter); 1108 else if (mode.type.equals_cs("simple")) 1109 um = new UserMode(mode.name.upper(), mode.letter); 1110 else 1111 Log(LOG_DEBUG) << "Unknown user mode: " << capab; 1112 1113 if (um) 1114 ModeManager::AddUserMode(um); 1115 } 1116 } 1117 else if (params[0].equals_cs("MODULES") && params.size() > 1) 1118 { 1119 spacesepstream ssep(params[1]); 1120 Anope::string module; 1121 1122 while (ssep.GetToken(module)) 1123 { 1124 if (module.equals_cs("m_svshold.so")) 1125 IRCD->CanSVSHold = true; 1126 else if (module.find("m_rline.so") == 0) 1127 { 1128 Servers::Capab.insert("RLINE"); 1129 const Anope::string ®exengine = Config->GetBlock("options")->Get<const Anope::string>("regexengine"); 1130 if (!regexengine.empty() && module.length() > 11 && regexengine != module.substr(11)) 1131 Log() << "Warning: InspIRCd is using regex engine " << module.substr(11) << ", but we have " << regexengine << ". This may cause inconsistencies."; 1132 } 1133 else if (module.equals_cs("m_topiclock.so")) 1134 Servers::Capab.insert("TOPICLOCK"); 1135 else if (module.equals_cs("m_cban.so=glob")) 1136 IRCD->CanSQLineChannel = true; 1137 } 1138 } 1139 else if (params[0].equals_cs("MODSUPPORT") && params.size() > 1) 1140 { 1141 spacesepstream ssep(params[1]); 1142 Anope::string module; 1143 1144 while (ssep.GetToken(module)) 1145 { 1146 if (module.equals_cs("m_services_account.so")) 1147 { 1148 Servers::Capab.insert("SERVICES"); 1149 ModeManager::AddChannelMode(new InspIRCdExtban::AccountMatcher("ACCOUNTBAN", "BAN", 'R')); 1150 ModeManager::AddChannelMode(new InspIRCdExtban::UnidentifiedMatcher("UNREGISTEREDBAN", "BAN", 'U')); 1151 } 1152 else if (module.equals_cs("m_chghost.so")) 1153 Servers::Capab.insert("CHGHOST"); 1154 else if (module.equals_cs("m_chgident.so")) 1155 Servers::Capab.insert("CHGIDENT"); 1156 else if (module == "m_channelban.so") 1157 ModeManager::AddChannelMode(new InspIRCdExtban::ChannelMatcher("CHANNELBAN", "BAN", 'j')); 1158 else if (module == "m_gecosban.so") 1159 ModeManager::AddChannelMode(new InspIRCdExtban::RealnameMatcher("REALNAMEBAN", "BAN", 'r')); 1160 else if (module == "m_nopartmessage.so") 1161 ModeManager::AddChannelMode(new InspIRCdExtban::EntryMatcher("PARTMESSAGEBAN", "BAN", 'p')); 1162 else if (module == "m_serverban.so") 1163 ModeManager::AddChannelMode(new InspIRCdExtban::ServerMatcher("SERVERBAN", "BAN", 's')); 1164 else if (module == "m_muteban.so") 1165 ModeManager::AddChannelMode(new InspIRCdExtban::EntryMatcher("QUIET", "BAN", 'm')); 1166 } 1167 } 1168 else if (params[0].equals_cs("CAPABILITIES") && params.size() > 1) 1169 { 1170 spacesepstream ssep(params[1]); 1171 Anope::string capab; 1172 while (ssep.GetToken(capab)) 1173 { 1174 if (capab.find("MAXMODES=") != Anope::string::npos) 1175 { 1176 Anope::string maxmodes(capab.begin() + 9, capab.end()); 1177 IRCD->MaxModes = maxmodes.is_pos_number_only() ? convertTo<unsigned>(maxmodes) : 3; 1178 } 1179 else if (capab == "GLOBOPS=1") 1180 Servers::Capab.insert("GLOBOPS"); 1181 } 1182 } 1183 else if (params[0].equals_cs("END")) 1184 { 1185 if (!Servers::Capab.count("SERVICES")) 1186 { 1187 UplinkSocket::Message() << "ERROR :The services_account module is not loaded. This is required by Anope"; 1188 Anope::QuitReason = "ERROR: Remote server does not have the services_account module loaded, and this is required."; 1189 Anope::Quitting = true; 1190 return; 1191 } 1192 if (!ModeManager::FindUserModeByName("PRIV")) 1193 { 1194 UplinkSocket::Message() << "ERROR :The hidechans module is not loaded. This is required by Anope"; 1195 Anope::QuitReason = "ERROR: Remote server does not have the hidechans module loaded, and this is required."; 1196 Anope::Quitting = true; 1197 return; 1198 } 1199 if (!IRCD->CanSVSHold) 1200 Log() << "SVSHOLD missing, Usage disabled until module is loaded."; 1201 if (!Servers::Capab.count("CHGHOST")) 1202 Log() << "CHGHOST missing, Usage disabled until module is loaded."; 1203 if (!Servers::Capab.count("CHGIDENT")) 1204 Log() << "CHGIDENT missing, Usage disabled until module is loaded."; 1205 } 1206 1207 Message::Capab::Run(source, params); 1208 } 1209 }; 1210 1211 struct IRCDMessageEncap : IRCDMessage 1212 { 1213 IRCDMessageEncap(Module *creator) : IRCDMessage(creator, "ENCAP", 4) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); } 1214 1215 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1216 { 1217 if (!Anope::Match(Me->GetSID(), params[0]) && !Anope::Match(Me->GetName(), params[0])) 1218 return; 1219 1220 if (params[1] == "CHGIDENT") 1221 { 1222 User *u = User::Find(params[2]); 1223 if (!u || u->server != Me) 1224 return; 1225 1226 u->SetIdent(params[3]); 1227 UplinkSocket::Message(u) << "FIDENT :" << params[3]; 1228 } 1229 else if (params[1] == "CHGHOST") 1230 { 1231 User *u = User::Find(params[2]); 1232 if (!u || u->server != Me) 1233 return; 1234 1235 u->SetDisplayedHost(params[3]); 1236 UplinkSocket::Message(u) << "FHOST :" << params[3]; 1237 } 1238 else if (params[1] == "CHGNAME") 1239 { 1240 User *u = User::Find(params[2]); 1241 if (!u || u->server != Me) 1242 return; 1243 1244 u->SetRealname(params[3]); 1245 UplinkSocket::Message(u) << "FNAME :" << params[3]; 1246 } 1247 else if (SASL::sasl && params[1] == "SASL" && params.size() >= 6) 1248 { 1249 SASL::Message m; 1250 m.source = params[2]; 1251 m.target = params[3]; 1252 m.type = params[4]; 1253 m.data = params[5]; 1254 m.ext = params.size() > 6 ? params[6] : ""; 1255 1256 SASL::sasl->ProcessMessage(m); 1257 } 1258 } 1259 }; 1260 1261 struct IRCDMessageFHost : IRCDMessage 1262 { 1263 IRCDMessageFHost(Module *creator) : IRCDMessage(creator, "FHOST", 1) { SetFlag(IRCDMESSAGE_REQUIRE_USER); } 1264 1265 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1266 { 1267 User *u = source.GetUser(); 1268 if (u->HasMode("CLOAK")) 1269 u->RemoveModeInternal(source, ModeManager::FindUserModeByName("CLOAK")); 1270 u->SetDisplayedHost(params[0]); 1271 } 1272 }; 1273 1274 struct IRCDMessageFIdent : IRCDMessage 1275 { 1276 IRCDMessageFIdent(Module *creator) : IRCDMessage(creator, "FIDENT", 1) { SetFlag(IRCDMESSAGE_REQUIRE_USER); } 1277 1278 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1279 { 1280 source.GetUser()->SetIdent(params[0]); 1281 } 1282 }; 1283 1284 struct IRCDMessageKick : IRCDMessage 1285 { 1286 IRCDMessageKick(Module *creator) : IRCDMessage(creator, "KICK", 3) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); } 1287 1288 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1289 { 1290 // Received: :715AAAAAA KICK #chan 715AAAAAD :reason 1291 // Received: :715AAAAAA KICK #chan 628AAAAAA 4 :reason 1292 Channel *c = Channel::Find(params[0]); 1293 if (!c) 1294 return; 1295 1296 const Anope::string &reason = params.size() > 3 ? params[3] : params[2]; 1297 c->KickInternal(source, params[1], reason); 1298 } 1299 }; 1300 1301 struct IRCDMessageSave : IRCDMessage 1302 { 1303 time_t last_collide; 1304 1305 IRCDMessageSave(Module *creator) : IRCDMessage(creator, "SAVE", 2), last_collide(0) { } 1306 1307 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1308 { 1309 User *targ = User::Find(params[0]); 1310 time_t ts; 1311 1312 try 1313 { 1314 ts = convertTo<time_t>(params[1]); 1315 } 1316 catch (const ConvertException &) 1317 { 1318 return; 1319 } 1320 1321 if (!targ || targ->timestamp != ts) 1322 return; 1323 1324 BotInfo *bi; 1325 if (targ->server == Me && (bi = dynamic_cast<BotInfo *>(targ))) 1326 { 1327 if (last_collide == Anope::CurTime) 1328 { 1329 Anope::QuitReason = "Nick collision fight on " + targ->nick; 1330 Anope::Quitting = true; 1331 return; 1332 } 1333 1334 IRCD->SendKill(Me, targ->nick, "Nick collision"); 1335 IRCD->SendNickChange(targ, targ->nick); 1336 last_collide = Anope::CurTime; 1337 } 1338 else 1339 targ->ChangeNick(targ->GetUID()); 1340 } 1341 }; 1342 1343 class IRCDMessageMetadata : IRCDMessage 1344 { 1345 const bool &do_topiclock; 1346 const bool &do_mlock; 1347 PrimitiveExtensibleItem<ListLimits> &maxlist; 1348 1349 public: 1350 IRCDMessageMetadata(Module *creator, const bool &handle_topiclock, const bool &handle_mlock, PrimitiveExtensibleItem<ListLimits> &listlimits) : IRCDMessage(creator, "METADATA", 3), do_topiclock(handle_topiclock), do_mlock(handle_mlock), maxlist(listlimits) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); SetFlag(IRCDMESSAGE_SOFT_LIMIT); } 1351 1352 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1353 { 1354 // We deliberately ignore non-bursting servers to avoid pseudoserver fights 1355 // Channel METADATA has an additional parameter: the channel TS 1356 // Received: :715 METADATA #chan 1572026333 mlock :nt 1357 if ((params[0][0] == '#') && (params.size() > 3) && (!source.GetServer()->IsSynced())) 1358 { 1359 Channel *c = Channel::Find(params[0]); 1360 if (c) 1361 { 1362 if ((c->ci) && (do_mlock) && (params[2] == "mlock")) 1363 { 1364 ModeLocks *modelocks = c->ci->GetExt<ModeLocks>("modelocks"); 1365 Anope::string modes; 1366 if (modelocks) 1367 modes = modelocks->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", ""); 1368 1369 // Mode lock string is not what we say it is? 1370 if (modes != params[3]) 1371 UplinkSocket::Message(Me) << "METADATA " << c->name << " " << c->creation_time << " mlock :" << modes; 1372 } 1373 else if ((c->ci) && (do_topiclock) && (params[2] == "topiclock")) 1374 { 1375 bool mystate = c->ci->HasExt("TOPICLOCK"); 1376 bool serverstate = (params[3] == "1"); 1377 if (mystate != serverstate) 1378 UplinkSocket::Message(Me) << "METADATA " << c->name << " " << c->creation_time << " topiclock :" << (mystate ? "1" : ""); 1379 } 1380 else if (params[2] == "maxlist") 1381 { 1382 ListLimits limits; 1383 spacesepstream limitstream(params[3]); 1384 Anope::string modechr, modelimit; 1385 while (limitstream.GetToken(modechr) && limitstream.GetToken(modelimit)) 1386 { 1387 limits.insert(std::make_pair(modechr[0], convertTo<unsigned>(modelimit))); 1388 } 1389 maxlist.Set(c, limits); 1390 } 1391 } 1392 } 1393 else if (isdigit(params[0][0])) 1394 { 1395 if (params[1].equals_cs("accountname")) 1396 { 1397 User *u = User::Find(params[0]); 1398 NickCore *nc = NickCore::Find(params[2]); 1399 if (u && nc) 1400 u->Login(nc); 1401 } 1402 1403 /* 1404 * possible incoming ssl_cert messages: 1405 * Received: :409 METADATA 409AAAAAA ssl_cert :vTrSe c38070ce96e41cc144ed6590a68d45a6 <...> <...> 1406 * Received: :409 METADATA 409AAAAAC ssl_cert :vTrSE Could not get peer certificate: error:00000000:lib(0):func(0):reason(0) 1407 */ 1408 else if (params[1].equals_cs("ssl_cert")) 1409 { 1410 User *u = User::Find(params[0]); 1411 if (!u) 1412 return; 1413 u->Extend<bool>("ssl"); 1414 Anope::string data = params[2].c_str(); 1415 size_t pos1 = data.find(' ') + 1; 1416 size_t pos2 = data.find(' ', pos1); 1417 if ((pos2 - pos1) >= 32) // inspircd supports md5 and sha1 fingerprint hashes -> size 32 or 40 bytes. 1418 { 1419 u->fingerprint = data.substr(pos1, pos2 - pos1); 1420 } 1421 FOREACH_MOD(OnFingerprint, (u)); 1422 } 1423 } 1424 else if (params[0] == "*") 1425 { 1426 // Wed Oct 3 15:40:27 2012: S[14] O :20D METADATA * modules :-m_svstopic.so 1427 1428 if (params[1].equals_cs("modules") && !params[2].empty()) 1429 { 1430 // only interested when it comes from our uplink 1431 Server* server = source.GetServer(); 1432 if (!server || server->GetUplink() != Me) 1433 return; 1434 1435 bool plus = (params[2][0] == '+'); 1436 if (!plus && params[2][0] != '-') 1437 return; 1438 1439 bool required = false; 1440 Anope::string capab, module = params[2].substr(1); 1441 1442 if (module.equals_cs("m_services_account.so")) 1443 required = true; 1444 else if (module.equals_cs("m_hidechans.so")) 1445 required = true; 1446 else if (module.equals_cs("m_chghost.so")) 1447 capab = "CHGHOST"; 1448 else if (module.equals_cs("m_chgident.so")) 1449 capab = "CHGIDENT"; 1450 else if (module.equals_cs("m_svshold.so")) 1451 capab = "SVSHOLD"; 1452 else if (module.equals_cs("m_rline.so")) 1453 capab = "RLINE"; 1454 else if (module.equals_cs("m_topiclock.so")) 1455 capab = "TOPICLOCK"; 1456 else 1457 return; 1458 1459 if (required) 1460 { 1461 if (!plus) 1462 Log() << "Warning: InspIRCd unloaded module " << module << ", Anope won't function correctly without it"; 1463 } 1464 else 1465 { 1466 if (plus) 1467 Servers::Capab.insert(capab); 1468 else 1469 Servers::Capab.erase(capab); 1470 1471 Log() << "InspIRCd " << (plus ? "loaded" : "unloaded") << " module " << module << ", adjusted functionality"; 1472 } 1473 1474 } 1475 } 1476 } 1477 }; 1478 1479 struct IRCDMessageEndburst : IRCDMessage 1480 { 1481 IRCDMessageEndburst(Module *creator) : IRCDMessage(creator, "ENDBURST", 0) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); } 1482 1483 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1484 { 1485 Server *s = source.GetServer(); 1486 1487 Log(LOG_DEBUG) << "Processed ENDBURST for " << s->GetName(); 1488 1489 s->Sync(true); 1490 } 1491 }; 1492 1493 struct IRCDMessageFJoin : IRCDMessage 1494 { 1495 IRCDMessageFJoin(Module *creator) : IRCDMessage(creator, "FJOIN", 2) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); SetFlag(IRCDMESSAGE_SOFT_LIMIT); } 1496 1497 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1498 { 1499 Anope::string modes; 1500 if (params.size() >= 3) 1501 { 1502 for (unsigned i = 2; i < params.size() - 1; ++i) 1503 modes += " " + params[i]; 1504 if (!modes.empty()) 1505 modes.erase(modes.begin()); 1506 } 1507 1508 std::list<Message::Join::SJoinUser> users; 1509 1510 spacesepstream sep(params[params.size() - 1]); 1511 Anope::string buf; 1512 while (sep.GetToken(buf)) 1513 { 1514 Message::Join::SJoinUser sju; 1515 1516 /* Loop through prefixes and find modes for them */ 1517 for (char c; (c = buf[0]) != ',' && c;) 1518 { 1519 buf.erase(buf.begin()); 1520 sju.first.AddMode(c); 1521 } 1522 /* Erase the , */ 1523 if (!buf.empty()) 1524 buf.erase(buf.begin()); 1525 1526 /* Erase the :membid */ 1527 if (!buf.empty()) 1528 { 1529 Anope::string::size_type membid = buf.find(':'); 1530 if (membid != Anope::string::npos) 1531 buf.erase(membid, Anope::string::npos); 1532 } 1533 1534 sju.second = User::Find(buf); 1535 if (!sju.second) 1536 { 1537 Log(LOG_DEBUG) << "FJOIN for nonexistent user " << buf << " on " << params[0]; 1538 continue; 1539 } 1540 1541 users.push_back(sju); 1542 } 1543 1544 time_t ts = Anope::string(params[1]).is_pos_number_only() ? convertTo<time_t>(params[1]) : Anope::CurTime; 1545 Message::Join::SJoin(source, params[0], ts, modes, users); 1546 } 1547 }; 1548 1549 struct IRCDMessageFMode : IRCDMessage 1550 { 1551 IRCDMessageFMode(Module *creator) : IRCDMessage(creator, "FMODE", 3) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); } 1552 1553 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1554 { 1555 /* :source FMODE #test 12345678 +nto foo */ 1556 1557 Anope::string modes = params[2]; 1558 for (unsigned n = 3; n < params.size(); ++n) 1559 modes += " " + params[n]; 1560 1561 Channel *c = Channel::Find(params[0]); 1562 time_t ts; 1563 1564 try 1565 { 1566 ts = convertTo<time_t>(params[1]); 1567 } 1568 catch (const ConvertException &) 1569 { 1570 ts = 0; 1571 } 1572 1573 if (c) 1574 c->SetModesInternal(source, modes, ts); 1575 } 1576 }; 1577 1578 struct IRCDMessageFTopic : IRCDMessage 1579 { 1580 IRCDMessageFTopic(Module *creator) : IRCDMessage(creator, "FTOPIC", 4) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); } 1581 1582 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1583 { 1584 // :source FTOPIC channel ts topicts :topic 1585 // :source FTOPIC channel ts topicts setby :topic (burst or RESYNC) 1586 1587 const Anope::string &setby = params.size() > 4 ? params[3] : source.GetName(); 1588 const Anope::string &topic = params.size() > 4 ? params[4] : params[3]; 1589 1590 Channel *c = Channel::Find(params[0]); 1591 if (c) 1592 c->ChangeTopicInternal(NULL, setby, topic, params[2].is_pos_number_only() ? convertTo<time_t>(params[2]) : Anope::CurTime); 1593 } 1594 }; 1595 1596 struct IRCDMessageIdle : IRCDMessage 1597 { 1598 IRCDMessageIdle(Module *creator) : IRCDMessage(creator, "IDLE", 1) { } 1599 1600 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1601 { 1602 BotInfo *bi = BotInfo::Find(params[0]); 1603 if (bi) 1604 UplinkSocket::Message(bi) << "IDLE " << source.GetSource() << " " << Anope::StartTime << " " << (Anope::CurTime - bi->lastmsg); 1605 else 1606 { 1607 User *u = User::Find(params[0]); 1608 if (u && u->server == Me) 1609 UplinkSocket::Message(u) << "IDLE " << source.GetSource() << " " << Anope::StartTime << " 0"; 1610 } 1611 } 1612 }; 1613 1614 struct IRCDMessageIJoin : IRCDMessage 1615 { 1616 IRCDMessageIJoin(Module *creator) : IRCDMessage(creator, "IJOIN", 2) { SetFlag(IRCDMESSAGE_REQUIRE_USER); SetFlag(IRCDMESSAGE_SOFT_LIMIT); } 1617 1618 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1619 { 1620 // :<uid> IJOIN <chan> <membid> [<ts> [<flags>]] 1621 Channel *c = Channel::Find(params[0]); 1622 if (!c) 1623 { 1624 // When receiving an IJOIN, first check if the target channel exists. If it does not exist, 1625 // ignore the join (that is, do not create the channel) and send a RESYNC back to the source. 1626 UplinkSocket::Message(Me) << "RESYNC :" << params[0]; 1627 return; 1628 } 1629 1630 // If the channel does exist then join the user, and in case any prefix modes were sent (found in 1631 // the 3rd parameter), compare the TS of the channel to the TS in the IJOIN (2nd parameter). If 1632 // the timestamps match, set the modes on the user, otherwise ignore the modes. 1633 Message::Join::SJoinUser user; 1634 user.second = source.GetUser(); 1635 1636 time_t chants = Anope::CurTime; 1637 if (params.size() >= 4) 1638 { 1639 chants = params[2].is_pos_number_only() ? convertTo<unsigned>(params[2]) : 0; 1640 for (unsigned i = 0; i < params[3].length(); ++i) 1641 user.first.AddMode(params[3][i]); 1642 } 1643 1644 std::list<Message::Join::SJoinUser> users; 1645 users.push_back(user); 1646 Message::Join::SJoin(source, params[0], chants, "", users); 1647 } 1648 }; 1649 1650 struct IRCDMessageMode : IRCDMessage 1651 { 1652 IRCDMessageMode(Module *creator) : IRCDMessage(creator, "MODE", 2) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); } 1653 1654 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1655 { 1656 if (IRCD->IsChannelValid(params[0])) 1657 { 1658 Channel *c = Channel::Find(params[0]); 1659 1660 Anope::string modes = params[1]; 1661 for (unsigned n = 2; n < params.size(); ++n) 1662 modes += " " + params[n]; 1663 1664 if (c) 1665 c->SetModesInternal(source, modes); 1666 } 1667 else 1668 { 1669 /* InspIRCd lets opers change another 1670 users modes, we have to kludge this 1671 as it slightly breaks RFC1459 1672 */ 1673 User *u = User::Find(params[0]); 1674 if (u) 1675 u->SetModesInternal(source, "%s", params[1].c_str()); 1676 } 1677 } 1678 }; 1679 1680 struct IRCDMessageNick : IRCDMessage 1681 { 1682 IRCDMessageNick(Module *creator) : IRCDMessage(creator, "NICK", 2) { SetFlag(IRCDMESSAGE_REQUIRE_USER); } 1683 1684 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1685 { 1686 source.GetUser()->ChangeNick(params[0]); 1687 } 1688 }; 1689 1690 struct IRCDMessageOperType : IRCDMessage 1691 { 1692 IRCDMessageOperType(Module *creator) : IRCDMessage(creator, "OPERTYPE", 0) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); SetFlag(IRCDMESSAGE_REQUIRE_USER); } 1693 1694 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1695 { 1696 /* opertype is equivalent to mode +o because servers 1697 don't do this directly */ 1698 User *u = source.GetUser(); 1699 if (!u->HasMode("OPER")) 1700 u->SetModesInternal(source, "+o"); 1701 } 1702 }; 1703 1704 struct IRCDMessagePing : IRCDMessage 1705 { 1706 IRCDMessagePing(Module *creator) : IRCDMessage(creator, "PING", 1) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); SetFlag(IRCDMESSAGE_REQUIRE_SERVER); } 1707 1708 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1709 { 1710 if (params[0] == Me->GetSID()) 1711 IRCD->SendPong(params[0], source.GetServer()->GetSID()); 1712 } 1713 }; 1714 1715 struct IRCDMessageRSQuit : IRCDMessage 1716 { 1717 IRCDMessageRSQuit(Module *creator) : IRCDMessage(creator, "RSQUIT", 1) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); } 1718 1719 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1720 { 1721 Server *s = Server::Find(params[0]); 1722 const Anope::string &reason = params.size() > 1 ? params[1] : ""; 1723 if (!s) 1724 return; 1725 1726 UplinkSocket::Message(Me) << "SQUIT " << s->GetSID() << " :" << reason; 1727 s->Delete(s->GetName() + " " + s->GetUplink()->GetName()); 1728 } 1729 }; 1730 1731 struct IRCDMessageServer : IRCDMessage 1732 { 1733 IRCDMessageServer(Module *creator) : IRCDMessage(creator, "SERVER", 3) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); SetFlag(IRCDMESSAGE_SOFT_LIMIT); } 1734 1735 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1736 { 1737 if (!source.GetServer() && params.size() == 5) 1738 { 1739 /* 1740 * SERVER testnet.inspircd.org hunter7 0 123 :InspIRCd Test Network 1741 * 0: name 1742 * 1: pass 1743 * 2: hops 1744 * 3: numeric 1745 * 4: desc 1746 */ 1747 unsigned int hops = Anope::string(params[2]).is_pos_number_only() ? convertTo<unsigned>(params[2]) : 0; 1748 new Server(Me, params[0], hops, params[4], params[3]); 1749 } 1750 else if (source.GetServer()) 1751 { 1752 /* 1753 * SERVER testnet.inspircd.org 123 burst=1234 hidden=0 :InspIRCd Test Network 1754 * 0: name 1755 * 1: numeric 1756 * 2 to N-1: various key=value pairs. 1757 * N: desc 1758 */ 1759 new Server(source.GetServer(), params[0], 1, params.back(), params[1]); 1760 } 1761 } 1762 }; 1763 1764 struct IRCDMessageSQuit : Message::SQuit 1765 { 1766 IRCDMessageSQuit(Module *creator) : Message::SQuit(creator) { } 1767 1768 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1769 { 1770 if (params[0] == rsquit_id || params[0] == rsquit_server) 1771 { 1772 /* squit for a recently squit server, introduce the juped server now */ 1773 Server *s = Server::Find(rsquit_server); 1774 1775 rsquit_id.clear(); 1776 rsquit_server.clear(); 1777 1778 if (s && s->IsJuped()) 1779 IRCD->SendServer(s); 1780 } 1781 else 1782 Message::SQuit::Run(source, params); 1783 } 1784 }; 1785 1786 struct IRCDMessageTime : IRCDMessage 1787 { 1788 IRCDMessageTime(Module *creator) : IRCDMessage(creator, "TIME", 2) { } 1789 1790 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1791 { 1792 UplinkSocket::Message(Me) << "TIME " << source.GetSource() << " " << params[1] << " " << Anope::CurTime; 1793 } 1794 }; 1795 1796 struct IRCDMessageUID : IRCDMessage 1797 { 1798 IRCDMessageUID(Module *creator) : IRCDMessage(creator, "UID", 8) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); SetFlag(IRCDMESSAGE_SOFT_LIMIT); } 1799 1800 /* 1801 * [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> 1802 * 0: uid 1803 * 1: ts 1804 * 2: nick 1805 * 3: host 1806 * 4: dhost 1807 * 5: ident 1808 * 6: ip 1809 * 7: signon 1810 * 8+: modes and params -- IMPORTANT, some modes (e.g. +s) may have parameters. So don't assume a fixed position of realname! 1811 * last: realname 1812 */ 1813 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1814 { 1815 time_t ts = convertTo<time_t>(params[1]); 1816 1817 Anope::string modes = params[8]; 1818 for (unsigned i = 9; i < params.size() - 1; ++i) 1819 modes += " " + params[i]; 1820 1821 NickAlias *na = NULL; 1822 if (SASL::sasl) 1823 for (std::list<SASLUser>::iterator it = saslusers.begin(); it != saslusers.end();) 1824 { 1825 SASLUser &u = *it; 1826 1827 if (u.created + 30 < Anope::CurTime) 1828 it = saslusers.erase(it); 1829 else if (u.uid == params[0]) 1830 { 1831 na = NickAlias::Find(u.acc); 1832 it = saslusers.erase(it); 1833 } 1834 else 1835 ++it; 1836 } 1837 1838 User *u = User::OnIntroduce(params[2], params[5], params[3], params[4], params[6], source.GetServer(), params[params.size() - 1], ts, modes, params[0], na ? *na->nc : NULL); 1839 if (u) 1840 u->signon = convertTo<time_t>(params[7]); 1841 } 1842 }; 1843 1844 class ProtoInspIRCd3 : public Module 1845 { 1846 InspIRCd3Proto ircd_proto; 1847 ExtensibleItem<bool> ssl; 1848 1849 /* Core message handlers */ 1850 Message::Error message_error; 1851 Message::Invite message_invite; 1852 Message::Kill message_kill; 1853 Message::MOTD message_motd; 1854 Message::Notice message_notice; 1855 Message::Part message_part; 1856 Message::Privmsg message_privmsg; 1857 Message::Quit message_quit; 1858 Message::Stats message_stats; 1859 1860 /* Our message handlers */ 1861 IRCDMessageAway message_away; 1862 IRCDMessageCapab message_capab; 1863 IRCDMessageEncap message_encap; 1864 IRCDMessageEndburst message_endburst; 1865 IRCDMessageFHost message_fhost; 1866 IRCDMessageFIdent message_fident; 1867 IRCDMessageFJoin message_fjoin; 1868 IRCDMessageFMode message_fmode; 1869 IRCDMessageFTopic message_ftopic; 1870 IRCDMessageIdle message_idle; 1871 IRCDMessageIJoin message_ijoin; 1872 IRCDMessageKick message_kick; 1873 IRCDMessageMetadata message_metadata; 1874 IRCDMessageMode message_mode; 1875 IRCDMessageNick message_nick; 1876 IRCDMessageOperType message_opertype; 1877 IRCDMessagePing message_ping; 1878 IRCDMessageRSQuit message_rsquit; 1879 IRCDMessageSave message_save; 1880 IRCDMessageServer message_server; 1881 IRCDMessageSQuit message_squit; 1882 IRCDMessageTime message_time; 1883 IRCDMessageUID message_uid; 1884 1885 bool use_server_side_topiclock, use_server_side_mlock; 1886 1887 void SendChannelMetadata(Channel *c, const Anope::string &metadataname, const Anope::string &value) 1888 { 1889 UplinkSocket::Message(Me) << "METADATA " << c->name << " " << c->creation_time << " " << metadataname << " :" << value; 1890 } 1891 1892 public: 1893 ProtoInspIRCd3(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, PROTOCOL | VENDOR), 1894 ircd_proto(this), ssl(this, "ssl"), 1895 message_error(this), message_invite(this), message_kill(this), message_motd(this), message_notice(this), 1896 message_part(this), message_privmsg(this), message_quit(this), message_stats(this), 1897 message_away(this), message_capab(this), message_encap(this), message_endburst(this), message_fhost(this), 1898 message_fident(this), message_fjoin(this), message_fmode(this), message_ftopic(this), message_idle(this), 1899 message_ijoin(this), message_kick(this), message_metadata(this, use_server_side_topiclock, use_server_side_mlock, ircd_proto.maxlist), 1900 message_mode(this), message_nick(this), message_opertype(this), message_ping(this), message_rsquit(this), 1901 message_save(this), message_server(this), message_squit(this), message_time(this), message_uid(this) 1902 { 1903 } 1904 1905 void OnReload(Configuration::Conf *conf) anope_override 1906 { 1907 use_server_side_topiclock = conf->GetModule(this)->Get<bool>("use_server_side_topiclock"); 1908 use_server_side_mlock = conf->GetModule(this)->Get<bool>("use_server_side_mlock"); 1909 } 1910 1911 void OnUserNickChange(User *u, const Anope::string &) anope_override 1912 { 1913 u->RemoveModeInternal(Me, ModeManager::FindUserModeByName("REGISTERED")); 1914 } 1915 1916 void OnChannelSync(Channel *c) anope_override 1917 { 1918 if (c->ci) 1919 this->OnChanRegistered(c->ci); 1920 } 1921 1922 void OnChanRegistered(ChannelInfo *ci) anope_override 1923 { 1924 ModeLocks *modelocks = ci->GetExt<ModeLocks>("modelocks"); 1925 if (use_server_side_mlock && ci->c && modelocks && !modelocks->GetMLockAsString(false).empty()) 1926 { 1927 Anope::string modes = modelocks->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", ""); 1928 SendChannelMetadata(ci->c, "mlock", modes); 1929 } 1930 1931 if (use_server_side_topiclock && Servers::Capab.count("TOPICLOCK") && ci->c) 1932 { 1933 if (ci->HasExt("TOPICLOCK")) 1934 SendChannelMetadata(ci->c, "topiclock", "1"); 1935 } 1936 } 1937 1938 void OnDelChan(ChannelInfo *ci) anope_override 1939 { 1940 if (use_server_side_mlock && ci->c) 1941 SendChannelMetadata(ci->c, "mlock", ""); 1942 1943 if (use_server_side_topiclock && Servers::Capab.count("TOPICLOCK") && ci->c) 1944 SendChannelMetadata(ci->c, "topiclock", ""); 1945 } 1946 1947 EventReturn OnMLock(ChannelInfo *ci, ModeLock *lock) anope_override 1948 { 1949 ModeLocks *modelocks = ci->GetExt<ModeLocks>("modelocks"); 1950 ChannelMode *cm = ModeManager::FindChannelModeByName(lock->name); 1951 if (use_server_side_mlock && cm && ci->c && modelocks && (cm->type == MODE_REGULAR || cm->type == MODE_PARAM)) 1952 { 1953 Anope::string modes = modelocks->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", "") + cm->mchar; 1954 SendChannelMetadata(ci->c, "mlock", modes); 1955 } 1956 1957 return EVENT_CONTINUE; 1958 } 1959 1960 EventReturn OnUnMLock(ChannelInfo *ci, ModeLock *lock) anope_override 1961 { 1962 ModeLocks *modelocks = ci->GetExt<ModeLocks>("modelocks"); 1963 ChannelMode *cm = ModeManager::FindChannelModeByName(lock->name); 1964 if (use_server_side_mlock && cm && ci->c && modelocks && (cm->type == MODE_REGULAR || cm->type == MODE_PARAM)) 1965 { 1966 Anope::string modes = modelocks->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", "").replace_all_cs(cm->mchar, ""); 1967 SendChannelMetadata(ci->c, "mlock", modes); 1968 } 1969 1970 return EVENT_CONTINUE; 1971 } 1972 1973 EventReturn OnSetChannelOption(CommandSource &source, Command *cmd, ChannelInfo *ci, const Anope::string &setting) anope_override 1974 { 1975 if (cmd->name == "chanserv/topic" && ci->c) 1976 { 1977 if (setting == "topiclock on") 1978 SendChannelMetadata(ci->c, "topiclock", "1"); 1979 else if (setting == "topiclock off") 1980 SendChannelMetadata(ci->c, "topiclock", "0"); 1981 } 1982 1983 return EVENT_CONTINUE; 1984 } 1985 }; 1986 1987 MODULE_INIT(ProtoInspIRCd3)