LICENSE: The Artistic License 2.0

/*
 * qstat.h
 * by Steve Jankowski
 * steve@qstat.org
 * http://www.qstat.org
 *
 * Copyright 1996,1997,1998,1999,2000,2001,2002 by Steve Jankowski
 */

 
char ravenshield_serverquery[] = "REPORT";

 
{
    /* RAVENSHIELD PROTOCOL */
    RAVENSHIELD_SERVER,		/* id */
    "RSS",			/* type_prefix */
    "rss",			/* type_string */
    "-rss",			/* type_option */
    "Ravenshield",		/* game_name */
    0,				/* master */
    RAVENSHIELD_DEFAULT_PORT,	/* default_port */
    1000,				/* port_offset */
    TF_QUERY_ARG,		/* flags */
    "gametype",			/* game_rule */
    "RAVENSHIELD",			/* template_var */
    (char*)ravenshield_serverquery,			/* status_packet */
    sizeof( ravenshield_serverquery ) - 1,	/* status_len */
    NULL,			/* player_packet */
    0,				/* player_len */
    NULL,			/* rule_packet */
    0,				/* rule_len */
    NULL,			/* master_packet */
    0,				/* master_len */
    NULL,			/* master_protocol */
    NULL,			/* master_query */
    display_ravenshield_player_info,	/* display_player_func */
    display_server_rules,		/* display_rule_func */
    raw_display_ravenshield_player_info,	/* display_raw_player_func */
    raw_display_server_rules,		/* display_raw_rule_func */
    xml_display_ravenshield_player_info,	/* display_xml_player_func */
    xml_display_server_rules,		/* display_xml_rule_func */
    send_qserver_request_packet,	/* status_query_func */
    NULL,				/* rule_query_func */
    NULL,				/* player_query_func */
    deal_with_ravenshield_packet,	/* packet_func */
},




query_status_t deal_with_ravenshield_packet(struct qserver *server, char *rawpkt, int pktlen)
{
	char *s, *key, *value;

	debug( 2, "deal_with_ravenshield_packet %p, %d", server, pktlen );

	server->n_servers++;
	if (NULL == server->server_name)
	{
		server->ping_total += time_delta(&packet_recv_time, &server->packet_time1);
	}
	else
	{
		gettimeofday(&server->packet_time1, NULL);
	}

	rawpkt[pktlen] = '\0';

	s = rawpkt;
	while (*s)
	{
		// Find the seperator
		while (*s && *s != '\xB6')
		{
			s++;
		}

		if (! *s)
		{
			// Hit the end no more
			break;
		}

		// key start
		key = ++s;
		while (*s && *s != ' ')
		{
			s++;
		}
		if (*s != ' ')
		{
			// malformed
			break;
		}
		*s++ = '\0';
		// key end
		// value start
		value = s;

		while (*s && *s != '\xB6')
		{
			s++;
		}

		if (*s == '\xB6')
		{
			*(s - 1) = '\0';
		}

		// Decode current key par
		if (0 == strcmp("A1", key))
		{
			// Max players
			server->max_players = atoi(value);
		}
		else if (0 == strcmp("A2", key))
		{
			// TeamKillerPenalty
			add_rule(server, "TeamKillerPenalty", value, NO_FLAGS);
		}
		else if (0 == strcmp("B1", key))
		{
			// Current players
			server->num_players = atoi(value);
		}
		else if (0 == strcmp("B2", key))
		{
			// AllowRadar
			add_rule(server, "AllowRadar", value, NO_FLAGS);
		}
		else if (0 == strcmp("D2", key))
		{
			// Version info
			add_rule(server, "Version", value, NO_FLAGS);
		}
		else if (0 == strcmp("E1", key))
		{
			// Current map
			server->map_name = strdup(value);
		}
		else if (0 == strcmp("E2", key))
		{
			// Unknown
		}
		else if (0 == strcmp("F1", key))
		{
			// Game type
			server->game = find_ravenshield_game(value);
			add_rule(server, server->type->game_rule, server->game, NO_FLAGS);
		}
		else if (0 == strcmp("F2", key))
		{
			// Unknown
		}
		else if (0 == strcmp("G1", key))
		{
			// Password
			add_rule(server, "Password", value, NO_FLAGS);
		}
		else if (0 == strcmp("G2", key))
		{
			// Query port
		}
		else if (0 == strcmp("H1", key))
		{
			// Unknown
		}
		else if (0 == strcmp("H2", key))
		{
			// Number of Terrorists
			add_rule(server, "nbTerro", value, NO_FLAGS);
		}
		else if (0 == strcmp("I1", key))
		{
			// Server name
			server->server_name = strdup(value);
		}
		else if (0 == strcmp("I2", key))
		{
			// Unknown
		}
		else if (0 == strcmp("J1", key))
		{
			// Game Type Order
			// Not pretty ignore for now
			//add_rule( server, "Game Type Order", value, NO_FLAGS );
		}
		else if (0 == strcmp("J2", key))
		{
			// RotateMap
			add_rule(server, "RotateMap", value, NO_FLAGS);
		}
		else if (0 == strcmp("K1", key))
		{
			// Map Cycle
			// Not pretty ignore for now
			//add_rule( server, "Map Cycle", value, NO_FLAGS );
		}
		else if (0 == strcmp("K2", key))
		{
			// Force First Person Weapon
			add_rule(server, "ForceFPersonWeapon", value, NO_FLAGS);
		}
		else if (0 == strcmp("L1", key))
		{
			// Players names
			int player_number = 0;
			char *n = value;

			if (*n == '/')
			{
				// atleast 1 player
				n++;
				while (*n && *n != '\xB6')
				{
					char *player_name = n;
					while (*n && *n != '/' && *n != '\xB6')
					{
						n++;
					}

					if (*n == '/')
					{
						*n++ = '\0';
					}
					else if (*n == '\xB6')
					{
						*(n - 1) = '\0';
					}

					if (0 != strlen(player_name))
					{
						struct player *player = add_player(server, player_number);
						if (NULL != player)
						{
							player->name = strdup(player_name);
						}
						player_number++;
					}
				}
			}
		}
		else if (0 == strcmp("L3", key))
		{
			// PunkBuster state
			add_rule(server, "PunkBuster", value, NO_FLAGS);
		}
		else if (0 == strcmp("M1", key))
		{
			// Players times
			int player_number = 0;
			char *n = value;
			if (*n == '/')
			{
				// atleast 1 player
				n++;
				while (*n && *n != '\xB6')
				{
					char *time = n;
					while (*n && *n != '/' && *n != '\xB6')
					{
						n++;
					}

					if (*n == '/')
					{
						*n++ = '\0';
					}
					else if (*n == '\xB6')
					{
						*(n - 1) = '\0';
					}

					if (0 != strlen(time))
					{
						int mins, seconds;
						if (2 == sscanf(time, "%d:%d", &mins, &seconds))
						{
							struct player *player = get_player_by_number(server, player_number);
							if (NULL != player)
							{
								player->connect_time = mins * 60+seconds;
							}
						}
						player_number++;
					}
				}
			}
		}
		else if (0 == strcmp("N1", key))
		{
			// Players ping
			int player_number = 0;
			char *n = value;
			if (*n == '/')
			{
				// atleast 1 player
				n++;
				while (*n && *n != '\xB6')
				{
					char *ping = n;
					while (*n && *n != '/' && *n != '\xB6')
					{
						n++;
					}

					if (*n == '/')
					{
						*n++ = '\0';
					}
					else if (*n == '\xB6')
					{
						*(n - 1) = '\0';
					}

					if (0 != strlen(ping))
					{
						struct player *player = get_player_by_number(server, player_number);
						if (NULL != player)
						{
							player->ping = atoi(ping);
						} player_number++;
					}
				}
			}
		}
		else if (0 == strcmp("O1", key))
		{
			// Players fags
			int player_number = 0;
			char *n = value;
			if (*n == '/')
			{
				// atleast 1 player
				n++;
				while (*n && *n != '\xB6')
				{
					char *frags = n;
					while (*n && *n != '/' && *n != '\xB6')
					{
						n++;
					}

					if (*n == '/')
					{
						*n++ = '\0';
					}
					else if (*n == '\xB6')
					{
						*(n - 1) = '\0';
					}

					if (0 != strlen(frags))
					{
						struct player *player = get_player_by_number(server, player_number);
						if (NULL != player)
						{
							player->frags = atoi(frags);
						} player_number++;
					}
				}
			}
		}
		else if (0 == strcmp("P1", key))
		{
			// Game port
			// Not pretty ignore for now
			/*
			change_server_port( server, atoi( value ), 0 );
			 */
		}
		else if (0 == strcmp("Q1", key))
		{
			// RoundsPerMatch
			add_rule(server, "RoundsPerMatch", value, NO_FLAGS);
		}
		else if (0 == strcmp("R1", key))
		{
			// RoundTime
			add_rule(server, "RoundTime", value, NO_FLAGS);
		}
		else if (0 == strcmp("S1", key))
		{
			// BetweenRoundTime
			add_rule(server, "BetweenRoundTime", value, NO_FLAGS);
		}
		else if (0 == strcmp("T1", key))
		{
			// BombTime
			add_rule(server, "BombTime", value, NO_FLAGS);
		}
		else if (0 == strcmp("W1", key))
		{
			// ShowNames
			add_rule(server, "ShowNames", value, NO_FLAGS);
		}
		else if (0 == strcmp("X1", key))
		{
			// InternetServer
			add_rule(server, "InternetServer", value, NO_FLAGS);
		}
		else if (0 == strcmp("Y1", key))
		{
			// FriendlyFire
			add_rule(server, "FriendlyFire", value, NO_FLAGS);
		}
		else if (0 == strcmp("Z1", key))
		{
			// Autobalance
			add_rule(server, "Autobalance", value, NO_FLAGS);
		}
	}

	return DONE_FORCE;
}


char *find_ravenshield_game(char *gameno)
{
	switch (atoi(gameno))
	{
		case 8:
			return strdup("Team Deathmatch");
			break;
		case 13:
			return strdup("Deathmatch");
			break;
		case 14:
			return strdup("Team Deathmatch");
			break;
		case 15:
			return strdup("Bomb");
			break;
		case 16:
			return strdup("Escort Pilot");
			break;
		default:
			// 1.50 and above actually uses a string so
			// return that
			return strdup(gameno);
			break;
	}
}
