string CIncomingGameHost :: GetIPString( ) { string Result; if( m_IP.size( ) >= 4 ) { for( unsigned int i = 0; i < 4; i++ ) { Result += UTIL_ToString( (unsigned int)m_IP[i] ); if( i < 3 ) Result += "."; } } return Result; }
bool CUDPSocket :: Broadcast( uint16_t port, BYTEARRAY message ) { if( m_Socket == INVALID_SOCKET || m_HasError ) return false; struct sockaddr_in sin; sin.sin_family = AF_INET; sin.sin_addr.s_addr = m_BroadcastTarget.s_addr; sin.sin_port = htons( port ); string MessageString = string( message.begin( ), message.end( ) ); if( sendto( m_Socket, MessageString.c_str( ), MessageString.size( ), 0, (struct sockaddr *)&sin, sizeof( sin ) ) == -1 ) { CONSOLE_Print( "[UDPSOCKET] failed to broadcast packet (port " + UTIL_ToString( port ) + ", size " + UTIL_ToString( MessageString.size( ) ) + " bytes)" ); return false; } return true; }
CLanguage :: CLanguage( string nCFGFile ) { m_CFG = new CConfig( ); m_CFG->Read( nCFGFile ); ifstream in; in.open( "jokes.txt" ); if( in.fail( ) ) CONSOLE_Print( "[JOKES] error loading jokes from [jokes.txt]" ); else { CONSOLE_Print( "[JOKES] loading jokes from [jokes.txt]" ); m_Jokes.clear(); string Line; while( !in.eof( ) ) { getline( in, Line ); // ignore blank lines and comments if( Line.empty( ) || Line[0] == '#' ) continue; // remove newlines and partial newlines to help fix issues with Windows formatted files on Linux systems //Line.erase( remove( Line.begin( ), Line.end( ), ' ' ), Line.end( ) ); Line.erase( remove( Line.begin( ), Line.end( ), '\r' ), Line.end( ) ); Line.erase( remove( Line.begin( ), Line.end( ), '\n' ), Line.end( ) ); m_Jokes.push_back( Line ); } in.close( ); CONSOLE_Print( "[JOKES] loaded " + UTIL_ToString( m_Jokes.size( ) ) + " jokes." ); } }
CCCBot :: CCCBot( CConfig *CFG ) : m_Exiting( false), m_Version( "1.04" ) { CONSOLE_Print( "[CCBOT] Channel && Clan Bot - " + m_Version + ", based on GHost++" ); m_DB = new CCCBotDB( CFG ); m_Language = new CLanguage( LanguageFile ); m_Warcraft3Path = CFG->GetString( "bot_war3path", "C:\\Program Files\\Warcraft III\\" ); // load the battle.net connections // we're just loading the config data and creating the CBNET classes here, the connections are established later (in the Update function) if( CFG->GetGenerated( ) ) { CONSOLE_Print( "[CONFIG] EDIT ccbot.cfg IN THE cfg FOLDER AND RESTART CCBOT!" ); CONSOLE_Print( "[CONFIG] EDIT ccbot.cfg IN THE cfg FOLDER AND RESTART CCBOT!" ); CONSOLE_Print( "[CONFIG] EDIT ccbot.cfg IN THE cfg FOLDER AND RESTART CCBOT!" ); CONSOLE_Print( "[CONFIG] EDIT ccbot.cfg IN THE cfg FOLDER AND RESTART CCBOT!" ); return; } for( unsigned int i = 1; i < 10; ++i ) { string Prefix; if( i == 1 ) Prefix = "bnet_"; else Prefix = "bnet" + UTIL_ToString( i ) + "_"; string Server = CFG->GetString( Prefix + "server", string( ) ); transform( Server.begin( ), Server.end( ), Server.begin( ), (int(*)(int))tolower ); string CDKeyROC = CFG->GetString( Prefix + "cdkeyroc", string( ) ); string CDKeyTFT = CFG->GetString( Prefix + "cdkeytft", string( ) ); string CountryAbbrev = CFG->GetString( Prefix + "countryabbrev", "FIN" ); string Country = CFG->GetString( Prefix + "country", "Finland" ); string UserName = CFG->GetString( Prefix + "username", string( ) ); string UserPassword = CFG->GetString( Prefix + "password", string( ) ); string FirstChannel = CFG->GetString( Prefix + "firstchannel", "The Void" ); string RootAdmin = CFG->GetString( Prefix + "rootadmin", string( ) ); string BNETCommandTrigger = CFG->GetString( Prefix + "commandtrigger", "!" ); string ClanTag = CFG->GetString( Prefix + "clantag", "" ); string HostbotName = CFG->GetString( Prefix + "hostbotname", "" ); bool AntiSpam = CFG->GetInt( Prefix + "antispam", 0 ) == 0 ? false : true; bool GreetUsers = CFG->GetInt( Prefix + "greetusers", 0 ) == 0 ? false : true; bool SwearingKick = CFG->GetInt( Prefix + "swearingkick", 0 ) == 0 ? false : true; bool AnnounceGames = CFG->GetInt( Prefix + "announcegames", 0 ) == 0 ? false : true; bool SelfJoin = CFG->GetInt( Prefix + "selfjoin", 0 ) == 0 ? false : true; bool BanChat = CFG->GetInt( Prefix + "banchat", 0 ) == 0 ? false : true; unsigned char ClanDefaultAccess = CFG->GetInt( Prefix + "clanmembersdefaultaccess", 4 ); if( ClanDefaultAccess > 9 ) ClanDefaultAccess = 9; unsigned char War3Version = CFG->GetInt( Prefix + "custom_war3version", 24 ); BYTEARRAY EXEVersion = UTIL_ExtractNumbers( CFG->GetString( Prefix + "custom_exeversion", string( ) ), 4 ); BYTEARRAY EXEVersionHash = UTIL_ExtractNumbers( CFG->GetString( Prefix + "custom_exeversionhash", string( ) ), 4 ); string PasswordHashType = CFG->GetString( Prefix + "custom_passwordhashtype", string( ) ); unsigned char MaxMessageLength = CFG->GetInt( Prefix + "custom_maxmessagelength", 200 ); if( Server.empty( ) ) break; CONSOLE_Print( "[CCBOT] found battle.net connection #" + UTIL_ToString( i ) + " for server [" + Server + "]" ); m_BNETs.push_back( new CBNET( this, Server, CDKeyROC, CDKeyTFT, CountryAbbrev, Country, UserName, UserPassword, FirstChannel, RootAdmin, BNETCommandTrigger[0], War3Version, EXEVersion, EXEVersionHash, PasswordHashType, MaxMessageLength, ClanTag, GreetUsers, SwearingKick, AnnounceGames, SelfJoin, BanChat, ClanDefaultAccess, HostbotName, AntiSpam ) ); } if( m_BNETs.empty( ) ) CONSOLE_Print( "[CCBOT] warning - no battle.net connections found in config file" ); // Update the swears.cfg file UpdateSwearList( ); // Check for the default access system values UpdateCommandAccess( ); m_Uptime = GetTime( ); }
void CReplay :: ParseReplay( bool parseBlocks ) { m_HostPID = 0; m_HostName.clear( ); m_GameName.clear( ); m_StatString.clear( ); m_PlayerCount = 0; m_MapGameType = 0; m_Players.clear( ); m_Slots.clear( ); m_RandomSeed = 0; m_SelectMode = 0; m_StartSpotCount = 0; m_LoadingBlocks = queue<BYTEARRAY>( ); m_Blocks = queue<BYTEARRAY>( ); m_CheckSums = queue<uint32_t>( ); if( m_Flags != 32768 ) { CONSOLE_Print( "[REPLAY] invalid replay (flags mismatch)" ); m_Valid = false; return; } istringstream ISS( m_Decompressed ); unsigned char Garbage1; uint32_t Garbage4; string GarbageString; unsigned char GarbageData[65535]; READB( ISS, &Garbage4, 4 ); // Unknown (4.0) if( Garbage4 != 272 ) { CONSOLE_Print( "[REPLAY] invalid replay (4.0 Unknown mismatch)" ); m_Valid = false; return; } READB( ISS, &Garbage1, 1 ); // Host RecordID (4.1) if( Garbage1 != 0 ) { CONSOLE_Print( "[REPLAY] invalid replay (4.1 Host RecordID mismatch)" ); m_Valid = false; return; } READB( ISS, &m_HostPID, 1 ); if( m_HostPID > 15 ) { CONSOLE_Print( "[REPLAY] invalid replay (4.1 Host PlayerID is invalid)" ); m_Valid = false; return; } READSTR( ISS, m_HostName ); // Host PlayerName (4.1) READB( ISS, &Garbage1, 1 ); // Host AdditionalSize (4.1) if( Garbage1 != 1 ) { CONSOLE_Print( "[REPLAY] invalid replay (4.1 Host AdditionalSize mismatch)" ); m_Valid = false; return; } READB( ISS, &Garbage1, 1 ); // Host AdditionalData (4.1) if( Garbage1 != 0 ) { CONSOLE_Print( "[REPLAY] invalid replay (4.1 Host AdditionalData mismatch)" ); m_Valid = false; return; } AddPlayer( m_HostPID, m_HostName ); READSTR( ISS, m_GameName ); // GameName (4.2) READSTR( ISS, GarbageString ); // Null (4.0) READSTR( ISS, m_StatString ); // StatString (4.3) READB( ISS, &m_PlayerCount, 4 ); // PlayerCount (4.6) if( m_PlayerCount > 12 ) { CONSOLE_Print( "[REPLAY] invalid replay (4.6 PlayerCount is invalid)" ); m_Valid = false; return; } READB( ISS, &m_MapGameType, 4 ); // GameType (4.7) READB( ISS, &Garbage4, 4 ); // LanguageID (4.8) while( 1 ) { READB( ISS, &Garbage1, 1 ); // Player RecordID (4.1) if( Garbage1 == 22 ) { unsigned char PlayerID; string PlayerName; READB( ISS, &PlayerID, 1 ); // Player PlayerID (4.1) if( PlayerID > 15 ) { CONSOLE_Print( "[REPLAY] invalid replay (4.9 Player PlayerID is invalid)" ); m_Valid = false; return; } READSTR( ISS, PlayerName ); // Player PlayerName (4.1) READB( ISS, &Garbage1, 1 ); // Player AdditionalSize (4.1) if( Garbage1 != 1 ) { CONSOLE_Print( "[REPLAY] invalid replay (4.9 Player AdditionalSize mismatch)" ); m_Valid = false; return; } READB( ISS, &Garbage1, 1 ); // Player AdditionalData (4.1) if( Garbage1 != 0 ) { CONSOLE_Print( "[REPLAY] invalid replay (4.9 Player AdditionalData mismatch)" ); m_Valid = false; return; } READB( ISS, &Garbage4, 4 ); // Unknown if( Garbage4 != 0 ) { CONSOLE_Print( "[REPLAY] invalid replay (4.9 Unknown mismatch)" ); m_Valid = false; return; } AddPlayer( PlayerID, PlayerName ); } else if( Garbage1 == 25 ) break; else { CONSOLE_Print( "[REPLAY] invalid replay (4.9 Player RecordID mismatch)" ); m_Valid = false; return; } } uint16_t Size; unsigned char NumSlots; READB( ISS, &Size, 2 ); // Size (4.10) READB( ISS, &NumSlots, 1 ); // NumSlots (4.10) if( Size != 7 + NumSlots * 9 ) { CONSOLE_Print( "[REPLAY] invalid replay (4.10 Size is invalid)" ); m_Valid = false; return; } if( NumSlots == 0 || NumSlots > 12 ) { CONSOLE_Print( "[REPLAY] invalid replay (4.10 NumSlots is invalid)" ); m_Valid = false; return; } for( int i = 0; i < NumSlots; ++i ) { unsigned char SlotData[9]; READB( ISS, SlotData, 9 ); BYTEARRAY SlotDataBA = UTIL_CreateByteArray( SlotData, 9 ); m_Slots.push_back( CGameSlot( SlotDataBA ) ); } READB( ISS, &m_RandomSeed, 4 ); // RandomSeed (4.10) READB( ISS, &m_SelectMode, 1 ); // SelectMode (4.10) READB( ISS, &m_StartSpotCount, 1 ); // StartSpotCount (4.10) if( ISS.eof( ) || ISS.fail( ) ) { CONSOLE_Print( "[SAVEGAME] failed to parse replay header" ); m_Valid = false; return; } if( !parseBlocks ) return; READB( ISS, &Garbage1, 1 ); // first start block ID (5.0) if( Garbage1 != CReplay :: REPLAY_FIRSTSTARTBLOCK ) { CONSOLE_Print( "[REPLAY] invalid replay (5.0 first start block ID mismatch)" ); m_Valid = false; return; } READB( ISS, &Garbage4, 4 ); // first start block data (5.0) if( Garbage4 != 1 ) { CONSOLE_Print( "[REPLAY] invalid replay (5.0 first start block data mismatch)" ); m_Valid = false; return; } READB( ISS, &Garbage1, 1 ); // second start block ID (5.0) if( Garbage1 != CReplay :: REPLAY_SECONDSTARTBLOCK ) { CONSOLE_Print( "[REPLAY] invalid replay (5.0 second start block ID mismatch)" ); m_Valid = false; return; } READB( ISS, &Garbage4, 4 ); // second start block data (5.0) if( Garbage4 != 1 ) { CONSOLE_Print( "[REPLAY] invalid replay (5.0 second start block data mismatch)" ); m_Valid = false; return; } while( 1 ) { READB( ISS, &Garbage1, 1 ); // third start block ID *or* loading block ID (5.0) if( ISS.eof( ) || ISS.fail( ) ) { CONSOLE_Print( "[REPLAY] invalid replay (5.0 third start block unexpected end of file found)" ); m_Valid = false; return; } if( Garbage1 == CReplay :: REPLAY_LEAVEGAME ) { READB( ISS, GarbageData, 13 ); BYTEARRAY LoadingBlock; LoadingBlock.push_back( Garbage1 ); UTIL_AppendByteArray( LoadingBlock, GarbageData, 13 ); m_LoadingBlocks.push( LoadingBlock ); } else if( Garbage1 == CReplay :: REPLAY_THIRDSTARTBLOCK ) break; else { CONSOLE_Print( "[REPLAY] invalid replay (5.0 third start block ID mismatch)" ); m_Valid = false; return; } } READB( ISS, &Garbage4, 4 ); // third start block data (5.0) if( Garbage4 != 1 ) { CONSOLE_Print( "[REPLAY] invalid replay (5.0 third start block data mismatch)" ); m_Valid = false; return; } if( ISS.eof( ) || ISS.fail( ) ) { CONSOLE_Print( "[SAVEGAME] failed to parse replay start blocks" ); m_Valid = false; return; } uint32_t ActualReplayLength = 0; while( 1 ) { READB( ISS, &Garbage1, 1 ); // block ID (5.0) if( ISS.eof( ) || ISS.fail( ) ) break; else if( Garbage1 == CReplay :: REPLAY_LEAVEGAME ) { READB( ISS, GarbageData, 13 ); // reconstruct the block BYTEARRAY Block; Block.push_back( CReplay :: REPLAY_LEAVEGAME ); UTIL_AppendByteArray( Block, GarbageData, 13 ); m_Blocks.push( Block ); } else if( Garbage1 == CReplay :: REPLAY_TIMESLOT ) { uint16_t BlockSize; READB( ISS, &BlockSize, 2 ); READB( ISS, GarbageData, BlockSize ); if( BlockSize >= 2 ) ActualReplayLength += GarbageData[0] | GarbageData[1] << 8; // reconstruct the block BYTEARRAY Block; Block.push_back( CReplay :: REPLAY_TIMESLOT ); UTIL_AppendByteArray( Block, BlockSize, false ); UTIL_AppendByteArray( Block, GarbageData, BlockSize ); m_Blocks.push( Block ); } else if( Garbage1 == CReplay :: REPLAY_CHATMESSAGE ) { unsigned char PID; uint16_t BlockSize; READB( ISS, &PID, 1 ); if( PID > 15 ) { CONSOLE_Print( "[REPLAY] invalid replay (5.0 chatmessage pid is invalid)" ); m_Valid = false; return; } READB( ISS, &BlockSize, 2 ); READB( ISS, GarbageData, BlockSize ); // reconstruct the block BYTEARRAY Block; Block.push_back( CReplay :: REPLAY_CHATMESSAGE ); Block.push_back( PID ); UTIL_AppendByteArray( Block, BlockSize, false ); UTIL_AppendByteArray( Block, GarbageData, BlockSize ); m_Blocks.push( Block ); } else if( Garbage1 == CReplay :: REPLAY_CHECKSUM ) { READB( ISS, &Garbage1, 1 ); if( Garbage1 != 4 ) { CONSOLE_Print( "[REPLAY] invalid replay (5.0 checksum unknown mismatch)" ); m_Valid = false; return; } uint32_t CheckSum; READB( ISS, &CheckSum, 4 ); m_CheckSums.push( CheckSum ); } else { // it's not necessarily an error if we encounter an unknown block ID since replays can contain extra data break; } } if( m_ReplayLength != ActualReplayLength ) CONSOLE_Print( "[REPLAY] warning - replay length mismatch (" + UTIL_ToString( m_ReplayLength ) + "ms/" + UTIL_ToString( ActualReplayLength ) + "ms)" ); m_Valid = true; }
string CSocket :: GetErrorString( ) { if( !m_HasError ) return "NO ERROR"; switch( m_Error ) { case EWOULDBLOCK: return "EWOULDBLOCK"; case EINPROGRESS: return "EINPROGRESS"; case EALREADY: return "EALREADY"; case ENOTSOCK: return "ENOTSOCK"; case EDESTADDRREQ: return "EDESTADDRREQ"; case EMSGSIZE: return "EMSGSIZE"; case EPROTOTYPE: return "EPROTOTYPE"; case ENOPROTOOPT: return "ENOPROTOOPT"; case EPROTONOSUPPORT: return "EPROTONOSUPPORT"; case ESOCKTNOSUPPORT: return "ESOCKTNOSUPPORT"; case EOPNOTSUPP: return "EOPNOTSUPP"; case EPFNOSUPPORT: return "EPFNOSUPPORT"; case EAFNOSUPPORT: return "EAFNOSUPPORT"; case EADDRINUSE: return "EADDRINUSE"; case EADDRNOTAVAIL: return "EADDRNOTAVAIL"; case ENETDOWN: return "ENETDOWN"; case ENETUNREACH: return "ENETUNREACH"; case ENETRESET: return "ENETRESET"; case ECONNABORTED: return "ECONNABORTED"; case ECONNRESET: return "ECONNRESET"; case ENOBUFS: return "ENOBUFS"; case EISCONN: return "EISCONN"; case ENOTCONN: return "ENOTCONN"; case ESHUTDOWN: return "ESHUTDOWN"; case ETOOMANYREFS: return "ETOOMANYREFS"; case ETIMEDOUT: return "ETIMEDOUT"; case ECONNREFUSED: return "ECONNREFUSED"; case ELOOP: return "ELOOP"; case ENAMETOOLONG: return "ENAMETOOLONG"; case EHOSTDOWN: return "EHOSTDOWN"; case EHOSTUNREACH: return "EHOSTUNREACH"; case ENOTEMPTY: return "ENOTEMPTY"; case EUSERS: return "EUSERS"; case EDQUOT: return "EDQUOT"; case ESTALE: return "ESTALE"; case EREMOTE: return "EREMOTE"; } return "UNKNOWN ERROR (" + UTIL_ToString( m_Error ) + ")"; }
void CReplay :: BuildReplay( string gameName, string statString ) { CONSOLE_Print( "[REPLAY] building replay" ); uint32_t LanguageID = 0x0012F8B0; BYTEARRAY Replay; Replay.push_back( 16 ); // Unknown (4.0) Replay.push_back( 1 ); // Unknown (4.0) Replay.push_back( 0 ); // Unknown (4.0) Replay.push_back( 0 ); // Unknown (4.0) Replay.push_back( 0 ); // Host RecordID (4.1) Replay.push_back( m_HostPID ); // Host PlayerID (4.1) UTIL_AppendByteArray( Replay, m_HostName ); // Host PlayerName (4.1) Replay.push_back( 1 ); // Host AdditionalSize (4.1) Replay.push_back( 0 ); // Host AdditionalData (4.1) UTIL_AppendByteArray( Replay, gameName ); // GameName (4.2) Replay.push_back( 0 ); // Null (4.0) UTIL_AppendByteArray( Replay, statString ); // StatString (4.3) UTIL_AppendByteArray( Replay, (uint32_t)m_Slots.size( ), false ); // PlayerCount (4.6) Replay.push_back( m_MapGameType ); // GameType (4.7) Replay.push_back( 32 ); // GameType (4.7) Replay.push_back( 73 ); // GameType (4.7) Replay.push_back( 0 ); // GameType (4.7) UTIL_AppendByteArray( Replay, LanguageID, false ); // LanguageID (4.8) // PlayerList (4.9) for( vector<ReplayPlayer> :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { if( (*i).first != m_HostPID ) { Replay.push_back( 22 ); // Player RecordID (4.1) Replay.push_back( (*i).first ); // Player PlayerID (4.1) UTIL_AppendByteArray( Replay, (*i).second ); // Player PlayerName (4.1) Replay.push_back( 1 ); // Player AdditionalSize (4.1) Replay.push_back( 0 ); // Player AdditionalData (4.1) UTIL_AppendByteArray( Replay, (uint32_t)0, false ); // Unknown } } // GameStartRecord (4.10) Replay.push_back( 25 ); // RecordID (4.10) UTIL_AppendByteArray( Replay, (uint16_t)( 7 + m_Slots.size( ) * 9 ), false ); // Size (4.10) Replay.push_back( m_Slots.size( ) ); // NumSlots (4.10) for( unsigned char i = 0; i < m_Slots.size( ); i++ ) UTIL_AppendByteArray( Replay, m_Slots[i].GetByteArray( ) ); UTIL_AppendByteArray( Replay, m_RandomSeed, false ); // RandomSeed (4.10) Replay.push_back( m_SelectMode ); // SelectMode (4.10) Replay.push_back( m_StartSpotCount ); // StartSpotCount (4.10) // ReplayData (5.0) Replay.push_back( REPLAY_FIRSTSTARTBLOCK ); UTIL_AppendByteArray( Replay, (uint32_t)1, false ); Replay.push_back( REPLAY_SECONDSTARTBLOCK ); UTIL_AppendByteArray( Replay, (uint32_t)1, false ); // leavers during loading need to be stored between the second and third start blocks while( !m_LoadingBlocks.empty( ) ) { UTIL_AppendByteArray( Replay, m_LoadingBlocks.front( ) ); m_LoadingBlocks.pop( ); } Replay.push_back( REPLAY_THIRDSTARTBLOCK ); UTIL_AppendByteArray( Replay, (uint32_t)1, false ); // initialize replay length to zero // we'll accumulate the replay length as we iterate through the timeslots // this is necessary because we might be discarding some timeslots due to not enough checksums and the replay length needs to be accurate m_ReplayLength = 0; uint32_t TimeSlotsDiscarded = 0; while( !m_Blocks.empty( ) ) { BYTEARRAY Block = m_Blocks.front( ); m_Blocks.pop( ); if( Block.size( ) >= 5 && Block[0] == REPLAY_TIMESLOT ) { if( m_CheckSums.empty( ) ) { TimeSlotsDiscarded++; continue; } // append timeslot UTIL_AppendByteArray( Replay, Block ); // append checksum BYTEARRAY CheckSum; CheckSum.push_back( REPLAY_CHECKSUM ); CheckSum.push_back( 4 ); UTIL_AppendByteArray( CheckSum, m_CheckSums.front( ), false ); m_CheckSums.pop( ); UTIL_AppendByteArray( Replay, CheckSum ); // accumulate replay length m_ReplayLength += UTIL_ByteArrayToUInt16( Block, false, 3 ); } else UTIL_AppendByteArray( Replay, Block ); } if( TimeSlotsDiscarded > 0 ) CONSOLE_Print( "[REPLAY] ran out of checksums, discarded " + UTIL_ToString( TimeSlotsDiscarded ) + " timeslots" ); // done m_Decompressed = string( Replay.begin( ), Replay.end( ) ); }
bool MySQLBanAdd( void *conn, string *error, uint32_t botid, string server, string user, string ip, string gamename, string admin, string reason ) { transform( user.begin( ), user.end( ), user.begin( ), (int(*)(int))tolower ); string EscServer = MySQLEscapeString( conn, server ); string EscUser = MySQLEscapeString( conn, user ); string EscIP = MySQLEscapeString( conn, ip ); string EscGameName = MySQLEscapeString( conn, gamename ); string EscAdmin = MySQLEscapeString( conn, admin ); string EscReason = MySQLEscapeString( conn, reason ); bool Success = false; string Query = "INSERT INTO bans ( botid, server, name, ip, date, gamename, admin, reason ) VALUES ( " + UTIL_ToString( botid ) + ", '" + EscServer + "', '" + EscUser + "', '" + EscIP + "', CURDATE( ), '" + EscGameName + "', '" + EscAdmin + "', '" + EscReason + "' )"; if( mysql_real_query( (MYSQL *)conn, Query.c_str( ), Query.size( ) ) != 0 ) *error = mysql_error( (MYSQL *)conn ); else Success = true; return Success; }
uint32_t MySQLW3MMDPlayerAdd( void *conn, string *error, uint32_t botid, string category, uint32_t gameid, uint32_t pid, string name, string flag, uint32_t leaver, uint32_t practicing ) { transform( name.begin( ), name.end( ), name.begin( ), (int(*)(int))tolower ); uint32_t RowID = 0; string EscCategory = MySQLEscapeString( conn, category ); string EscName = MySQLEscapeString( conn, name ); string EscFlag = MySQLEscapeString( conn, flag ); string Query = "INSERT INTO w3mmdplayers ( botid, category, gameid, pid, name, flag, leaver, practicing ) VALUES ( " + UTIL_ToString( botid ) + ", '" + EscCategory + "', " + UTIL_ToString( gameid ) + ", " + UTIL_ToString( pid ) + ", '" + EscName + "', '" + EscFlag + "', " + UTIL_ToString( leaver ) + ", " + UTIL_ToString( practicing ) + " )"; if( mysql_real_query( (MYSQL *)conn, Query.c_str( ), Query.size( ) ) != 0 ) *error = mysql_error( (MYSQL *)conn ); else RowID = mysql_insert_id( (MYSQL *)conn ); return RowID; }
bool CGamePlayer :: Update( void *fd ) { // wait 4 seconds after joining before sending the /whois or /w // if we send the /whois too early battle.net may not have caught up with where the player is and return erroneous results if( m_WhoisShouldBeSent && !m_Spoofed && !m_WhoisSent && !m_JoinedRealm.empty( ) && GetTime( ) - m_JoinTime >= 4 ) { // todotodo: we could get kicked from battle.net for sending a command with invalid characters, do some basic checking // check if we have this ip in our spoofed cached ip list bool isspoofed = m_Game->m_GHost->IsSpoofedIP(GetName(), GetExternalIPString()); if (isspoofed) { CONSOLE_Print("[OPT] Player "+GetName()+" is in the cached spoof checked list"); m_Game->AddToSpoofed(m_Game->m_Server, GetName(), false); } if (!isspoofed && GetExternalIPString()!="127.0.0.1") for( vector<CBNET *> :: iterator i = m_Game->m_GHost->m_BNETs.begin( ); i != m_Game->m_GHost->m_BNETs.end( ); i++ ) { if( (*i)->GetServer( ) == m_JoinedRealm ) { if( m_Game->GetGameState( ) == GAME_PUBLIC ) { if ((*i)->GetWhereis() || (*i)->GetPasswordHashType( ) == "pvpgn" ) (*i)->QueueChatCommand( "/whereis " + m_Name ); else (*i)->QueueChatCommand( "/whois " + m_Name ); } else if( m_Game->GetGameState( ) == GAME_PRIVATE ) (*i)->QueueChatCommand( m_Game->m_GHost->m_Language->SpoofCheckByReplying( ), m_Name, true ); } } m_WhoisSent = true; } // check for socket timeouts // if we don't receive anything from a player for 30 seconds we can assume they've dropped // this works because in the lobby we send pings every 5 seconds and expect a response to each one // and in the game the Warcraft 3 client sends keepalives frequently (at least once per second it looks like) if( m_Socket && GetTime( ) - m_Socket->GetLastRecv( ) >= 30 ) m_Game->EventPlayerDisconnectTimedOut( this ); // make sure we're not waiting too long for the first MAPSIZE packet if( m_ConnectionState == 1 && GetTicks( ) - m_ConnectionTime > m_Game->m_GHost->m_DenyMaxMapsizeTime && !m_Game->GetGameLoaded() && !m_Game->GetGameLoading() ) { CONSOLE_Print( "[DENY] Kicking player: MAPSIZE not received within a few seconds" ); m_DeleteMe = true; SetLeftReason( "MAPSIZE not received within a few seconds" ); SetLeftCode( PLAYERLEAVE_LOBBY ); m_Game->OpenSlot( m_Game->GetSIDFromPID( GetPID( ) ), false ); m_Game->m_GHost->DenyIP( GetExternalIPString( ), m_Game->m_GHost->m_DenyMapsizeDuration, "MAPSIZE not received within a few seconds" ); } // disconnect if the player is downloading too slowly if( m_DownloadStarted && !m_DownloadFinished && !m_Game->GetGameLoaded() && !m_Game->GetGameLoading() && GetLastMapPartSent( ) != 0 ) { uint32_t downloadingTime = GetTicks( ) - m_StartedDownloadingTicks; uint32_t Seconds = downloadingTime / 1000; uint32_t Rate = GetLastMapPartSent( ) / 1024; // Rate in miliseconds if (Seconds>0) Rate /= Seconds; if(!(m_Game->IsSafe(GetName()) || m_Game->IsAdmin(GetName()) || m_Game->IsRootAdmin(GetName()) || m_Game->IsOwner(GetName()) )){ // uint32_t iRate = (uint32_t)Rate; if ( m_Game->m_GHost->m_DLRateLimit != 0 ) if ( GetLastMapPartSent( ) <= 102400 ) if ( 0 < Rate && Rate < m_Game->m_GHost->m_DLRateLimit ){ m_Game->DelTempOwner( GetName() ); m_Game->SendAllChat( m_Game->m_GHost->m_Language->KickMsgForSlowDL( GetName( ) , UTIL_ToString( Rate ), UTIL_ToString(m_Game->m_GHost->m_DLRateLimit) ) ); m_Game->m_GHost->m_Callables.push_back( m_Game->m_GHost->m_DB->ThreadedBanAdd( GetJoinedRealm( ), GetName( ), GetExternalIPString(), m_Game->GetGameName( ), "AUTOBAN", "Slow internet", 1, 0 )); if ( m_Game->m_GHost->m_BlacklistSlowDLder && !m_Game->IsBlacklisted(m_Game->GetBannedNames( ),GetName( )) ) m_Game->AddBannedNames(GetName( )); m_DeleteMe = true; SetLeftReason( "kicked for downloading too slowly " + UTIL_ToString( Rate ) + " KB/s" ); SetLeftCode( PLAYERLEAVE_LOBBY ); m_Game->OpenSlot( m_Game->GetSIDFromPID( GetPID( ) ), false ); } if( downloadingTime > m_Game->m_GHost->m_DenyMaxDownloadTime ) { m_Game->DelTempOwner( GetName() ); m_Game->SendAllChat( m_Game->m_GHost->m_Language->KickMsgForSlowDL( GetName( ),"","" ) ); m_DeleteMe = true; SetLeftReason( "download time is too long" ); SetLeftCode( PLAYERLEAVE_LOBBY ); m_Game->OpenSlot( m_Game->GetSIDFromPID( GetPID( ) ), false ); m_Game->m_GHost->DenyIP( GetExternalIPString( ), m_Game->m_GHost->m_DenyDownloadDuration, "("+ GetName( ) +") rejected because download time is too long" ); } } } // unmute player if( GetMuted( ) && ( GetTicks( ) - m_MutedTicks > 60000 || ( m_MutedAuto && GetTicks( ) - m_MutedTicks > 15000 ) ) ) { SetMuted( false ); m_Game->SendAllChat( "[" + m_Name + "] has been automatically unmuted. (Don't spam or you'll be muted again!)" ); m_MuteMessages.clear( ); } // GProxy++ acks if( m_GProxy && GetTime( ) - m_LastGProxyAckTime >= 10 ) { if( m_Socket ) m_Socket->PutBytes( m_Game->m_GHost->m_GPSProtocol->SEND_GPSS_ACK( m_TotalPacketsReceived ) ); m_LastGProxyAckTime = GetTime( ); } // base class update CPotentialPlayer :: Update( fd ); bool Deleting; if( m_GProxy && m_Game->GetGameLoaded( ) ) Deleting = m_DeleteMe || m_Error; else Deleting = m_DeleteMe || m_Error || m_Socket->HasError( ) || !m_Socket->GetConnected( ); // try to find out why we're requesting deletion // in cases other than the ones covered here m_LeftReason should have been set when m_DeleteMe was set if( m_Error ){ m_Game->m_GHost->DenyIP( GetExternalIPString( ), 180000, "player error" ); m_Game->EventPlayerDisconnectPlayerError( this ); m_Socket->Reset( ); return Deleting; } if( m_Socket ) { if( m_Socket->HasError( ) ){ m_Game->EventPlayerDisconnectSocketError( this ); if( !m_GProxy ) m_Game->m_GHost->DenyIP( GetExternalIPString( ), 20000, "socket error" ); } else if( !m_Socket->GetConnected( ) ){ m_Game->EventPlayerDisconnectConnectionClosed( this ); if( !m_GProxy ) m_Game->m_GHost->DenyIP( GetExternalIPString( ), 30000, "connection closed" ); } } return Deleting; }
inline void CIRC :: ExtractPackets( ) { string Token, PreviousToken, Recv = *( m_Socket->GetBytes( ) ); uint32_t Time = GetTime( ); unsigned int i; /* loop through whole recv buffer */ for( i = 0; i < Recv.size( ); ++i ) { // add chars to token if( Recv[i] != ' ' && Recv[i] != CR && Recv[i] != LF ) { Token += Recv[i]; } else if( Recv[i] == ' ' || Recv[i] == LF ) { // end of token, examine if( Token == "PRIVMSG" ) { // parse the PreviousToken as it holds the user info and then the Token for the message itself string Nickname, Hostname, Message, Command, Payload; bool IsCommand = true; unsigned int j = 1; // get nickname for( ; PreviousToken[j] != '!'; ++j ) Nickname += PreviousToken[j]; // skip username for( j += 2; PreviousToken[j] != '@'; ++j ); // get hostname for( ++j; j < PreviousToken.size( ); ++j ) Hostname += PreviousToken[j]; // skip channel for( i += 3; Recv[i] != ':'; ++i ); // process message for( ++i; Recv[i] != CR; ++i ) { Message += Recv[i]; if( Recv[i] == ' ' && IsCommand ) { IsCommand = false; continue; } if( Message.size( ) != 1 ) { if( IsCommand ) Command += tolower( Recv[i] ); else Payload += Recv[i]; } } // move position after the \n i += 2; if( Message.empty( ) ) { PreviousToken = Token; Token.clear( ); continue; } if( Message[0] != SOH ) { for( vector<CBNET *> :: iterator i = m_Aura->m_BNETs.begin( ); i != m_Aura->m_BNETs.end( ); ++i ) { if( Message[0] == (*i)->GetCommandTrigger( ) ) { CIncomingChatEvent event = CIncomingChatEvent( CBNETProtocol :: EID_IRC, Nickname, Message ); (*i)->ProcessChatEvent( &event ); break; } } if( Message[0] == m_CommandTrigger[0] ) { bool Root = Hostname.substr( 0, 6 ) == "Aurani" || Hostname.substr( 0, 8 ) == "h4x0rz88"; if( Command == "nick" && Root ) { SendIRC( "NICK :" + Payload ); m_Nickname = Payload; m_OriginalNick= false; } else if( Command == "dcclist" ) { string on, off; for( vector<CDCC *> :: iterator i = m_DCC.begin( ); i != m_DCC.end( ); ++i ) { if( (*i)->m_Socket->GetConnected( ) ) on += (*i)->m_Nickname + "[" + UTIL_ToString( (*i)->m_Port ) +"] "; else off += (*i)->m_Nickname + "[" + UTIL_ToString( (*i)->m_Port ) +"] "; } SendMessageIRC( "ON: " + on, string( ) ); SendMessageIRC( "OFF: " + off, string( ) ); } else if( Command == "bnetoff" ) { if( Payload.empty( ) ) { for( vector<CBNET *> :: iterator i = m_Aura->m_BNETs.begin( ); i != m_Aura->m_BNETs.end( ); ++i ) { (*i)->Deactivate( ); SendMessageIRC( "[BNET: " + (*i)->GetServerAlias( ) + "] deactivated.", string( ) ); } } else { for( vector<CBNET *> :: iterator i = m_Aura->m_BNETs.begin( ); i != m_Aura->m_BNETs.end( ); ++i ) { if( (*i)->GetServerAlias( ) == Payload ) { (*i)->Deactivate( ); SendMessageIRC( "[BNET: " + (*i)->GetServerAlias( ) + "] deactivated.", string( ) ); break; } } } } else if( Command == "bneton" ) { if( Payload.empty( ) ) { for( vector<CBNET *> :: iterator i = m_Aura->m_BNETs.begin( ); i != m_Aura->m_BNETs.end( ); ++i ) { (*i)->Activate( ); SendMessageIRC( "[BNET: " + (*i)->GetServerAlias( ) + "] activated.", string( ) ); } } else { for( vector<CBNET *> :: iterator i = m_Aura->m_BNETs.begin( ); i != m_Aura->m_BNETs.end( ); ++i ) { if( (*i)->GetServerAlias( ) == Payload ) { (*i)->Activate( ); SendMessageIRC( "[BNET: " + (*i)->GetServerAlias( ) + "] activated.", string( ) ); break; } } } } } } else if( Payload.size( ) > 12 && Payload.substr( 0, 4 ) == "CHAT" ) { // CHAT chat 3162588924 1025 string strIP, strPort; bool IsPort = false; for( unsigned int j = 10; j < ( Payload.size( ) - 1 ); ++j ) { if( !IsPort && Payload[j] == ' ' ) { IsPort = true; continue; } if( !IsPort ) strIP += Payload[j]; else strPort += Payload[j]; } unsigned int Port = UTIL_ToUInt16( strPort ); if( Port < 1024 || 1026 < Port ) Port = 1024; bool Local = false; for( vector<string> :: iterator i = m_Locals.begin( ); i != m_Locals.end( ); ++i ) { if( Nickname == (*i) ) { strIP = "127.0.0.1"; Local = true; break; } } if( !Local ) { unsigned long IP = UTIL_ToUInt32( strIP ), divider = 16777216UL; strIP = ""; for( int i = 0; i <= 3; ++i ) { stringstream ss; ss << (unsigned long) IP / divider; IP %= divider; divider /= 256; strIP += ss.str( ); if( i != 3 ) strIP += '.'; } } bool Existing = false; for( vector<CDCC *> :: iterator i = m_DCC.begin( ); i != m_DCC.end( ); ++i ) { if( (*i)->m_Nickname == Nickname ) { (*i)->Connect( strIP, Port ); Existing = true; break; } } if( !Existing ) m_DCC.push_back( new CDCC( this, strIP, Port, Nickname ) ); } // remember last packet time m_LastPacketTime = Time; } else if( Token == "391" ) { // move position after the \n (next packet) for( ++i; Recv[i] != CR; ++i ); i += 2; // remember last packet time m_LastPacketTime = Time; } else if( Token == "PING" ) { string Packet; // PING :blabla // skip until : for( ++i; Recv[i] != ':'; ++i ); for( ++i; Recv[i] != CR; ++i ) Packet += Recv[i]; SendIRC( "PONG :" + Packet ); // move position after the \n i += 2; // remember last packet time m_LastPacketTime = Time; } else if( Token == "NOTICE" ) { // move position after the \n for( ++i; Recv[i] != CR; ++i ); i += 2; // remember last packet time m_LastPacketTime = Time; } else if( Token == "221" ) { // Q auth if the server is QuakeNet if( m_Server.find( "quakenet.org" ) != string :: npos && !m_Password.empty( ) ) { SendMessageIRC( "AUTH " + m_Username + " " + m_Password, "*****@*****.**" ); SendIRC( "MODE " + m_Nickname + " +x" ); } // join channels for( vector<string> :: iterator j = m_Channels.begin( ); j != m_Channels.end( ); ++j ) { SendIRC( "JOIN " + (*j) ); } // move position after the \n for( ++i; Recv[i] != CR; ++i ); i += 2; // remember last packet time m_LastPacketTime = Time; } else if( Token == "433" ) { // nick taken, append _ m_OriginalNick = false; m_Nickname += '_'; SendIRC( "NICK " + m_Nickname ); // move position after the \n (next packet) for( ++i; Recv[i] != CR; ++i ); i += 2; // remember last packet time m_LastPacketTime = Time; } else if( Token == "353" ) { // move position after the \n (next packet) for( ++i; Recv[i] != CR; ++i ); i += 2; // remember last packet time m_LastPacketTime = Time; } else if( Token == "KICK" ) { string Channel, Victim; bool Space = false; // get channel for( ++i; Recv[i] != ' '; ++i ) Channel += Recv[i]; // get the victim for( ++i ; i < Recv.size( ); ++i ) { if( Recv[i] == ' ' ) Space = true; else if( Recv[i] == CR ) break; else if( Space && Recv[i] != ':' ) Victim += Recv[i]; } // we're the victim here! rejoin if( Victim == m_Nickname ) { SendIRC( "JOIN " + Channel ); } // move position after the \n i += 2; // remember last packet time m_LastPacketTime = Time; } // empty the token PreviousToken = Token; Token.clear( ); } } m_Socket->ClearRecvBuffer( ); }
void CBNET :: ProcessChatEvent( CIncomingChatEvent *chatEvent ) { CBNETProtocol :: IncomingChatEvent Event = chatEvent->GetChatEvent( ); string User = chatEvent->GetUser( ), lowerUser = chatEvent->GetUser( ), Message = chatEvent->GetMessage( ); transform( lowerUser.begin( ), lowerUser.end( ), lowerUser.begin( ), (int(*)(int))tolower ); unsigned char Access = m_CCBot->m_DB->AccessCheck( m_Server, lowerUser ); if( Access == 255 ) Access = 0; bool Output = ( Event == CBNETProtocol :: CONSOLE_INPUT ); bool Whisper = ( Event == CBNETProtocol :: EID_WHISPER ); bool ClanMember = IsClanMember( m_UserName ); if( Event == CBNETProtocol :: EID_TALK ) CONSOLE_Print( "[LOCAL: " + m_ServerAlias + ":" + m_CurrentChannel + "][" + User + "] " + Message ); else if( Event == CBNETProtocol :: EID_WHISPER ) CONSOLE_Print( "[WHISPER: " + m_ServerAlias + "][" + User + "] " + Message ); else if( Event == CBNETProtocol :: EID_EMOTE ) CONSOLE_Print( "[EMOTE: " + m_ServerAlias + ":" + m_CurrentChannel + "][" + User + "] " + Message ); if( Event == CBNETProtocol :: EID_TALK || Event == CBNETProtocol :: EID_WHISPER || Event == CBNETProtocol :: EID_EMOTE || Event == CBNETProtocol :: CONSOLE_INPUT ) { // Anti-Spam // TODO: improve this to be more robust and efficient if( m_AntiSpam && !Message.empty( ) && Message[0] != m_CommandTrigger[0] && Access < 5 && IsInChannel( User ) && User != m_UserName ) { string message = Message; transform( message.begin( ), message.end( ), message.begin( ), (int(*)(int))tolower ); uint32_t SpamCacheSize = m_Channel.size( ) * 3; if( m_SpamCache.size( ) > SpamCacheSize ) m_SpamCache.erase( m_SpamCache.begin( ) ); m_SpamCache.insert( pair<string, string>( lowerUser, message ) ); int mesgmatches = 0, nickmatches = 0; for( multimap<string, string> :: iterator i = m_SpamCache.begin( ); i != m_SpamCache.end( ); ++i ) { if( (*i).first == lowerUser ) ++nickmatches; if( (*i).second.find( message ) ) ++mesgmatches; } if( mesgmatches > 2 || nickmatches > 3 ) SendChatCommand( "/kick " + User + " Anti-Spam", Output ); } // Swearing kick if ( m_SwearingKick && !Message.empty( ) && !Match( User, m_HostbotName ) && !m_CCBot->m_DB->SafelistCheck( m_Server, User ) && IsInChannel( User ) && Access < 5 ) { string message = Message; transform( message.begin( ), message.end( ), message.begin( ), (int(*)(int))tolower ); for( uint32_t i = 0; i < m_CCBot->m_SwearList.size( ); ++i ) { if( message.find( m_CCBot->m_SwearList[i] ) != string :: npos ) QueueChatCommand( m_CCBot->m_Language->SwearKick( User, m_CCBot->m_SwearList[i] ), Output ); } } // ?TRIGGER if( Match( Message, "?trigger" ) ) { QueueChatCommand( m_CCBot->m_Language->CommandTrigger( m_CommandTrigger ), User, Whisper, Output ); } else if( !Message.empty( ) && Message[0] == m_CommandTrigger[0] && Event != CBNETProtocol :: EID_EMOTE ) { // extract the command trigger, the command, and the payload // e.g. "!say hello world" -> command: "say", payload: "hello world" string Command, Payload; string :: size_type PayloadStart = Message.find( " " ); if( PayloadStart != string :: npos ) { Command = Message.substr( 1, PayloadStart - 1 ); Payload = Message.substr( PayloadStart + 1 ); } else Command = Message.substr( 1 ); transform( Command.begin( ), Command.end( ), Command.begin( ), (int(*)(int))tolower ); /******************************** ************ COMMANDS *********** ********************************/ // // !ACCEPT // if( Command == "accept" && Payload.empty( ) && Access >= m_CCBot->m_DB->CommandAccess( "accept" ) && m_ActiveInvitation ) { m_Socket->PutBytes( m_Protocol->SEND_SID_CLANINVITATIONRESPONSE( m_Protocol->GetClanTag( ), m_Protocol->GetInviter( ), true ) ); QueueChatCommand( m_CCBot->m_Language->InvitationAccepted( ), User, Whisper, Output ); SendGetClanList( ); m_ActiveInvitation = false; } // // !ACCESS // else if( Command == "access" && Payload.empty( ) && Access >= m_CCBot->m_DB->CommandAccess( "access" ) ) { SendChatCommand( "/w " + User + " " + m_CCBot->m_Language->HasFollowingAccess( UTIL_ToString( Access ) ), Output ); for( unsigned char n = 0; n <= Access; ++n ) { string Commands; vector<string> m_CommandList = m_CCBot->m_DB->CommandList( n ); for( vector<string> :: iterator i = m_CommandList.begin( ); i != m_CommandList.end( ); ++i ) Commands = Commands + m_CommandTrigger + (*i) + ", "; Commands = Commands.substr( 0, Commands.size( ) -2 ); if( m_CommandList.size ( ) ) SendChatCommand( "/w " + User + " [" + UTIL_ToString( n ) + "]: " + Commands, Output ); else break; } } // // !ADDSAFELIST // !ADDS // else if( ( Command == "addsafelist" || Command == "adds" ) && !Payload.empty( ) && Access >= m_CCBot->m_DB->CommandAccess( "addsafelist" ) ) { if( m_CCBot->m_DB->SafelistCheck( m_Server, Payload ) ) QueueChatCommand( m_CCBot->m_Language->UserAlreadySafelisted( Payload ), User, Whisper, Output ); else { if( m_CCBot->m_DB->SafelistAdd( m_Server, Payload ) ) QueueChatCommand( m_CCBot->m_Language->UserSafelisted( Payload ), User, Whisper, Output ); else QueueChatCommand( m_CCBot->m_Language->ErrorSafelisting( Payload ), User, Whisper, Output ); } } // // !ANNOUNCE // else if( Command == "announce" && !Payload.empty( ) && Access >= m_CCBot->m_DB->CommandAccess( "announce" ) ) { string Interval, AnnounceMessage; stringstream SS; SS << Payload; SS >> Interval; if( !SS.eof( ) ) { getline( SS, AnnounceMessage ); string :: size_type Start = AnnounceMessage.find_first_not_of( " " ); if( Start != string :: npos ) AnnounceMessage = AnnounceMessage.substr( Start ); } if( ( UTIL_ToInt32( Interval ) > 0 ) && AnnounceMessage.size( ) ) { m_Announce = true; m_AnnounceMsg = AnnounceMessage; m_AnnounceInterval = UTIL_ToInt32( Interval ); if( m_AnnounceInterval < 3 ) m_AnnounceInterval = 4; QueueChatCommand( m_CCBot->m_Language->AnnounceEnabled( Interval ), User, Whisper, Output ); } else if( Interval == "off" && m_Announce == true ) { m_Announce = false; QueueChatCommand( m_CCBot->m_Language->AnnounceDisabled( ), User, Whisper, Output ); } } // // !BAN // !ADDBAN // else if( ( Command == "ban" || Command == "addban" ) && !Payload.empty( ) && Access >= m_CCBot->m_DB->CommandAccess( "ban" ) )
bool MySQLDownloadAdd( void *conn, string *error, uint32_t botid, string map, uint32_t mapsize, string name, string ip, uint32_t spoofed, string spoofedrealm, uint32_t downloadtime ) { bool Success = false; string EscMap = MySQLEscapeString( conn, map ); string EscName = MySQLEscapeString( conn, name ); string EscIP = MySQLEscapeString( conn, ip ); string EscSpoofedRealm = MySQLEscapeString( conn, spoofedrealm ); string Query = "INSERT INTO downloads ( botid, map, mapsize, datetime, name, ip, spoofed, spoofedrealm, downloadtime ) VALUES ( " + UTIL_ToString( botid ) + ", '" + EscMap + "', " + UTIL_ToString( mapsize ) + ", NOW( ), '" + EscName + "', '" + EscIP + "', " + UTIL_ToString( spoofed ) + ", '" + EscSpoofedRealm + "', " + UTIL_ToString( downloadtime ) + " )"; if( mysql_real_query( (MYSQL *)conn, Query.c_str( ), Query.size( ) ) != 0 ) *error = mysql_error( (MYSQL *)conn ); else Success = true; return Success; }
void CMap :: Load( CConfig *CFG, string nCFGFile ) { m_Valid = true; m_CFGFile = nCFGFile; // load the map data m_MapLocalPath = CFG->GetString( "map_localpath", string( ) ); m_MapData.clear( ); if( !m_MapLocalPath.empty( ) ) m_MapData = UTIL_FileRead( m_GHost->m_MapPath + m_MapLocalPath ); // load the map MPQ string MapMPQFileName = m_GHost->m_MapPath + m_MapLocalPath; HANDLE MapMPQ; bool MapMPQReady = false; if( SFileOpenArchive( MapMPQFileName.c_str( ), 0, MPQ_OPEN_FORCE_MPQ_V1, &MapMPQ ) ) { CONSOLE_Print( "[MAP] loading MPQ file [" + MapMPQFileName + "]" ); MapMPQReady = true; } else CONSOLE_Print( "[MAP] warning - unable to load MPQ file [" + MapMPQFileName + "]" ); // try to calculate map_size, map_info, map_crc, map_sha1 BYTEARRAY MapSize; BYTEARRAY MapInfo; BYTEARRAY MapCRC; BYTEARRAY MapSHA1; if( !m_MapData.empty( ) ) { m_GHost->m_SHA->Reset( ); // calculate map_size MapSize = UTIL_CreateByteArray( (uint32_t)m_MapData.size( ), false ); CONSOLE_Print( "[MAP] calculated map_size = " + UTIL_ByteArrayToDecString( MapSize ) ); // calculate map_info (this is actually the CRC) MapInfo = UTIL_CreateByteArray( (uint32_t)m_GHost->m_CRC->FullCRC( (unsigned char *)m_MapData.c_str( ), m_MapData.size( ) ), false ); CONSOLE_Print( "[MAP] calculated map_info = " + UTIL_ByteArrayToDecString( MapInfo ) ); // calculate map_crc (this is not the CRC) and map_sha1 // a big thank you to Strilanc for figuring the map_crc algorithm out string CommonJ = UTIL_FileRead( m_GHost->m_MapCFGPath + "common.j" ); if( CommonJ.empty( ) ) CONSOLE_Print( "[MAP] unable to calculate map_crc/sha1 - unable to read file [" + m_GHost->m_MapCFGPath + "common.j]" ); else { string BlizzardJ = UTIL_FileRead( m_GHost->m_MapCFGPath + "blizzard.j" ); if( BlizzardJ.empty( ) ) CONSOLE_Print( "[MAP] unable to calculate map_crc/sha1 - unable to read file [" + m_GHost->m_MapCFGPath + "blizzard.j]" ); else { uint32_t Val = 0; // update: it's possible for maps to include their own copies of common.j and/or blizzard.j // this code now overrides the default copies if required bool OverrodeCommonJ = false; bool OverrodeBlizzardJ = false; if( MapMPQReady ) { HANDLE SubFile; // override common.j if( SFileOpenFileEx( MapMPQ, "Scripts\\common.j", 0, &SubFile ) ) { uint32_t FileLength = SFileGetFileSize( SubFile, NULL ); if( FileLength > 0 && FileLength != 0xFFFFFFFF ) { char *SubFileData = new char[FileLength]; DWORD BytesRead = 0; if( SFileReadFile( SubFile, SubFileData, FileLength, &BytesRead ) ) { CONSOLE_Print( "[MAP] overriding default common.j with map copy while calculating map_crc/sha1" ); OverrodeCommonJ = true; Val = Val ^ XORRotateLeft( (unsigned char *)SubFileData, BytesRead ); m_GHost->m_SHA->Update( (unsigned char *)SubFileData, BytesRead ); } delete [] SubFileData; } SFileCloseFile( SubFile ); } } if( !OverrodeCommonJ ) { Val = Val ^ XORRotateLeft( (unsigned char *)CommonJ.c_str( ), CommonJ.size( ) ); m_GHost->m_SHA->Update( (unsigned char *)CommonJ.c_str( ), CommonJ.size( ) ); } if( MapMPQReady ) { HANDLE SubFile; // override blizzard.j if( SFileOpenFileEx( MapMPQ, "Scripts\\blizzard.j", 0, &SubFile ) ) { uint32_t FileLength = SFileGetFileSize( SubFile, NULL ); if( FileLength > 0 && FileLength != 0xFFFFFFFF ) { char *SubFileData = new char[FileLength]; DWORD BytesRead = 0; if( SFileReadFile( SubFile, SubFileData, FileLength, &BytesRead ) ) { CONSOLE_Print( "[MAP] overriding default blizzard.j with map copy while calculating map_crc/sha1" ); OverrodeBlizzardJ = true; Val = Val ^ XORRotateLeft( (unsigned char *)SubFileData, BytesRead ); m_GHost->m_SHA->Update( (unsigned char *)SubFileData, BytesRead ); } delete [] SubFileData; } SFileCloseFile( SubFile ); } } if( !OverrodeBlizzardJ ) { Val = Val ^ XORRotateLeft( (unsigned char *)BlizzardJ.c_str( ), BlizzardJ.size( ) ); m_GHost->m_SHA->Update( (unsigned char *)BlizzardJ.c_str( ), BlizzardJ.size( ) ); } Val = ROTL( Val, 3 ); Val = ROTL( Val ^ 0x03F1379E, 3 ); m_GHost->m_SHA->Update( (unsigned char *)"\x9E\x37\xF1\x03", 4 ); if( MapMPQReady ) { vector<string> FileList; FileList.push_back( "war3map.j" ); FileList.push_back( "scripts\\war3map.j" ); FileList.push_back( "war3map.w3e" ); FileList.push_back( "war3map.wpm" ); FileList.push_back( "war3map.doo" ); FileList.push_back( "war3map.w3u" ); FileList.push_back( "war3map.w3b" ); FileList.push_back( "war3map.w3d" ); FileList.push_back( "war3map.w3a" ); FileList.push_back( "war3map.w3q" ); bool FoundScript = false; for( vector<string> :: iterator i = FileList.begin( ); i != FileList.end( ); i++ ) { // don't use scripts\war3map.j if we've already used war3map.j (yes, some maps have both but only war3map.j is used) if( FoundScript && *i == "scripts\\war3map.j" ) continue; HANDLE SubFile; if( SFileOpenFileEx( MapMPQ, (*i).c_str( ), 0, &SubFile ) ) { uint32_t FileLength = SFileGetFileSize( SubFile, NULL ); if( FileLength > 0 && FileLength != 0xFFFFFFFF ) { char *SubFileData = new char[FileLength]; DWORD BytesRead = 0; if( SFileReadFile( SubFile, SubFileData, FileLength, &BytesRead ) ) { if( *i == "war3map.j" || *i == "scripts\\war3map.j" ) FoundScript = true; Val = ROTL( Val ^ XORRotateLeft( (unsigned char *)SubFileData, BytesRead ), 3 ); m_GHost->m_SHA->Update( (unsigned char *)SubFileData, BytesRead ); // DEBUG_Print( "*** found: " + *i ); } delete [] SubFileData; } SFileCloseFile( SubFile ); } else { // DEBUG_Print( "*** not found: " + *i ); } } if( !FoundScript ) CONSOLE_Print( "[MAP] couldn't find war3map.j or scripts\\war3map.j in MPQ file, calculated map_crc/sha1 is probably wrong" ); MapCRC = UTIL_CreateByteArray( Val, false ); CONSOLE_Print( "[MAP] calculated map_crc = " + UTIL_ByteArrayToDecString( MapCRC ) ); m_GHost->m_SHA->Final( ); unsigned char SHA1[20]; memset( SHA1, 0, sizeof( unsigned char ) * 20 ); m_GHost->m_SHA->GetHash( SHA1 ); MapSHA1 = UTIL_CreateByteArray( SHA1, 20 ); CONSOLE_Print( "[MAP] calculated map_sha1 = " + UTIL_ByteArrayToDecString( MapSHA1 ) ); } else CONSOLE_Print( "[MAP] unable to calculate map_crc/sha1 - map MPQ file not loaded" ); } } } else CONSOLE_Print( "[MAP] no map data available, using config file for map_size, map_info, map_crc, map_sha1" ); // try to calculate map_width, map_height, map_slot<x>, map_numplayers, map_numteams uint32_t MapOptions = 0; BYTEARRAY MapWidth; BYTEARRAY MapHeight; uint32_t MapNumPlayers = 0; uint32_t MapNumTeams = 0; vector<CGameSlot> Slots; if( !m_MapData.empty( ) ) { if( MapMPQReady ) { HANDLE SubFile; if( SFileOpenFileEx( MapMPQ, "war3map.w3i", 0, &SubFile ) ) { uint32_t FileLength = SFileGetFileSize( SubFile, NULL ); if( FileLength > 0 && FileLength != 0xFFFFFFFF ) { char *SubFileData = new char[FileLength]; DWORD BytesRead = 0; if( SFileReadFile( SubFile, SubFileData, FileLength, &BytesRead ) ) { istringstream ISS( string( SubFileData, BytesRead ) ); // war3map.w3i format found at http://www.wc3campaigns.net/tools/specs/index.html by Zepir/PitzerMike string GarbageString; uint32_t FileFormat; uint32_t RawMapWidth; uint32_t RawMapHeight; uint32_t RawMapFlags; uint32_t RawMapNumPlayers; uint32_t RawMapNumTeams; ISS.read( (char *)&FileFormat, 4 ); // file format (18 = ROC, 25 = TFT) if( FileFormat == 18 || FileFormat == 25 ) { ISS.seekg( 4, ios :: cur ); // number of saves ISS.seekg( 4, ios :: cur ); // editor version getline( ISS, GarbageString, '\0' ); // map name getline( ISS, GarbageString, '\0' ); // map author getline( ISS, GarbageString, '\0' ); // map description getline( ISS, GarbageString, '\0' ); // players recommended ISS.seekg( 32, ios :: cur ); // camera bounds ISS.seekg( 16, ios :: cur ); // camera bounds complements ISS.read( (char *)&RawMapWidth, 4 ); // map width ISS.read( (char *)&RawMapHeight, 4 ); // map height ISS.read( (char *)&RawMapFlags, 4 ); // flags ISS.seekg( 1, ios :: cur ); // map main ground type if( FileFormat == 18 ) ISS.seekg( 4, ios :: cur ); // campaign background number else if( FileFormat == 25 ) { ISS.seekg( 4, ios :: cur ); // loading screen background number getline( ISS, GarbageString, '\0' ); // path of custom loading screen model } getline( ISS, GarbageString, '\0' ); // map loading screen text getline( ISS, GarbageString, '\0' ); // map loading screen title getline( ISS, GarbageString, '\0' ); // map loading screen subtitle if( FileFormat == 18 ) ISS.seekg( 4, ios :: cur ); // map loading screen number else if( FileFormat == 25 ) { ISS.seekg( 4, ios :: cur ); // used game data set getline( ISS, GarbageString, '\0' ); // prologue screen path } getline( ISS, GarbageString, '\0' ); // prologue screen text getline( ISS, GarbageString, '\0' ); // prologue screen title getline( ISS, GarbageString, '\0' ); // prologue screen subtitle if( FileFormat == 25 ) { ISS.seekg( 4, ios :: cur ); // uses terrain fog ISS.seekg( 4, ios :: cur ); // fog start z height ISS.seekg( 4, ios :: cur ); // fog end z height ISS.seekg( 4, ios :: cur ); // fog density ISS.seekg( 1, ios :: cur ); // fog red value ISS.seekg( 1, ios :: cur ); // fog green value ISS.seekg( 1, ios :: cur ); // fog blue value ISS.seekg( 1, ios :: cur ); // fog alpha value ISS.seekg( 4, ios :: cur ); // global weather id getline( ISS, GarbageString, '\0' ); // custom sound environment ISS.seekg( 1, ios :: cur ); // tileset id of the used custom light environment ISS.seekg( 1, ios :: cur ); // custom water tinting red value ISS.seekg( 1, ios :: cur ); // custom water tinting green value ISS.seekg( 1, ios :: cur ); // custom water tinting blue value ISS.seekg( 1, ios :: cur ); // custom water tinting alpha value } ISS.read( (char *)&RawMapNumPlayers, 4 ); // number of players uint32_t ClosedSlots = 0; for( uint32_t i = 0; i < RawMapNumPlayers; i++ ) { CGameSlot Slot( 0, 255, SLOTSTATUS_OPEN, 0, 0, 1, SLOTRACE_RANDOM ); uint32_t Colour; uint32_t Status; uint32_t Race; ISS.read( (char *)&Colour, 4 ); // colour Slot.SetColour( Colour ); ISS.read( (char *)&Status, 4 ); // status if( Status == 1 ) Slot.SetSlotStatus( SLOTSTATUS_OPEN ); else if( Status == 2 ) { Slot.SetSlotStatus( SLOTSTATUS_OCCUPIED ); Slot.SetComputer( 1 ); Slot.SetComputerType( SLOTCOMP_NORMAL ); } else { Slot.SetSlotStatus( SLOTSTATUS_CLOSED ); ClosedSlots++; } ISS.read( (char *)&Race, 4 ); // race if( Race == 1 ) Slot.SetRace( SLOTRACE_HUMAN ); else if( Race == 2 ) Slot.SetRace( SLOTRACE_ORC ); else if( Race == 3 ) Slot.SetRace( SLOTRACE_UNDEAD ); else if( Race == 4 ) Slot.SetRace( SLOTRACE_NIGHTELF ); else Slot.SetRace( SLOTRACE_RANDOM ); ISS.seekg( 4, ios :: cur ); // fixed start position getline( ISS, GarbageString, '\0' ); // player name ISS.seekg( 4, ios :: cur ); // start position x ISS.seekg( 4, ios :: cur ); // start position y ISS.seekg( 4, ios :: cur ); // ally low priorities ISS.seekg( 4, ios :: cur ); // ally high priorities if( Slot.GetSlotStatus( ) != SLOTSTATUS_CLOSED ) Slots.push_back( Slot ); } ISS.read( (char *)&RawMapNumTeams, 4 ); // number of teams for( uint32_t i = 0; i < RawMapNumTeams; i++ ) { uint32_t Flags; uint32_t PlayerMask; ISS.read( (char *)&Flags, 4 ); // flags ISS.read( (char *)&PlayerMask, 4 ); // player mask for( unsigned char j = 0; j < 12; j++ ) { if( PlayerMask & 1 ) { for( vector<CGameSlot> :: iterator k = Slots.begin( ); k != Slots.end( ); k++ ) { if( (*k).GetColour( ) == j ) (*k).SetTeam( i ); } } PlayerMask >>= 1; } getline( ISS, GarbageString, '\0' ); // team name } // the bot only cares about the following options: melee, fixed player settings, custom forces // let's not confuse the user by displaying erroneous map options so zero them out now MapOptions = RawMapFlags & ( MAPOPT_MELEE | MAPOPT_FIXEDPLAYERSETTINGS | MAPOPT_CUSTOMFORCES ); CONSOLE_Print( "[MAP] calculated map_options = " + UTIL_ToString( MapOptions ) ); MapWidth = UTIL_CreateByteArray( (uint16_t)RawMapWidth, false ); CONSOLE_Print( "[MAP] calculated map_width = " + UTIL_ByteArrayToDecString( MapWidth ) ); MapHeight = UTIL_CreateByteArray( (uint16_t)RawMapHeight, false ); CONSOLE_Print( "[MAP] calculated map_height = " + UTIL_ByteArrayToDecString( MapHeight ) ); MapNumPlayers = RawMapNumPlayers - ClosedSlots; CONSOLE_Print( "[MAP] calculated map_numplayers = " + UTIL_ToString( MapNumPlayers ) ); MapNumTeams = RawMapNumTeams; CONSOLE_Print( "[MAP] calculated map_numteams = " + UTIL_ToString( MapNumTeams ) ); uint32_t SlotNum = 1; for( vector<CGameSlot> :: iterator i = Slots.begin( ); i != Slots.end( ); i++ ) { CONSOLE_Print( "[MAP] calculated map_slot" + UTIL_ToString( SlotNum ) + " = " + UTIL_ByteArrayToDecString( (*i).GetByteArray( ) ) ); SlotNum++; } if( MapOptions & MAPOPT_MELEE ) { CONSOLE_Print( "[MAP] found melee map, initializing slots" ); // give each slot a different team and set the race to random unsigned char Team = 0; for( vector<CGameSlot> :: iterator i = Slots.begin( ); i != Slots.end( ); i++ ) { (*i).SetTeam( Team++ ); (*i).SetRace( SLOTRACE_RANDOM ); } } if( !( MapOptions & MAPOPT_FIXEDPLAYERSETTINGS ) ) { // make races selectable for( vector<CGameSlot> :: iterator i = Slots.begin( ); i != Slots.end( ); i++ ) (*i).SetRace( (*i).GetRace( ) | SLOTRACE_SELECTABLE ); } } } else
string CGHostDBMySQL :: GetStatus( ) { return "DB STATUS --- Connections: " + UTIL_ToString( m_IdleConnections.size( ) ) + "/" + UTIL_ToString( m_NumConnections ) + " idle. Outstanding callables: " + UTIL_ToString( m_OutstandingCallables ) + "."; }
uint32_t MySQLDotAPlayerAdd( void *conn, string *error, uint32_t botid, uint32_t gameid, uint32_t colour, uint32_t kills, uint32_t deaths, uint32_t creepkills, uint32_t creepdenies, uint32_t assists, uint32_t gold, uint32_t neutralkills, string item1, string item2, string item3, string item4, string item5, string item6, string hero, uint32_t newcolour, uint32_t towerkills, uint32_t raxkills, uint32_t courierkills ) { uint32_t RowID = 0; string EscItem1 = MySQLEscapeString( conn, item1 ); string EscItem2 = MySQLEscapeString( conn, item2 ); string EscItem3 = MySQLEscapeString( conn, item3 ); string EscItem4 = MySQLEscapeString( conn, item4 ); string EscItem5 = MySQLEscapeString( conn, item5 ); string EscItem6 = MySQLEscapeString( conn, item6 ); string EscHero = MySQLEscapeString( conn, hero ); string Query = "INSERT INTO dotaplayers ( botid, gameid, colour, kills, deaths, creepkills, creepdenies, assists, gold, neutralkills, item1, item2, item3, item4, item5, item6, hero, newcolour, towerkills, raxkills, courierkills ) VALUES ( " + UTIL_ToString( botid ) + ", " + UTIL_ToString( gameid ) + ", " + UTIL_ToString( colour ) + ", " + UTIL_ToString( kills ) + ", " + UTIL_ToString( deaths ) + ", " + UTIL_ToString( creepkills ) + ", " + UTIL_ToString( creepdenies ) + ", " + UTIL_ToString( assists ) + ", " + UTIL_ToString( gold ) + ", " + UTIL_ToString( neutralkills ) + ", '" + EscItem1 + "', '" + EscItem2 + "', '" + EscItem3 + "', '" + EscItem4 + "', '" + EscItem5 + "', '" + EscItem6 + "', '" + EscHero + "', " + UTIL_ToString( newcolour ) + ", " + UTIL_ToString( towerkills ) + ", " + UTIL_ToString( raxkills ) + ", " + UTIL_ToString( courierkills ) + " )"; if( mysql_real_query( (MYSQL *)conn, Query.c_str( ), Query.size( ) ) != 0 ) *error = mysql_error( (MYSQL *)conn ); else RowID = mysql_insert_id( (MYSQL *)conn ); return RowID; }
uint32_t MySQLDotAGameAdd( void *conn, string *error, uint32_t botid, uint32_t gameid, uint32_t winner, uint32_t min, uint32_t sec ) { uint32_t RowID = 0; string Query = "INSERT INTO dotagames ( botid, gameid, winner, min, sec ) VALUES ( " + UTIL_ToString( botid ) + ", " + UTIL_ToString( gameid ) + ", " + UTIL_ToString( winner ) + ", " + UTIL_ToString( min ) + ", " + UTIL_ToString( sec ) + " )"; if( mysql_real_query( (MYSQL *)conn, Query.c_str( ), Query.size( ) ) != 0 ) *error = mysql_error( (MYSQL *)conn ); else RowID = mysql_insert_id( (MYSQL *)conn ); return RowID; }
uint32_t MySQLGamePlayerAdd( void *conn, string *error, uint32_t botid, uint32_t gameid, string name, string ip, uint32_t spoofed, string spoofedrealm, uint32_t reserved, uint32_t loadingtime, uint32_t left, string leftreason, uint32_t team, uint32_t colour ) { transform( name.begin( ), name.end( ), name.begin( ), (int(*)(int))tolower ); uint32_t RowID = 0; string EscName = MySQLEscapeString( conn, name ); string EscIP = MySQLEscapeString( conn, ip ); string EscSpoofedRealm = MySQLEscapeString( conn, spoofedrealm ); string EscLeftReason = MySQLEscapeString( conn, leftreason ); string Query = "INSERT INTO gameplayers ( botid, gameid, name, ip, spoofed, reserved, loadingtime, `left`, leftreason, team, colour, spoofedrealm ) VALUES ( " + UTIL_ToString( botid ) + ", " + UTIL_ToString( gameid ) + ", '" + EscName + "', '" + EscIP + "', " + UTIL_ToString( spoofed ) + ", " + UTIL_ToString( reserved ) + ", " + UTIL_ToString( loadingtime ) + ", " + UTIL_ToString( left ) + ", '" + EscLeftReason + "', " + UTIL_ToString( team ) + ", " + UTIL_ToString( colour ) + ", '" + EscSpoofedRealm + "' )"; if( mysql_real_query( (MYSQL *)conn, Query.c_str( ), Query.size( ) ) != 0 ) *error = mysql_error( (MYSQL *)conn ); else RowID = mysql_insert_id( (MYSQL *)conn ); return RowID; }
uint32_t MySQLGameAdd( void *conn, string *error, uint32_t botid, string server, string map, string gamename, string ownername, uint32_t duration, uint32_t gamestate, string creatorname, string creatorserver ) { uint32_t RowID = 0; string EscServer = MySQLEscapeString( conn, server ); string EscMap = MySQLEscapeString( conn, map ); string EscGameName = MySQLEscapeString( conn, gamename ); string EscOwnerName = MySQLEscapeString( conn, ownername ); string EscCreatorName = MySQLEscapeString( conn, creatorname ); string EscCreatorServer = MySQLEscapeString( conn, creatorserver ); string Query = "INSERT INTO games ( botid, server, map, datetime, gamename, ownername, duration, gamestate, creatorname, creatorserver ) VALUES ( " + UTIL_ToString( botid ) + ", '" + EscServer + "', '" + EscMap + "', NOW( ), '" + EscGameName + "', '" + EscOwnerName + "', " + UTIL_ToString( duration ) + ", " + UTIL_ToString( gamestate ) + ", '" + EscCreatorName + "', '" + EscCreatorServer + "' )"; if( mysql_real_query( (MYSQL *)conn, Query.c_str( ), Query.size( ) ) != 0 ) *error = mysql_error( (MYSQL *)conn ); else RowID = mysql_insert_id( (MYSQL *)conn ); return RowID; }
void CCCBot :: UpdateCommandAccess( ) { // load default access values and insert them into database if a access number hasn't already been set // format: m_Commands["<command keyword>"] = <value> (must be equal or higher than 0 and lower than 10) m_Commands[ "accept"] = 9; m_Commands[ "access"] = 0; m_Commands[ "addsafelist" ] = 6; m_Commands[ "announce" ] = 6; m_Commands[ "ban" ] = 7; m_Commands[ "chanlist" ] = 3; m_Commands[ "channel" ] = 5; m_Commands[ "checkaccess" ] = 5; m_Commands[ "checkban" ] = 3; m_Commands[ "checksafelist" ] = 5; m_Commands[ "chieftain" ] = 9; m_Commands[ "clanlist" ] = 1; m_Commands[ "clearqueue" ] = 3; m_Commands[ "command" ] = 7; m_Commands[ "countaccess" ] = 7; m_Commands[ "countbans" ] = 5; m_Commands[ "countsafelist" ] = 5; m_Commands[ "delaccess" ] = 8; m_Commands[ "delsafelist" ] = 6; m_Commands[ "exit" ] = 9; m_Commands[ "games" ] = 4; m_Commands[ "getclan" ] = 2; m_Commands[ "gn8" ] = 1; m_Commands[ "greet" ] = 6; m_Commands[ "grunt" ] = 7; m_Commands[ "invite" ] = 2; m_Commands[ "kick" ] = 5; m_Commands[ "lockdown" ] = 8; m_Commands[ "motd" ] = 5; m_Commands[ "online" ] = 1; m_Commands[ "peon" ] = 7; m_Commands[ "ping" ] = 0; m_Commands[ "rejoin" ] = 4; m_Commands[ "restart" ] = 9; m_Commands[ "remove" ] = 9; m_Commands[ "reload" ] = 4; m_Commands[ "say" ] = 6; m_Commands[ "setaccess" ] = 8; m_Commands[ "setcommand" ] = 9; m_Commands[ "shaman" ] = 9; m_Commands[ "slap" ] = 0; m_Commands[ "spit" ] = 0; m_Commands[ "status" ] = 2; m_Commands[ "squelch" ] = 5; m_Commands[ "topic" ] = 5; m_Commands[ "unban" ] = 7; m_Commands[ "uptime" ] = 1; for( map<string, unsigned char> :: iterator i = m_Commands.begin( ); i != m_Commands.end( ); ++i ) { if( m_DB->CommandAccess( i->first ) == 255 ) { m_DB->CommandSetAccess( i->first, i->second ); CONSOLE_Print( "[ACCESS] no value found for command [" + i->first + "] - setting default value of [" + UTIL_ToString( i->second ) + "]" ); } } }
void CReplay :: BuildReplay( string gameName, string statString, uint32_t war3Version, uint16_t buildNumber ) { m_War3Version = war3Version; m_BuildNumber = buildNumber; m_Flags = 32768; CONSOLE_Print( "[REPLAY] building replay" ); uint32_t LanguageID = 0x0012F8B0; BYTEARRAY Replay; Replay.push_back( 16 ); // Unknown (4.0) Replay.push_back( 1 ); // Unknown (4.0) Replay.push_back( 0 ); // Unknown (4.0) Replay.push_back( 0 ); // Unknown (4.0) Replay.push_back( 0 ); // Host RecordID (4.1) Replay.push_back( m_HostPID ); // Host PlayerID (4.1) UTIL_AppendByteArrayFast( Replay, m_HostName ); // Host PlayerName (4.1) Replay.push_back( 1 ); // Host AdditionalSize (4.1) Replay.push_back( 0 ); // Host AdditionalData (4.1) UTIL_AppendByteArrayFast( Replay, gameName ); // GameName (4.2) Replay.push_back( 0 ); // Null (4.0) UTIL_AppendByteArrayFast( Replay, statString ); // StatString (4.3) UTIL_AppendByteArray( Replay, (uint32_t)m_Slots.size( ), false ); // PlayerCount (4.6) Replay.push_back( m_MapGameType ); // GameType (4.7) Replay.push_back( 32 ); // GameType (4.7) Replay.push_back( 73 ); // GameType (4.7) Replay.push_back( 0 ); // GameType (4.7) UTIL_AppendByteArray( Replay, LanguageID, false ); // LanguageID (4.8) // PlayerList (4.9) for( vector<PIDPlayer> :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { if( (*i).first != m_HostPID ) { Replay.push_back( 22 ); // Player RecordID (4.1) Replay.push_back( (*i).first ); // Player PlayerID (4.1) UTIL_AppendByteArrayFast( Replay, (*i).second ); // Player PlayerName (4.1) Replay.push_back( 1 ); // Player AdditionalSize (4.1) Replay.push_back( 0 ); // Player AdditionalData (4.1) UTIL_AppendByteArray( Replay, (uint32_t)0, false ); // Unknown } } // GameStartRecord (4.10) Replay.push_back( 25 ); // RecordID (4.10) UTIL_AppendByteArray( Replay, (uint16_t)( 7 + m_Slots.size( ) * 9 ), false ); // Size (4.10) Replay.push_back( m_Slots.size( ) ); // NumSlots (4.10) for( unsigned char i = 0; i < m_Slots.size( ); i++ ) UTIL_AppendByteArray( Replay, m_Slots[i].GetByteArray( ) ); UTIL_AppendByteArray( Replay, m_RandomSeed, false ); // RandomSeed (4.10) Replay.push_back( m_SelectMode ); // SelectMode (4.10) Replay.push_back( m_StartSpotCount ); // StartSpotCount (4.10) // ReplayData (5.0) Replay.push_back( REPLAY_FIRSTSTARTBLOCK ); UTIL_AppendByteArray( Replay, (uint32_t)1, false ); Replay.push_back( REPLAY_SECONDSTARTBLOCK ); UTIL_AppendByteArray( Replay, (uint32_t)1, false ); // leavers during loading need to be stored between the second and third start blocks while( !m_LoadingBlocks.empty( ) ) { UTIL_AppendByteArray( Replay, m_LoadingBlocks.front( ) ); m_LoadingBlocks.pop( ); } Replay.push_back( REPLAY_THIRDSTARTBLOCK ); UTIL_AppendByteArray( Replay, (uint32_t)1, false ); // initialize replay length to zero // we'll accumulate the replay length as we iterate through the timeslots // this is necessary because we might be discarding some timeslots due to not enough checksums and the replay length needs to be accurate m_ReplayLength = 0; uint32_t TimeSlotsDiscarded = 0; bool EndOfTimeSlots = false; while( !m_Blocks.empty( ) ) { BYTEARRAY Block = m_Blocks.front( ); m_Blocks.pop( ); if( Block.size( ) >= 5 && Block[0] == REPLAY_TIMESLOT ) { uint16_t TimeIncrement = UTIL_ByteArrayToUInt16( Block, false, 3 ); if( TimeIncrement != 0 && m_CheckSums.empty( ) ) EndOfTimeSlots = true; if( EndOfTimeSlots ) { TimeSlotsDiscarded++; continue; } // append timeslot UTIL_AppendByteArrayFast( Replay, Block ); // append checksum // todotodo: after experimenting, Strilanc discovered that checksums are NOT required in replays // we could optimize saving of replays by building a complete stream without waiting for checksums as the game progresses // alternatively, we could build that stream as the checksums were added if we wanted to keep them // rather than building it in one go right now, which might take a few hundred ms and cause a spike in other games if( TimeIncrement != 0 ) { BYTEARRAY CheckSum; CheckSum.reserve( 6 ); CheckSum.push_back( REPLAY_CHECKSUM ); CheckSum.push_back( 4 ); UTIL_AppendByteArray( CheckSum, m_CheckSums.front( ), false ); m_CheckSums.pop( ); UTIL_AppendByteArrayFast( Replay, CheckSum ); } // accumulate replay length m_ReplayLength += TimeIncrement; } else UTIL_AppendByteArrayFast( Replay, Block ); } if( TimeSlotsDiscarded > 0 ) CONSOLE_Print( "[REPLAY] ran out of checksums, discarded " + UTIL_ToString( TimeSlotsDiscarded ) + " timeslots" ); // done m_Decompressed = string( Replay.begin( ), Replay.end( ) ); }
bool CIRC :: Update( void *fd, void *send_fd ) { uint32_t Time = GetTime( ); if( m_Socket->GetConnected( ) ) { // the socket is connected and everything appears to be working properly if( Time - m_LastPacketTime > 210 ) { Print( "[IRC: " + m_Server + "] ping timeout, reconnecting" ); m_Socket->Reset( ); m_WaitingToConnect = true; return m_Exiting; } if( Time - m_LastAntiIdleTime > 60 ) { SendIRC( "TIME" ); m_LastAntiIdleTime = Time; } m_Socket->DoRecv( (fd_set *)fd ); ExtractPackets( ); m_Socket->DoSend( (fd_set *)send_fd ); return m_Exiting; } if( m_Socket->HasError( ) ) { // the socket has an error Print( "[IRC: " + m_Server + "] disconnected due to socket error, waiting 60 seconds to reconnect" ); m_Socket->Reset( ); m_WaitingToConnect = true; m_LastConnectionAttemptTime = Time; return m_Exiting; } if( !m_Socket->GetConnecting( ) && !m_Socket->GetConnected( ) && !m_WaitingToConnect ) { // the socket was disconnected Print( "[IRC: " + m_Server + "] disconnected, waiting 60 seconds to reconnect" ); m_Socket->Reset( ); m_WaitingToConnect = true; m_LastConnectionAttemptTime = Time; return m_Exiting; } if( m_Socket->GetConnecting( ) ) { // we are currently attempting to connect to irc if( m_Socket->CheckConnect( ) ) { // the connection attempt completed if( !m_OriginalNick ) m_Nickname = m_NicknameCpy; SendIRC( "NICK " + m_Nickname ); SendIRC( "USER " + m_Username + " " + m_Nickname + " " + m_Username + " :by h4x0rz88" ); m_Socket->DoSend( (fd_set *)send_fd ); Print( "[IRC: " + m_Server + "] connected" ); m_LastPacketTime = Time; return m_Exiting; } else if( Time - m_LastConnectionAttemptTime > 15 ) { // the connection attempt timed out (15 seconds) Print( "[IRC: " + m_Server + "] connect timed out, waiting 60 seconds to reconnect" ); m_Socket->Reset( ); m_LastConnectionAttemptTime = Time; m_WaitingToConnect = true; return m_Exiting; } } if( !m_Socket->GetConnecting( ) && !m_Socket->GetConnected( ) && ( Time - m_LastConnectionAttemptTime > 60 ) ) { // attempt to connect to irc Print( "[IRC: " + m_Server + "] connecting to server [" + m_Server + "] on port " + UTIL_ToString( m_Port ) ); if( m_ServerIP.empty( ) ) { m_Socket->Connect( string( ), m_Server, m_Port ); if( !m_Socket->HasError( ) ) { m_ServerIP = m_Socket->GetIPString( ); } } else { // use cached server IP address since resolving takes time and is blocking m_Socket->Connect( string( ), m_ServerIP, m_Port ); } m_WaitingToConnect = false; m_LastConnectionAttemptTime = Time; } return m_Exiting; }
string CPotentialPlayer :: GetExternalIPString( ) { BYTEARRAY IP; string EIP; if( m_Socket ) { if( m_IncomingGarenaUser != NULL ) { BYTEARRAY GarenaIP = GetGarenaIP( ); return UTIL_ToString(GarenaIP[0]) + "." + UTIL_ToString(GarenaIP[1]) + "." + UTIL_ToString(GarenaIP[2]) + "." + UTIL_ToString(GarenaIP[3]); } else { bool local=m_LAN; if (!m_LANSet) { IP= m_Socket->GetIP( ); if (IP.size()>=2) { if (IP[0]==10) local=true; else if (IP[0]==192 && IP[1]==168) local=true; else if (IP[0]==169 && IP[1]==254) local=true; else if (IP[0]==172 && IP[1]==16) local=true; else if (IP[0]==172 && IP[1]==17) local=true; else if (IP[0]==172 && IP[1]==18) local=true; else if (IP[0]==172 && IP[1]==19) local=true; else if (IP[0]==172 && IP[1]==20) local=true; else if (IP[0]==172 && IP[1]==21) local=true; else if (IP[0]==172 && IP[1]==22) local=true; else if (IP[0]==172 && IP[1]==23) local=true; else if (IP[0]==172 && IP[1]==24) local=true; else if (IP[0]==172 && IP[1]==25) local=true; else if (IP[0]==172 && IP[1]==26) local=true; else if (IP[0]==172 && IP[1]==27) local=true; else if (IP[0]==172 && IP[1]==28) local=true; else if (IP[0]==172 && IP[1]==29) local=true; else if (IP[0]==172 && IP[1]==30) local=true; else if (IP[0]==172 && IP[1]==31) local=true; } if (UTIL_IsLocalIP(IP, m_Game->m_GHost->m_LocalAddresses)) local = true; m_LANSet = true; m_LAN = local; } EIP=m_Socket->GetIPString( ); if (local && m_Game->m_GHost->m_ExternalIP!="") { EIP=m_Game->m_GHost->m_ExternalIP; } if( !EIP.empty( ) && EIP != "0.0.0.0" ) return EIP; else return m_CachedIP; } } return m_CachedIP; }
void CSaveGame :: ParseSaveGame( ) { m_MapPath.clear( ); m_Slots.clear( ); m_MagicNumber.clear( ); istringstream ISS( m_Decompressed ); // savegame format figured out by Varlock: // string -> map path // 0 (string?) -> ??? (no idea what this is) // string -> original game name // 0 (string?) -> ??? (maybe original game password) // string -> stat string // 4 bytes -> ??? (seems to be # of slots) // 4 bytes -> ??? (seems to be 0x01 0x28 0x49 0x00 on both of the savegames examined) // 2 bytes -> ??? (no idea what this is) // slot structure // 4 bytes -> magic number string GarbageString; unsigned char NumSlots; uint32_t MagicNumber; getline( ISS, m_MapPath, '\0' ); // map path getline( ISS, GarbageString, '\0' ); // ??? getline( ISS, GarbageString, '\0' ); // original game name getline( ISS, GarbageString, '\0' ); // ??? getline( ISS, GarbageString, '\0' ); // stat string ISS.seekg( 4, ios :: cur ); // ??? ISS.seekg( 4, ios :: cur ); // ??? ISS.seekg( 2, ios :: cur ); // ??? ISS.read( (char *)&NumSlots, 1 ); // number of slots if( NumSlots > 12 ) { CONSOLE_Print( "[SAVEGAME] too many slots in decompressed data" ); m_Valid = false; return; } CONSOLE_Print( "[SAVEGAME] found " + UTIL_ToString( NumSlots ) + " slots" ); for( unsigned char i = 0; i < NumSlots; i++ ) { unsigned char SlotData[9]; ISS.read( (char *)SlotData, 9 ); // slot data m_Slots.push_back( CGameSlot( SlotData[0], SlotData[1], SlotData[2], SlotData[3], SlotData[4], SlotData[5], SlotData[6], SlotData[7], SlotData[8] ) ); } ISS.seekg( 4, ios :: cur ); // GetTicks ISS.seekg( 1, ios :: cur ); // GameType ISS.seekg( 1, ios :: cur ); // number of player slots (non observer) ISS.read( (char *)&MagicNumber, 4 ); // magic number if( ISS.fail( ) ) { CONSOLE_Print( "[SAVEGAME] failed to parse decompressed data" ); m_Valid = false; return; } m_MagicNumber = UTIL_CreateByteArray( MagicNumber, false ); CONSOLE_Print( "[SAVEGAME] found map path [" + m_MapPath + "]" ); CONSOLE_Print( "[SAVEGAME] found magic number [" + UTIL_ToString( m_MagicNumber[0] ) + " " + UTIL_ToString( m_MagicNumber[1] ) + " " + UTIL_ToString( m_MagicNumber[2] ) + " " + UTIL_ToString( m_MagicNumber[3] ) + "]" ); }
void CGHostGenie :: LoadIPToCountryData( string file ) { ifstream in; in.open( file.c_str( ) ); if( in.fail( ) ) LogWarning( "[GHOST] warning - unable to read file [" + file + "], iptocountry data not loaded" ); else { LogInfo( "[GHOST] started loading [" + file + "]" ); // the begin and commit statements are optimizations // we're about to insert ~4 MB of data into the database so if we allow the database to treat each insert as a transaction it will take a LONG time // todotodo: handle begin/commit failures a bit more gracefully if( !m_DBLocal->Begin( ) ) LogWarning( "[GHOST] warning - failed to begin local database transaction, iptocountry data not loaded" ); else { unsigned char Percent = 0; string Line; string IP1; string IP2; string Country; CSVParser parser; // get length of file for the progress meter in.seekg( 0, ios :: end ); uint32_t FileLength = in.tellg( ); in.seekg( 0, ios :: beg ); while( !in.eof( ) ) { getline( in, Line ); if( Line.empty( ) ) continue; parser << Line; parser >> IP1; parser >> IP2; parser >> Country; m_DBLocal->FromAdd( UTIL_ToUInt32( IP1 ), UTIL_ToUInt32( IP2 ), Country ); // it's probably going to take awhile to load the iptocountry data (~10 seconds on my 3.2 GHz P4 when using SQLite3) // so let's print a progress meter just to keep the user from getting worried unsigned char NewPercent = (unsigned char)( (float)in.tellg( ) / FileLength * 100 ); if( NewPercent != Percent ) { if( NewPercent % 10 == 0 ) LogInfo( "[GHOST] iptocountry data: " + UTIL_ToString( NewPercent ) + "% loaded" ); Percent = NewPercent; if( ip2countryCallback ) ip2countryCallback( callbackObject, NewPercent ); } } if( !m_DBLocal->Commit( ) ) LogWarning( "[GHOST] warning - failed to commit local database transaction, iptocountry data not loaded" ); else LogInfo( "[GHOST] finished loading [ip-to-country.csv]" ); } in.close( ); } }