diff options
Diffstat (limited to 'src/modules')
35 files changed, 352 insertions, 494 deletions
diff --git a/src/modules/extra/m_ssl_gnutls.cpp b/src/modules/extra/m_ssl_gnutls.cpp index 6ca876d4c..7d8e9581e 100644 --- a/src/modules/extra/m_ssl_gnutls.cpp +++ b/src/modules/extra/m_ssl_gnutls.cpp @@ -28,8 +28,19 @@ #include "ssl.h" #include "m_cap.h" +#ifdef WINDOWS +# pragma comment(lib, "libgnutls.lib") +# pragma comment(lib, "libgcrypt.lib") +# pragma comment(lib, "libgpg-error.lib") +# pragma comment(lib, "user32.lib") +# pragma comment(lib, "advapi32.lib") +# pragma comment(lib, "libgcc.lib") +# pragma comment(lib, "libmingwex.lib") +# pragma comment(lib, "gdi32.lib") +#endif + /* $ModDesc: Provides SSL support for clients */ -/* $CompileFlags: pkgconfincludes("gnutls","/gnutls/gnutls.h","") */ +/* $CompileFlags: pkgconfincludes("gnutls","/gnutls/gnutls.h","") -Wno-deprecated-declarations */ /* $LinkerFlags: rpath("pkg-config --libs gnutls") pkgconflibs("gnutls","/libgnutls.so","-lgnutls") -lgcrypt */ enum issl_status { ISSL_NONE, ISSL_HANDSHAKING_READ, ISSL_HANDSHAKING_WRITE, ISSL_HANDSHAKEN, ISSL_CLOSING, ISSL_CLOSED }; @@ -151,6 +162,7 @@ class ModuleSSLGnuTLS : public Module gnutls_certificate_credentials x509_cred; gnutls_dh_params dh_params; gnutls_digest_algorithm_t hash; + gnutls_priority_t priority; std::string sslports; int dh_bits; @@ -172,6 +184,8 @@ class ModuleSSLGnuTLS : public Module gnutls_global_init(); // This must be called once in the program gnutls_x509_privkey_init(&x509_key); + // Init this here so it's always initialized, avoids an extra boolean + gnutls_priority_init(&priority, "NORMAL", NULL); cred_alloc = false; dh_alloc = false; @@ -203,6 +217,10 @@ class ModuleSSLGnuTLS : public Module if (Conf->getBool("showports", true)) { + sslports = Conf->getString("advertisedports"); + if (!sslports.empty()) + return; + for (size_t i = 0; i < ServerInstance->ports.size(); i++) { ListenSocket* port = ServerInstance->ports[i]; @@ -213,11 +231,20 @@ class ModuleSSLGnuTLS : public Module ServerInstance->Logs->Log("m_ssl_gnutls", DEFAULT, "m_ssl_gnutls.so: Enabling SSL for port %s", portid.c_str()); if (port->bind_tag->getString("type", "clients") == "clients" && port->bind_addr != "127.0.0.1") - sslports.append(portid).append(";"); + { + /* + * Found an SSL port for clients that is not bound to 127.0.0.1 and handled by us, display + * the IP:port in ISUPPORT. + * + * We used to advertise all ports seperated by a ';' char that matched the above criteria, + * but this resulted in too long ISUPPORT lines if there were lots of ports to be displayed. + * To solve this by default we now only display the first IP:port found and let the user + * configure the exact value for the 005 token, if necessary. + */ + sslports = portid; + break; + } } - - if (!sslports.empty()) - sslports.erase(sslports.end() - 1); } } @@ -241,6 +268,13 @@ class ModuleSSLGnuTLS : public Module dh_bits = Conf->getInt("dhbits"); std::string hashname = Conf->getString("hash", "md5"); + // The GnuTLS manual states that the gnutls_set_default_priority() + // call we used previously when initializing the session is the same + // as setting the "NORMAL" priority string. + // Thus if the setting below is not in the config we will behave exactly + // the same as before, when the priority setting wasn't available. + std::string priorities = Conf->getString("priority", "NORMAL"); + if((dh_bits != 768) && (dh_bits != 1024) && (dh_bits != 2048) && (dh_bits != 3072) && (dh_bits != 4096)) dh_bits = 1024; @@ -305,6 +339,21 @@ class ModuleSSLGnuTLS : public Module if((ret = gnutls_certificate_set_x509_key(x509_cred, &x509_certs[0], certcount, x509_key)) < 0) throw ModuleException("Unable to set GnuTLS cert/key pair: " + std::string(gnutls_strerror(ret))); + // It's safe to call this every time as we cannot have this uninitialized, see constructor and below. + gnutls_priority_deinit(priority); + + // Try to set the priorities for ciphers, kex methods etc. to the user supplied string + // If the user did not supply anything then the string is already set to "NORMAL" + const char* priocstr = priorities.c_str(); + const char* prioerror; + + if ((ret = gnutls_priority_init(&priority, priocstr, &prioerror)) < 0) + { + // gnutls did not understand the user supplied string, log and fall back to the default priorities + ServerInstance->Logs->Log("m_ssl_gnutls",DEFAULT, "m_ssl_gnutls.so: Failed to set priorities to \"%s\": %s Syntax error at position %d, falling back to default (NORMAL)", priorities.c_str(), gnutls_strerror(ret), (prioerror - priocstr)); + gnutls_priority_init(&priority, "NORMAL", NULL); + } + gnutls_certificate_client_set_retrieve_function (x509_cred, cert_callback); ret = gnutls_dh_params_init(&dh_params); @@ -338,6 +387,7 @@ class ModuleSSLGnuTLS : public Module gnutls_x509_crt_deinit(x509_certs[i]); gnutls_x509_privkey_deinit(x509_key); + gnutls_priority_deinit(priority); if (dh_alloc) gnutls_dh_params_deinit(dh_params); @@ -399,44 +449,39 @@ class ModuleSSLGnuTLS : public Module } } - void OnStreamSocketAccept(StreamSocket* user, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) + void InitSession(StreamSocket* user, bool me_server) { - int fd = user->GetFd(); - issl_session* session = &sessions[fd]; - - /* For STARTTLS: Don't try and init a session on a socket that already has a session */ - if (session->sess) - return; + issl_session* session = &sessions[user->GetFd()]; - gnutls_init(&session->sess, GNUTLS_SERVER); + gnutls_init(&session->sess, me_server ? GNUTLS_SERVER : GNUTLS_CLIENT); - gnutls_set_default_priority(session->sess); // Avoid calling all the priority functions, defaults are adequate. + gnutls_priority_set(session->sess, priority); gnutls_credentials_set(session->sess, GNUTLS_CRD_CERTIFICATE, x509_cred); gnutls_dh_set_prime_bits(session->sess, dh_bits); - gnutls_transport_set_ptr(session->sess, reinterpret_cast<gnutls_transport_ptr_t>(user)); gnutls_transport_set_push_function(session->sess, gnutls_push_wrapper); gnutls_transport_set_pull_function(session->sess, gnutls_pull_wrapper); - gnutls_certificate_server_set_request(session->sess, GNUTLS_CERT_REQUEST); // Request client certificate if any. + if (me_server) + gnutls_certificate_server_set_request(session->sess, GNUTLS_CERT_REQUEST); // Request client certificate if any. Handshake(session, user); } - void OnStreamSocketConnect(StreamSocket* user) + void OnStreamSocketAccept(StreamSocket* user, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) { issl_session* session = &sessions[user->GetFd()]; - gnutls_init(&session->sess, GNUTLS_CLIENT); + /* For STARTTLS: Don't try and init a session on a socket that already has a session */ + if (session->sess) + return; - gnutls_set_default_priority(session->sess); // Avoid calling all the priority functions, defaults are adequate. - gnutls_credentials_set(session->sess, GNUTLS_CRD_CERTIFICATE, x509_cred); - gnutls_dh_set_prime_bits(session->sess, dh_bits); - gnutls_transport_set_ptr(session->sess, reinterpret_cast<gnutls_transport_ptr_t>(user)); - gnutls_transport_set_push_function(session->sess, gnutls_push_wrapper); - gnutls_transport_set_pull_function(session->sess, gnutls_pull_wrapper); + InitSession(user, true); + } - Handshake(session, user); + void OnStreamSocketConnect(StreamSocket* user) + { + InitSession(user, false); } void OnStreamSocketClose(StreamSocket* user) diff --git a/src/modules/extra/m_ssl_openssl.cpp b/src/modules/extra/m_ssl_openssl.cpp index 0a5a76792..a8020bba1 100644 --- a/src/modules/extra/m_ssl_openssl.cpp +++ b/src/modules/extra/m_ssl_openssl.cpp @@ -159,20 +159,34 @@ class ModuleSSLOpenSSL : public Module if (Conf->getBool("showports", true)) { + sslports = Conf->getString("advertisedports"); + if (!sslports.empty()) + return; + for (size_t i = 0; i < ServerInstance->ports.size(); i++) { ListenSocket* port = ServerInstance->ports[i]; if (port->bind_tag->getString("ssl") != "openssl") continue; - std::string portid = port->bind_desc; + const std::string& portid = port->bind_desc; ServerInstance->Logs->Log("m_ssl_openssl", DEFAULT, "m_ssl_openssl.so: Enabling SSL for port %s", portid.c_str()); + if (port->bind_tag->getString("type", "clients") == "clients" && port->bind_addr != "127.0.0.1") - sslports.append(portid).append(";"); + { + /* + * Found an SSL port for clients that is not bound to 127.0.0.1 and handled by us, display + * the IP:port in ISUPPORT. + * + * We used to advertise all ports seperated by a ';' char that matched the above criteria, + * but this resulted in too long ISUPPORT lines if there were lots of ports to be displayed. + * To solve this by default we now only display the first IP:port found and let the user + * configure the exact value for the 005 token, if necessary. + */ + sslports = portid; + break; + } } - - if (!sslports.empty()) - sslports.erase(sslports.end() - 1); } } @@ -198,6 +212,16 @@ class ModuleSSLOpenSSL : public Module throw ModuleException("Unknown hash type " + hash); use_sha = (hash == "sha1"); + std::string ciphers = conf->getString("ciphers", ""); + + if (!ciphers.empty()) + { + if ((!SSL_CTX_set_cipher_list(ctx, ciphers.c_str())) || (!SSL_CTX_set_cipher_list(clictx, ciphers.c_str()))) + { + ServerInstance->Logs->Log("m_ssl_openssl",DEFAULT, "m_ssl_openssl.so: Can't set cipher list to %s.", ciphers.c_str()); + ERR_print_errors_cb(error_callback, this); + } + } /* Load our keys and certificates * NOTE: OpenSSL's error logging API sucks, don't blame us for this clusterfuck. @@ -262,8 +286,10 @@ class ModuleSSLOpenSSL : public Module if (sessions[user->eh.GetFd()].sess) { if (!sessions[user->eh.GetFd()].cert->fingerprint.empty()) - user->WriteServ("NOTICE %s :*** You are connected using SSL fingerprint %s", - user->nick.c_str(), sessions[user->eh.GetFd()].cert->fingerprint.c_str()); + user->WriteServ("NOTICE %s :*** You are connected using SSL cipher \"%s\"" + " and your SSL fingerprint is %s", user->nick.c_str(), SSL_get_cipher(sessions[user->eh.GetFd()].sess), sessions[user->eh.GetFd()].cert->fingerprint.c_str()); + else + user->WriteServ("NOTICE %s :*** You are connected using SSL cipher \"%s\"", user->nick.c_str(), SSL_get_cipher(sessions[user->eh.GetFd()].sess)); } } } diff --git a/src/modules/m_blockamsg.cpp b/src/modules/m_blockamsg.cpp index 1d26b7639..8160fcf54 100644 --- a/src/modules/m_blockamsg.cpp +++ b/src/modules/m_blockamsg.cpp @@ -98,8 +98,8 @@ class ModuleBlockAmsg : public Module virtual ModResult OnPreCommand(std::string &command, std::vector<std::string> ¶meters, LocalUser *user, bool validated, const std::string &original_line) { - // Don't do anything with unregistered users, or remote ones. - if(!user || (user->registered != REG_ALL) || !IS_LOCAL(user)) + // Don't do anything with unregistered users + if (user->registered != REG_ALL) return MOD_RES_PASSTHRU; // We want case insensitive command comparison. diff --git a/src/modules/m_chanhistory.cpp b/src/modules/m_chanhistory.cpp index 482d526eb..16eba953f 100644 --- a/src/modules/m_chanhistory.cpp +++ b/src/modules/m_chanhistory.cpp @@ -129,12 +129,7 @@ class ModuleChanHistory : public Module { ConfigTag* tag = ServerInstance->Config->ConfValue("chanhistory"); m.maxlines = tag->getInt("maxlines", 50); - sendnotice = tag->getInt("notice", true); - } - - ~ModuleChanHistory() - { - ServerInstance->Modes->DelMode(&m); + sendnotice = tag->getBool("notice", true); } void OnUserMessage(User* user,void* dest,int target_type, const std::string &text, char status, const CUList&) diff --git a/src/modules/m_chanlog.cpp b/src/modules/m_chanlog.cpp index ed5063fad..29385b8e2 100644 --- a/src/modules/m_chanlog.cpp +++ b/src/modules/m_chanlog.cpp @@ -28,7 +28,8 @@ class ModuleChanLog : public Module /* * Multimap so people can redirect a snomask to multiple channels. */ - std::multimap<char, std::string> logstreams; + typedef std::multimap<char, std::string> ChanLogTargets; + ChanLogTargets logstreams; public: ModuleChanLog() { @@ -72,30 +73,21 @@ class ModuleChanLog : public Module virtual ModResult OnSendSnotice(char &sno, std::string &desc, const std::string &msg) { - std::multimap<char, std::string>::const_iterator it = logstreams.find(sno); - char buf[MAXBUF]; - - if (it == logstreams.end()) + std::pair<ChanLogTargets::const_iterator, ChanLogTargets::const_iterator> itpair = logstreams.equal_range(sno); + if (itpair.first == itpair.second) return MOD_RES_PASSTHRU; + char buf[MAXBUF]; snprintf(buf, MAXBUF, "\2%s\2: %s", desc.c_str(), msg.c_str()); - while (it != logstreams.end()) + for (ChanLogTargets::const_iterator it = itpair.first; it != itpair.second; ++it) { - if (it->first != sno) - { - it++; - continue; - } - Channel *c = ServerInstance->FindChan(it->second); if (c) { c->WriteChannelWithServ(ServerInstance->Config->ServerName.c_str(), "PRIVMSG %s :%s", c->name.c_str(), buf); ServerInstance->PI->SendChannelPrivmsg(c, 0, buf); } - - it++; } return MOD_RES_PASSTHRU; diff --git a/src/modules/m_chgname.cpp b/src/modules/m_chgname.cpp index 667ddd928..2ac24c5d5 100644 --- a/src/modules/m_chgname.cpp +++ b/src/modules/m_chgname.cpp @@ -52,14 +52,14 @@ class CommandChgname : public Command if (parameters[1].length() > ServerInstance->Config->Limits.MaxGecos) { - user->WriteServ("NOTICE %s :*** GECOS too long", user->nick.c_str()); + user->WriteServ("NOTICE %s :*** CHGNAME: GECOS too long", user->nick.c_str()); return CMD_FAILURE; } if (IS_LOCAL(dest)) { dest->ChangeName(parameters[1].c_str()); - ServerInstance->SNO->WriteGlobalSno('a', "%s used CHGNAME to change %s's real name to '%s'", user->nick.c_str(), dest->nick.c_str(), dest->fullname.c_str()); + ServerInstance->SNO->WriteGlobalSno('a', "%s used CHGNAME to change %s's GECOS to '%s'", user->nick.c_str(), dest->nick.c_str(), dest->fullname.c_str()); } return CMD_SUCCESS; diff --git a/src/modules/m_commonchans.cpp b/src/modules/m_commonchans.cpp index ac8a7ba29..877ba87d7 100644 --- a/src/modules/m_commonchans.cpp +++ b/src/modules/m_commonchans.cpp @@ -23,32 +23,10 @@ /** Handles user mode +c */ -class PrivacyMode : public ModeHandler +class PrivacyMode : public SimpleUserModeHandler { public: - PrivacyMode(Module* Creator) : ModeHandler(Creator, "deaf_commonchan", 'c', PARAM_NONE, MODETYPE_USER) { } - - ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) - { - if (adding) - { - if (!dest->IsModeSet('c')) - { - dest->SetMode('c',true); - return MODEACTION_ALLOW; - } - } - else - { - if (dest->IsModeSet('c')) - { - dest->SetMode('c',false); - return MODEACTION_ALLOW; - } - } - - return MODEACTION_DENY; - } + PrivacyMode(Module* Creator) : SimpleUserModeHandler(Creator, "deaf_commonchan", 'c') { } }; class ModulePrivacyMode : public Module diff --git a/src/modules/m_connflood.cpp b/src/modules/m_connflood.cpp index d0e925716..9d7c9cb2c 100644 --- a/src/modules/m_connflood.cpp +++ b/src/modules/m_connflood.cpp @@ -23,27 +23,25 @@ /* $ModDesc: Connection throttle */ -int conns = 0, throttled = 0; - class ModuleConnFlood : public Module { private: - int seconds, maxconns, timeout, boot_wait; + int seconds, timeout, boot_wait; + unsigned int conns; + unsigned int maxconns; + bool throttled; time_t first; std::string quitmsg; public: - ModuleConnFlood() { - + ModuleConnFlood() + : conns(0), throttled(false) + { InitConf(); Implementation eventlist[] = { I_OnRehash, I_OnUserRegister }; ServerInstance->Modules->Attach(eventlist, this, 2); } - virtual ~ModuleConnFlood() - { - } - virtual Version GetVersion() { return Version("Connection throttle", VF_VENDOR); @@ -78,12 +76,12 @@ public: /* increase connection count */ conns++; - if (throttled == 1) + if (throttled) { if (tdiff > seconds + timeout) { /* expire throttle */ - throttled = 0; + throttled = false; ServerInstance->SNO->WriteGlobalSno('a', "Connection throttle deactivated"); return MOD_RES_PASSTHRU; } @@ -96,7 +94,7 @@ public: { if (conns >= maxconns) { - throttled = 1; + throttled = true; ServerInstance->SNO->WriteGlobalSno('a', "Connection throttle activated"); ServerInstance->Users->QuitUser(user, quitmsg); return MOD_RES_DENY; diff --git a/src/modules/m_cycle.cpp b/src/modules/m_cycle.cpp index b28edde83..1eb3c1899 100644 --- a/src/modules/m_cycle.cpp +++ b/src/modules/m_cycle.cpp @@ -20,7 +20,7 @@ #include "inspircd.h" -/* $ModDesc: Provides support for unreal-style CYCLE command. */ +/* $ModDesc: Provides command CYCLE, acts as a server-side HOP command to part and rejoin a channel. */ /** Handle /CYCLE */ @@ -97,7 +97,7 @@ class ModuleCycle : public Module virtual Version GetVersion() { - return Version("Provides support for unreal-style CYCLE command.", VF_VENDOR); + return Version("Provides command CYCLE, acts as a server-side HOP command to part and rejoin a channel.", VF_VENDOR); } }; diff --git a/src/modules/m_halfop.cpp b/src/modules/m_halfop.cpp index f0eda3e56..7a43f0241 100644 --- a/src/modules/m_halfop.cpp +++ b/src/modules/m_halfop.cpp @@ -92,11 +92,6 @@ class ModuleHalfop : public Module throw ModuleException("Could not add new modes!"); } - ~ModuleHalfop() - { - ServerInstance->Modes->DelMode(&mh); - } - Version GetVersion() { return Version("Channel half-operator mode provider", VF_VENDOR); diff --git a/src/modules/m_helpop.cpp b/src/modules/m_helpop.cpp index bbc7ae3ac..60c23f45b 100644 --- a/src/modules/m_helpop.cpp +++ b/src/modules/m_helpop.cpp @@ -29,35 +29,13 @@ static std::map<irc::string, std::string> helpop_map; /** Handles user mode +h */ -class Helpop : public ModeHandler +class Helpop : public SimpleUserModeHandler { public: - Helpop(Module* Creator) : ModeHandler(Creator, "helpop", 'h', PARAM_NONE, MODETYPE_USER) + Helpop(Module* Creator) : SimpleUserModeHandler(Creator, "helpop", 'h') { oper = true; } - - ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) - { - if (adding) - { - if (!dest->IsModeSet('h')) - { - dest->SetMode('h',true); - return MODEACTION_ALLOW; - } - } - else - { - if (dest->IsModeSet('h')) - { - dest->SetMode('h',false); - return MODEACTION_ALLOW; - } - } - - return MODEACTION_DENY; - } }; /** Handles /HELPOP diff --git a/src/modules/m_hidechans.cpp b/src/modules/m_hidechans.cpp index 17e2e8605..9c582551b 100644 --- a/src/modules/m_hidechans.cpp +++ b/src/modules/m_hidechans.cpp @@ -24,32 +24,10 @@ /** Handles user mode +I */ -class HideChans : public ModeHandler +class HideChans : public SimpleUserModeHandler { public: - HideChans(Module* Creator) : ModeHandler(Creator, "hidechans", 'I', PARAM_NONE, MODETYPE_USER) { } - - ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) - { - if (adding) - { - if (!dest->IsModeSet('I')) - { - dest->SetMode('I',true); - return MODEACTION_ALLOW; - } - } - else - { - if (dest->IsModeSet('I')) - { - dest->SetMode('I',false); - return MODEACTION_ALLOW; - } - } - - return MODEACTION_DENY; - } + HideChans(Module* Creator) : SimpleUserModeHandler(Creator, "hidechans", 'I') { } }; class ModuleHideChans : public Module diff --git a/src/modules/m_hideoper.cpp b/src/modules/m_hideoper.cpp index cde50b1a9..998a57bb3 100644 --- a/src/modules/m_hideoper.cpp +++ b/src/modules/m_hideoper.cpp @@ -25,35 +25,13 @@ /** Handles user mode +H */ -class HideOper : public ModeHandler +class HideOper : public SimpleUserModeHandler { public: - HideOper(Module* Creator) : ModeHandler(Creator, "hideoper", 'H', PARAM_NONE, MODETYPE_USER) + HideOper(Module* Creator) : SimpleUserModeHandler(Creator, "hideoper", 'H') { oper = true; } - - ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) - { - if (adding) - { - if (!dest->IsModeSet('H')) - { - dest->SetMode('H',true); - return MODEACTION_ALLOW; - } - } - else - { - if (dest->IsModeSet('H')) - { - dest->SetMode('H',false); - return MODEACTION_ALLOW; - } - } - - return MODEACTION_DENY; - } }; class ModuleHideOper : public Module diff --git a/src/modules/m_hostchange.cpp b/src/modules/m_hostchange.cpp index 2635015c7..e63c61631 100644 --- a/src/modules/m_hostchange.cpp +++ b/src/modules/m_hostchange.cpp @@ -28,12 +28,22 @@ class Host { public: - std::string action; + enum HostChangeAction + { + HCA_SET, + HCA_SUFFIX, + HCA_ADDNICK + }; + + HostChangeAction action; std::string newhost; std::string ports; + + Host(HostChangeAction Action, const std::string& Newhost, const std::string& Ports) : + action(Action), newhost(Newhost), ports(Ports) {} }; -typedef std::map<std::string,Host*> hostchanges_t; +typedef std::vector<std::pair<std::string, Host> > hostchanges_t; class ModuleHostChange : public Module { @@ -51,44 +61,39 @@ class ModuleHostChange : public Module ServerInstance->Modules->Attach(eventlist, this, 2); } - virtual ~ModuleHostChange() - { - for (hostchanges_t::iterator i = hostchanges.begin(); i != hostchanges.end(); i++) - { - delete i->second; - } - hostchanges.clear(); - } - - void Prioritize() - { - Module* cloak = ServerInstance->Modules->Find("m_cloaking.so"); - ServerInstance->Modules->SetPriority(this, I_OnUserConnect, PRIORITY_AFTER, &cloak); - } - - virtual void OnRehash(User* user) { ConfigReader Conf; MySuffix = Conf.ReadValue("host","suffix",0); MyPrefix = Conf.ReadValue("host","prefix","",0); MySeparator = Conf.ReadValue("host","separator",".",0); - for (hostchanges_t::iterator i = hostchanges.begin(); i != hostchanges.end(); i++) - { - delete i->second; - } hostchanges.clear(); - for (int index = 0; index < Conf.Enumerate("hostchange"); index++) + + std::set<std::string> dupecheck; + ConfigTagList tags = ServerInstance->Config->ConfTags("hostchange"); + for (ConfigIter i = tags.first; i != tags.second; ++i) { - std::string mask = Conf.ReadValue("hostchange", "mask", index); - std::string ports = Conf.ReadValue("hostchange", "ports", index); - std::string action = Conf.ReadValue("hostchange", "action", index); - std::string newhost = Conf.ReadValue("hostchange", "value", index); - Host* x = new Host; - x->action = action; - x->ports = ports; - x->newhost = newhost; - hostchanges[mask] = x; + ConfigTag* tag = i->second; + std::string mask = tag->getString("mask"); + if (!dupecheck.insert(mask).second) + throw ModuleException("Duplicate hostchange entry: " + mask); + + Host::HostChangeAction act; + std::string newhost; + std::string action = tag->getString("action"); + if (!strcasecmp(action.c_str(), "set")) + { + act = Host::HCA_SET; + newhost = tag->getString("newhost"); + } + else if (!strcasecmp(action.c_str(), "suffix")) + act = Host::HCA_SUFFIX; + else if (!strcasecmp(action.c_str(), "addnick")) + act = Host::HCA_ADDNICK; + else + throw ModuleException("Invalid hostchange action: " + action); + + hostchanges.push_back(std::make_pair(mask, Host(act, tag->getString("ports"), newhost))); } } @@ -105,11 +110,11 @@ class ModuleHostChange : public Module { if (((InspIRCd::MatchCIDR(user->MakeHost(), i->first)) || (InspIRCd::MatchCIDR(user->MakeHostIP(), i->first)))) { - Host* h = i->second; + const Host& h = i->second; - if (!h->ports.empty()) + if (!h.ports.empty()) { - irc::portparser portrange(h->ports, false); + irc::portparser portrange(h.ports, false); long portno = -1; bool foundany = false; @@ -123,27 +128,26 @@ class ModuleHostChange : public Module // host of new user matches a hostchange tag's mask std::string newhost; - if (h->action == "set") + if (h.action == Host::HCA_SET) { - newhost = h->newhost; + newhost = h.newhost; } - else if (h->action == "suffix") + else if (h.action == Host::HCA_SUFFIX) { newhost = MySuffix; } - else if (h->action == "addnick") + else if (h.action == Host::HCA_ADDNICK) { // first take their nick and strip out non-dns, leaving just [A-Z0-9\-] std::string complete; - std::string old = user->nick; - for (unsigned int j = 0; j < old.length(); j++) + for (std::string::const_iterator j = user->nick.begin(); j != user->nick.end(); ++j) { - if (((old[j] >= 'A') && (old[j] <= 'Z')) || - ((old[j] >= 'a') && (old[j] <= 'z')) || - ((old[j] >= '0') && (old[j] <= '9')) || - (old[j] == '-')) + if (((*j >= 'A') && (*j <= 'Z')) || + ((*j >= 'a') && (*j <= 'z')) || + ((*j >= '0') && (*j <= '9')) || + (*j == '-')) { - complete = complete + old[j]; + complete = complete + *j; } } if (complete.empty()) diff --git a/src/modules/m_ident.cpp b/src/modules/m_ident.cpp index b7c9c1cfd..c30e4d200 100644 --- a/src/modules/m_ident.cpp +++ b/src/modules/m_ident.cpp @@ -216,15 +216,17 @@ class IdentRequestSocket : public EventHandler char ibuf[MAXBUF]; int recvresult = ServerInstance->SE->Recv(this, ibuf, MAXBUF-1, 0); + /* Close (but don't delete from memory) our socket + * and flag as done since the ident lookup has finished + */ + Close(); + done = true; + /* Cant possibly be a valid response shorter than 3 chars, * because the shortest possible response would look like: '1,1' */ if (recvresult < 3) - { - Close(); - done = true; return; - } ServerInstance->Logs->Log("m_ident",DEBUG,"ReadResponse()"); @@ -263,13 +265,6 @@ class IdentRequestSocket : public EventHandler break; } - - /* Close (but dont delete from memory) our socket - * and flag as done - */ - Close(); - done = true; - return; } }; @@ -388,7 +383,11 @@ class ModuleIdent : public Module { /* Module unloading, tidy up users */ if (target_type == TYPE_USER) - OnUserDisconnect((LocalUser*)item); + { + LocalUser* user = IS_LOCAL((User*) item); + if (user) + OnUserDisconnect(user); + } } virtual void OnUserDisconnect(LocalUser *user) diff --git a/src/modules/m_messageflood.cpp b/src/modules/m_messageflood.cpp index f3045cf52..ff92fcaa3 100644 --- a/src/modules/m_messageflood.cpp +++ b/src/modules/m_messageflood.cpp @@ -33,47 +33,30 @@ class floodsettings { public: bool ban; - int secs; - int lines; + unsigned int secs; + unsigned int lines; time_t reset; - std::map<User*,int> counters; + std::map<User*, unsigned int> counters; floodsettings(bool a, int b, int c) : ban(a), secs(b), lines(c) { reset = ServerInstance->Time() + secs; - }; + } - void addmessage(User* who) + bool addmessage(User* who) { - std::map<User*,int>::iterator iter = counters.find(who); - if (iter != counters.end()) - { - iter->second++; - } - else - { - counters[who] = 1; - } if (ServerInstance->Time() > reset) { counters.clear(); reset = ServerInstance->Time() + secs; } - } - bool shouldkick(User* who) - { - std::map<User*,int>::iterator iter = counters.find(who); - if (iter != counters.end()) - { - return (iter->second >= this->lines); - } - else return false; + return (++counters[who] >= this->lines); } void clear(User* who) { - std::map<User*,int>::iterator iter = counters.find(who); + std::map<User*, unsigned int>::iterator iter = counters.find(who); if (iter != counters.end()) { counters.erase(iter); @@ -92,101 +75,45 @@ class MsgFlood : public ModeHandler ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) { - floodsettings *f = ext.get(channel); - if (adding) { - char ndata[MAXBUF]; - char* data = ndata; - strlcpy(ndata,parameter.c_str(),MAXBUF); - char* lines = data; - char* secs = NULL; - bool ban = false; - if (*data == '*') - { - ban = true; - lines++; - } - else + std::string::size_type colon = parameter.find(':'); + if ((colon == std::string::npos) || (parameter.find('-') != std::string::npos)) { - ban = false; - } - while (*data) - { - if (*data == ':') - { - *data = 0; - data++; - secs = data; - break; - } - else data++; - } - if (secs) - { - /* Set up the flood parameters for this channel */ - int nlines = atoi(lines); - int nsecs = atoi(secs); - if ((nlines<2) || (nsecs<1)) - { - source->WriteNumeric(608, "%s %s :Invalid flood parameter",source->nick.c_str(),channel->name.c_str()); - parameter.clear(); - return MODEACTION_DENY; - } - else - { - if (!f) - { - parameter = std::string(ban ? "*" : "") + ConvToStr(nlines) + ":" +ConvToStr(nsecs); - f = new floodsettings(ban,nsecs,nlines); - ext.set(channel, f); - channel->SetModeParam('f', parameter); - return MODEACTION_ALLOW; - } - else - { - std::string cur_param = channel->GetModeParameter('f'); - parameter = std::string(ban ? "*" : "") + ConvToStr(nlines) + ":" +ConvToStr(nsecs); - if (cur_param == parameter) - { - // mode params match - return MODEACTION_DENY; - } - else - { - if ((((nlines != f->lines) || (nsecs != f->secs) || (ban != f->ban))) && (((nsecs > 0) && (nlines > 0)))) - { - floodsettings *fs = new floodsettings(ban,nsecs,nlines); - ext.set(channel, fs); - channel->SetModeParam('f', parameter); - return MODEACTION_ALLOW; - } - else - { - return MODEACTION_DENY; - } - } - } - } + source->WriteNumeric(608, "%s %s :Invalid flood parameter",source->nick.c_str(),channel->name.c_str()); + return MODEACTION_DENY; } - else + + /* Set up the flood parameters for this channel */ + bool ban = (parameter[0] == '*'); + unsigned int nlines = ConvToInt(parameter.substr(ban ? 1 : 0, ban ? colon-1 : colon)); + unsigned int nsecs = ConvToInt(parameter.substr(colon+1)); + + if ((nlines<2) || (nsecs<1)) { source->WriteNumeric(608, "%s %s :Invalid flood parameter",source->nick.c_str(),channel->name.c_str()); - parameter.clear(); return MODEACTION_DENY; } + + floodsettings* f = ext.get(channel); + if ((f) && (nlines == f->lines) && (nsecs == f->secs) && (ban == f->ban)) + // mode params match + return MODEACTION_DENY; + + ext.set(channel, new floodsettings(ban, nsecs, nlines)); + parameter = std::string(ban ? "*" : "") + ConvToStr(nlines) + ":" + ConvToStr(nsecs); + channel->SetModeParam('f', parameter); + return MODEACTION_ALLOW; } else { - if (f) - { - ext.unset(channel); - channel->SetModeParam('f', ""); - return MODEACTION_ALLOW; - } - } + if (!channel->IsModeSet('f')) + return MODEACTION_DENY; - return MODEACTION_DENY; + ext.unset(channel); + channel->SetModeParam('f', ""); + return MODEACTION_ALLOW; + } } }; @@ -208,15 +135,16 @@ class ModuleMsgFlood : public Module ModResult ProcessMessages(User* user,Channel* dest, const std::string &text) { - ModResult res = ServerInstance->OnCheckExemption(user,dest,"flood"); - if (!IS_LOCAL(user) || res == MOD_RES_ALLOW) + if ((!IS_LOCAL(user)) || !dest->IsModeSet('f')) + return MOD_RES_PASSTHRU; + + if (ServerInstance->OnCheckExemption(user,dest,"flood") == MOD_RES_ALLOW) return MOD_RES_PASSTHRU; floodsettings *f = mf.ext.get(dest); if (f) { - f->addmessage(user); - if (f->shouldkick(user)) + if (f->addmessage(user)) { /* Youre outttta here! */ f->clear(user); @@ -230,7 +158,7 @@ class ModuleMsgFlood : public Module } char kickmessage[MAXBUF]; - snprintf(kickmessage, MAXBUF, "Channel flood triggered (limit is %d lines in %d secs)", f->lines, f->secs); + snprintf(kickmessage, MAXBUF, "Channel flood triggered (limit is %u lines in %u secs)", f->lines, f->secs); dest->KickUser(ServerInstance->FakeClient, user, kickmessage); diff --git a/src/modules/m_namesx.cpp b/src/modules/m_namesx.cpp index 2603b0ce5..535f6ec10 100644 --- a/src/modules/m_namesx.cpp +++ b/src/modules/m_namesx.cpp @@ -52,13 +52,12 @@ class ModuleNamesX : public Module ModResult OnPreCommand(std::string &command, std::vector<std::string> ¶meters, LocalUser *user, bool validated, const std::string &original_line) { - irc::string c = command.c_str(); /* We don't actually create a proper command handler class for PROTOCTL, * because other modules might want to have PROTOCTL hooks too. * Therefore, we just hook its as an unvalidated command therefore we * can capture it even if it doesnt exist! :-) */ - if (c == "PROTOCTL") + if (command == "PROTOCTL") { if ((parameters.size()) && (!strcasecmp(parameters[0].c_str(),"NAMESX"))) { @@ -83,13 +82,16 @@ class ModuleNamesX : public Module void OnSendWhoLine(User* source, const std::vector<std::string>& params, User* user, std::string& line) { - if (!cap.ext.get(source) || line.empty()) + if (!cap.ext.get(source)) return; - std::string::size_type pos = line.find(':'); - if (pos == std::string::npos || pos < 2) + // Channel names can contain ":", and ":" as a 'start-of-token' delimiter is + // only ever valid after whitespace, so... find the actual delimiter first! + // Thanks to FxChiP for pointing this out. + std::string::size_type pos = line.find(" :"); + if (pos == std::string::npos || pos == 0) return; - pos -= 2; + pos--; // Don't do anything if the user has no prefixes if ((line[pos] == 'H') || (line[pos] == 'G') || (line[pos] == '*')) return; diff --git a/src/modules/m_noctcp.cpp b/src/modules/m_noctcp.cpp index 8c8e1c473..d6db7a7f7 100644 --- a/src/modules/m_noctcp.cpp +++ b/src/modules/m_noctcp.cpp @@ -67,7 +67,7 @@ class ModuleNoCTCP : public Module if (!c->IsModeSet('C')) return MOD_RES_PASSTHRU; - if ((text.empty()) || (text[0] != '\001') || (strncmp(text.c_str(),"\1ACTION ",8))) + if ((text.empty()) || (text[0] != '\001') || (!strncmp(text.c_str(),"\1ACTION ",8))) return MOD_RES_PASSTHRU; ModResult res = ServerInstance->OnCheckExemption(user,c,"noctcp"); diff --git a/src/modules/m_nokicks.cpp b/src/modules/m_nokicks.cpp index 2e598dafe..58e6fbea1 100644 --- a/src/modules/m_nokicks.cpp +++ b/src/modules/m_nokicks.cpp @@ -22,7 +22,7 @@ #include "inspircd.h" -/* $ModDesc: Provides support for unreal-style channel mode +Q */ +/* $ModDesc: Provides channel mode +Q to prevent kicks on the channel. */ class NoKicks : public SimpleChannelModeHandler { @@ -74,7 +74,7 @@ class ModuleNoKicks : public Module Version GetVersion() { - return Version("Provides support for unreal-style channel mode +Q", VF_VENDOR); + return Version("Provides channel mode +Q to prevent kicks on the channel.", VF_VENDOR); } }; diff --git a/src/modules/m_operchans.cpp b/src/modules/m_operchans.cpp index 074c644e1..2e6fad79f 100644 --- a/src/modules/m_operchans.cpp +++ b/src/modules/m_operchans.cpp @@ -24,32 +24,13 @@ /* $ModDesc: Provides support for oper-only chans via the +O channel mode */ -class OperChans : public ModeHandler +class OperChans : public SimpleChannelModeHandler { public: /* This is an oper-only mode */ - OperChans(Module* Creator) : ModeHandler(Creator, "operonly", 'O', PARAM_NONE, MODETYPE_CHANNEL) { oper = true; } - - ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) + OperChans(Module* Creator) : SimpleChannelModeHandler(Creator, "operonly", 'O') { - if (adding) - { - if (!channel->IsModeSet('O')) - { - channel->SetMode('O',true); - return MODEACTION_ALLOW; - } - } - else - { - if (channel->IsModeSet('O')) - { - channel->SetMode('O',false); - return MODEACTION_ALLOW; - } - } - - return MODEACTION_DENY; + oper = true; } }; diff --git a/src/modules/m_opermotd.cpp b/src/modules/m_opermotd.cpp index 3a05fbd56..5c107b6b1 100644 --- a/src/modules/m_opermotd.cpp +++ b/src/modules/m_opermotd.cpp @@ -24,42 +24,47 @@ /* $ModDesc: Shows a message to opers after oper-up, adds /opermotd */ -static FileReader* opermotd; - -CmdResult ShowOperMOTD(User* user) -{ - if(!opermotd->FileSize()) - { - user->WriteServ(std::string("425 ") + user->nick + std::string(" :OPERMOTD file is missing")); - return CMD_FAILURE; - } - - user->WriteServ(std::string("375 ") + user->nick + std::string(" :- IRC Operators Message of the Day")); - - for(int i=0; i != opermotd->FileSize(); i++) - { - user->WriteServ(std::string("372 ") + user->nick + std::string(" :- ") + opermotd->GetLine(i)); - } - - user->WriteServ(std::string("376 ") + user->nick + std::string(" :- End of OPERMOTD")); - - /* don't route me */ - return CMD_SUCCESS; -} - /** Handle /OPERMOTD */ class CommandOpermotd : public Command { public: - CommandOpermotd(Module* Creator) : Command(Creator,"OPERMOTD", 0) + FileReader opermotd; + + CommandOpermotd(Module* Creator) : Command(Creator,"OPERMOTD", 0, 1) { flags_needed = 'o'; syntax = "[<servername>]"; } CmdResult Handle (const std::vector<std::string>& parameters, User* user) { - return ShowOperMOTD(user); + if ((parameters.empty()) || (parameters[0] == ServerInstance->Config->ServerName)) + ShowOperMOTD(user); + return CMD_SUCCESS; + } + + RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) + { + if (!parameters.empty()) + return ROUTE_OPT_UCAST(parameters[0]); + return ROUTE_LOCALONLY; + } + + void ShowOperMOTD(User* user) + { + const std::string& servername = ServerInstance->Config->ServerName; + if (!opermotd.FileSize()) + { + user->SendText(":%s 455 %s :OPERMOTD file is missing", servername.c_str(), user->nick.c_str()); + return; + } + + user->SendText(":%s 375 %s :- IRC Operators Message of the Day", servername.c_str(), user->nick.c_str()); + + for (int i=0; i != opermotd.FileSize(); i++) + user->SendText(":%s 372 %s :- %s", servername.c_str(), user->nick.c_str(), opermotd.GetLine(i).c_str()); + + user->SendText(":%s 376 %s :- End of OPERMOTD", servername.c_str(), user->nick.c_str()); } }; @@ -73,36 +78,28 @@ class ModuleOpermotd : public Module void LoadOperMOTD() { ConfigTag* conf = ServerInstance->Config->ConfValue("opermotd"); - opermotd->LoadFile(conf->getString("file","opermotd")); + cmd.opermotd.LoadFile(conf->getString("file","opermotd")); onoper = conf->getBool("onoper", true); } ModuleOpermotd() : cmd(this) { - opermotd = NULL; ServerInstance->AddCommand(&cmd); - opermotd = new FileReader; LoadOperMOTD(); Implementation eventlist[] = { I_OnRehash, I_OnOper }; ServerInstance->Modules->Attach(eventlist, this, 2); } - virtual ~ModuleOpermotd() - { - delete opermotd; - opermotd = NULL; - } - virtual Version GetVersion() { - return Version("Shows a message to opers after oper-up, adds /opermotd", VF_VENDOR); + return Version("Shows a message to opers after oper-up, adds /opermotd", VF_VENDOR | VF_OPTCOMMON); } virtual void OnOper(User* user, const std::string &opertype) { - if (onoper) - ShowOperMOTD(user); + if (onoper && IS_LOCAL(user)) + cmd.ShowOperMOTD(user); } virtual void OnRehash(User* user) diff --git a/src/modules/m_sapart.cpp b/src/modules/m_sapart.cpp index 1a19c6645..c1e6f6c08 100644 --- a/src/modules/m_sapart.cpp +++ b/src/modules/m_sapart.cpp @@ -21,7 +21,7 @@ #include "inspircd.h" -/* $ModDesc: Provides support for unreal-style SAPART command */ +/* $ModDesc: Provides command SAPART to force-part users from a channel. */ /** Handle /SAPART */ @@ -116,7 +116,7 @@ class ModuleSapart : public Module virtual Version GetVersion() { - return Version("Provides support for unreal-style SAPART command", VF_OPTCOMMON | VF_VENDOR); + return Version("Provides command SAPART to force-part users from a channel.", VF_OPTCOMMON | VF_VENDOR); } }; diff --git a/src/modules/m_satopic.cpp b/src/modules/m_satopic.cpp index bf65cc5d5..a0e3319af 100644 --- a/src/modules/m_satopic.cpp +++ b/src/modules/m_satopic.cpp @@ -44,8 +44,7 @@ class CommandSATopic : public Command // 3rd parameter overrides access checks target->SetTopic(user, newTopic, true); - ServerInstance->SNO->WriteToSnoMask('a', user->nick + " used SATOPIC on " + target->name + ", new topic: " + newTopic); - ServerInstance->PI->SendSNONotice("A", user->nick + " used SATOPIC on " + target->name + ", new topic: " + newTopic); + ServerInstance->SNO->WriteGlobalSno('a', user->nick + " used SATOPIC on " + target->name + ", new topic: " + newTopic); return CMD_SUCCESS; } diff --git a/src/modules/m_services_account.cpp b/src/modules/m_services_account.cpp index 57a08ada4..08986d53c 100644 --- a/src/modules/m_services_account.cpp +++ b/src/modules/m_services_account.cpp @@ -40,19 +40,17 @@ class Channel_r : public ModeHandler if (!IS_LOCAL(source) || ServerInstance->ULine(source->nick.c_str()) || ServerInstance->ULine(source->server)) { // Only change the mode if it's not redundant - if ((adding && !channel->IsModeSet('r')) || (!adding && channel->IsModeSet('r'))) + if ((adding != channel->IsModeSet('r'))) { channel->SetMode('r',adding); return MODEACTION_ALLOW; } - - return MODEACTION_DENY; } else { source->WriteNumeric(500, "%s :Only a server may modify the +r channel mode", source->nick.c_str()); - return MODEACTION_DENY; } + return MODEACTION_DENY; } }; @@ -68,18 +66,17 @@ class User_r : public ModeHandler { if (!IS_LOCAL(source) || ServerInstance->ULine(source->nick.c_str()) || ServerInstance->ULine(source->server)) { - if ((adding && !dest->IsModeSet('r')) || (!adding && dest->IsModeSet('r'))) + if ((adding != dest->IsModeSet('r'))) { dest->SetMode('r',adding); return MODEACTION_ALLOW; } - return MODEACTION_DENY; } else { source->WriteNumeric(500, "%s :Only a server may modify the +r user mode", source->nick.c_str()); - return MODEACTION_DENY; } + return MODEACTION_DENY; } }; diff --git a/src/modules/m_servprotect.cpp b/src/modules/m_servprotect.cpp index 7df9effcc..c98eebec3 100644 --- a/src/modules/m_servprotect.cpp +++ b/src/modules/m_servprotect.cpp @@ -21,7 +21,7 @@ #include "inspircd.h" -/* $ModDesc: Provides support for Austhex style +k / UnrealIRCD +S services mode */ +/* $ModDesc: Provides usermode +k to protect services from kicks, kills and mode changes. */ /** Handles user mode +k */ @@ -64,7 +64,7 @@ class ModuleServProtectMode : public Module Version GetVersion() { - return Version("Provides support for Austhex style +k / UnrealIRCD +S services mode", VF_VENDOR); + return Version("Provides usermode +k to protect services from kicks, kills, and mode changes.", VF_VENDOR); } void OnWhois(User* src, User* dst) diff --git a/src/modules/m_setname.cpp b/src/modules/m_setname.cpp index 3b8d4d149..32c1d5dc3 100644 --- a/src/modules/m_setname.cpp +++ b/src/modules/m_setname.cpp @@ -50,7 +50,7 @@ class CommandSetname : public Command if (user->ChangeName(parameters[0].c_str())) { - ServerInstance->SNO->WriteGlobalSno('a', "%s used SETNAME to change their GECOS to %s", user->nick.c_str(), parameters[0].c_str()); + ServerInstance->SNO->WriteGlobalSno('a', "%s used SETNAME to change their GECOS to '%s'", user->nick.c_str(), parameters[0].c_str()); } return CMD_SUCCESS; diff --git a/src/modules/m_showwhois.cpp b/src/modules/m_showwhois.cpp index 6eec64bd5..d81dd553d 100644 --- a/src/modules/m_showwhois.cpp +++ b/src/modules/m_showwhois.cpp @@ -27,35 +27,13 @@ /** Handle user mode +W */ -class SeeWhois : public ModeHandler +class SeeWhois : public SimpleUserModeHandler { public: - SeeWhois(Module* Creator, bool IsOpersOnly) : ModeHandler(Creator, "showwhois", 'W', PARAM_NONE, MODETYPE_USER) + SeeWhois(Module* Creator, bool IsOpersOnly) : SimpleUserModeHandler(Creator, "showwhois", 'W') { oper = IsOpersOnly; } - - ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) - { - if (adding) - { - if (!dest->IsModeSet('W')) - { - dest->SetMode('W',true); - return MODEACTION_ALLOW; - } - } - else - { - if (dest->IsModeSet('W')) - { - dest->SetMode('W',false); - return MODEACTION_ALLOW; - } - } - - return MODEACTION_DENY; - } }; class WhoisNoticeCmd : public Command diff --git a/src/modules/m_spanningtree/encap.cpp b/src/modules/m_spanningtree/encap.cpp index 51194e6d7..0cc293fa5 100644 --- a/src/modules/m_spanningtree/encap.cpp +++ b/src/modules/m_spanningtree/encap.cpp @@ -38,7 +38,7 @@ void TreeSocket::Encap(User* who, parameterlist ¶ms) params[params.size() - 1] = ":" + params[params.size() - 1]; - if (params[0].find('*') != std::string::npos) + if (params[0].find_first_of("*?") != std::string::npos) { Utils->DoOneToAllButSender(who->uuid, "ENCAP", params, who->server); } diff --git a/src/modules/m_spanningtree/protocolinterface.cpp b/src/modules/m_spanningtree/protocolinterface.cpp index efc00334d..3ab5dae9d 100644 --- a/src/modules/m_spanningtree/protocolinterface.cpp +++ b/src/modules/m_spanningtree/protocolinterface.cpp @@ -48,7 +48,7 @@ void SpanningTreeProtocolInterface::GetServerList(ProtoServerList &sl) bool SpanningTreeProtocolInterface::SendEncapsulatedData(const parameterlist &encap) { - if (encap[0].find('*') != std::string::npos) + if (encap[0].find_first_of("*?") != std::string::npos) { Utils->DoOneToMany(ServerInstance->Config->GetSID(), "ENCAP", encap); return true; @@ -164,26 +164,16 @@ void SpanningTreeProtocolInterface::SendChannelNotice(Channel* target, char stat void SpanningTreeProtocolInterface::SendUserPrivmsg(User* target, const std::string &text) { - TreeServer* serv = Utils->FindServer(target->server); - if (serv) - { - TreeSocket* sock = serv->GetSocket(); - if (sock) - { - sock->WriteLine(":" + ServerInstance->Config->GetSID() + " PRIVMSG " + target->nick + " :"+text); - } - } + parameterlist p; + p.push_back(target->uuid); + p.push_back(":" + text); + Utils->DoOneToOne(ServerInstance->Config->GetSID(), "PRIVMSG", p, target->server); } void SpanningTreeProtocolInterface::SendUserNotice(User* target, const std::string &text) { - TreeServer* serv = Utils->FindServer(target->server); - if (serv) - { - TreeSocket* sock = serv->GetSocket(); - if (sock) - { - sock->WriteLine(":" + ServerInstance->Config->GetSID() + " NOTICE " + target->nick + " :"+text); - } - } + parameterlist p; + p.push_back(target->uuid); + p.push_back(":" + text); + Utils->DoOneToOne(ServerInstance->Config->GetSID(), "NOTICE", p, target->server); } diff --git a/src/modules/m_spanningtree/treesocket.h b/src/modules/m_spanningtree/treesocket.h index be5455bce..aebc7e03b 100644 --- a/src/modules/m_spanningtree/treesocket.h +++ b/src/modules/m_spanningtree/treesocket.h @@ -94,6 +94,7 @@ class TreeSocket : public BufferedSocket time_t NextPing; /* Time when we are due to ping this server */ bool LastPingWasGood; /* Responded to last ping we sent? */ int proto_version; /* Remote protocol version */ + bool ConnectionFailureShown; /* Set to true if a connection failure message was shown */ public: time_t age; @@ -315,6 +316,10 @@ class TreeSocket : public BufferedSocket /** Handle server quit on close */ virtual void Close(); + + /** Returns true if this server was introduced to the rest of the network + */ + bool Introduced(); }; #endif diff --git a/src/modules/m_spanningtree/treesocket1.cpp b/src/modules/m_spanningtree/treesocket1.cpp index dcb35af31..3e916544b 100644 --- a/src/modules/m_spanningtree/treesocket1.cpp +++ b/src/modules/m_spanningtree/treesocket1.cpp @@ -49,6 +49,7 @@ TreeSocket::TreeSocket(SpanningTreeUtilities* Util, Link* link, Autoconnect* mya capab->capab_phase = 0; MyRoot = NULL; proto_version = 0; + ConnectionFailureShown = false; LinkState = CONNECTING; if (!link->Hook.empty()) { @@ -78,6 +79,7 @@ TreeSocket::TreeSocket(SpanningTreeUtilities* Util, int newfd, ListenSocket* via age = ServerInstance->Time(); LinkState = WAIT_AUTH_1; proto_version = 0; + ConnectionFailureShown = false; linkID = "inbound from " + client->addr(); FOREACH_MOD(I_OnHookIO, OnHookIO(this, via)); @@ -134,7 +136,7 @@ void TreeSocket::OnConnected() void TreeSocket::OnError(BufferedSocketError e) { - ServerInstance->SNO->WriteGlobalSno('l', "Connection to \002%s\002 failed with error: %s", + ServerInstance->SNO->WriteGlobalSno('l', "Connection to '\002%s\002' failed with error: %s", linkID.c_str(), getError().c_str()); LinkState = DYING; } @@ -183,7 +185,7 @@ void TreeSocket::Squit(TreeServer* Current, const std::string &reason) { DelServerEvent(Utils->Creator, Current->GetName()); - if (!Current->GetSocket() || Current->GetSocket()->GetLinkState() == CONNECTED) + if (!Current->GetSocket() || Current->GetSocket()->Introduced()) { parameterlist params; params.push_back(Current->GetName()); @@ -245,3 +247,8 @@ void TreeSocket::OnDataReady() SendError("RecvQ overrun (line too long)"); Utils->Creator->loopCall = false; } + +bool TreeSocket::Introduced() +{ + return (capab == NULL); +} diff --git a/src/modules/m_spanningtree/treesocket2.cpp b/src/modules/m_spanningtree/treesocket2.cpp index e6fbad4c6..0a0c22e39 100644 --- a/src/modules/m_spanningtree/treesocket2.cpp +++ b/src/modules/m_spanningtree/treesocket2.cpp @@ -484,13 +484,13 @@ void TreeSocket::Close() if (MyRoot) Squit(MyRoot,getError()); - if (!linkID.empty()) + if (!ConnectionFailureShown) { + ConnectionFailureShown = true; ServerInstance->SNO->WriteGlobalSno('l', "Connection to '\2%s\2' failed.",linkID.c_str()); time_t server_uptime = ServerInstance->Time() - this->age; if (server_uptime) ServerInstance->SNO->WriteGlobalSno('l', "Connection to '\2%s\2' was established for %s", linkID.c_str(), Utils->Creator->TimeToStr(server_uptime).c_str()); - linkID.clear(); } } diff --git a/src/modules/m_uhnames.cpp b/src/modules/m_uhnames.cpp index 37bd67440..5693eb807 100644 --- a/src/modules/m_uhnames.cpp +++ b/src/modules/m_uhnames.cpp @@ -51,13 +51,12 @@ class ModuleUHNames : public Module ModResult OnPreCommand(std::string &command, std::vector<std::string> ¶meters, LocalUser *user, bool validated, const std::string &original_line) { - irc::string c = command.c_str(); /* We don't actually create a proper command handler class for PROTOCTL, * because other modules might want to have PROTOCTL hooks too. * Therefore, we just hook its as an unvalidated command therefore we * can capture it even if it doesnt exist! :-) */ - if (c == "PROTOCTL") + if (command == "PROTOCTL") { if ((parameters.size()) && (!strcasecmp(parameters[0].c_str(),"UHNAMES"))) { diff --git a/src/modules/m_uninvite.cpp b/src/modules/m_uninvite.cpp index 6c392fe49..9287589bb 100644 --- a/src/modules/m_uninvite.cpp +++ b/src/modules/m_uninvite.cpp @@ -63,22 +63,27 @@ class CommandUninvite : public Command } } - irc::string xname(c->name.c_str()); - - if (IS_LOCAL(u)) + /* Servers remember invites only for their local users, so act + * only if the target is local. Otherwise the command will be + * passed to the target users server. + */ + LocalUser* lu = IS_LOCAL(u); + if (lu) { - // TODO send messages & such out to remote servers - LocalUser* lu = IS_LOCAL(u); + irc::string xname(c->name.c_str()); if (!lu->IsInvited(xname)) { - user->WriteNumeric(505, "%s %s %s :Is not invited to channel %s", user->nick.c_str(), u->nick.c_str(), c->name.c_str(), c->name.c_str()); + user->SendText(":%s 505 %s %s %s :Is not invited to channel %s", user->server.c_str(), user->nick.c_str(), u->nick.c_str(), c->name.c_str(), c->name.c_str()); return CMD_FAILURE; } - user->WriteNumeric(494, "%s %s %s :Uninvited", user->nick.c_str(), c->name.c_str(), u->nick.c_str()); + + user->SendText(":%s 494 %s %s %s :Uninvited", user->server.c_str(), user->nick.c_str(), c->name.c_str(), u->nick.c_str()); lu->RemoveInvite(xname); lu->WriteNumeric(493, "%s :You were uninvited from %s by %s", u->nick.c_str(), c->name.c_str(), user->nick.c_str()); - c->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :*** %s uninvited %s.", - c->name.c_str(), user->nick.c_str(), u->nick.c_str()); + + std::string msg = "*** " + user->nick + " uninvited " + u->nick + "."; + c->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE " + c->name + " :" + msg); + ServerInstance->PI->SendChannelNotice(c, 0, msg); } return CMD_SUCCESS; diff --git a/src/modules/m_xline_db.cpp b/src/modules/m_xline_db.cpp index 1918f3fc5..683c14afa 100644 --- a/src/modules/m_xline_db.cpp +++ b/src/modules/m_xline_db.cpp @@ -25,6 +25,7 @@ class ModuleXLineDB : public Module { + std::vector<XLine *> xlines; bool reading_db; // If this is true, addlines are as a result of db reading, so don't bother flushing the db to disk. // DO REMEMBER TO SET IT, otherwise it's annoying :P public: @@ -49,6 +50,7 @@ class ModuleXLineDB : public Module void OnAddLine(User* source, XLine* line) { ServerInstance->Logs->Log("m_xline_db",DEBUG, "xlinedb: Adding a line"); + xlines.push_back(line); if (!reading_db) { @@ -74,6 +76,15 @@ class ModuleXLineDB : public Module void RemoveLine(XLine *line) { ServerInstance->Logs->Log("m_xline_db",DEBUG, "xlinedb: Removing a line"); + for (std::vector<XLine *>::iterator i = xlines.begin(); i != xlines.end(); i++) + { + if ((*i) == line) + { + xlines.erase(i); + break; + } + } + WriteDatabase(); } @@ -108,19 +119,12 @@ class ModuleXLineDB : public Module fprintf(f, "VERSION 1\n"); // Now, let's write. - std::vector<std::string> types = ServerInstance->XLines->GetAllTypes(); - for (std::vector<std::string>::const_iterator it = types.begin(); it != types.end(); ++it) + XLine *line; + for (std::vector<XLine *>::iterator i = xlines.begin(); i != xlines.end(); i++) { - XLineLookup* lookup = ServerInstance->XLines->GetAll(*it); - if (!lookup) - continue; - - for (LookupIter i = lookup->begin(); i != lookup->end(); ++i) - { - XLine *line = i->second; - fprintf(f, "LINE %s %s %s %lu %lu :%s\n", line->type.c_str(), line->Displayable(), - ServerInstance->Config->ServerName.c_str(), (unsigned long)line->set_time, (unsigned long)line->duration, line->reason.c_str()); - } + line = (*i); + fprintf(f, "LINE %s %s %s %lu %lu :%s\n", line->type.c_str(), line->Displayable(), + ServerInstance->Config->ServerName.c_str(), (unsigned long)line->set_time, (unsigned long)line->duration, line->reason.c_str()); } ServerInstance->Logs->Log("m_xline_db",DEBUG, "xlinedb: Finished writing XLines. Checking for error.."); |