Main Page | Class List | File List | Class Members | File Members

CountryFilter.cpp

Go to the documentation of this file.
00001 /* Countryfilter.cpp
00002  *
00003  * Copyright (C) 2005 Guwashi <guwashi[AT]fooos[DOT]com>
00004  *
00005  * This library is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU General Public
00007  * License as published by the Free Software Foundation; either
00008  * version 2.1 of the License, or (at your option) any later version.
00009  *
00010  * This library is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  * General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public
00016  * License along with this library; if not, write to the Free Software
00017  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018  */
00019 
00020 // This code is based on
00021 // http://www.sourcemod.net/forums/viewtopic.php?t=628
00022 
00023 #include <stdio.h>
00024 #include <stdlib.h>
00025 #include "CountryFilter.h"
00026 #include "MRecipientFilter.h"
00027 
00028 CountryFilter g_CF;
00029 
00030 //Expose the singleton
00031 EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CountryFilter, IServerPluginCallbacks, INTERFACEVERSION_ISERVERPLUGINCALLBACKS, g_CF);
00032 
00033 
00034 // Macros for interface loading
00035 #define LOAD_EINTERFACE(var, type, version, name) !((var = (type *)interfaceFactory(version, 0)) \
00036         || (Error("[CF] Could not load %s interface\n", name), false)) ||
00037 #define LOAD_EINTERFACE_OPT(var, type, version, name) ((var = (type *)interfaceFactory(version, 0)), false) ||
00038 
00039 #define LOAD_GINTERFACE(var, type, version, name) !((var = (type *)gameServerFactory(version, 0)) \
00040         || (Error("[CF] Could not load %s interface\n", name), false)) ||
00041 #define LOAD_GINTERFACE_OPT(var, type, version, name) ((var = (type *)gameServerFactory(version, 0)), false) ||
00042 
00043 #define LOAD_INTERFACES_BEGIN if (
00044 #define LOAD_INTERFACES_END false) return false;
00045 
00047 ConVar g_Version("cf_version", "1.0.3", 0, "CountryFilter version.");
00048 ConVar g_AllowMessage("cf_allow_message", "%s (Country: %s) was allowed to connect.", 0, "Message format when player was allowed to connect.");
00049 ConVar g_DenyMessage("cf_deny_message", "%s (Country: %s) was rejected by CountryFilter.", 0, "Message format when player was denied to connect.");
00050 ConVar g_MessageExcludeFrom("cf_message_exclude_from", "", 0, "Specify the country(s) which is excluded from printing messages. ex.1) \"JP US --\"  ex.2) \"all\"");
00051 ConVar g_Order("cf_order", "deny,allow", 0, "Controls the default access state and the order in which cf_allow_from and cf_deny_from are evaluated. ex1) \"deny,allow\" (default)  ex2) \"allow,deny\"");
00052 ConVar g_AllowFrom("cf_allow_from", "all", 0, "Specify the country(s) which is allowed to connect. ex.1) \"JP US --\"  ex.2) \"all\"");
00053 ConVar g_DenyFrom("cf_deny_from", "", 0, "Specify the country(s) which is deny to connect.  ex.1) \"all\"  ex.2) \"JP US --\"");
00054 ConVar g_CountryPrintMode("cf_country_print_mode", "code", 0, "Sets country print mode. Allowed values: \"code\" (default), \"code3\" and \"name\".");
00055 ConVar g_StatusCommandAlias("cf_status_command_alias", "listplayers", 0, "Sets alias of status command.  ex.) \"listplayers\" (default).");
00056 ConVar g_ForceChangeName("cf_force_change_name", "0", 0, "*** EXPERIMENTAL ***: Adding the country tag to player name. 0: off (default), 1: on.");
00057 ConVar g_CountryTag("cf_country_tag", "%s|", 0, "*** EXPERIMENTAL ***: Specify the country tag format.");
00058 
00059 CountryFilter::CountryFilter()
00060 {
00061   m_Loaded = false;
00062   m_Paused = false;
00063   m_Initialized = false;
00064 }
00065 
00066 CountryFilter::~CountryFilter()
00067 {
00068   m_Loaded = false;
00069   m_Paused = false;
00070   m_Initialized = false;
00071 }
00072 
00073 bool CountryFilter::Load(CreateInterfaceFn interfaceFactory, CreateInterfaceFn gameServerFactory)
00074 {
00075   if (m_Loaded) return true;
00076 
00077   LOAD_INTERFACES_BEGIN
00078     LOAD_EINTERFACE(m_IVEngine,
00079                     IVEngineServer,
00080                     INTERFACEVERSION_VENGINESERVER,
00081                     INTERFACEVERSION_VENGINESERVER)
00082     LOAD_EINTERFACE(m_GameEventManager,
00083                     IGameEventManager,
00084                     INTERFACEVERSION_GAMEEVENTSMANAGER,
00085                     INTERFACEVERSION_GAMEEVENTSMANAGER)
00086     LOAD_EINTERFACE(m_CvarFactory,
00087                     ICvar,
00088                     VENGINE_CVAR_INTERFACE_VERSION,
00089                     VENGINE_CVAR_INTERFACE_VERSION)
00090     LOAD_EINTERFACE(m_Helpers,
00091                     IServerPluginHelpers,
00092                     INTERFACEVERSION_ISERVERPLUGINHELPERS,
00093                     INTERFACEVERSION_ISERVERPLUGINHELPERS)
00094     LOAD_EINTERFACE(m_IEngineSound,
00095                     IEngineSound,
00096                     IENGINESOUND_SERVER_INTERFACE_VERSION,
00097                     IENGINESOUND_SERVER_INTERFACE_VERSION)
00098     LOAD_GINTERFACE(m_IEffects,
00099                     IEffects,
00100                     IEFFECTS_INTERFACE_VERSION,
00101                     IEFFECTS_INTERFACE_VERSION)
00102     LOAD_GINTERFACE(m_PlayerInfoManager,
00103                     IPlayerInfoManager,
00104                     INTERFACEVERSION_PLAYERINFOMANAGER,
00105                     INTERFACEVERSION_PLAYERINFOMANAGER)
00106   LOAD_INTERFACES_END
00107 
00108   m_pConVarAccessor = new CPluginConVarAccessor(this);
00109 
00110   if (!m_pConVarAccessor) {
00111     Error("[CF] Fatal error: could not allocates %d bytes (%s, line %d)\n", sizeof(CPluginConVarAccessor), __FILE__, __LINE__);
00112     return false;
00113   }
00114 
00115   ConCommandBaseMgr::OneTimeInit(m_pConVarAccessor);
00116 
00117   // ".../addons/GeoIP.dat"
00118   char dataPath[COUNTRYFILTER_TMP_BUFFER_LENGTH];
00119   m_IVEngine->GetGameDir(dataPath, sizeof(dataPath));
00120   Q_strncat(dataPath, COUNTRYFILTER_PATH_SEPARATOR, sizeof(dataPath), COPY_ALL_CHARACTERS);
00121   Q_strncat(dataPath, "addons", sizeof(dataPath), COPY_ALL_CHARACTERS);
00122   Q_strncat(dataPath, COUNTRYFILTER_PATH_SEPARATOR, sizeof(dataPath), COPY_ALL_CHARACTERS);
00123   Q_strncat(dataPath, "GeoIP.dat", sizeof(dataPath), COPY_ALL_CHARACTERS);
00124   m_giw = new GeoIPWrapper(dataPath, GEOIP_STANDARD);
00125 
00126   m_Loaded = true;
00127 
00128   return true;
00129 }
00130 
00131 void CountryFilter::Unload()
00132 {
00133   if (m_giw) {
00134     delete m_giw;
00135     m_giw = 0;
00136   }
00137 
00138   // make sure we are unloaded from the event system
00139   m_GameEventManager->RemoveListener(this);
00140 
00141   if (m_pConVarAccessor) {
00142     delete m_pConVarAccessor;
00143     m_pConVarAccessor = 0;
00144   }
00145 
00146   m_Loaded = false;
00147 }
00148 
00149 void CountryFilter::ClientActive(edict_t* pEntity)
00150 {
00151 }
00152 
00153 PLUGIN_RESULT CountryFilter::ClientCommand(edict_t* pEntity)
00154 {
00155   if (!pEntity || pEntity->IsFree()) {
00156     return PLUGIN_CONTINUE;
00157   }
00158 
00159   const char* commandName = m_IVEngine->Cmd_Argv(0);
00160   if ((Q_strncmp(commandName, "cf_status", sizeof("cf_status")) == 0) ||
00161       (Q_strlen(g_StatusCommandAlias.GetString()) > 0 &&
00162        Q_strncmp(commandName, g_StatusCommandAlias.GetString(), Q_strlen(g_StatusCommandAlias.GetString())) == 0)) {
00163     return handleStatusCommand(pEntity);
00164   } else if (Q_strncmp(commandName, "cf_country_by_addr", sizeof("cf_country_by_addr")) == 0) { // for DEBUG
00165     return handleCountryByAddrCommand(pEntity);
00166   } else if (Q_strncmp(commandName, "cf_test_geoip", sizeof("cf_test_geoip")) == 0) { // for DEBUG
00167     return handleTestGeoIPCommand(pEntity);
00168   }
00169 
00170   return PLUGIN_CONTINUE;
00171 }
00172 
00173 PLUGIN_RESULT CountryFilter::handleStatusCommand(edict_t* pEntity)
00174 {
00175   return printCountryStatus(pEntity, false) ? PLUGIN_STOP : PLUGIN_CONTINUE;
00176 }
00177 
00178 PLUGIN_RESULT CountryFilter::handleCountryByAddrCommand(edict_t* pEntity)
00179 {
00180   // check arg length
00181   int argc = m_IVEngine->Cmd_Argc();
00182   if (argc < 2) {
00183     m_IVEngine->ClientPrintf(pEntity, "Usage:\n  cf_country_by_addr IPaddress\n");
00184     return PLUGIN_STOP;
00185   }
00186 
00187   // check arg
00188   const char* addr = m_IVEngine->Cmd_Argv(1);
00189   if (!(addr && Q_strlen(addr) > 0)) {
00190     m_IVEngine->ClientPrintf(pEntity, "Usage:\n  cf_country_by_addr IPaddress\n");
00191     return PLUGIN_STOP;
00192   }
00193 
00194   int countryId = m_giw->getIdByAddr(addr);
00195   const char* country = idToCountry(countryId);
00196   char buf[COUNTRYFILTER_TMP_BUFFER_LENGTH];
00197   Q_snprintf(buf, sizeof(buf), "[CF] %s ==> %s\n", addr, country);
00198   m_IVEngine->ClientPrintf(pEntity, buf);
00199 
00200   return PLUGIN_STOP;
00201 }
00202 
00203 PLUGIN_RESULT CountryFilter::handleTestGeoIPCommand(edict_t* pEntity)
00204 {
00205   testGeoIP(pEntity);
00206 
00207   return PLUGIN_STOP;
00208 }
00209 
00210 PLUGIN_RESULT CountryFilter::ClientConnect(bool* bAllowConnect, edict_t* pEntity, const char* pszName, const char* pszAddress, char* reject, int maxrejectlen)
00211 {
00212   // "123.123.123.123:12345" ==> "123.123.123.123"
00213   char addr[COUNTRYFILTER_TMP_BUFFER_LENGTH];
00214   Q_strncpy(addr, "", sizeof(addr));
00215   size_t colonPos = indexOf(pszAddress, ":");
00216   if (colonPos != -1) {
00217     substring(pszAddress, 0, colonPos, addr);
00218   }
00219 
00220   int countryId = m_giw->getIdByAddr(addr);
00221   const char* countryCode = GeoIPWrapper::idToCountryCode(countryId);
00222   const char* country = idToCountry(countryId);
00223 
00224   if (isAllowConnect(countryCode)) {
00225     // print allow message
00226     if (Q_strlen(g_AllowMessage.GetString()) > 0 &&
00227         !isMessageExcludeFrom(countryCode)) {
00228       char buf[COUNTRYFILTER_TMP_BUFFER_LENGTH];
00229       Q_snprintf(buf, sizeof(buf), g_AllowMessage.GetString(), pszName, country);
00230       Q_strncat(buf, "\n", sizeof(buf), COPY_ALL_CHARACTERS);
00231       clientSendAllChatMessage(buf);
00232       m_IVEngine->LogPrint(buf);
00233     }
00234 
00235     // store player's country ID
00236     int playerIndex = m_IVEngine->IndexOfEdict(pEntity);
00237     setPlayerCountryId(playerIndex, countryId);
00238 
00239     // change name
00240     if (g_ForceChangeName.GetInt()) {
00241       setPlayerOriginalName(playerIndex, pszName);
00242       char buf[COUNTRYFILTER_TMP_BUFFER_LENGTH];
00243       Q_snprintf(buf, sizeof(buf), g_CountryTag.GetString(), countryCode);
00244       if (indexOf(pszName, buf) != 0) {
00245         m_IVEngine->ClientCommand(pEntity, "name \"%s%s\"\n", buf, pszName);
00246       }
00247     }
00248 
00249     return PLUGIN_CONTINUE;
00250   } else {
00251     // print deny message
00252     if (Q_strlen(g_DenyMessage.GetString()) > 0 &&
00253         !isMessageExcludeFrom(countryCode)) {
00254       char buf[COUNTRYFILTER_TMP_BUFFER_LENGTH];
00255       Q_snprintf(buf, sizeof(buf), g_DenyMessage.GetString(), pszName, country);
00256       Q_strncat(buf, "\n", sizeof(buf), COPY_ALL_CHARACTERS);
00257       clientSendAllChatMessage(buf);
00258       m_IVEngine->LogPrint(buf);
00259     }
00260     *bAllowConnect = false; // reject
00261     return PLUGIN_STOP;
00262   }
00263 }
00264 
00265 void CountryFilter::ClientDisconnect(edict_t* pEntity)
00266 {
00267   // clear player's country ID
00268   int playerIndex = m_IVEngine->IndexOfEdict(pEntity);
00269   setPlayerCountryId(playerIndex, 0);
00270   // change name
00271   if (g_ForceChangeName.GetInt()) {
00272     m_IVEngine->ClientCommand(pEntity, "name \"%s\"\n", getPlayerOriginalName(playerIndex));
00273     setPlayerOriginalName(playerIndex, "");
00274   }
00275 }
00276 
00277 void CountryFilter::ClientPutInServer(edict_t* pEntity, const char* playername)
00278 {
00279 }
00280 
00281 void CountryFilter::ClientSettingsChanged(edict_t* pEntity)
00282 {
00283   /*
00284   // change name
00285   if (g_ForceChangeName.GetInt()) {
00286     if (!pEntity) return;
00287     int playerIndex = m_IVEngine->IndexOfEdict(pEntity);
00288     int countryId = getPlayerCountryId(playerIndex);
00289     const char* countryCode = GeoIPWrapper::idToCountryCode(countryId);
00290     char buf[COUNTRYFILTER_TMP_BUFFER_LENGTH];
00291     Q_snprintf(buf, sizeof(buf), g_CountryTag.GetString(), countryCode);
00292     if (indexOf(newName, buf) != 0) {
00293       m_IVEngine->ClientCommand(playerEdict, "name \"%s%s\"\n", buf, newName);
00294     }
00295   }
00296   */
00297 }
00298 
00299 void CountryFilter::GameFrame(bool simulation)
00300 {
00301   if (m_Paused || !m_Initialized) return;
00302   return;
00303 }
00304 
00305 const char* CountryFilter::GetPluginDescription()
00306 {
00307   return "CountryFilter-1.0.3 by Guwashi, http://d3.jpn.org/";
00308 }
00309 
00310 void CountryFilter::LevelInit(const char* pMapName)
00311 {
00312   testGeoIP(0); // for DEBUG
00313 
00314   m_GameEventManager->AddListener(this, true);
00315   m_Initialized = true;
00316 }
00317 
00318 void CountryFilter::LevelShutdown()
00319 {
00320   m_GameEventManager->RemoveListener(this);
00321   m_Initialized = false;
00322 }
00323 
00324 PLUGIN_RESULT CountryFilter::NetworkIDValidated(const char* pszUserName, const char* pszNetworkID)
00325 {
00326   return PLUGIN_CONTINUE;
00327 }
00328 
00329 void CountryFilter::Pause()
00330 {
00331   m_Paused = true;
00332 }
00333 
00334 void CountryFilter::ServerActivate(edict_t* pEdictList, int edictCount, int clientMax)
00335 {
00336   m_ClientMax = clientMax;
00337   initPlayerCountryIdList(m_ClientMax);
00338   initPlayerOriginalNameList(m_ClientMax);
00339 }
00340 
00341 void CountryFilter::SetCommandClient(int index)
00342 {
00343   m_ClCommandIndex = index;
00344 }
00345 
00346 void CountryFilter::UnPause()
00347 {
00348   m_Paused = false;
00349 }
00350 
00351 void CountryFilter::FireGameEvent(KeyValues* event)
00352 {
00353   const char* name = event->GetName();
00354 
00355   if (Q_strncmp(name, "player_say", sizeof("player_say")) == 0) {
00356     handlePlayerSayEvent(event);
00357   } else if (Q_strncmp(name, "player_disconnect", sizeof("player_disconnect")) == 0) {
00358     // change name
00359     if (g_ForceChangeName.GetInt()) {
00360       const int playerUserID = event->GetInt("userid");
00361       edict_t* playerEdict = getPlayerEdictByUserID(playerUserID);
00362       if (!playerEdict) return;
00363       int playerIndex = m_IVEngine->IndexOfEdict(playerEdict);
00364       m_IVEngine->ClientCommand(playerEdict, "name \"%s\"\n", getPlayerOriginalName(playerIndex));
00365     }
00366   } else if (Q_strncmp(name, "player_changename", sizeof("player_changename")) == 0) {
00367     // change name
00368     if (g_ForceChangeName.GetInt()) {
00369       const int playerUserID = event->GetInt("userid");
00370       edict_t* playerEdict = getPlayerEdictByUserID(playerUserID);
00371       if (!playerEdict) return;
00372       const char* newName = event->GetString("newname");
00373       const char* oldName = event->GetString("oldname");
00374       int playerIndex = m_IVEngine->IndexOfEdict(playerEdict);
00375       setPlayerOriginalName(playerIndex, newName);
00376       int countryId = getPlayerCountryId(playerIndex);
00377       const char* countryCode = GeoIPWrapper::idToCountryCode(countryId);
00378       char buf[COUNTRYFILTER_TMP_BUFFER_LENGTH];
00379       Q_snprintf(buf, sizeof(buf), g_CountryTag.GetString(), countryCode);
00380       if (indexOf(newName, buf) != 0) {
00381         m_IVEngine->ClientCommand(playerEdict, "name \"%s%s\"\n", buf, newName);
00382       }
00383     }
00384   }
00385 }
00386 
00387 bool CountryFilter::handlePlayerSayEvent(KeyValues* event)
00388 {
00389   const int playerUserID = event->GetInt("userid");
00390   const char* text = event->GetString("text");
00391 
00392   if ((Q_strncmp(text, "cf_status", sizeof("cf_status")) == 0) ||
00393       (Q_strlen(g_StatusCommandAlias.GetString()) > 0 &&
00394        Q_strncmp(text, g_StatusCommandAlias.GetString(), Q_strlen(g_StatusCommandAlias.GetString())) == 0)) {
00395     edict_t* playerEdict = getPlayerEdictByUserID(playerUserID);
00396     if (playerEdict) {
00397       printCountryStatus(playerEdict, true);
00398       return true;
00399     }
00400   }
00401 
00402   return false;
00403 }
00404 
00405 
00406 CountryFilter::CPluginConVarAccessor::CPluginConVarAccessor(CountryFilter* cf)
00407 {
00408   m_cf = cf;
00409 }
00410 
00411 bool CountryFilter::CPluginConVarAccessor::RegisterConCommandBase(ConCommandBase* pCommand)
00412 {
00413   pCommand->SetNext(0);
00414   m_cf->m_CvarFactory->RegisterConCommandBase(pCommand);
00415 
00416   return true;
00417 }
00418 
00419 edict_t* CountryFilter::getPlayerEdictByIndex(int playerIndex)
00420 {
00421   if (playerIndex > 0 && playerIndex <= m_ClientMax) {
00422     edict_t* pPlayerEdict = m_IVEngine->PEntityOfEntIndex(playerIndex);
00423     if (pPlayerEdict && !pPlayerEdict->IsFree()) {
00424       return pPlayerEdict;
00425     }
00426   }
00427   return 0;
00428 }
00429 
00430 edict_t* CountryFilter::getPlayerEdictByUserID(int userID)
00431 {
00432   for (int i = 1; i <= m_ClientMax; i++) {
00433     edict_t* pPlayerEdict = getPlayerEdictByIndex(i);
00434     IPlayerInfo* pPlayerInfo = getPlayerInfoByEdict(pPlayerEdict);
00435     if (pPlayerInfo && pPlayerInfo->GetUserID() == userID) {
00436       return pPlayerEdict;
00437     }
00438   }
00439   return 0;
00440 }
00441 
00442 IPlayerInfo* CountryFilter::getPlayerInfoByEdict(edict_t* pPlayerEdict)
00443 {
00444   if (!pPlayerEdict) return 0;
00445   IPlayerInfo* pPlayerInfo = m_PlayerInfoManager->GetPlayerInfo(pPlayerEdict);
00446   return (pPlayerInfo && pPlayerInfo->IsConnected()) ? pPlayerInfo : 0;
00447 }
00448 
00449 IPlayerInfo* CountryFilter::getPlayerInfoByIndex(int playerIndex)
00450 {
00451   return getPlayerInfoByEdict(getPlayerEdictByIndex(playerIndex));
00452 }
00453 
00454 
00455 IPlayerInfo* CountryFilter::getPlayerInfoByUserID(int userID)
00456 {
00457   for (int i = 1; i <= m_ClientMax; i++) {
00458     IPlayerInfo* pPlayerInfo = getPlayerInfoByIndex(i);
00459     if (pPlayerInfo && pPlayerInfo->GetUserID() == userID) {
00460       return pPlayerInfo;
00461     }
00462   }
00463   return 0;
00464 }
00465 
00466 int CountryFilter::getPlayerCount()
00467 {
00468   int count = 0;
00469   for (int i = 1; i <= m_ClientMax; i++) {
00470     IPlayerInfo* pPlayerInfo = getPlayerInfoByIndex(i);
00471     if (pPlayerInfo && pPlayerInfo->IsConnected()) {
00472       const char* steamId = pPlayerInfo->GetNetworkIDString();
00473       if (isValidSteamId(steamId) && !isBOTSteamId(steamId)) {
00474         ++count;
00475       }
00476     }
00477   }
00478   return count;
00479 }
00480 
00481 bool CountryFilter::isMessageExcludeFrom(const char* countryCode) const
00482 {
00483   const char* exclude = g_MessageExcludeFrom.GetString();
00484 
00485   bool result = false;
00486   if (indexOf(exclude, "all") != -1) result = true;
00487   if (indexOf(exclude, countryCode) != -1) result = true;
00488   return result;
00489 }
00490 
00491 bool CountryFilter::isAllowConnect(const char* countryCode) const
00492 {
00493   const char* order = g_Order.GetString();
00494   const char* allow = g_AllowFrom.GetString();
00495   const char* deny = g_DenyFrom.GetString();
00496 
00497   // http://httpd.apache.org/docs/mod/mod_access.html
00498   bool result;
00499   if (Q_strncmp(order, "allow,deny", sizeof("allow,deny")) == 0) {
00500     result = false; // deny
00501     if (indexOf(allow, "all") != -1) result = true;
00502     if (indexOf(allow, countryCode) != -1) result = true;
00503     if (indexOf(deny, "all") != -1) result = false;
00504     if (indexOf(deny, countryCode) != -1) result = false;
00505   } else { // "deny,allow" (default)
00506     result = true; // allow
00507     if (indexOf(deny, "all") != -1) result = false;
00508     if (indexOf(deny, countryCode) != -1) result = false;
00509     if (indexOf(allow, "all") != -1) result = true;
00510     if (indexOf(allow, countryCode) != -1) result = true;
00511   }
00512   return result;
00513 }
00514 
00515 const char* CountryFilter::idToCountry(int countryId) const
00516 {
00517   const char* printMode = g_CountryPrintMode.GetString();
00518   if (Q_strncmp(printMode, "code3", sizeof("code3")) == 0) {
00519     return GeoIPWrapper::idToCountryCode3(countryId);
00520   } else if (Q_strncmp(printMode, "name", sizeof("name")) == 0) {
00521     return GeoIPWrapper::idToCountryName(countryId);
00522   } else { // "code" (default)
00523     return GeoIPWrapper::idToCountryCode(countryId);
00524   }
00525 }
00526 
00527 int CountryFilter::getPlayerCountryId(int playerIndex) const
00528 {
00529   return m_playerCountryIdList.IsValidIndex(playerIndex) ? m_playerCountryIdList[playerIndex] : 0;
00530 }
00531 
00532 const char* CountryFilter::getPlayerOriginalName(int playerIndex) const
00533 {
00534   return playerIndex >= 0 && playerIndex < 64 ? m_playerOriginalNameList[playerIndex] : 0; // TODO
00535 }
00536 
00537 bool CountryFilter::setPlayerCountryId(int playerIndex, int countryId)
00538 {
00539   if (m_playerCountryIdList.IsValidIndex(playerIndex)) {
00540     m_playerCountryIdList[playerIndex] = countryId;
00541     return true;
00542   } else {
00543     return false;
00544   }
00545 }
00546 
00547 bool CountryFilter::setPlayerOriginalName(int playerIndex, const char* name)
00548 {
00549   if (playerIndex > 0 && playerIndex < 64) { // TODO
00550     Q_strncpy(m_playerOriginalNameList[playerIndex], name, sizeof(m_playerOriginalNameList[playerIndex]));
00551     return true;
00552   } else {
00553     return false;
00554   }
00555 }
00556 
00557 bool CountryFilter::initPlayerCountryIdList(int clientMax)
00558 {
00559   m_playerCountryIdList.SetCount(clientMax + 1); // m_playerCountryIdList[0] is unused
00560   bool result = true;
00561   for (int i = 0; i < m_playerCountryIdList.Count(); i++) {
00562     if (!setPlayerCountryId(i, 0)) result = false;
00563   }
00564   return result;
00565 }
00566 
00567 bool CountryFilter::initPlayerOriginalNameList(int clientMax)
00568 {
00569   bool result = true;
00570   for (int i = 0; i < 64; i++) { // TODO
00571     if (!setPlayerOriginalName(i, "")) result = false;
00572   }
00573   return result;
00574 }
00575 
00576 bool CountryFilter::printCountryStatus(edict_t* pEntity, bool isChat)
00577 {
00578   IPlayerInfo* pPrintInfo = getPlayerInfoByEdict(pEntity);
00579   if (!pPrintInfo) return false;
00580 
00581   const char* printSteamId = pPrintInfo->GetNetworkIDString();
00582   if (!(isValidSteamId(printSteamId) && !isBOTSteamId(printSteamId))) return false;
00583 
00584   // Should I enable to customize this format with convar?
00585   const char* firstLine = "# userid name uniqueid country\n";
00586   if (isChat) {
00587     clientSendChatMessage(pEntity, firstLine);
00588   } else {
00589     m_IVEngine->ClientPrintf(pEntity, firstLine);
00590   }
00591 
00592   /*
00593   { // DEBUG
00594     for (int i = 0; i < m_playerCountryIdList.Count(); i++) {
00595       char buf[COUNTRYFILTER_TMP_BUFFER_LENGTH];
00596       Q_snprintf(buf, sizeof(buf), "m_playerCountryIdList[%d] == %d\n", i, m_playerCountryIdList[i]);
00597       if (isChat) {
00598         clientSendChatMessage(pEntity, buf);
00599       } else {
00600         m_IVEngine->ClientPrintf(pEntity, buf);
00601       }
00602     }
00603   }
00604   */
00605 
00606   /*
00607   { // DEBUG
00608     for (int i = 1; i <= m_ClientMax; i++) {
00609       char buf[COUNTRYFILTER_TMP_BUFFER_LENGTH];
00610       Q_snprintf(buf, sizeof(buf), "getPlayerOriginalName(%d) == %s\n", i, getPlayerOriginalName(i));
00611       if (isChat) {
00612         clientSendChatMessage(pEntity, buf);
00613       } else {
00614         m_IVEngine->ClientPrintf(pEntity, buf);
00615       }
00616     }
00617   }
00618   */
00619 
00620   for (int i = 1; i <= m_ClientMax; i++) {
00621     edict_t *pPlayerEdict = getPlayerEdictByIndex(i);
00622     if (!pPlayerEdict) continue;
00623 
00624     IPlayerInfo* pPlayerInfo = getPlayerInfoByEdict(pPlayerEdict);
00625     if (!pPlayerInfo) continue;
00626 
00627     const char* playerSteamId = pPlayerInfo->GetNetworkIDString();
00628     if (!(isValidSteamId(playerSteamId) && !isBOTSteamId(playerSteamId))) continue;
00629 
00630     int countryId = getPlayerCountryId(i);
00631     const char* country = idToCountry(countryId);
00632 
00633     char buf[COUNTRYFILTER_TMP_BUFFER_LENGTH];
00634 
00635     // Should I enable to customize this format with convar?
00636     Q_snprintf(buf, sizeof(buf), "# %2d \"%s\" %s \"%s\"\n", pPlayerInfo->GetUserID(), pPlayerInfo->GetName(), pPlayerInfo->GetNetworkIDString(), country);
00637     if (isChat) {
00638       clientSendChatMessage(pEntity, buf);
00639     } else {
00640       m_IVEngine->ClientPrintf(pEntity, buf);
00641     }
00642   }
00643 
00644   return true;
00645 }
00646 
00647 bool CountryFilter::testGeoIP(edict_t* pEntity)
00648 {
00649   char buf[COUNTRYFILTER_TMP_BUFFER_LENGTH];
00650   Q_snprintf(buf, sizeof(buf), "[CF] testing GeoIP ...\n");
00651   if (pEntity) {
00652     m_IVEngine->ClientPrintf(pEntity, buf);
00653   } else {
00654     m_IVEngine->LogPrint(buf);
00655   }
00656 
00657   const char* testAddr = "66.94.234.13"; // yahoo.com
00658   const char* correctCountryCode = "US";
00659   int resultCountryId = m_giw->getIdByAddr(testAddr);
00660   const char* resultCountryCode = GeoIPWrapper::idToCountryCode(resultCountryId);
00661   bool result = Q_strncmp(correctCountryCode, resultCountryCode, sizeof(correctCountryCode)) == 0;
00662   Q_snprintf(buf, sizeof(buf), "[CF] %s: %s ==> %s\n", result ? "OK" : "NG", testAddr, resultCountryCode);
00663   if (pEntity) {
00664     m_IVEngine->ClientPrintf(pEntity, buf);
00665   } else {
00666     m_IVEngine->LogPrint(buf);
00667   }
00668 
00669   return result;
00670 }
00671 
00672 bool CountryFilter::clientSendChatMessage(edict_t* pEntity, const char* msg)
00673 {
00674   int playerIndex = m_IVEngine->IndexOfEdict(pEntity);
00675   MRecipientFilter mrf; 
00676   mrf.AddPlayerByIndex(m_IVEngine, m_PlayerInfoManager, playerIndex);
00677   bf_write* pWrite = m_IVEngine->UserMessageBegin((IRecipientFilter*)&mrf, 3); // 3 = chat
00678   pWrite->WriteByte(playerIndex); 
00679   pWrite->WriteString(msg); 
00680   pWrite->WriteByte(true); //bChat
00681   m_IVEngine->MessageEnd();
00682   return true;
00683 }
00684 
00685 bool CountryFilter::clientSendAllChatMessage(const char* msg)
00686 {
00687   for (int i = 1; i <= m_ClientMax; i++) {
00688     edict_t *pPlayerEdict = getPlayerEdictByIndex(i);
00689     if (pPlayerEdict) {
00690       IPlayerInfo* pPlayerInfo = getPlayerInfoByEdict(pPlayerEdict);
00691       if (pPlayerInfo) {
00692         const char* steamId = pPlayerInfo->GetNetworkIDString();
00693         if (isValidSteamId(steamId) && !isBOTSteamId(steamId)) {
00694           clientSendChatMessage(pPlayerEdict, msg);
00695         }
00696       }
00697     }
00698   }
00699   return true;
00700 }
00701 
00702 
00703 bool CountryFilter::isValidSteamId(const char* steamId)
00704 {
00705   return steamId && (Q_strlen(steamId) > 0);
00706 }
00707 
00708 bool CountryFilter::isBOTSteamId(const char* steamId)
00709 {
00710   return Q_strncmp(steamId, "BOT", sizeof("BOT")) == 0;
00711 }
00712 
00713 size_t CountryFilter::indexOf(const char* s1, const char* s2, size_t begin)
00714 {
00715   size_t s1Len = Q_strlen(s1);
00716   if (begin > s1Len) return -1;
00717   char* hit = Q_strstr(s1 + begin, s2);
00718   if (hit) {
00719     size_t hitLen = Q_strlen(hit);
00720     return s1Len - hitLen;
00721   } else {
00722     return -1;
00723   }
00724 }
00725 
00726 bool CountryFilter::substring(const char* src, size_t begin, size_t end, char* dst)
00727 {
00728   if (!src || !dst) return false;
00729   if (begin < 0 || begin > end) return false;
00730   size_t srcLen = Q_strlen(src);
00731   if (srcLen < 0) return false; 
00732   // if (end > srcLen) return false;
00733   if (end > srcLen) end = srcLen;
00734   size_t dstLen = end - begin;
00735 
00736   Q_memcpy(dst, src + begin, dstLen);
00737   *(dst + dstLen) = '\0';
00738 
00739   return true;
00740 }

Generated on Tue Jun 28 01:09:07 2005 for CountryFilter by  doxygen 1.4.3-20050623