/*
 * gstat.h
 * by Aaron Levinson
 * alevinsn@uiuc.edu
 * http://www.ews.uiuc.edu/~alevinsn/
 *
 * Copyright 1998 by Aaron Levinson
 *
 * This file was derived from qstat.h, by Steve Jankowski
 * Copyright from qstat.h:
 *
 *   Copyright 1996,1997 by Steve Jankowski
 *
 */

/* Various magic numbers.
 */

#ifndef _GSTAT_H_
#define _GSTAT_H_

#define MAXFD_DEFAULT		20
#define DEFAULT_HOST_LOOKUP_TIME                2       /* in seconds */
#define DEFAULT_PORT	                26000
#define HEXEN2_DEFAULT_PORT		26900
#define QUAKE2_DEFAULT_PORT		27910
#define DEFAULT_RETRIES		3
#define DEFAULT_RETRY_INTERVAL		500	/* milli-seconds */
#define MAXIP			4

/* Structures for keeping information about Quake servers, server
 * rules, and players.
 */

#define Q_UNKNOWN_TYPE 0
#define Q_SERVER 1
#define QW_SERVER 2
#define QW_MASTER 4
#define H2_SERVER 8
#define Q2_SERVER 16
#define Q2_MASTER 32
#define F_USERS_BACKSLASH	0x1
#define F_SEEN_BACKSLASH	0x2

typedef struct Player {
  int number;
  char *name;
  int frags;
  int connect_time;
  int shirt_color;
  int pants_color;
  char *address;
  int ping;
  char *skin;
  struct Player *next;
} player;

typedef struct Rule {
  char *name;
  char *value;
  struct Rule *next;
} rule;

typedef struct Qserver {
  char *arg;
  char *host_name;
  struct in_addr ip[MAXIP];
  int type;
  int fd;
  unsigned short port;
  int retry1;
  int retry2;
  int n_retries;
  struct timeval packet_time1;
  struct timeval packet_time2;
  int ping_total; /* average is ping_total / n_requests */
  int n_requests;
  int n_packets;

  int n_servers;
  char *error;

  char *server_name;
  char *address;
  char *map_name;
  int max_players;
  int num_players;
  int protocol_version;

  int next_player_info;
  int n_player_info;
  player *players;

  char *next_rule;
  int n_rules;
  rule *rules;
  int missing_rules;

  struct Qserver *next;
} qserver;

/* Definitions for the original Quake network protocol.
 */

#define PACKET_LEN 0xffff

/* Quake packet formats and magic numbers
 */
struct qheader  {
  unsigned char flag1;
  unsigned char flag2;
  unsigned short length;
  unsigned char op_code;
};

#define QPACKET_DATA_SIZE 1501 /* to get even size so there is no padding */

struct qpacket {
  unsigned char flag1;
  unsigned char flag2;
  unsigned short length;
  unsigned char op_code;
  unsigned char data[QPACKET_DATA_SIZE];
};

#define Q_FLAG1			0x80
#define Q_FLAG2			0x00
#define Q_NET_PROTOCOL_VERSION	3
#define HEXEN2_NET_PROTOCOL_VERSION	4
#define Q_HEADER_SIZE		5

#define Q_CCREQ_CONNECT		0x01
#define Q_CCREP_ACCEPT		0x81
#define Q_CCREP_REJECT		0x82

#define Q_CCREQ_SERVER_INFO	0x02
#define Q_CCREP_SERVER_INFO	0x83

#define Q_CCREQ_PLAYER_INFO	0x03
#define Q_CCREP_PLAYER_INFO	0x84

#define Q_CCREQ_RULE_INFO	0x04
#define Q_CCREP_RULE_INFO	0x85

#define Q_DEFAULT_SV_MAXSPEED	"320"
#define Q_DEFAULT_SV_FRICTION	"4"
#define Q_DEFAULT_SV_GRAVITY	"800"
#define Q_DEFAULT_NOEXIT	"0"
#define Q_DEFAULT_TEAMPLAY	"0"
#define Q_DEFAULT_TIMELIMIT	"0"
#define Q_DEFAULT_FRAGLIMIT	"0"


/* Definitions for the QuakeWorld (and Quake2) network protocol
 */

#define QW_DEFAULT_PORT			27500
#define QW_MASTER_DEFAULT_PORT		27000
#define Q2_MASTER_DEFAULT_PORT          27900

#define QW_GET_SERVERS    'c'
#define QW_SERVERS        'd'
#define QW_GET_USERINFO   'o'
#define QW_USERINFO       'p'
#define QW_GET_SEENINFO   'u'
#define QW_SEENINFO       'v'
#define QW_NACK           'm'
#define QW_NEWLINE        '\n'
#define QW_RULE_SEPARATOR '\\'

#define QW_REQUEST_LENGTH 20

#define MASTER_FILE "master.dat"

/* Output and formatting functions
 */
 
/*Special Quakeworld Packet*/

#define MAX_COMMAND_LENGTH 201

typedef struct {
  char prefix[4];
  char command[MAX_COMMAND_LENGTH+1];
} QWPack;

typedef struct {
  char ipaddress[26];
  char name[100];
} QWMasterD;

void display_server(qserver *server);
void display_qwmaster(qserver *server, char *prefix);
void display_qwmaster_players(void);
void display_server_rules(qserver *server);
void display_player_info(qserver *server);
void display_q_player_info(qserver *server);
void display_qw_player_info(qserver *server);
void display_q2_player_info(qserver *server);

void display_header(void);
void display_progress(void);
void display_progress_got_host(int num);
void raw_display_server(qserver *server);
void raw_display_server_rules(qserver *server);
void raw_display_player_info(qserver *server);
void raw_display_q_player_info(qserver *server);
void raw_display_qw_player_info(qserver *server);
void raw_display_q2_player_info(qserver *server);
 
int is_default_rule(rule *rule);
char *escape(unsigned char* string);
char *quake_color(int color);
char *play_time(int seconds, int show_seconds);
char *ping_time(int ms);
char *get_qw_game(qserver *server);
void usage(char *msg, char **argv);

void freeQserver(qserver *server);
void freeRule(rule *rules);
void freePlayer(player *players);


/* Query status and packet handling functions
 */

void cleanup_qserver(qserver *server, int force);
 
int deal_with_packet(qserver *server, char *pkt, int pktlen);
int deal_with_q_packet(qserver *server, char *pkt, int pktlen);
int deal_with_qw_packet(qserver *server, char *pkt, int pktlen);
int deal_with_q1qw_packet(qserver *server, char *pkt, int pktlen);
int deal_with_qwmaster_packet(qserver *server, char *pkt, int pktlen);
int server_info_packet(qserver *server, struct qpacket *pkt,
	       int datalen);
int player_info_packet(qserver *server, struct qpacket *pkt,
	       int datalen);
int rule_info_packet(qserver *server, struct qpacket *pkt, int datalen);
 
int time_delta(struct timeval *later, struct timeval *past);
char *strherror(int h_err);
int connection_refused(void);
 
int add_file(char *filename);
int add_qserver(char *arg, int type);
int add_qserver_byaddr(unsigned long ipaddr, unsigned short port, int type, int num);
void init_qserver(qserver *server);
int bind_qserver(qserver *server);
void bind_sockets(void);
void send_packets(void);
int send_server_request_packet(qserver *server);
int send_qserver_request_packet(qserver *server);
int send_qwserver_request_packet(qserver *server);
int send_qwmaster_request_packet(qserver *server);
int send_rule_request_packet(qserver *server);
int send_player_request_packet(qserver *server);

int set_fds(fd_set *fds);
void get_next_timeout(struct timeval *timeout);

void print_packet(char *buf, int buflen);
char* use_master_file(char *execpath);
int count_bits(int n);
void print_file_location(void);
char *getNthWordInString(char *str, int num, int dir);
void FREE(void *something);
char *getCommandLine(char *exec);
static void interrupt_gethost(int signo);

#endif /* _GSTAT_H_ */
