diff options
Diffstat (limited to 'src/modules/m_geoclass.cpp')
-rw-r--r-- | src/modules/m_geoclass.cpp | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/src/modules/m_geoclass.cpp b/src/modules/m_geoclass.cpp new file mode 100644 index 000000000..6ec03c71f --- /dev/null +++ b/src/modules/m_geoclass.cpp @@ -0,0 +1,109 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2019 Peter Powell <petpow@saberuk.com> + * + * This file is part of InspIRCd. InspIRCd is free software: you can + * redistribute it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "inspircd.h" +#include "modules/geolocation.h" +#include "modules/stats.h" + +enum +{ + // InspIRCd-specific. + RPL_STATSCOUNTRY = 801 +}; + +class ModuleGeoClass + : public Module + , public Stats::EventListener +{ + private: + Geolocation::API geoapi; + + public: + ModuleGeoClass() + : Stats::EventListener(this) + , geoapi(this) + { + } + + Version GetVersion() CXX11_OVERRIDE + { + return Version("Provides a way to assign users to connect classes by country", VF_VENDOR); + } + + ModResult OnSetConnectClass(LocalUser* user, ConnectClass* myclass) CXX11_OVERRIDE + { + const std::string country = myclass->config->getString("country"); + if (country.empty()) + return MOD_RES_PASSTHRU; + + // If we can't find the location of this user then we can't assign + // them to a location-specific connect class. + Geolocation::Location* location = geoapi ? geoapi->GetLocation(user) : NULL; + const std::string code = location ? location->GetCode() : "XX"; + + irc::spacesepstream codes(country); + for (std::string token; codes.GetToken(token); ) + { + // If the user matches this country code then they can use this + // connect class. + if (stdalgo::string::equalsci(token, code)) + return MOD_RES_PASSTHRU; + } + + // A list of country codes were specified but the user didn't match + // any of them. + return MOD_RES_DENY; + } + + ModResult OnStats(Stats::Context& stats) CXX11_OVERRIDE + { + if (stats.GetSymbol() != 'G') + return MOD_RES_PASSTHRU; + + // Counter for the number of users in each country. + typedef std::map<Geolocation::Location*, size_t> CountryCounts; + CountryCounts counts; + + // Counter for the number of users in an unknown country. + size_t unknown = 0; + + const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers(); + for (UserManager::LocalList::const_iterator iter = list.begin(); iter != list.end(); ++iter) + { + Geolocation::Location* location = geoapi ? geoapi->GetLocation(*iter) : NULL; + if (location) + counts[location]++; + else + unknown++; + } + + for (CountryCounts::const_iterator iter = counts.begin(); iter != counts.end(); ++iter) + { + Geolocation::Location* location = iter->first; + stats.AddRow(RPL_STATSCOUNTRY, iter->second, location->GetCode(), location->GetName()); + } + + if (unknown) + stats.AddRow(RPL_STATSCOUNTRY, unknown, "*", "Unknown Country"); + + return MOD_RES_DENY; + } +}; + +MODULE_INIT(ModuleGeoClass) |