/* $Id$
 * 
 * This file is a part of Amp2p.  Amp2p is Copyright 2004 Joseph
 * Curtis.  jocurtis@gmail.com
 *
 *
 *  Amp2p is free software; you can redistribute it and/or modify it
 *  under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  Amp2p is distributed in the hope that it will be useful, but
 *  WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with Amp2p; if not, write to the Free Software Foundation,
 *  Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

/* This file containeth all of the defines, global variables and
 * function prototypes for amp2p.  The functions which are expected to
 * be in xmms-amp2p.c and winamp-amp2p.c are prototyped here.
 *
 * Any xmms or winamp specific stuff goes in xmms-amp2p.h and
 * winamp-amp2p.h respectivly.
 */

//#include <openssl/sha.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

/* The version of amp2p. */
#define VERSION "0.0.1"

/* There are two modes of operation (damn you NAT), live node where
 * you can accept incoming connections on a port, and NAT mode where
 * you can't.  The plan is to implement live node mode first because,
 * seriously how hard is it to forward a port on your NAT box.  When
 * this works then the no port forwarding mode will be implemented.
 * This complicates things somewhat as you might imagine.
 */

/* Maximum number of nodes in the nodelist */
#define MAX_NODELIST 100

/* The default port to listen on for connections */
#define LISTEN_PORT 1337

/* Maximum number of threads that may be spawned to handle the
 * transferal of data from another node.  Pretty much this is the max
 * number of transfers.  Who wants to do over 100 transfers
 * simultaneously anyway?
 */
#define MAX_TRANSFER_THREADS 100

/* Maximum number of threads that may be spawned to handle the
 * forwarding of searches.  This will probably not ever get very high.
 * I can't imagine any more than 5 threads being required for this.
 */
#define MAX_FORWARD_THREADS 10

#define MAX_REQUEST_HANDLERS 3

#define MAX_THREADS 1000

#define MAX_RESULTS 100

/* The maximum backlog for TCP connections */
#define MAX_DOWNLOADS 10

/* This value is the maximum amount of data to be sent in each data
 * packet.  Search request packets and file request packets will be
 * considerably smaller than this though.  Incidentally this value is
 * the MTU of ethernet minus the length of the UDP and IP headers. 576/548.
 */
#define PACK_SIZE 548

/* Size of the packet header in bytes. */
#define HEADER_SIZE 18

#define DATA_SIZE (PACK_SIZE - HEADER_SIZE)

#define NODELIST ".nodelist"

#define CHECKSUMS_FILE ".checksums"

/* Number of microseconds to sleep between processing a chunk of data
   for md5 hashing.  Keeps cpu utilisation slow and steady instead of
   spikey.  Slows things down a tad though.
*/
#define HASH_WAIT 1

/* Maximum recent queries to remember */
#define MAX_RECENT 3

/* Message types */
#define QUERY 1
#define REQUEST 2
#define DATA 3
#define PING 4
#define PING_REPLY 5
#define QUERY_REPLY 6

/* The maximum number of sockets that may be open at any one time. */
#define MAX_SOCKETS 10

/* The buffer length for reading/writing */
#define BUFLEN 1024

#define CLIST 0
#define DLIST 1

/* Debug statements */
#define DEBUG

/* Message data structure. */
struct msg {
  unsigned int origin; /* address of original querier/file requester */
  unsigned int from; /* address of the sender of this message.  redundant? */
  unsigned int to; /* address of the node this message is to. */
  short int type; /* message type, QUERY | REQUEST | DATA | PING | ...
	       If type is 0 then this message is corrupted/invalid. */
  int length; /* length of the data in bytes. */
  char * data; /* The data of the message.  No fixed size because I
		  don't wan't to take up 1500 bytes of memory for each
		  message even if it has no data. */  
};
/* Messages are structured in this way.  The first 18 bytes are the
 * message header and are organised in the following way:
 *
 *      Byte No(s)  |  C Type  |   Represents
 *      -------------------------------------
 *        0 - 3     |   int    |    origin
 *        4 - 7     |   int    |    from 
 *        8 - 11    |   int    |    to
 *        12 - 13   |   short  |    type
 *        14 - 17   |   int    |    length
 *
 * All components of the header are always present nomatter what type
 * of message it is.  If it is not a data message then length shall be
 * zero and data in the msg structure will be null.
 *
 * The next length bytes of the message are the data.  There is no end
 * of message character(s) and thus the data can contain any bytes.
 * If length > PACK_SIZE then the message is invalid.
 *
 * Note that although messages are a character array they are not
 * strings and have no null terminator.  I guess they could have one
 * after then end of the data but it would not be part of the data
 * because it would be after length.
 *
 * Also note that ALL addresses are stored in NETWORK (MSB first) byte
 * order.  That is opposite of the default on my box so watch out!
 * Use ntohl() to convert it you wish.  It shouldn't ever be needed
 * though since you can use inet_ntoa() to get a string representation
 * of the address if you need it.
 */

/* Node data structure. Contains all info this node knows about any
   other node.  The nodelist is an array of these structures. */
struct node {
  unsigned int addr;
  int ping;
};

struct file {
  char * name;
  char * title;
  unsigned int length; /* Decided to go with normal int despite the
			  4GB barrier.  Large files are not what this
			  app is about and it complicates things
			  somewhat */
  unsigned int offset; /* may or may not be appripriate but it is staying! */
  unsigned char checksum[16]; //TODO: change to MD5_DIGEST_LENGTH
};


/* This is here so I can pass both the socket of the TCP connection
   and the client address details to a create thread at once. */
struct data {
  int sock;
  struct sockaddr_in addr;
};

/* Now that I think about it, I will just do this with a hashtable. */

struct file_list {
  struct file item;
  struct file_list * next;
};

/* functions for this list (may be implemented later) */
struct file_list file_list_init(struct file);
void file_list_append(struct file_list, struct file);
void file_list_get(struct file_list, int);
void file_list_clear(struct file_list);

/* PROTOTYPES -- ADD MORE HERE!! */
char * i2d(unsigned int);
unsigned int local_addr(void);
void send_msg(struct msg);
void listen_for_requests(void);
void listen_for_data(void);
struct msg rcv_msg(void);
int inc_sindex(int);
void handle_request(char *);
void ping(unsigned int);

/* Abstraction. Threads and XMMS/Winamp specific stuff all have
 * abstraction functions, prototyped here.  They will refer to
 * different code depending on which module is linked in (xmms or
 * winamp).
 *
 * I am still not quite sure how this is going to work.
 */
  
int create_thread(void *, void *);
void exit_thread(void);
int search_playlist(char *, struct msg);
void ui(void);
void _send_msg(unsigned int, unsigned int, unsigned int,
	       short int, int, char *);
void send_query(unsigned int, char *);
void query(char *);
int list_append(struct file, int);
int is_recent_query(struct msg);
void initial(void);
void end(void);
void print_checksum(unsigned char *);
void hash_playlist(void);
char * checksum_str(unsigned char *);
unsigned char * str_checksum(char *);
unsigned char * md5_wait(char *, int);
char * lower(char *);
void download(struct file, int);
struct file decode_file(unsigned char *);
int encode_file(struct file, unsigned char **);
void reverse_str(char[]);
void update_download(int, float);

int die(char *);

static unsigned long sdbm(unsigned char *);
static int equalkeys(void *, void *);

ssize_t con_write(int fd, const void *buf, size_t count);
ssize_t con_read(int fd, void *buf, size_t count);

