/*
 * qstat
 * by Steve Jankowski
 *
 * Battlefield Bad Company 2 query protocol
 * Copyright 2009 Steven Hartland
 *
 * Licensed under the Artistic License, see LICENSE.txt for license terms
 *
 */

#include <sys/types.h>
#ifndef _WIN32
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
#else
 #include <winsock.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_bfbc2_request_packet(struct qserver *server)
{
	char buf[50];
	int size = 0;

	switch (server->challenge) {
	case 0:
		// Initial connect send serverInfo
		size = 27;
		memcpy(buf, "\x00\x00\x00\x00\x1b\x00\x00\x00\x01\x00\x00\x00\x0a\x00\x00\x00serverInfo\x00", size);
		break;

	case 1:
		// All Done send quit
		size = 21;
		memcpy(buf, "\x01\x00\x00\x00\x15\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00quit\x00", size);
		break;

	case 2:
		return (DONE_FORCE);
	}
	debug(3, "send_bfbc2_request_packet: state = %ld", server->challenge);

	return (send_packet(server, buf, size));
}


query_status_t
deal_with_bfbc2_packet(struct qserver *server, char *rawpkt, int pktlen)
{
	char *s, *end, *crlf;
	int words, word = 0;

	debug(2, "processing...");

	if (17 > pktlen) {
		// Invalid packet
		return (REQ_ERROR);
	}

	rawpkt[pktlen - 1] = '\0';
	end = &rawpkt[pktlen - 1];
	s = rawpkt;

	server->ping_total = time_delta(&packet_recv_time, &server->packet_time1);
	server->n_requests++;

	// Header Sequence
	s += 4;

	// Packet Size
	s += 4;

	// Num Words
	words = *(int *)s;
	s += 4;

	// Words
	while (words > 0 && s + 5 < end) {
		// Size
		int ws = *(int *)s;
		s += 4;

		// Content
		debug(6, "word: %s\n", s);
		switch (word) {
		case 0:
			// Status
			break;

		case 1:
			// Server Name
			// prevent CR & LF in the server name
			crlf = strchr(s, '\015');
			if (NULL != crlf) {
				*crlf = '\0';
			}
			crlf = strchr(s, '\012');
			if (NULL != crlf) {
				*crlf = '\0';
			}
			server->server_name = strdup(s);
			break;

		case 2:
			// Player Count
			server->num_players = atoi(s);
			break;

		case 3:
			// Max Players
			server->max_players = atoi(s);
			break;

		case 4:
			// Game Mode
			add_rule(server, "gametype", s, NO_FLAGS);
			break;

		case 5:
			// Map
			server->map_name = strdup(s);
			break;
		}
		word++;

		s += ws + 1;

		words--;
	}

	server->challenge++;
	gettimeofday(&server->packet_time1, NULL);

	if (1 == server->challenge) {
		send_bfbc2_request_packet(server);
		return (INPROGRESS);
	}

	return (DONE_FORCE);
}
