summaryrefslogtreecommitdiff
path: root/src/modules/m_geoclass.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/modules/m_geoclass.cpp')
-rw-r--r--src/modules/m_geoclass.cpp109
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)