All pastes #938654 Raw Edit

Systeme de Precache Comptes @ Ma

public text v1 · immutable
·published 2008-03-11 20:04 UTC
rendered paste body
Index: AuthSocket.h
===================================================================
--- AuthSocket.h	(révision 5401)
+++ AuthSocket.h	(copie de travail)
@@ -53,6 +53,11 @@
         bool _HandleXferCancel();
         bool _HandleXferAccept();
 
+        bool _HandleInformationRetrieveAnsw();
+        bool _HandleGMLevelAnsw();
+        bool _HandleBanIPAnsw();
+        bool _HandleRealmCharsAnsw();
+
         void _SetVSFields(std::string rI);
 
         FILE *pPatch;
Index: AccountHandler.h
===================================================================
--- AccountHandler.h	(révision 0)
+++ AccountHandler.h	(révision 0)
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/** \file
+    \ingroup realmd
+*/
+
+#include "Common.h"
+
+struct Account
+{
+    uint32 id;
+    uint8 security;
+    uint8 locale;
+    bool tbc;
+    bool banned;
+    bool locked;
+    std::string name;
+    std::string I;
+    std::string LastIp;
+};
+
+struct BanIp
+{
+  std::string Ip;
+};
+
+struct RealmCharacter
+{
+  uint32 realmId;
+  uint32 acctId;
+  uint8 numChars;
+};
+
+class AcctContainer
+{
+  public:
+
+   AcctContainer();
+   Account* FindAccountById(uint32 acctid);
+   Account* FindAccountByName(std::string name);
+   bool IpBan(std::string ClientIp);
+   void LoadAll();
+   void ReloadEverythingIfNeed();
+   void Initialize(uint32 updateInterval);
+   void AddAccount(Account* account,uint32 id, uint8 security, uint8 locale, uint8 tbc, bool banned, uint8 locked, std::string name, std::string I, std::string lastip);
+   void AddCharacter(RealmCharacter* rcharacter, uint32 realmId, uint32 acctId, uint8 numChars);
+   void AddBan(BanIp* banip, std::string Ip){ banip->Ip = Ip; }
+   uint8 GetNumChar(uint32 realmId, uint32 accountId);
+    
+  private:
+
+    typedef HM_NAMESPACE::hash_map<uint32, Account*> AccountList;
+    typedef std::map<std::string, BanIp*> IpBanList;
+    typedef HM_NAMESPACE::hash_map<uint32, RealmCharacter*> CharactersList;
+
+    AccountList m_accounts;
+    IpBanList m_banips;
+    CharactersList m_characters;
+
+    uint32   m_UpdateInterval;
+    time_t   m_NextUpdateTime;
+};
+
+#define AcctMgr MaNGOS::Singleton<AcctContainer>::Instance()
Index: SpecialCodes.h
===================================================================
--- SpecialCodes.h	(révision 0)
+++ SpecialCodes.h	(révision 0)
@@ -0,0 +1,44 @@
+/* 
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/** \file
+    \ingroup realmd
+*/
+
+#ifndef _SPECIALCODES_H
+#define _SPECIALCODES_H
+
+enum eRealmSendCmds
+{
+    REALM_SEND_ACCT_INFOS = 0x100,
+    REALM_SEND_BANIP_STATUS = 0x101
+};
+
+enum eRealmReceivedCmds
+{
+    REALM_RECV_ACCT_INFOS_ANSW = 0x102,
+    REALM_RECV_ACCT_BANIP_ANSW = 0x103,  
+    REALM_RECV_ACCT_MOD_INFOS = 0x104,
+    REALM_RECV_ACCT_ADD_BANIP = 0x105,
+    REALM_RECV_ACCT_RM_BANIP = 0x106,
+    REALM_RECV_ACCT_ADD_BANACCT = 0x107,
+    REALM_RECV_ACCT_RM_BANACCT = 0x108,
+    REALM_RECV_ACCT_ADDACCOUNT = 0x109,
+    REALM_RECV_ACCT_DELACCOUNT = 0x110    
+};
+#endif
Index: Main.cpp
===================================================================
--- Main.cpp	(révision 5401)
+++ Main.cpp	(copie de travail)
@@ -31,6 +31,8 @@
 #include "SystemConfig.h"
 #include "Util.h"
 
+#include "AccountHandler.h"
+
 #ifdef WIN32
 #include "ServiceWin32.h"
 char serviceName[] = "realmd";
@@ -182,6 +184,15 @@
         return 1;
     }
 
+    // Activate or not account caching system, precache them before launching connection port
+    if(sConfig.GetIntDefault("AccountCaching", 0) == 1)
+    {
+      AcctMgr.Initialize(sConfig.GetIntDefault("AccountReloadingDelay", 300));
+      AcctMgr.ReloadEverythingIfNeed();
+      sLog.outString();
+      sLog.outString("Accounts will be reloaded in %u seconds", sConfig.GetIntDefault("AccountReloadingDelay", 300));
+    }
+
     ///- Launch the listening network socket
     port_t rmport = sConfig.GetIntDefault( "RealmServerPort", DEFAULT_REALMSERVER_PORT );
     std::string bind_ip = sConfig.GetStringDefault("BindIP", "0.0.0.0");
Index: realmd.conf
===================================================================
--- realmd.conf	(révision 0)
+++ realmd.conf	(révision 0)
@@ -0,0 +1,120 @@
+############################################
+# MaNGOS realmd configuration file         #
+############################################
+ConfVersion=2007062001
+
+###################################################################################################################
+# REALMD SETTINGS
+#
+#    LoginDatabaseInfo
+#        Database connection settings for the realm server.
+#        Default: hostname;port;username;password;database
+#                 .;somenumber;username;password;database - use named pipes at Windows
+#                       Named pipes: mySQL required adding "enable-named-pipe" to [mysqld] section my.ini
+#                 .;/path/to/unix_socket;username;password;database - use Unix sockets at Unix/Linux
+#                       Unix sockets: experimental, not tested
+#
+#    LogsDir
+#         Logs directory setting.
+#         Important: Logs dir must exists, or all logs be disable
+#         Default: "" - no log directory prefix, if used log names isn't absolute path then logs will be 
+#                       stored in current directory for run program.
+#
+#    MaxPingTime
+#         Settings for maximum database-ping interval (minutes between pings)
+#
+#    RealmServerPort
+#         Default RealmServerPort
+#
+#    BindIP
+#         Bind Realm Server to IP/hostname
+#
+#    PidFile
+#        Realmd daemon PID file
+#        Default: ""             - do not create PID file
+#                 "./realmd.pid" - create PID file (recommended name)
+#
+#    LogLevel
+#        Server console level of logging
+#        0 = Minimum; 1 = Error; 2 = Detail; 3 = Full/Debug
+#        Default: 0
+#
+#    LogTime
+#        Include time in server console output [hh:mm:ss]
+#        Default: 0 (no time)
+#                 1 (print time)
+#
+#    LogFile
+#        Logfile name
+#        Default: "Realmd.log"
+#                 "" - empty name disable creating log file
+#
+#    LogTimestamp
+#        Logfile with timestamp of server start in name
+#        Default: 0 - no timestamp in name
+#                 1 - add timestamp in name in form Logname_YYYY-MM-DD_HH-MM-SS.Ext for Logname.Ext
+#
+#    LogFileLevel
+#        Server file level of logging
+#        0 = Minimum; 1 = Error; 2 = Detail; 3 = Full/Debug
+#        Default: 0
+#
+#    LogColors
+#        Color for messages (format "normal_color details_color debug_color error_color)
+#        Colors: 0 - BLACK, 1 - RED, 2 - GREEN,  3 - BROWN, 4 - BLUE, 5 - MAGENTA, 6 -  CYAN, 7 - GREY,
+#                8 - YELLOW, 9 - LRED, 10 - LGREEN, 11 - LBLUE, 12 - LMAGENTA, 13 - LCYAN, 14 - WHITE
+#        Default: "" - none colors
+#                 "13 7 11 9" - for example :)
+#
+#    UseProcessors
+#        Used processors mask for multi-processors system (Used only at Windows)
+#        Default: 0 (selected by OS)
+#                 number (bitmask value of selected processors)
+#
+#    ProcessPriority
+#        Process proirity setting (Used only at Windows)
+#        Default: 1 (HIGH)
+#                 0 (Normal)
+#
+#    RealmsStateUpdateDelay
+#        Realm list Update up delay (updated at realm list request if delay expired).
+#        Default: 20 
+#                 0  (Disabled)
+#
+#    AccountCaching
+#        Enable or disable accounts caching into memory instead of using database acces (usefull when population is high)
+#        Default: 0 (Disabled)
+#
+#   AccountReloadingDelay
+#        Delay before reloading every accounts in seconds (Needed if using AccountCaching)
+#        Default: 1800 (15 mins)
+#
+#    SecureRealmServerPass
+#        Securised password for answers between Game Server and Realm Server (Needed if using AccountCaching)
+#        WARNING : THIS PASSWORD SHOULD BE THE SAME ON EVERY GAME SERVERS AND ON THE REALM SERVER !
+#        Default: MaNGOS
+#        
+#
+#
+#	
+#
+###################################################################################################################
+
+LoginDatabaseInfo = "127.0.0.1;3306;root;mangos;realmd"
+LogsDir = ""
+MaxPingTime = 30
+RealmServerPort = 3724
+BindIP = "0.0.0.0"
+PidFile = ""
+LogLevel = 0
+LogTime = 0
+LogFile = "Realmd.log"
+LogTimestamp = 0
+LogFileLevel = 0
+LogColors = ""
+UseProcessors = 0
+ProcessPriority = 1
+RealmsStateUpdateDelay = 20
+AccountCaching = 0
+AccountReloadingDelay = 1800
+SecureRealmServerPass = "MaNGOS"
Index: Makefile.am
===================================================================
--- Makefile.am	(révision 5401)
+++ Makefile.am	(copie de travail)
@@ -27,7 +27,10 @@
 	AuthSocket.h \
 	Main.cpp \
 	RealmList.cpp \
-	RealmList.h
+	RealmList.h \
+       AccountHandler.cpp \
+       AccountHandler.h \
+       SpecialCodes.h
 
 ## Link realm list daemon against the shared library
 mangos_realmd_LDADD = ../shared/Database/libmangosdatabase.a ../shared/Config/libmangosconfig.a ../shared/Auth/libmangosauth.a ../shared/libmangosshared.a ../framework/libmangosframework.a ../../dep/src/sockets/libmangossockets.a ../../dep/src/zthread/libZThread.la
Index: AuthSocket.cpp
===================================================================
--- AuthSocket.cpp	(révision 5401)
+++ AuthSocket.cpp	(copie de travail)
@@ -30,6 +30,10 @@
 #include <cwctype>                                          // needs for towupper
 #include <openssl/md5.h>
 #include "Auth/Sha1.h"
+#include "AccountHandler.h"
+#include "Config/ConfigEnv.h"
+#include <sstream>
+#include "SpecialCodes.h"
 
 extern RealmList m_realmList;
 
@@ -156,6 +160,12 @@
     bool (AuthSocket::*handler)(void);
 }AuthHandler;
 
+typedef struct SpecialCodesHandler
+{
+    eRealmReceivedCmds cmd;
+    bool (AuthSocket::*handler)(void);
+}SpecialCodesHandler;
+
 // GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some paltform
 #if defined( __GNUC__ )
 #pragma pack()
@@ -206,7 +216,24 @@
     { XFER_CANCEL,              STATUS_CONNECTED, &AuthSocket::_HandleXferCancel    }
 };
 
+const SpecialCodesHandler sptable[] =
+{
+    { REALM_RECV_ACCT_INFOS_ANSW,      &AuthSocket::_HandleInformationRetrieveAnsw},
+    { REALM_RECV_ACCT_BANIP_ANSW,      &AuthSocket::_HandleBanIPAnsw              }
+
+    // Reserved for future implementation of features like ban without waiting reload time etc
+    /*{ REALM_RECV_ACCT_MOD_INFOS,
+    { REALM_RECV_ACCT_ADD_BANIP,
+    { REALM_RECV_ACCT_RM_BANIP,
+    { REALM_RECV_ACCT_ADD_BANACCT,
+    { REALM_RECV_ACCT_RM_BANACCT,
+    { REALM_RECV_ACCT_MOD_REALMCHARS,
+    { REALM_RECV_ACCT_ADDACCOUNT,
+    { REALM_RECV_ACCT_DELACCOUNT,*/
+};
+
 #define AUTH_TOTAL_COMMANDS sizeof(table)/sizeof(AuthHandler)
+#define TOTAL_SPECIAL_COMMANDS sizeof(sptable)/sizeof(SpecialCodesHandler)
 
 ///Holds the MD5 hash of client patches present on the server
 Patcher PatchesCache;
@@ -260,6 +287,17 @@
         //      assert(0);
         size_t i;
 
+        for(i=0;i<TOTAL_SPECIAL_COMMANDS;i++)
+        {
+          if ((uint8)sptable[i].cmd == _cmd)
+            if(!(*this.*sptable[i].handler) ())
+            {
+              DEBUG_LOG("Special Commands Handler failed for cmd %u ibuf length %u", (uint32)_cmd, ibuf.GetLength());
+              return;
+            }
+            break;
+        }
+
         ///- Circle through known commands and call the correct command handler
         for (i=0;i<AUTH_TOTAL_COMMANDS; i++)
         {
@@ -287,6 +325,107 @@
     }
 }
 
+bool AuthSocket::_HandleInformationRetrieveAnsw()
+{
+    std::vector<uint8> buf;
+    buf.resize(2);
+
+    // Verify Packet Size
+    if(ibuf.GetLength() < 2) 
+      return false;
+
+    ibuf.Read((char *)&buf[0], 2);
+
+    /*
+       Buf[0] = cmd
+       Buf[1] = account id
+       Buf[2] = account name
+       Buf[3] = Security Code (Prevent abuse by sending this from not allowed computer
+    */
+
+    if(strcmp((char*)buf[2],sConfig.GetStringDefault("SecureRealmServerPass", "MaNGOS").c_str()) != 0)
+     return false;
+
+    Account* acct;
+
+    if(buf[1] != 0)
+     acct = AcctMgr.FindAccountById(buf[1]);
+    else
+     acct = AcctMgr.FindAccountByName((char *)buf[2]);
+
+    ByteBuffer pkt;
+
+    // Packet REALM_SEND_ACCT_INFOS
+
+    // Account ID
+    // Account name
+    // Account security level
+    // Account locale
+    // Account is tbc or not
+    // Account is banned or not
+    // Account is locked or not
+    // Account I hash
+    // Account last ip
+
+    // Sending account infos
+    pkt << REALM_SEND_ACCT_INFOS;
+    pkt << acct->id;
+    pkt << acct->name;
+    pkt << acct->security;
+    pkt << acct->locale;
+    pkt << acct->tbc;
+    pkt << acct->banned;
+    pkt << acct->locked;
+    pkt << acct->I;
+    pkt << acct->LastIp;
+
+    SendBuf((char const*)pkt.contents(), pkt.size());
+    return true;
+}
+
+bool AuthSocket::_HandleBanIPAnsw()
+{
+    std::vector<uint8> buf;
+    buf.resize(1);
+
+    // Verify Packet Size
+    if(ibuf.GetLength() < 1)
+      return false;
+
+    ibuf.Read((char *)&buf[0], 1);
+
+    /*
+       Buf[0] = cmd
+       Buf[1] = IP
+       Buf[2] = Security Code (Prevent abuse by sending this from not allowed computer
+    */
+    
+    if(strcmp((char*)buf[2],sConfig.GetStringDefault("SecureRealmServerPass", "MaNGOS").c_str()) != 0)
+     return false;
+
+    bool IpIsBanned = AcctMgr.IpBan((char *)buf[1]);
+
+    // Packet REALM_SEND_BANIP_STATUS :
+
+    // BanStatus ( 0 not banned, 1 banned )
+    // IP
+
+    ByteBuffer pkt;
+
+    pkt << REALM_SEND_BANIP_STATUS;
+
+    if(IpIsBanned)
+     pkt << (uint8)1;
+    else
+     pkt << (uint8)0;
+
+    pkt << buf[1];
+
+    SendBuf((char const*)pkt.contents(), pkt.size());
+
+    return true;
+}
+
 /// Make the SRP6 calculation from hash in dB
 void AuthSocket::_SetVSFields(std::string rI)
 {
@@ -320,6 +459,8 @@
 /// Logon Challenge command handler
 bool AuthSocket::_HandleLogonChallenge()
 {
+    AcctMgr.ReloadEverythingIfNeed();
+
     DEBUG_LOG("Entering _HandleLogonChallenge");
     if (ibuf.GetLength() < sizeof(sAuthLogonChallenge_C))
         return false;
@@ -370,6 +511,8 @@
         pkt << (uint8) AUTH_LOGON_CHALLENGE;
         pkt << (uint8) 0x00;
 
+      if(sConfig.GetIntDefault("AccountCaching", 0) != 1)
+      {
         ///- Verify that this IP is not in the ip_banned table
         // No SQL injection possible (paste the IP address as passed by the socket)
         dbRealmServer.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate");
@@ -484,10 +627,98 @@
             {
                 pkt<< (uint8) REALM_AUTH_NO_MATCH;
             }
-        }
-    }                                                       //valid version
+       }
+   }
+   else
+   {
+     if(AcctMgr.IpBan(GetRemoteAddress()))
+     {
+       pkt << (uint8)REALM_AUTH_ACCOUNT_BANNED;
+     }
+     else
+     {
+      Account* acct = AcctMgr.FindAccountByName(_safelogin);
+       
+      if(acct)
+      {
+             bool locked = false;
+
+             if(acct->locked == 1)            // if ip is locked
+             {
+                 if ( strcmp(acct->LastIp.c_str(),GetRemoteAddress().c_str()) )
+                 {
+                    pkt << (uint8) REALM_AUTH_ACCOUNT_FREEZED;
+                    locked=true;
+                 }
+             }
+
+             if (!locked)
+             {
+                if(acct->banned)
+                {
+                  pkt << (uint8) REALM_AUTH_ACCOUNT_BANNED;
+                }
+                else
+                {
+                     ///- Get the password from the account table, upper it, and make the SRP6 calculation
+                     std::string rI = acct->I;
+                     _SetVSFields(rI);
+                      b.SetRand(19 * 8);
+                      BigNumber gmod=g.ModExp(b, N);
+                      B = ((v * 3) + gmod) % N;
+
+                      if (B.GetNumBytes() < 32)
+                         sLog.outDetail("Interesting, calculation of B in realmd is < 32.");
+
+                      ASSERT(gmod.GetNumBytes() <= 32);
+
+                      BigNumber unk3;
+                      unk3.SetRand(16*8);
+
+                      ///- Fill the response packet with the result
+                      pkt << (uint8)REALM_AUTH_SUCCESS;
+                      pkt.append(B.AsByteArray(), B.GetNumBytes());
+                      pkt << (uint8)1;
+                      pkt.append(g.AsByteArray(), 1);
+                      pkt << (uint8)32;
+                      pkt.append(N.AsByteArray(), 32);
+                      pkt.append(s.AsByteArray(), s.GetNumBytes());
+                      pkt.append(unk3.AsByteArray(), 16);
+                      pkt << (uint8)0;                    // Added in 1.12.x client branch
+
+                      uint8 secLevel = acct->security;
+                        _accountSecurityLevel = secLevel <= SEC_ADMINISTRATOR ? AccountTypes(secLevel) : SEC_ADMINISTRATOR;
+
+                      // There isn't many differents locale so i think we can hardcode them all
+
+                        char charbuffer[3];
+                          charbuffer[0] = ch->country[3];
+                          charbuffer[1] = ch->country[2];
+                          charbuffer[2] = '\0';
+
+                        if(strcmp (charbuffer,"fr") == 0)
+                          _localization = 2;
+                        else if(strcmp (charbuffer,"de") == 0)
+                          _localization = 3;
+                        else
+                          _localization = 0;
+
+                   }
+            }
+            else
+            {
+               pkt << (uint8) REALM_AUTH_ACCOUNT_FREEZED;
+            }
+           }
+           else                                            //no account
+           {
+                pkt<< (uint8) REALM_AUTH_NO_MATCH;
+           }
+	   }
+	 }
+     }                                                       //valid version
     else
-        ///<li> else
+     ///<li> else
     {
         ///- Check if we have the apropriate patch on the disk
         char tmp[64];
@@ -535,7 +766,7 @@
     }
     /// </ul>
     SendBuf((char const*)pkt.contents(), pkt.size());
-    return true;
+    return true;    
 }
 
 /// Logon Proof command handler
@@ -661,9 +892,13 @@
 
     ibuf.Remove(5);
 
+    std::string rI;
+    uint32 id;
+   
+  if(sConfig.GetIntDefault("AccountCaching", 0) != 1)
+  {
     ///- Get the user id (else close the connection)
     // No SQL injection (escaped user name)
-
     QueryResult *result = dbRealmServer.PQuery("SELECT id,sha_pass_hash FROM account WHERE UPPER(username) = '%s'",_safelogin.c_str());
     if(!result)
     {
@@ -672,9 +907,16 @@
         return false;
     }
 
-    uint32 id = (*result)[0].GetUInt32();
-    std::string rI = (*result)[1].GetCppString();
+    id = (*result)[0].GetUInt32();
+    rI = (*result)[1].GetCppString();
     delete result;
+  }
+  else
+  {
+   Account* acct = AcctMgr.FindAccountByName(_safelogin);
+   id = acct->id;
+   rI = acct->I;
+  }
 
     ///- Update realm list if need
     m_realmList.UpdateIfNeed();
@@ -687,17 +929,22 @@
     for( i = m_realmList.begin(); i != m_realmList.end(); i++ )
     {
         uint8 AmountOfCharacters;
-
-        // No SQL injection. id of realm is controlled by the database.
-        result = dbRealmServer.PQuery( "SELECT numchars FROM realmcharacters WHERE realmid = '%d' AND acctid='%u'",i->second.m_ID,id);
-        if( result )
-        {
-            Field *fields = result->Fetch();
-            AmountOfCharacters = fields[0].GetUInt8();
-            delete result;
-        }
-        else
+       if(sConfig.GetIntDefault("AccountCaching", 0) != 1)
+       {
+          // No SQL injection. id of realm is controlled by the database.
+          QueryResult* result = dbRealmServer.PQuery( "SELECT numchars FROM realmcharacters WHERE realmid = '%d' AND acctid='%u'",i->second.m_ID,id);
+          if( result )
+          {
+              Field *fields = result->Fetch();
+              AmountOfCharacters = fields[0].GetUInt8();
+              delete result;
+          }
+          else
             AmountOfCharacters = 0;
+       }
+       else
+         AmountOfCharacters = AcctMgr.GetNumChar(i->second.m_ID, id);
+        
 
         uint8 lock = (i->second.allowedSecurityLevel > _accountSecurityLevel) ? 1 : 0;
 
Index: AccountHandler.cpp
===================================================================
--- AccountHandler.cpp	(révision 0)
+++ AccountHandler.cpp	(révision 0)
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/** \file
+    \ingroup realmd
+*/
+
+#include "Database/DatabaseEnv.h"
+#include "Policies/SingletonImp.h"
+#include "AccountHandler.h"
+#include "ProgressBar.h"
+
+#ifdef DO_POSTGRESQL
+extern DatabasePostgre dbRealmServer;
+#else
+extern DatabaseMysql dbRealmServer;
+#endif
+
+INSTANTIATE_SINGLETON_1( AcctContainer);
+
+AcctContainer::AcctContainer( ) : m_UpdateInterval(0), m_NextUpdateTime(time(NULL))
+{
+}
+
+void AcctContainer::Initialize(uint32 updateInterval)
+{
+  m_UpdateInterval = updateInterval;
+}
+
+void AcctContainer::AddAccount(Account* account,uint32 id, uint8 security, uint8 locale, uint8 tbc, bool banned, uint8 locked, std::string name, std::string I, std::string lastip)
+{
+  account->id = id;
+  account->security = security;
+  account->locale = locale;
+  account->tbc = tbc;
+  account->banned = banned;
+  account->locked = locked;
+  account->name = name;
+  account->I = I;
+  account->LastIp = lastip;
+}
+
+void AcctContainer::AddCharacter(RealmCharacter* rcharacter, uint32 realmId, uint32 acctId, uint8 numChars)
+{
+  rcharacter->realmId = realmId;
+  rcharacter->acctId = acctId;
+  rcharacter->numChars = numChars;
+}
+
+void AcctContainer::ReloadEverythingIfNeed()
+{
+    if(!m_UpdateInterval || m_NextUpdateTime > time(NULL))
+        return;
+
+    m_NextUpdateTime = time(NULL) + m_UpdateInterval;
+
+    // Clear maps
+    m_characters.clear();
+    m_banips.clear();
+    m_accounts.clear();
+
+    LoadAll();
+}
+
+void AcctContainer::LoadAll()
+{
+  // Load accounts
+  QueryResult* result = dbRealmServer.PQuery("SELECT id,username,sha_pass_hash,gmlevel,last_ip,locked,tbc,locale FROM account");
+
+  uint32 count = 0;
+
+  if(!result)
+   return;
+
+  sLog.outString();
+
+  sLog.outString("Loading Accounts In Progress...");
+
+  barGoLink bar( result->GetRowCount());
+
+  // Periodic Database Update ...
+  dbRealmServer.Execute("UPDATE account_banned SET active = 0 WHERE unbandate <= UNIX_TIMESTAMP() AND unbandate <> bandate");
+  dbRealmServer.Execute("DELETE FROM ip_banned WHERE unbandate <= UNIX_TIMESTAMP() AND unbandate <> bandate");
+
+  Account *acct;
+
+  do
+  {
+    Field *fields = result->Fetch();
+    bool banned = false;
+  
+    bar.step();
+
+    QueryResult* banresult = dbRealmServer.PQuery("SELECT bandate,unbandate FROM account_banned WHERE id = %u AND active = 1", fields[0].GetUInt32());
+  
+    if(banresult)
+    {
+      banned = true;
+      delete banresult;
+    }
+
+    // Create the account
+    acct = new Account();
+    
+    AddAccount(acct, fields[0].GetUInt32(), fields[3].GetUInt8(), fields[7].GetUInt8(), fields[6].GetUInt8(), banned, fields[5].GetUInt8(), fields[1].GetCppString(), fields[2].GetCppString(), fields[4].GetCppString());
+
+    m_accounts[acct->id] = acct;
+
+    count++;
+
+  }while (result->NextRow());
+
+  sLog.outString();
+  sLog.outString(">> Loaded %u accounts", count);
+
+  delete result;
+
+ // Now load Ban by ip
+
+  result = dbRealmServer.PQuery("SELECT * FROM ip_banned");
+
+  BanIp* ban;
+
+  // If there is no ban don't load
+  if(result)
+  {
+    sLog.outString();
+
+    count = 0;
+
+    sLog.outString("Loading Ban Ip In Progress...");
+
+    barGoLink bar( result->GetRowCount());
+
+     do
+     {
+       Field *fields = result->Fetch();
+       bar.step();     
+       ban = new BanIp();
+       AddBan(ban, fields[0].GetCppString());
+       m_banips[ban->Ip] = ban;
+       count++;
+
+     }while (result->NextRow());
+ 
+    delete result; 
+    sLog.outString();
+
+    sLog.outString(">> Loaded %u ip banned", count);
+
+    count = 0;
+  }
+
+ // Now load Realm Characters
+
+  result = dbRealmServer.PQuery("SELECT * FROM realmcharacters");
+
+  RealmCharacter *realmcharacter;
+
+  // If there is no ban don't load
+  if(result)
+  {
+    sLog.outString();
+
+    count = 0;
+
+   sLog.outString("Loading Realm Characters In Progress...");
+
+   barGoLink bar( result->GetRowCount());
+
+   do
+   {
+     Field *fields = result->Fetch();
+
+     bar.step();
+     
+     realmcharacter = new RealmCharacter();
+
+     AddCharacter(realmcharacter, fields[0].GetUInt32(), fields[1].GetUInt32(), fields[2].GetUInt8());
+
+     // Since nothing on this table is unique, order it by increment count value
+     m_characters[count] = realmcharacter;
+
+     count++;
+
+   }while (result->NextRow());
+ 
+    delete result; 
+
+    sLog.outString();
+
+    sLog.outString(">> Loaded %u realm characters", count);
+  }
+
+
+}
+
+Account* AcctContainer::FindAccountById(uint32 acctid)
+{
+   AccountList::const_iterator itr = m_accounts.find(acctid);
+  
+  if(itr != m_accounts.end())
+    return itr->second;
+}
+
+Account* AcctContainer::FindAccountByName(std::string name)
+{
+  for(AccountList::const_iterator itr = m_accounts.begin(); itr != m_accounts.end(); itr++)
+  {
+    if(!stricmp(itr->second->name.c_str(), name.c_str()))
+       return itr->second;
+  }
+
+  return NULL;
+}
+
+bool AcctContainer::IpBan(std::string ClientIp)
+{
+  for(IpBanList::const_iterator itr = m_banips.begin(); itr != m_banips.end(); itr++)
+  {
+    if(!stricmp(itr->second->Ip.c_str(), ClientIp.c_str()))
+      return true;
+  }
+  
+  return false;
+}
+
+uint8 AcctContainer::GetNumChar(uint32 realmId, uint32 accountId)
+{
+  for(CharactersList::const_iterator itr = m_characters.begin(); itr != m_characters.end(); itr++)
+  {
+    if(itr->second->realmId == realmId && itr->second->acctId == accountId)
+      return itr->second->numChars;
+  }
+
+  return 0;
+}