=== RCON CLIENT-DAEMON PROTOCOL SPECIFICATION ===


== GENERAL NOTES ==

Any of the following commands might yield one of the following responses, even if they are not 
documented under the command in question. 
	ServerError - The daemon encountered a serious error while trying to complete the request. 
				The daemon might close the connection, or even crash, as a result to this. 
	NotAuthorized - If the client is trying to execute commands that it is not authorized to use.
	InvalidCommand - If the command that was sent is not recognized by the daemon.
	InvalidArguments - If the command that was sent does not have the correct amount or type of 
				arguments. 
	NotConnected - The daemon is currently not connected to the game server, and cannot process
				the request. 

= Admin rights =
The following admin rights are available:
	inGame, console, warn, kick, ban, permBan, adminChat, yell, whisper, report, unban, 
	listBans, playerHistory, runNextMap, restartMap, setRights, registerAdmin, editAdmin,
	applyConfiguration, changeConfiguration, editMessages, shutdownDaemon


== UNAUTHORIZED COMMANDS ==

Request: version
Rights: none
Response: OK <daemonName: String> <version: String>
Effect: Retrieves the version of the daemon.
Comments: This is returned in the following format: OK TGAC 0.1

Request: quit
Rights: none
Response: OK
Effect: After replying with the OK response the daemon will properly close the connection to 
		the client. The client should assume this and do the same. 
Comment: This is the preferred way to disconnect from the daemon. 

Request: logout
Rights: none
Response: OK
Effect: The user will be logged out no matter if he was logged in or not. 
Comment: This is recommended, but not required, before issuing the quit command. This should 
		also be used before trying to log in as another user. 

== LOGIN COMMANDS ==

Request: login.hashed
Rights: none
Response: OK <salt: HexString>
Response: InvalidArguments
Effect: The server will generate a new salt value that must be used when logging in, and return 
		it in the response. 
Comment: This step is required prior to sending the extended login.hashed command. 

Request: login.hashed <username: String> <passwordHash: HexString>
Rights: console
Response: OK <admin rights list> -- User is now logged in.
Response: InvalidLogin -- Wrong username or password. 
Response: MissingSalt -- No salt was generated with the short login.hashed command.
Response: InvalidArguments
Effect: If the username and passwordHash are correct, then the user will be considered to be 
		authenticated, and can issue authenticated commands. The password salt that was generated 
		with the login.hash command will be discarded after this command, no matter if it succeeded 
		or not. 
Comment: It is possible to log in on top of an old login, but this is not recommended. The list of 
		admin rights that is returned upon successful login starts with an integer argument specifying 
		the amount of admin rights that follow. Then follows that many arguments, each representing an 
		admin right. 


== AUTHENTICATED COMMANDS ==

daemon.status
Rights: console
Response: OK <daemonStartTime: integer> <serverConnectionStartTime: integer> <connectedAdminClients: integer>
Effect: Retrieves some status information for the daemon such as when the current instance of the daemon was started, 
		when the current connection instance to the game server was established, and how many admin clients are currently 
		connected. 
Comments: All return values that represent times are given as a UNIX time stamp (amount of seconds to the UNIX epoch). If 
		no connection to the game server is active, then the returned serverConnectionStartTime will be -1. 

server.status
Rights: console
Response: OK <serverHost: string> <serverPort: integer> <gameMode: string> <map: string> <playerCount: integer> <maxPlayerCount: integer>
		<currentRound: integer> <maxRounds: integer>
Response: ServerOffline
Effect: Retrieves some status information of the game server.  
Comments: The returned data is: The host name/IP address of the game server, the port for the admin interface on the game server, the 
		current game mode of the game server, the current game map, the current amount of players and the maximum amount of players. If the 
		daemon is not connected to a game server the ServerOffline response is sent. 

= BAN MANAGEMENT COMMANDS =

bans.list <method: string> <method argument(s)> <type: string>
bans.list exact <playername: string> <type: string>
bans.list partial <playername: string> <type: string>
bans.list eaguid <eaguid: string> <type: string>
bans.list pbguid <pbguid: string> <type: string>
bans.list last <amount: integer> <type: string>
bans.list issuer <issuer id: integer> <type: string>
Rights: listBans
Response: OK <player ban entries>
Response: InvalidArguments
Effect: Returns a list of all the bans associated with the given filter method. 
Comments: The response starts with an integer specifying the amount of bans that will follow. Each ban 
		will then consist of 11 words with the following information, in the given order:
			<ban id: integer> - Id number of the ban. 
			<player name: string> - Full name of the banned player.
			<player eaguid: string> - The EA GUID of the banned player.
			<player pbguid: string> - The PB GUID of the banned player.  
			<ban type: string> - Type of ban. Can be either warn, kick or ban. 
			<start time: integer> - Start time of the ban, given in unix time format. 
			<end time: integer> - End time of the ban, given in unix time format.
			<reason: string> - The reason for the ban. Possibly given in short format. 
			<issuer id: integer> - The id of the admin that issued the ban.
			<issuer username: string> - The username of the admin that issued the ban. 
			<enabled: boolean> - True if this ban has not been removed/disabled. 
		If the player does not exist in the database, or does not have any bans, then only the first word
		is sent, and its value will be zero. 
		
		The type argument of the command must be one of: warn, kick, ban or all. The playername argument 
		must be an exact match of the player's name. The method argument specifies how to search for matching
		bans. Can be one of:
			exact - 	Exact name match.
			partial - 	Partial name match.
			eaguid - 	Exact match of the EA GUID. In this case the second argument is assumed to be the EA GUID of the 
							player. 
			pbguid - 	Exact match of PB GUID. In this case the second argument is assumed to be the PB GUID of the 
							player. 
			last - 		Returns the last N bans matching the specified type, where N is given by the "amount" argument. 
							N may not be greater then 50. If it is, then it will be set to 50. 
			issuer - 	Returns all the bans of the requested type that are issued by the admin with the id given by 
							the "issuer id" argument. 

bans.remove <banId: integer>
Rights: unban
Response: OK
Response: InvalidBan
Response: InvalidArguments
Effect: Removes a specific ban from the database. 
Comments: The ban might not be completely removed from the database, but just marked as disabled/removed. In 
		any case the ban will no longer be in effect. 

bans.history <playername: string>
Rights: playerHistory
Response: OK <warns: integer> <kicks: integer> <bans: integer>
Response: InvalidArguments
Effect: Counts and returns the amount of previous warns, kicks and bans for the specified player. 
Comments: The player name must be an exact match to a player that is either online on the server, or in the 
		database. If the specified player is online on the server, then the player history will be matched by 
		EA and PB GUID as well, and not only the player name. 

bans.ban <playername: string> <eaguid: string> <pbguid: string> <duration: integer | "perm"> <reason: string>
Rights: ban [permBan]
Response: OK <ban id: integer>
Response: InvalidArguments
Effect: Bans the player with the specified name EA GUID and PB GUID for the given time and reason. 
Comments: The player name must be an exact match for the ban to apply for the player name. The duration
		is given in seconds, counting from when the command was executed on the daemon. If perm is given
		instead of a duration, then the ban will be made permanent. In order to issue a permanent ban the
		permBan right is required. 

bans.kick <playername: string> <reason: string>
Rights: kick
Response: OK <kick id: integer>
Response: PlayerNotFound
Response: InvalidArguments
Effect: Kicks a player from the server with the specified reason.
Comments: It is only possible to kick a player that is currently online on the server. Once the player has been 
		kicked the ID of the kick will be returned. 

bans.warn <playername: string> <reason: string>
Rights: kick
Response: OK <warn id: integer>
Response: PlayerNotFound
Response: InvalidArguments
Effect: Warns a player on the server with the specified reason.
Comments: It is only possible to warn a player that is currently online on the server. Once the player has been 
		warned the ID of the warn will be returned.

bans.edit <ban id: integer> <playername: string> <eaguid: string> <pbguid: string> <endtime: integer> 
			<reason: string> <enabled: boolean>
Rights: unban
Response: OK
Response: BanNotFound
Response: InvalidArguments
Effect: Modifies the specified ban. 
Comments: It is not possible to change the issuer, the type or the start time of a ban. And end time of zero is
		considered to be permanent for bans of type ban. For all other types the end time should be zero. 

bans.get <ban id: integer>
Rights: listBans
Response: OK <playername: string> <eaguid: string> <pbguid: string> <type: string> <starttime: integer> 
		<endtime: integer> <reason: string> <issuer id: integer> <issuer name: string> <enabled: boolean>
Response: BanNotFound
Response: InvalidArguments
Effect: Returns information about the requested ban. 
Comments: The ban may be of any type, may have expired, or may be disabled. 


= ADMIN MANAGEMENT COMMANDS =

admins.setRights <admin id: integer> <admin rights list>
Rights: setRights
Response: OK <admin right count: integer>
Response: AdminNotFound
Response: InvalidArguments
Effect: Sets the specified admin's list of rights. 
Comments: This command will replace the old list rather then to append to it. The admin rights list must 
		start with one integer word specifying the amount of admin rights that follow. Then that many admin 
		rights are expected, one per word. The admin rights are case sensitive. Unknown admin rights are ignored.
		The recommended way to see if wall rights were applied successfully is to compare the returned admin rights 
		count with the amount of rights that were requested. 

admins.get <method: string> <username: string | id: integer | eaguid: string>
Rights: console
Response: OK <id: integer> <eaguid: string> <username: string> <admin rights list>
Response: AdminNotFound
Response: InvalidMethod
Response: InvalidArguments
Effect: Returns information about the requested admin from the database. 
Comments: The method argument can be one of:
		name - Get admin by exact match of names. In this case the username argument is expected. 
		id - Get admin by id. In this case the id argument is expected.
		eaguid - Get admin by EA GUID. In this case the eaguid argument is expected. 

admins.setPassword <id: integer> <password: string>
Rights: console [editAdmin]
Response OK
Response AdminNotFound
Response: InvalidArguments
Effect: Changes the password for the specified admin. 
Comments: The password is currently sent in plain text. This can be expected to change in the future in favor for a 
		safer solution. Any user can change their own password. In order to change the password of another user the 
		editAdmin right is required. 

admins.register <eaguid: string> <username: string> <password: string>
Rights: registerAdmin
Response: OK <id: integer>
Response: GuidAlreadyExists
Response: NameAlreadyExists
Response: InvalidArguments
Effect: Registers a new admin with the specified EA GUID, username and password, but without any rights, and returns
		the ID of the newly registered admin.  
Comments: The PB GUID and the username have to be unique. If they are not then an error will be returned. The password is 
		sent as plain text over the network. This might change to a safer method in the future, but until then this command 
		should be avoided over an unsecure connection. An admin that is registered with this command will not have any rights.
		Normally, this command would be followed by a admins.setRights command. The reason for this is that this command can 
		be allowed by unregistered users, in order for them to register themselves. In that case a privileged admin (not the 
		one that just registered) would be the one to give the rights. 

admins.edit <id: integer> <eaguid: string>
Rights: editAdmin
Response: OK
Response: AdminNotFound
Response: GuidAlreadyExists. 
Response: InvalidArguments
Effect: Edits the specified admin.
Comments: At this time only the admin EA GUID can be changed. In the future other things might be added. The new guid must not be 
		registered to another admin. 

admins.list
Rights: console
Response: OK <admin list>
Effects: Returns a list of all the registered admins.
Comments: The first word in the returned admin list is an integer specifying the amount of admins that follows. Each admin is then
		represented by a set of the following words:
			<admin id: integer> <eaguid: string> <username: string>


= CONFIGURATION MANAGEMENT COMMANDS =

config.set <variable: string> <value: string> <enforce: boolean>
Rights: changeConfiguration
Response: OK
Response: InvalidVariable - Unknown variable. 
Response: InvalidValue - Value of invalid type, value out or range, value not allowed. 
Response: InvalidArguments
Effects: Changes the value of a server configuration variable. 
Comments: The configuration variable will automatically be applied on the server and if "enforce" 
		is true, then the daemon will attempt to enforce this value, even if it were to be changed in
		the future. If "enforce" is not true, but the daemon was previously enforcing that variable,
		then this has the same effect as first calling config.clear and then setting the value. 

config.get <variable: string>
Rights: console
Response: OK <value: string> <enforced: boolean>
Response: InvalidVariable - Unknown variable.
Response: InvalidArguments
Effects: Retrieves the value of the given configuration option from the daemon's configuration cache.
Comments: The value may be a few minutes old since the daemon configuration cache is only updated 
		periodically. If the value is enforced by the daemon then "enforced" will be true. In this case
		the returned value will always be the value that is enforced. 

config.clear <variable: string>
Rights: changeConfiguration
Response: OK
Response: InvalidVariable - Unknown variable.
Response: InvalidArguments
Effects: Stops the daemon from enfocring any value for this configuration variable. 
Comments: If the given variable was being enforced by the daemon, then it will no longer be enforced 
		after calling this.  

config.all
Rights: console
Returns: OK <amount: integer> <variable1: string> <value1: string> <enforced1: boolean> ... 
		<variableN: string> <valueN: string> <enforcedN: boolean>
Rights: console
Effects: Retrieves all the known configuration variables from the daemon configuration cache.
Comments: The first argument in the reply is the amount of variables that follow. For each variable the following three
		arguments are sent, in the given order:
		* Variable name.
		* Value.
		* Enforcement status. 

config.list
Rights: console
Returns: OK <amount: integer> <variable1: string> ... <variableN: string>
Effects: Returns a list of the known variable names. 
Comments: The first argument in the reply is the amount of known variables. After that follows that many 
		variable names, each in a separate argument.  

= PLAYER MANAGEMENT COMMANDS =

players.list
Rights: console
Response: OK <player list>
Effect: Returns the list of players on the server. 
Comments: The first word in the list is an integer specifying the amount of players online. Then follows that many player entries 
		in the following format:
			<player id: integer> <name: string> <eaguid: string> <pbguid: string> <ip: string> <admin id: integer>
		If the player is not an admin, then the admin id will be zero. 

players.search <method: string> <partial name: string> <offset: integer> <limit: integer>
Rights: console
Response: OK <player list>
Response: InvalidMethod
Response: InvalidArguments
Effects: Returns a list of players that matches the search string.
Comments: Since the database might contain a huge amount of player records, this command requires a limit on the returned amount of 
		search matches. The limit can be at most 100. The discarded results can be retrieved by sending the command multiple times 
		with a different offset. 
		The only search method that is supported at this time is "partial" for a partial name search. The returned player list starts 
		with one word specifying the amount of returned players. That is followed by that many player entries in the following format:
			<player id: integer> <name: string> <eaguid: string> <pbguid: string> <ip: string>
		The returned players will be sorted in ascending order with regard to the player name. 

players.yell <message: string> <target type (all|player): string> <target name: string | target id: integer>
Rights: yell
Response: OK
Response: InvalidArguments -- If the argument count is not valid, or if the target type is unknown. 
Response: InvalidTarget -- If the specified target does not exist on the server. 
Effects: Displays the given message with big flashy letters across the screens of the specified target screens. 
Comments: If the target type is "all", then all players on the server will receive the message. In this case the last argument 
		should not be sent. If the target type is "player" then the target name argument should be the name of the single player 
		that the message should be sent to. 
		
		In future versions the target types "team", "squad" and "admins" might be added. 

players.say <message: string> <target type (all|player): string> <target name: string | target id: integer>
Rights: yell
Response: OK
Response: InvalidArguments
Response: InvalidTarget
Effects: Displays the given message with small green letters in the bottom left of the specified target screens. 
Comments: If the target type is "all", then all players on the server will receive the message. In this case the last argument 
		should not be sent. If the target type is "player" then the target name argument should be the name of the single player 
		that the message should be sent to. 
		
		In future versions the target types "team", "squad" and "admins" might be added. 


= PUNKBUSTER COMMANDS =

punkbuster.execute <command: string>
Rights: pbAdmin
Response: OK
Response: InvalidCommand - Malformed or illegal command. 
Response: InvalidArguments
Effects: Executes the given raw punkbuster command on the punkbuster server. 
Comments: The command must be a pb_sv_* command, and all arguments should be sent along with the command within the same word. 
		The result of the punkbuster command is NOT returned by this command in any way, but might be sent separately as a 
		punkbuster event notification. 


= SERVER MESSAGE COMMANDS =

messages.list
Rights: console
Response OK <amount: integer> <id1: integer> <message1: string> ... <idn: integer> <messagen: string>
Response: InvalidArguments
Effects: Retrieves a list of all server messages and their unique id numbers.
Comments: The first word is an integer that specifies the amount of id-message pairs that follow. 
		After that amount messages will follow, each represented by two words - one integer id, and 
		the message itself as a string. Note that the ids are dynamically generated when the daemon 
		connects to the game server, and may not be the same during two separate sessions. 

messages.add <message: string>
Rights: editMessages
Response: OK <id: integer>
Response: InvalidArguments
Effects: Adds a new server message to the end of the rotation. 
Comments: The given message will be added to the end of the server message rotation, and assigned 
		an unique id number. This id number will be returned as an argument for the OK response. 

messages.edit <id: integer> <message: string>
Rights: editMessages
Response: OK
Response: UnknownMessage
Response: InvalidArguments
Effects: Edits the message with the given id to use the new message text.
Comments: Replaces the message with the given id with a new message that has the given string as the
		message text. The id must refer to an existing message, or UnknownMessage will be returned. 

messages.remove <id: integer>
Rights: editMessages
Response: OK
Response: UnknownMessage
Response: InvalidArguments
Effects: Removed the message with the given id from the server message rotation.
Comments: Deletes the message with the given id from the server message rotation. The id must refer 
		to an existing message, or UnknownMessage will be returned. 


= LOGS COMMANDS =

logs.admin <admin id: integer | "all"> <start: integer> <end: integer> <limit: integer> <offset: integer>
Rights: adminLogs
Response: OK <amount: integer> <time1: integer> <adminId1: integer> <adminName1: string> <message1: string> ... 
		<timeN: integer> <adminIdN: integer> <adminNameN: string> <messageN: string>
Response: InvalidArguments
Effects: Retrieves the admin action log entries from within the given time period. 
Comments: Returns a list of all the admin action log entries within the requested time period and optionally 
		for the specified admin. The first argument in the request can be either the string "all" or the integer 
		id of an admin. The start and end arguments are the unix timestamps (in seconds) for the start and end of 
		the time period, respectively. The limit argument is the maximum amount of log entries to return (with a 
		maximum value of 100), and the offset is how many log entries to skip over. 
		
		The response starts with an argument specifying the amount of returned log entries in this message. After 
		that follows that many tuples, each containing the following words, in the given order:
		* time: The timestamp for the log entry, given as the amount of seconds since the unix epoch.
		* adminId: The unique id of the admin for who the log entry was created.
		* adminName: The username of the admin.
		* message: The log message. 

logs.chat <start: integer> <end: integer> <limit: integer> <offset: integer>
Rights: chatLogs
Response: OK <amount: integer> <time1: integer> <from1: string> <to1: string> <message1: string> ... 
		<timeN: integer> <from1: string> <to1: string> <messageN: string>
Response: InvalidArguments
Effects: Retrieves the chat log entries from within the given time period. 
Comments: Returns a list of all the chat log entries within the requested time period. The start and end 
		arguments are the unix timestamps (in seconds) for the start and end of the time period, 
		respectively. The limit argument is the maximum amount of log entries to return (with a 
		maximum value of 100), and the offset is how many log entries to skip over. 
		
		The response starts with an argument specifying the amount of returned log entries in this message. After 
		that follows that many tuples, each containing the following words, in the given order:
		* time: The timestamp for the log entry, given as the amount of seconds since the unix epoch.
		* from: The sender of the chat message. This is usually the name of a player. 
		* to: The receiver of the chat message. This is usually either "all", "team" or "squad".
		* message: The log message. 

logs.event <start: integer> <end: integer> <limit: integer> <offset: integer>
Rights: eventLogs
Response: OK <amount: integer> <time1: integer> <message1: string> ... <timeN: integer> <messageN: string>
Response: InvalidArguments
Effects: Retrieves the event log entries from within the given time period. 
Comments: Returns a list of all the event log entries within the requested time period. The start and end 
		arguments are the unix timestamps (in seconds) for the start and end of the time period, 
		respectively. The limit argument is the maximum amount of log entries to return (with a 
		maximum value of 100), and the offset is how many log entries to skip over. 
		
		The response starts with an argument specifying the amount of returned log entries in this message. After 
		that follows that many tuples, each containing the following words, in the given order:
		* time: The timestamp for the log entry, given as the amount of seconds since the unix epoch.
		* message: The log message.


= RESERVED SLOTS COMMANDS =

reservedSlots.load
Rights: reservedSlots
Response: OK
Response: ServerError
Effects: Loads a previously saved list of reserved slots on the game server.
Comments: If loading succeeds, the reserved slots list will get updated. 
		If loading fails, the reserved slots list will remain unchanged. 

reservedSlots.save
Rights: reservedSlots
Response: OK
Response: ServerError
Effects: Saves all the current reserved slots to a file on the game server side for future loading.
Comments: This should be called after every change to the reserved slots list. 

reservedSlots.clear
Rights: reservedSlots
Response: OK
Response: ServerError
Effects: Removes all the reserved slots from the list. 
Comments: reservedSlots.save should be called after this if the changes are to be persistent. 

reservedSlots.list
Rights: console
Response: OK <amount: integer> <name1: string> ... <nameN: string>
Response: ServerError
Effects: Retrieves an up to date list of all reserved slots registered on the game server. 
Comments: Only currently loaded reserved slots are returned. Note that this command queries the 
		game server for an up to date list every time. 

reservedSlots.addPlayer <name: string>
Rights: reservedSlots
Response: OK
Response: InvalidArguments
Response: InvalidReservedSlot
Effects: Adds a player/soldier name to the list of reserved slots. 
Comments: Any error will result in a InvalidReservedSlot response. This might happen if the 
		given name is invalid, if it is already in the list, or if the list is full. 

reservedSlots.removePlayer <name: string>
Rights: reservedSlots
Response: OK
Response: InvalidArguments
Response: InvalidReservedSlot
Effects: Removes the reserved slot for the given player/soldier name. 
Comments: Any error will result in a InvalidReservedSlot response. This might happen if the 
		given name is not previously registered as a reserved slot. 
