//////////////////////////////
// COMMAND RECORDER 		//
// by Sir Drink a lot		//
// for Counter-Strike		//
//							//
// Logs all commands used	//
// by players on server.	//
// 							//
// - This plugin must the 	//
// first one in plugin.ini.	//
// - file_access_read and 	//
// file_access_write		//
// must be enabled!!!!		//
//							//
// v.85: added option <n/i>	//
//		 in admin_bbox_who	//
// v.84: added search <ID> 	//
//		 in admin_bbox_who	//
// v.83: optimized code of	//
//		 admin_bbox_who		//
// v.82: added 				//
//		 admin_bbox_who		//
// v.81: specmode for adding//
//		 /check steam_id	//
//////////////////////////////
 
#include <string>
#include <admin>
#include <adminlib>
 
new STRING_VERSION[10]="0.85";
 
new g_plugin;
 
new g_MainDir[MAX_TEXT_LENGTH]="addons/adminmod/config/blackbox";
 
new g_LogFiles[3][]={
	"say_cmds.log",
	"retribution_cmds.log",
	"admin_cmds.log"
};
 
#define MAX_ENTRIES	500
new g_STEAM_ID[MAX_ENTRIES][MAX_AUTHID_LENGTH];
new g_Names[MAX_ENTRIES][MAX_NAME_LENGTH];
new g_loaded;
 
#define MAX_RETR_CMDS	20
new g_Retribution_Cmds[MAX_RETR_CMDS][]={
	"slap",
	"slay",
	"kick",
	"ban",
	"bury",
	"unbury",
	"gag",
	"ungag",
	"llama",
	"unllama",
	"slayteam",
	"ct",
	"t",
	"vote_kick",
	"execclient",
	"execall",
	"execteam",
	"restrict",
	"unrestrict",
	"unban"
};
 
new g_User[MAX_PLAYERS];
 
public plugin_init() {
	new iread;
	new iwrite;
	iread = getvar("file_access_read");
	iwrite = getvar("file_access_write");
	if(iwrite & iread){
		plugin_registerinfo("Server Black Box","Logs all STEAM_IDs, say/say_team and admin_ commands in special logfiles",STRING_VERSION);
		plugin_registercmd("admin_bbox","admin_bbox",ACCESS_CONFIG,"admin_bbox <on/off>: turns plugin on/off");
		plugin_registercmd("admin_bbox_read","admin_bbox_read",ACCESS_CONFIG,"admin_bbox_read <user> <last entries>: searches for last commands executed by <user>");
		plugin_registercmd("admin_bbox_who","admin_bbox_who",ACCESS_CONFIG,"admin_bbox_who <option='n' or 'i'> <'n'=user/steam-id - 'i'=database_id>: searches for nicknames/steamid or displays database_id!");
 
		plugin_registercmd("specmode","specmode",ACCESS_ALL);
		if(!get_vaultnumdata("BLACK_BOX",g_plugin)){
			set_vaultnumdata("BLACK_BOX",1);
			g_plugin=1;
		}
		read_index_file();
	}else{
		plugin_registerinfo("COMMAND RECORDER","PLUGIN DISABLED, because file_access_write is not set to 1 in adminmod.cfg",STRING_VERSION);
		selfmessage("[BLACK BOX] Plugin is disabled, because file_access_write is not set to 1 in adminmod.cfg");
	}		
	return PLUGIN_CONTINUE;
}
 
//load index.log for fast search for Nickname or Steam_ID, if player is not available on server.
read_index_file(){
	new Data[MAX_DATA_LENGTH];
	new File[MAX_TEXT_LENGTH];
	new iFileSize;
	new i;
 
	snprintf(File,MAX_TEXT_LENGTH,"%s/index.log",g_MainDir);
	if(fileexists(File)){
		iFileSize = filesize(File);
		if(iFileSize>=MAX_ENTRIES){
			iFileSize=MAX_ENTRIES-1;
			selfmessage("[BLACK-BOX] To many entries in index.log! Increase MAX_ENTRIES in plugin_sdal_blackbox.sma and recompile!");
		}
		for(i=1;i<=iFileSize;i++){
			readfile(File,Data,i,MAX_DATA_LENGTH);
			strsplit(Data,"®",g_STEAM_ID[g_loaded],MAX_AUTHID_LENGTH,g_Names[g_loaded],MAX_NAME_LENGTH);
			g_loaded++;
		}
		g_loaded--;
	}
}
 
public specmode(HLCommand,HLData,HLUserName,UserIndex) {
	if(!g_User[UserIndex]){
		new AuthID[MAX_AUTHID_LENGTH];
		new User[MAX_NAME_LENGTH];
		convert_string(HLUserName,User,MAX_NAME_LENGTH);
		get_userAuthID(User,AuthID,MAX_AUTHID_LENGTH);
		g_User[UserIndex]=1;
		check_index(AuthID,User);
	}
	return PLUGIN_CONTINUE;
}
 
check_index(AuthID[],User[]){
	new Data[MAX_TEXT_LENGTH];
	new File[MAX_TEXT_LENGTH];
	new i;
	new found;
 
	for(i=0;i<=g_loaded;i++){
		if(strcmp(AuthID,g_STEAM_ID[i])==0){
			if(strcmp(User,g_Names[i])==0){
			  found=1;
			  break;
			}
		}
	}
	if(!found){
		snprintf(Data,MAX_TEXT_LENGTH,"%s®%s",AuthID,User);
		snprintf(File,MAX_TEXT_LENGTH,"%s/index.log",g_MainDir);
		writefile(File,Data,-1);
		g_loaded++;
		strcpy(g_STEAM_ID[g_loaded],AuthID,MAX_AUTHID_LENGTH);
		strcpy(g_Names[g_loaded],User,MAX_NAME_LENGTH);
	}
}
 
public plugin_command(HLCommand,HLData,HLUserName,UserIndex){
	if(g_plugin){
		new Data[MAX_DATA_LENGTH];
		new Command[MAX_COMMAND_LENGTH];
		new i;
 
		convert_string(HLData,Data,MAX_DATA_LENGTH);
		convert_string(HLCommand,Command,MAX_COMMAND_LENGTH);
 
		if(strcmp(Command,"say")==0 || strcmp(Command,"say_team")==0){
			strstripquotes(Data);
			record_file(UserIndex,Command,Data,0);
			return PLUGIN_CONTINUE;
		}else if(strncmp(Command,"admin_",6)==0){
			for(i=0;i<=MAX_RETR_CMDS;i++){
				if(strcmp(Command[6],g_Retribution_Cmds[i])==0){
					record_file(UserIndex,Command,Data,1);
					return PLUGIN_CONTINUE;
					break;
				}
			}
			record_file(UserIndex,Command,Data,2);
		}
	}
	return PLUGIN_CONTINUE;
}
 
record_file(UserIndex,Command[],Data[],iLogFile){
	new Text[MAX_TEXT_LENGTH];
	new File[MAX_TEXT_LENGTH];
	new ST[MAX_DATA_LENGTH];
	new User[MAX_NAME_LENGTH];
	new AuthID[MAX_AUTHID_LENGTH];
	new sTeam[MAX_NAME_LENGTH];
	new iSession;
	new iTeam;
 
	if(UserIndex!=0){
		playerinfo(UserIndex,User,MAX_NAME_LENGTH,iSession,_,iTeam,_,AuthID);
		if(iTeam==1){
			snprintf(sTeam,MAX_NAME_LENGTH,"TERRORIST");
		}else if (iTeam==2){
			snprintf(sTeam,MAX_NAME_LENGTH,"CT");
		}else{
			snprintf(sTeam,MAX_NAME_LENGTH,"SPECTATOR");
		}
	}else{
		strcpy(User,"RCON/ADMIN",MAX_NAME_LENGTH);
		strcpy(AuthID,"---",MAX_AUTHID_LENGTH);
		strcpy(sTeam,"NONE",MAX_NAME_LENGTH);
	}
 
	snprintf(File,MAX_TEXT_LENGTH,"%s/%s",g_MainDir,g_LogFiles[iLogFile]);
	servertime(ST, MAX_DATA_LENGTH, "L %m/%d/%y - %H:%M:%S:");
 
	//write data to global log files
	snprintf(Text,MAX_TEXT_LENGTH,"%s ^"%s<%i><%s><%s>^" %s ^"%s^"",ST,User,iSession,AuthID,sTeam,Command,Data);
	writefile(File,Text,-1);
 
	if(UserIndex!=0){
		//create an index entry, if player with this steam_id AND his nickname does not exist in index.log
		check_index(AuthID,User);
		//write data to users own log file
		strsubst(AuthID,":","_",MAX_AUTHID_LENGTH);
		snprintf(File,MAX_TEXT_LENGTH,"%s/database/%s.log",g_MainDir,AuthID);
		writefile(File,Text,-1);
	}
}
 
public plugin_disconnect(HLUserName,UserIndex) {
	g_User[UserIndex]=0;
	return PLUGIN_CONTINUE;
}
 
public plugin_connect(HLUserName,HLIP, UserIndex) {
	g_User[UserIndex]=0;
	return PLUGIN_CONTINUE;
}
 
//////////////////////
//	ADMIN COMMANDS	//
//////////////////////
//turn plugin on/off
public admin_bbox(HLCommand,HLData,HLUserName,UserIndex) {
	new Data[MAX_DATA_LENGTH];
	convert_string(HLData,Data,MAX_DATA_LENGTH);
 
	if(strlen(Data)){
		g_plugin=check_param(Data);
		set_vaultnumdata("BLACK_BOX",g_plugin);
	}	
	snprintf(Data,MAX_DATA_LENGTH,"[BLACK BOX] Plugin is set to %i",g_plugin);
	selfmessage(Data);
	return PLUGIN_HANDLED;
}
 
public admin_bbox_who(HLCommand,HLData,HLUserName,UserIndex) {
	new Data[MAX_DATA_LENGTH];
	new sOption[1];
	new iData;
	convert_string(HLData,Data,MAX_DATA_LENGTH);
 
	strsep(Data," ",sOption,1,Data,MAX_DATA_LENGTH);
 
	if(sOption[0]!='i' || sOption[0]!='n'){
		snprintf(Data,MAX_DATA_LENGTH,"%s%s",sOption,Data);
	}	
	if(sOption[0]=='i'){
		iData=strtonum(Data);
		read_users(Data,0,iData);
	}else{
		read_users(Data,0,0);
	}
	return PLUGIN_HANDLED;
}
 
//read log entries of player
public admin_bbox_read(HLCommand,HLData,HLUserName,UserIndex) {
	new Data[MAX_DATA_LENGTH];
	new Text[MAX_TEXT_LENGTH];
	new Target[MAX_NAME_LENGTH];
	new RealPlayer[MAX_NAME_LENGTH];
	new LastEntries[MAX_NUMBER_LENGTH];
	new AuthID[MAX_AUTHID_LENGTH];
	new ilast;
	new found;
	new read;
	convert_string(HLData,Data,MAX_DATA_LENGTH);
	strsep(Data," ",Target,MAX_NAME_LENGTH,LastEntries,MAX_NUMBER_LENGTH);
	ilast=strtonum(LastEntries);
	if(!ilast){
		ilast=10;
	}
	selfmessage("* SERVER BLACK BOX *");
	//check, if player is available on server
	if(!strlen(Target)){
		selfmessage("* No valid data for target! Please use admin_bbox_read <user> <last entries>");
	}else{
		if (check_user(Target)==1) {
			get_username(Target,RealPlayer,MAX_NAME_LENGTH);
			get_userAuthID(Target,AuthID,MAX_AUTHID_LENGTH);
			snprintf(Text,MAX_TEXT_LENGTH,"* Reading last %i log entries of %s",ilast,RealPlayer);
			selfmessage(Text);
			read_user_file(AuthID,ilast);
		}else{
		//not available...now we need to check index.log arrays and perform a search in database
			snprintf(Text,MAX_TEXT_LENGTH,"* Player '%s' is not available on server or is not unique.",Target);
			selfmessage(Text);
 
			read=read_users(Target,found,0);
 
			if(found==0){
				selfmessage("* Sorry! No entry found in database correspondig to this player.");
			}else if (found>1){
				selfmessage("* Sorry! Too many entries found in database. Please specify search!");
			}else{
				read_user_file(g_STEAM_ID[read],ilast);
			}		
		}
	}
	return PLUGIN_HANDLED;
}
 
read_users(Data[],found=0,ID){
	new Text[MAX_TEXT_LENGTH];
	new i;
	new read;
 
	selfmessage("* Start searching in database");
	selfmessage("* Player(s) found:");
 
	if(ID!=0){
		snprintf(Text,MAX_TEXT_LENGTH,"* Searching for %s:",g_STEAM_ID[ID]);
		selfmessage(Text);
	}else{
		snprintf(Text,MAX_TEXT_LENGTH,"* ID. - STEAM - PLAYER",g_STEAM_ID[ID]);
		selfmessage(Text);
	}
	for(i=0;i<=g_loaded;i++){
		if(ID!=0){
			if(strcmp(g_STEAM_ID[ID],g_STEAM_ID[i])==0){
				snprintf(Text,MAX_TEXT_LENGTH,"* - %s",g_Names[i]);
				found++;
				read=i;
				selfmessage(Text);
				strinit(Text);
			}
		}else if(strstrx(g_STEAM_ID[i],Data)!=-1 || strstrx(g_Names[i],Data)!=-1){
			snprintf(Text,MAX_TEXT_LENGTH,"* %i. %s - %s",i,g_STEAM_ID[i],g_Names[i]);
			found++;
			read=i;
			selfmessage(Text);
			strinit(Text);
		}
		if(found>10){
			selfmessage("* Stopped search. Too many entries found!");
			break;
		}
	}
 
	return read;
}
 
read_user_file(AuthID[],iLast){
	new Data[MAX_DATA_LENGTH];
	new File[MAX_TEXT_LENGTH];
	new iFileSize;
	new i;
 
	strsubst(AuthID,":","_",MAX_AUTHID_LENGTH);
	snprintf(File,MAX_TEXT_LENGTH,"%s/database/%s.log",g_MainDir,AuthID);
	selfmessage("* Players last log entries:");
	if(fileexists(File)){
		iFileSize=filesize(File);
		for(i=iFileSize;i>iFileSize-iLast;i--){
			readfile(File,Data,i,MAX_DATA_LENGTH);
			if(!strlen(Data)){
				break;
			}
			selfmessage(Data);
			strinit(Data);
		}
	}else{
		selfmessage("* No log entries available for this player.");
	}
}