text: /*
   * qstat
   * by Steve Jankowski
   *
   * Teamspeak 2 query protocol
   * Copyright 2005 Steven Hartland
   *
   * Licensed under the Artistic License, see LICENSE.txt for license terms
   *
   */
  
  #include <sys/types.h>
  #ifndef _WIN32
  #include <sys/socket.h>
  #endif
  #include <stdlib.h>
  #include <stdio.h>
  #include <ctype.h>
  
  #include "debug.h"
  #include "qstat.h"
  #include "packet_manip.h"
  
  
  query_status_t send_ts2_request_packet( struct qserver *server )
  {
  	char buf[256];
  
  	int serverport = get_param_i_value( server, "port", 0 );
  	change_server_port( server, serverport, 1 );
  
  	if ( get_player_info )
  	{
  		server->flags |= TF_PLAYER_QUERY|TF_RULES_QUERY;
  		sprintf( buf, "si %d\npl %d\nquit\n", serverport, serverport );
  		server->saved_data.pkt_index = 2;
  	}
  	else
  	{
  		server->flags |= TF_STATUS_QUERY;
  		sprintf( buf, "si %d\nquit\n", serverport );
  		server->saved_data.pkt_index = 1;
  	}
  
  	return send_packet( server, buf, strlen( buf ) );
  }
  
  
  query_status_t deal_with_ts2_packet( struct qserver *server, char *rawpkt, int pktlen )
  {
  	char *s;
  	int ping, connect_time, mode = 0;
  	char name[256];
  	debug( 2, "processing..." );
  
  	server->n_servers++;
  	server->n_requests++;
  	server->ping_total += time_delta( &packet_recv_time, &server->packet_time1 );
  
  	if ( 0 == pktlen )
  	{
  		// Invalid password
  		return REQ_ERROR;
  	}
  
  	rawpkt[pktlen]= '\0';
  
  	s = rawpkt;
  	s = strtok( rawpkt, "\015\012" );
  
  	while ( NULL != s )
  	{
  		if ( 0 == mode )
  		{
  			// Rules
  			char *key = s;
  			char *value = strchr( key, '=' );
  			if ( NULL != value )
  			{
  				// Server Rule
  				*value = '\0';
  				value++;
  				if ( 0 == strcmp( "server_name", key ) )
  				{
  					server->server_name = strdup( value );
  				}
  				else if ( 0 == strcmp( "server_udpport", key ) )
  				{
  					change_server_port( server, atoi( value ), 0 );
  					add_rule( server, key, value, NO_FLAGS );
  				}
  				else if ( 0 == strcmp( "server_maxusers", key ) )
  				{
  					server->max_players = atoi( value );
  				}
  				else if ( 0 == strcmp( "server_currentusers", key ) )
  				{
  					server->num_players = atoi( value);
  				}
  				else
  				{
  					add_rule( server, key, value, NO_FLAGS);
  				}
  			}
  			else if ( 0 == strcmp( "OK", s ) )
  			{
  				// end of rules request
  				server->saved_data.pkt_index--;
  				mode++;
  			}
  			else if ( 0 == strcmp( "[TS]", s ) )
  			{
  				// nothing to do
  			}
  			else if ( 0 == strcmp( "ERROR, invalid id", s ) )
  			{
  				// bad server
  				server->server_name = DOWN;
  				server->saved_data.pkt_index = 0;
  			}
  		}
  		else if ( 1 == mode )
  		{
  			// Player info
  			if ( 3 == sscanf( s, "%*d %*d %*d %*d %*d %*d %*d %d %d %*d %*d %*d %*d \"0.0.0.0\" \"%255[^\"]", &ping, &connect_time, name ) )
  			{
  				// Player info
  				struct player *player = add_player( server, server->n_player_info );
  				if ( NULL != player )
  				{
  					player->name = strdup( name );
  					player->ping = ping;
  					player->connect_time = connect_time;
  				}
  			}
  			else if ( 0 == strcmp( "OK", s ) )
  			{
  				// end of rules request
  				server->saved_data.pkt_index--;
  				mode++;
  			}
  			else if ( 0 == strcmp( "[TS]", s ) )
  			{
  				// nothing to do
  			}
  			else if ( 0 == strcmp( "ERROR, invalid id", s ) )
  			{
  				// bad server
  				server->server_name = DOWN;
  				server->saved_data.pkt_index = 0;
  			}
  		}
  		s = strtok( NULL, "\015\012" );
  	}
  
  	gettimeofday( &server->packet_time1, NULL );
  
  	if ( 0 == server->saved_data.pkt_index )
  	{
  		server->map_name = strdup( "N/A" );
  		return DONE_FORCE;
  	}
  
  	return INPROGRESS;
  }
  