anope- supernets anope source code & configuration |
git clone git://git.acid.vegas/anope.git |
Log | Files | Refs | Archive | README |
protocol.cpp (13463B)
1 /* 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 "services.h" 13 #include "modules.h" 14 #include "protocol.h" 15 #include "users.h" 16 #include "servers.h" 17 #include "config.h" 18 #include "uplink.h" 19 #include "bots.h" 20 #include "channels.h" 21 22 IRCDProto *IRCD = NULL; 23 24 IRCDProto::IRCDProto(Module *creator, const Anope::string &p) : Service(creator, "IRCDProto", creator->name), proto_name(p) 25 { 26 DefaultPseudoclientModes = "+io"; 27 CanSVSNick = CanSVSJoin = CanSetVHost = CanSetVIdent = CanSNLine = CanSQLine = CanSQLineChannel 28 = CanSZLine = CanSVSHold = CanSVSO = CanCertFP = RequiresID = AmbiguousID = false; 29 MaxModes = 3; 30 MaxLine = 512; 31 32 if (IRCD == NULL) 33 IRCD = this; 34 } 35 36 IRCDProto::~IRCDProto() 37 { 38 if (IRCD == this) 39 IRCD = NULL; 40 } 41 42 const Anope::string &IRCDProto::GetProtocolName() 43 { 44 return this->proto_name; 45 } 46 47 static inline char nextID(int pos, Anope::string &buf) 48 { 49 char &c = buf[pos]; 50 if (c == 'Z') 51 c = '0'; 52 else if (c != '9') 53 ++c; 54 else if (pos) 55 c = 'A'; 56 else 57 c = '0'; 58 return c; 59 } 60 61 Anope::string IRCDProto::UID_Retrieve() 62 { 63 if (!IRCD || !IRCD->RequiresID) 64 return ""; 65 66 static Anope::string current_uid = "AAAAAA"; 67 68 do 69 { 70 int current_len = current_uid.length() - 1; 71 while (current_len >= 0 && nextID(current_len--, current_uid) == 'A'); 72 } 73 while (User::Find(Me->GetSID() + current_uid) != NULL); 74 75 return Me->GetSID() + current_uid; 76 } 77 78 Anope::string IRCDProto::SID_Retrieve() 79 { 80 if (!IRCD || !IRCD->RequiresID) 81 return ""; 82 83 static Anope::string current_sid = Config->GetBlock("serverinfo")->Get<const Anope::string>("id"); 84 if (current_sid.empty()) 85 current_sid = "00A"; 86 87 do 88 { 89 int current_len = current_sid.length() - 1; 90 while (current_len >= 0 && nextID(current_len--, current_sid) == 'A'); 91 } 92 while (Server::Find(current_sid) != NULL); 93 94 return current_sid; 95 } 96 97 void IRCDProto::SendKill(const MessageSource &source, const Anope::string &target, const Anope::string &reason) 98 { 99 UplinkSocket::Message(source) << "KILL " << target << " :" << reason; 100 } 101 102 void IRCDProto::SendSVSKillInternal(const MessageSource &source, User *user, const Anope::string &buf) 103 { 104 UplinkSocket::Message(source) << "KILL " << user->GetUID() << " :" << buf; 105 } 106 107 void IRCDProto::SendModeInternal(const MessageSource &source, const Channel *dest, const Anope::string &buf) 108 { 109 UplinkSocket::Message(source) << "MODE " << dest->name << " " << buf; 110 } 111 112 void IRCDProto::SendModeInternal(const MessageSource &source, User *dest, const Anope::string &buf) 113 { 114 UplinkSocket::Message(source) << "MODE " << dest->GetUID() << " " << buf; 115 } 116 117 void IRCDProto::SendKickInternal(const MessageSource &source, const Channel *c, User *u, const Anope::string &r) 118 { 119 if (!r.empty()) 120 UplinkSocket::Message(source) << "KICK " << c->name << " " << u->GetUID() << " :" << r; 121 else 122 UplinkSocket::Message(source) << "KICK " << c->name << " " << u->GetUID(); 123 } 124 125 void IRCDProto::SendNoticeInternal(const MessageSource &source, const Anope::string &dest, const Anope::string &msg) 126 { 127 UplinkSocket::Message(source) << "NOTICE " << dest << " :" << msg; 128 } 129 130 void IRCDProto::SendPrivmsgInternal(const MessageSource &source, const Anope::string &dest, const Anope::string &buf) 131 { 132 UplinkSocket::Message(source) << "PRIVMSG " << dest << " :" << buf; 133 } 134 135 void IRCDProto::SendQuitInternal(User *u, const Anope::string &buf) 136 { 137 if (!buf.empty()) 138 UplinkSocket::Message(u) << "QUIT :" << buf; 139 else 140 UplinkSocket::Message(u) << "QUIT"; 141 } 142 143 void IRCDProto::SendPartInternal(User *u, const Channel *chan, const Anope::string &buf) 144 { 145 if (!buf.empty()) 146 UplinkSocket::Message(u) << "PART " << chan->name << " :" << buf; 147 else 148 UplinkSocket::Message(u) << "PART " << chan->name; 149 } 150 151 void IRCDProto::SendGlobopsInternal(const MessageSource &source, const Anope::string &buf) 152 { 153 UplinkSocket::Message(source) << "GLOBOPS :" << buf; 154 } 155 156 void IRCDProto::SendCTCPInternal(const MessageSource &source, const Anope::string &dest, const Anope::string &buf) 157 { 158 Anope::string s = Anope::NormalizeBuffer(buf); 159 this->SendNoticeInternal(source, dest, "\1" + s + "\1"); 160 } 161 162 void IRCDProto::SendNumericInternal(int numeric, const Anope::string &dest, const Anope::string &buf) 163 { 164 Anope::string n = stringify(numeric); 165 if (numeric < 10) 166 n = "0" + n; 167 if (numeric < 100) 168 n = "0" + n; 169 UplinkSocket::Message(Me) << n << " " << dest << " " << buf; 170 } 171 172 void IRCDProto::SendTopic(const MessageSource &source, Channel *c) 173 { 174 UplinkSocket::Message(source) << "TOPIC " << c->name << " :" << c->topic; 175 } 176 177 void IRCDProto::SendSVSKill(const MessageSource &source, User *user, const char *fmt, ...) 178 { 179 if (!user || !fmt) 180 return; 181 182 va_list args; 183 char buf[BUFSIZE] = ""; 184 va_start(args, fmt); 185 vsnprintf(buf, BUFSIZE - 1, fmt, args); 186 va_end(args); 187 SendSVSKillInternal(source, user, buf); 188 } 189 190 void IRCDProto::SendMode(const MessageSource &source, const Channel *dest, const char *fmt, ...) 191 { 192 va_list args; 193 char buf[BUFSIZE] = ""; 194 va_start(args, fmt); 195 vsnprintf(buf, BUFSIZE - 1, fmt, args); 196 va_end(args); 197 SendModeInternal(source, dest, buf); 198 } 199 200 void IRCDProto::SendMode(const MessageSource &source, User *u, const char *fmt, ...) 201 { 202 va_list args; 203 char buf[BUFSIZE] = ""; 204 va_start(args, fmt); 205 vsnprintf(buf, BUFSIZE - 1, fmt, args); 206 va_end(args); 207 SendModeInternal(source, u, buf); 208 } 209 210 void IRCDProto::SendKick(const MessageSource &source, const Channel *chan, User *user, const char *fmt, ...) 211 { 212 if (!chan || !user) 213 return; 214 215 va_list args; 216 char buf[BUFSIZE] = ""; 217 va_start(args, fmt); 218 vsnprintf(buf, BUFSIZE - 1, fmt, args); 219 va_end(args); 220 SendKickInternal(source, chan, user, buf); 221 } 222 223 void IRCDProto::SendNotice(const MessageSource &source, const Anope::string &dest, const char *fmt, ...) 224 { 225 va_list args; 226 char buf[BUFSIZE] = ""; 227 va_start(args, fmt); 228 vsnprintf(buf, BUFSIZE - 1, fmt, args); 229 va_end(args); 230 SendNoticeInternal(source, dest, buf); 231 } 232 233 void IRCDProto::SendAction(const MessageSource &source, const Anope::string &dest, const char *fmt, ...) 234 { 235 va_list args; 236 char buf[BUFSIZE] = ""; 237 va_start(args, fmt); 238 vsnprintf(buf, BUFSIZE - 1, fmt, args); 239 va_end(args); 240 Anope::string actionbuf = Anope::string("\1ACTION ") + buf + '\1'; 241 SendPrivmsgInternal(source, dest, actionbuf); 242 } 243 244 void IRCDProto::SendPrivmsg(const MessageSource &source, const Anope::string &dest, const char *fmt, ...) 245 { 246 va_list args; 247 char buf[BUFSIZE] = ""; 248 va_start(args, fmt); 249 vsnprintf(buf, BUFSIZE - 1, fmt, args); 250 va_end(args); 251 SendPrivmsgInternal(source, dest, buf); 252 } 253 254 void IRCDProto::SendQuit(User *u, const char *fmt, ...) 255 { 256 va_list args; 257 char buf[BUFSIZE] = ""; 258 va_start(args, fmt); 259 vsnprintf(buf, BUFSIZE - 1, fmt, args); 260 va_end(args); 261 SendQuitInternal(u, buf); 262 } 263 264 void IRCDProto::SendPing(const Anope::string &servname, const Anope::string &who) 265 { 266 if (servname.empty()) 267 UplinkSocket::Message(Me) << "PING " << who; 268 else 269 UplinkSocket::Message(Me) << "PING " << servname << " " << who; 270 } 271 272 /** 273 * Send a PONG reply to a received PING. 274 * servname should be left NULL to send a one param reply. 275 * @param servname Daemon or client that is responding to the PING. 276 * @param who Origin of the PING and destination of the PONG message. 277 **/ 278 void IRCDProto::SendPong(const Anope::string &servname, const Anope::string &who) 279 { 280 if (servname.empty()) 281 UplinkSocket::Message(Me) << "PONG " << who; 282 else 283 UplinkSocket::Message(Me) << "PONG " << servname << " " << who; 284 } 285 286 void IRCDProto::SendInvite(const MessageSource &source, const Channel *c, User *u) 287 { 288 UplinkSocket::Message(source) << "INVITE " << u->GetUID() << " " << c->name; 289 } 290 291 void IRCDProto::SendPart(User *user, const Channel *chan, const char *fmt, ...) 292 { 293 if (fmt) 294 { 295 va_list args; 296 char buf[BUFSIZE] = ""; 297 va_start(args, fmt); 298 vsnprintf(buf, BUFSIZE - 1, fmt, args); 299 va_end(args); 300 SendPartInternal(user, chan, buf); 301 } 302 else 303 SendPartInternal(user, chan, ""); 304 } 305 306 void IRCDProto::SendGlobops(const MessageSource &source, const char *fmt, ...) 307 { 308 va_list args; 309 char buf[BUFSIZE] = ""; 310 va_start(args, fmt); 311 vsnprintf(buf, BUFSIZE - 1, fmt, args); 312 va_end(args); 313 SendGlobopsInternal(source, buf); 314 } 315 316 void IRCDProto::SendSquit(Server *s, const Anope::string &message) 317 { 318 UplinkSocket::Message() << "SQUIT " << s->GetSID() << " :" << message; 319 } 320 321 void IRCDProto::SendNickChange(User *u, const Anope::string &newnick) 322 { 323 UplinkSocket::Message(u) << "NICK " << newnick << " " << Anope::CurTime; 324 } 325 326 void IRCDProto::SendForceNickChange(User *u, const Anope::string &newnick, time_t when) 327 { 328 UplinkSocket::Message() << "SVSNICK " << u->GetUID() << " " << newnick << " " << when; 329 } 330 331 void IRCDProto::SendCTCP(const MessageSource &source, const Anope::string &dest, const char *fmt, ...) 332 { 333 va_list args; 334 char buf[BUFSIZE] = ""; 335 va_start(args, fmt); 336 vsnprintf(buf, BUFSIZE - 1, fmt, args); 337 va_end(args); 338 SendCTCPInternal(source, dest, buf); 339 } 340 341 void IRCDProto::SendNumeric(int numeric, const Anope::string &dest, const char *fmt, ...) 342 { 343 va_list args; 344 char buf[BUFSIZE] = ""; 345 va_start(args, fmt); 346 vsnprintf(buf, BUFSIZE - 1, fmt, args); 347 va_end(args); 348 SendNumericInternal(numeric, dest, buf); 349 } 350 351 bool IRCDProto::IsNickValid(const Anope::string &nick) 352 { 353 /** 354 * RFC: definition of a valid nick 355 * nickname = ( letter / special ) ( letter / digit / special / "-" ) 356 * letter = A-Z / a-z 357 * digit = 0-9 358 * special = [, ], \, `, _, ^, {, |, } 359 **/ 360 361 if (nick.empty()) 362 return false; 363 364 Anope::string special = "[]\\`_^{|}"; 365 366 for (unsigned i = 0; i < nick.length(); ++i) 367 if (!(nick[i] >= 'A' && nick[i] <= 'Z') && !(nick[i] >= 'a' && nick[i] <= 'z') 368 && special.find(nick[i]) == Anope::string::npos 369 && (Config && Config->NickChars.find(nick[i]) == Anope::string::npos) 370 && (!i || (!(nick[i] >= '0' && nick[i] <= '9') && nick[i] != '-'))) 371 return false; 372 373 return true; 374 } 375 376 bool IRCDProto::IsChannelValid(const Anope::string &chan) 377 { 378 if (chan.empty() || chan[0] != '#' || chan.length() > Config->GetBlock("networkinfo")->Get<unsigned>("chanlen")) 379 return false; 380 381 if (chan.find_first_of(" ,") != Anope::string::npos) 382 return false; 383 384 return true; 385 } 386 387 bool IRCDProto::IsIdentValid(const Anope::string &ident) 388 { 389 if (ident.empty() || ident.length() > Config->GetBlock("networkinfo")->Get<unsigned>("userlen")) 390 return false; 391 392 for (unsigned i = 0; i < ident.length(); ++i) 393 { 394 const char &c = ident[i]; 395 396 if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '.' || c == '-') 397 continue; 398 399 return false; 400 } 401 402 return true; 403 } 404 405 bool IRCDProto::IsHostValid(const Anope::string &host) 406 { 407 if (host.empty() || host.length() > Config->GetBlock("networkinfo")->Get<unsigned>("hostlen")) 408 return false; 409 410 const Anope::string &vhostdisablebe = Config->GetBlock("networkinfo")->Get<const Anope::string>("disallow_start_or_end"), 411 vhostchars = Config->GetBlock("networkinfo")->Get<const Anope::string>("vhost_chars"); 412 413 if (vhostdisablebe.find_first_of(host[0]) != Anope::string::npos) 414 return false; 415 else if (vhostdisablebe.find_first_of(host[host.length() - 1]) != Anope::string::npos) 416 return false; 417 418 int dots = 0; 419 for (unsigned i = 0; i < host.length(); ++i) 420 { 421 if (host[i] == '.') 422 ++dots; 423 if (vhostchars.find_first_of(host[i]) == Anope::string::npos) 424 return false; 425 } 426 427 return dots > 0 || Config->GetBlock("networkinfo")->Get<bool>("allow_undotted_vhosts"); 428 } 429 430 void IRCDProto::SendOper(User *u) 431 { 432 SendNumericInternal(381, u->GetUID(), ":You are now an IRC operator (set by services)"); 433 u->SetMode(NULL, "OPER"); 434 } 435 436 unsigned IRCDProto::GetMaxListFor(Channel *c) 437 { 438 return c->HasMode("LBAN") ? 0 : Config->GetBlock("networkinfo")->Get<int>("modelistsize"); 439 } 440 441 unsigned IRCDProto::GetMaxListFor(Channel *c, ChannelMode *cm) 442 { 443 return GetMaxListFor(c); 444 } 445 446 Anope::string IRCDProto::NormalizeMask(const Anope::string &mask) 447 { 448 if (IsExtbanValid(mask)) 449 return mask; 450 return Entry("", mask).GetNUHMask(); 451 } 452 453 MessageSource::MessageSource(const Anope::string &src) : source(src), u(NULL), s(NULL) 454 { 455 /* no source for incoming message is our uplink */ 456 if (src.empty()) 457 this->s = Servers::GetUplink(); 458 else if (IRCD->RequiresID || src.find('.') != Anope::string::npos) 459 this->s = Server::Find(src); 460 if (this->s == NULL) 461 this->u = User::Find(src); 462 } 463 464 MessageSource::MessageSource(User *_u) : source(_u ? _u->nick : ""), u(_u), s(NULL) 465 { 466 } 467 468 MessageSource::MessageSource(Server *_s) : source(_s ? _s->GetName() : ""), u(NULL), s(_s) 469 { 470 } 471 472 const Anope::string &MessageSource::GetName() const 473 { 474 if (this->s) 475 return this->s->GetName(); 476 else if (this->u) 477 return this->u->nick; 478 else 479 return this->source; 480 } 481 482 const Anope::string &MessageSource::GetSource() const 483 { 484 return this->source; 485 } 486 487 User *MessageSource::GetUser() const 488 { 489 return this->u; 490 } 491 492 BotInfo *MessageSource::GetBot() const 493 { 494 return BotInfo::Find(this->GetName(), true); 495 } 496 497 Server *MessageSource::GetServer() const 498 { 499 return this->s; 500 } 501 502 IRCDMessage::IRCDMessage(Module *o, const Anope::string &n, unsigned p) : Service(o, "IRCDMessage", o->name + "/" + n.lower()), name(n), param_count(p) 503 { 504 } 505 506 unsigned IRCDMessage::GetParamCount() const 507 { 508 return this->param_count; 509 } 510 511 void IRCDMessage::Run(MessageSource &source, const std::vector<Anope::string> ¶ms, const Anope::map<Anope::string> &tags) 512 { 513 // Most IRCds don't support message tags yet so use the tagless variant. 514 Run(source, params); 515 } 516