#ifndef KEYLIB_H
#define KEYLIB_H 1

#ifdef __cplusplus
extern "C" {
#endif
//#define TEST_LAP 1

#ifdef TEST_LAP
#define KEYSERVER "lap:7025"
#else
#define KEYSERVER "key.netwinsite.com:80"  // Changed from netwinsite.com
#define KEYSERVERS "key.netwinsite.com:443"  // Changed from netwinsite.com
#endif

/*
README, - Instructions on implementing keylib in your application

#define SECRET_FILE "kfile.dat"  REPLACE WITH A FILE YOU HAVE WRITE ACCESS TO
#define PROD_NAME "dnews"  REPLACE WITH YOUR PRODUCT NAME
 
Call	
	keylib_imsg(imsg)
on startup, imsg is a logging function.

On startup and when each user logs in your application should call:
	    r = keylib_check_file(SECRET_FILE,PROD_NAME,&ulimit,reason);
	    if (!r) printf("License key faulty %s\n",reason);
	    if (nusers>ulimit) printf("User limit exceeded\n");

When a user wants to activate a registration number they will give you a 'regstring' and 
'emailstring' you process it like this:
	if (!keylib_activate_get(SECRET_FILE,PROD_NAME,regstring,emailstring,key,reason)) {
		printf("Unable to get license key from KEY server, reason follows:\n");
		printf("%s\n",reason);
		return 0;
	}
	printf("Loaded license key from server (%s) (%s)\n",key,reason);
	r = keylib_check_file(SECRET_FILE,PROD_NAME,&ulimit,reason);
	if (!r) printf("License key faulty %s\n",reason);
*/

enum {
	KEYLIB_DNEWS=1,
	KEYLIB_DMAIL,
	KEYLIB_SURGEMAIL,
	KEYLIB_SURGEFTP,
	KEYLIB_WEBMAIL,
	KEYLIB_CWMAIL,
	KEYLIB_DMAILWEB,
	KEYLIB_WATCHDOG,
	KEYLIB_WEBNEWS,
	KEYLIB_DBABBLE,

	KEYLIB_FERNGATE,
	KEYLIB_SMSGATE,
	KEYLIB_SURGELDAP,
	KEYLIB_SURGENEWS,
	KEYLIB_AVAST,

	KEYLIB_SURGEPLUS,
	KEYLIB_SURGEBUNDLE,
	KEYLIB_SURGEBUNDLE2,

	KEYLIB_SURGEBLOG,
	KEYLIB_CONSULTING,
	KEYLIB_SURGETORRENT,
	KEYLIB_FTPDAV,
	KEYLIB_SUPPORT,

	KEYLIB_LAST
};


typedef struct KNAMES {char *name; int id;} Knames;
static Knames knames[]={
	"DNews",KEYLIB_DNEWS,
//	"DMail",KEYLIB_DMAIL,
	"SurgeMail",KEYLIB_SURGEMAIL,
	"SurgeFTP",KEYLIB_SURGEFTP,
	"WebMail",KEYLIB_WEBMAIL,
	"WebNews",KEYLIB_WEBNEWS,
	"CWMail",KEYLIB_CWMAIL,
	"DMailWeb",KEYLIB_DMAILWEB,
	"WatchDog",KEYLIB_WATCHDOG,
	"DBabble",KEYLIB_DBABBLE,
	"Ferngate",KEYLIB_FERNGATE,
	"SmsGate",KEYLIB_SMSGATE,
	"SurgeLDAP",KEYLIB_SURGELDAP,
	"SurgeNews",KEYLIB_SURGENEWS,
	"avast",KEYLIB_AVAST,
	"SurgePlus",KEYLIB_SURGEPLUS,
	"SurgeBundle1",KEYLIB_SURGEBUNDLE,
	"SurgeBundle2",KEYLIB_SURGEBUNDLE2,
	"SurgeBlog",KEYLIB_SURGEBLOG,
	"Consulting",KEYLIB_CONSULTING,
	"SurgeTorrent",KEYLIB_SURGETORRENT,
	"ISyncUServer",KEYLIB_FTPDAV,
	"Priority_Support",KEYLIB_SUPPORT,
	NULL,KEYLIB_LAST
};

/*
Feature table	Mailling list, ftp,  Officemessenger, smsnotify.
Feature Table		Usenet	XSpam	Virus,  SSL,  OfficeMessage,  WebMail,  Domain Limit, User Limit

SurgeMail-Enterprise	y	y	y	y	y		y		none	none
SurgeMail-ISP		y	y	n	y	y		y		none	10 million
SurgeMail-Home		n	n	n	n	y		y		1	100
SurgeMail-Workplace 


  ------------------
User limit		2,000	6,000	2,0000	Unlimited
SurgeMail Enterprise   $4997	$5997	$9997	$17000

User Limit	1,000	5,000	10,000	100,000	1,000,000  10,000,000
SurgeMail ISP	$997	$1497	$1997	$4997	$9997	   $19997	

User Limit	5	100	500	1000
SurgeMail Work	$497	$997	$1997	$2997
		
User Limit	5	10
SurgeMail Home	$Free	$95

  -------------------------------------------------------------------------------------
			

  Usenet - low volume non binary sucking feed $x/month
  XSpam - weekly auto updated spam filter 

They download one of those three.
	The download form contains the 'name' only - surgemail
	The purchase form selects the actiual product code. and lists all
	with that name in the 'desc'

	When license generated, it will be for the matching product 
		name matches, and  list is empty, and code is in list of this bndle

*/

enum {
	KF_NOSSL = 1,		/* Disable SSL features */
	KF_DOMLIMIT = 2,	/* Limit virtual domains */
	KF_FREE = 4,		/* Free registration - enforce advertising features */
	KF_2GIG = 8,		/* 2 GIG USER LIMIT for dnews */
	KF_VIRUS = 16,		/* User has purchased anti virus license */
	KF_ENCRYPT = 32		/* Encryption module */
};
/* Use these functions to determine if flags were set or not */
char *keylib_mirror_url(void);

int keylib_nossl(void);
char *keylib_url_force(int force);
int keylib_domlimit(void);
int keylib_free(void);
int keylib_gethostid(char *kfile,char *reason);
int keylib_imsg(int (*ximsg)(const char *arg,...));
char *keylib_two(char *p1, char *p2);
int keylib_isflag(int x);
int keylib_setproduct(char *s);
char *keylib_url_upgrade(void);
int keylib_isfree(void);


typedef struct PRODUCT {
	char *code;  char *list; char *name; char *desc; 
	int flags; int ulimit; int price, supportx,upgradex,avastx;} Product;
static Product products[]={	//											flags		users		price		old stuff
	 "su_5", ""	,"SurgeMail", "SurgeMail"							,0			, 5			,0			,0,0,0
	 ,"su_5a", ""	,"SurgeMail", "SurgeMail +Support"			,KF_VIRUS	, 5			,75			,0,0,0
	 ,"su_10", ""	,"SurgeMail", "SurgeMail"							,0			, 10		,200		,0,0,0
	 ,"su_10a", ""	,"SurgeMail", "SurgeMail"							,KF_VIRUS	, 10		,200		,0,0,0
	 ,"su_50", ""	,"SurgeMail", "SurgeMail"							,0			, 50		,400		,0,0,0
	 ,"su_50a", ""	,"SurgeMail", "SurgeMail"							,KF_VIRUS	, 50		,400		,0,0,0
	 ,"su_100", ""	,"SurgeMail", "SurgeMail"							,0			, 100		,600		,0,0,0
	 ,"su_100a", ""	,"SurgeMail", "SurgeMail"							,KF_VIRUS	, 100		,600		,0,0,0
	 ,"su_1000", ""	,"SurgeMail", "SurgeMail"							,0			, 1000		,800		,0,0,0
	 ,"su_1000a", ""	,"SurgeMail", "SurgeMail"						,KF_VIRUS	, 1000		,800		,0,0,0
	 ,"su_10000", ""	,"SurgeMail", "SurgeMail"						,0			, 10000		,1000		,0,0,0
	 ,"su_10000a", ""	,"SurgeMail", "SurgeMail"						,KF_VIRUS	, 10000		,1000		,0,0,0
	 ,"su_100000", ""	,"SurgeMail", "SurgeMail"						,0			, 100000	,1100		,0,0,0
	 ,"su_100000a", ""	,"SurgeMail", "SurgeMail"						,KF_VIRUS	, 100000	,1100		,0,0,0
	 ,"su_100000b", ""	,"SurgeMail", "SurgeMail for Broadsoft"				,KF_VIRUS	, 100000	,1100		,0,0,0
	 ,"su_100000ba", ""	,"SurgeMail", "SurgeMail for Broadsoft-HIDE"				,KF_VIRUS	, 100000	,1100		,0,0,0
	 ,"su_inf", ""	,"SurgeMail", "SurgeMail"							,0			, 0			,1300		,0,0,0
	 ,"su_infa", ""	,"SurgeMail", "SurgeMail"							,KF_VIRUS	, 0			,1300		,0,0,0
	 ,"su_infb", ""	,"SurgeMail", "SurgeMail for Broadsoft"							,KF_VIRUS	, 0			,1300		,0,0,0
	 ,"su_infba", ""	,"SurgeMail", "SurgeMail for Broadsoft-HIDE"							,KF_VIRUS	, 0			,1300		,0,0,0
	 ,"su_cluster", ""	,"SurgeMail", "SurgeMail Cluster"				,0			, 0			,2500		,0,0,0
	 ,"su_clustera", ""	,"SurgeMail", "SurgeMail Cluster"				,KF_VIRUS	, 0			,2500		,0,0,0
	 ,"su_clusterba", ""	,"SurgeMail", "SurgeMail Cluster for Broadsoft"				,KF_VIRUS	, 0			,2500		,0,0,0
	 ,"su_clusterb", ""	,"SurgeMail", "SurgeMail Cluster for Broadsoft-HIDE"				,KF_VIRUS	, 0			,2500		,0,0,0
	 // all must end in 'a' as that means avast... 
	 ,"ssup1", ""	,"Priority_Support", "Gold 12/7 Emergency Support"			,0			, 0			,3000		,3000,0,0
	 ,"ssup2", ""	,"Priority_Support", "Diamond 24/7 Emergency Support"			,0			, 0			,6000		,6000,0,0

	 ,"su_test", ""	,"SurgeMail", "SurgeMail (internal use only) HIDE"
		,  KF_VIRUS, 0,5000,5000,5000,0		
	,"db1", "","DBabble","DBabble"	,0,0,485,290,160,0
	,"wm1", "","WebMail","WebMail"	,0,0,485,320,160,0
	,"dn1", "","DNews","DNews"	,0,0,485,290,160,0
	,"dn2", "","DNews","DNews-2GIG"	,KF_2GIG,0,345,230,115,0
	,"dn3", "","DNews","DNews"	,0,2,220,145,72,0
	,"dn4", "","DNews","DNews"	,0,1,95,60,30,0
	,"dn5", "","DNews","DNews-Feed"	,0,10,345,230,115,0
	,"sdn1", "","DNews","DNews-Support-Upgrade",0,0,290,290,160,0
	,"sdn2", "","DNews","DNews-Upgrade-Only",0,0,160,290,160,0
	,"es3", "","DNews","DNEWS+Priority-Phone-Support",0,0,2995,2995,2995,0

	,"fg1", "","Ferngate","Ferngate (FG Server+FernWeb+Fern+Fernphone)"	,0,1000,2995,400,200,0
	
//	,"sg1", "","SmsGate","SmsGate",0,5,75,50,25
//	,"sg2", "","SmsGate","SmsGate",0,1000,270,170,70
	,"sg3", "","SmsGate","SmsGate",0,0,370,270,170,0

	,"sl1", "","SurgeLDAP","SurgeLDAP",0,0,770,370,170,0
	,"sl2", "","SurgeLDAP","SurgeLDAP",0,1000,270,170,70,0
	,"wd1", "","Watchdog","Watchdog",0,0,97,47,47,0

/* Root product codes used for bundles -HIDE means never show as a real product 
flags must be set correctly !!! */
	,"su5", "","SurgeMail","SurgeMail-HIDE",0,5,485,320,160,0
	,"su10", "","SurgeMail","SurgeMail-HIDE",0,10,485,320,160,0
	,"su20", "","SurgeMail","SurgeMail-HIDE",0,20,485,320,160,0
	,"su200", "","SurgeMail","SurgeMail-HIDE",0,200,485,320,160,0
	,"su500", "","SurgeMail","SurgeMail-HIDE",0,500,485,320,160,0
	,"su2000", "","SurgeMail","SurgeMail-HIDE",0,2000,485,320,160,0
	,"su6000", "","SurgeMail","SurgeMail-HIDE",0,2000,485,320,160,0
	,"su10000", "","SurgeMail","SurgeMail-HIDE",0,10000,485,320,160,0
	,"su20000", "","SurgeMail","SurgeMail-HIDE",0,10000,485,320,160,0
	,"su100000", "","SurgeMail","SurgeMail-HIDE",0,100000,485,320,160,0
	,"su1000000", "","SurgeMail","SurgeMail-HIDE",0,1000000,485,320,160,0
	,"su0", "","SurgeMail","SurgeMail-HIDE",0,0,485,320,160,0

	,"sn2", "","SurgeNews","SurgeNews"		,0,2	,97,60,30,0
	,"sn10", "","SurgeNews","SurgeNews"		,0,10	,270,170,80,0
	,"sn100", "","SurgeNews","SurgeNews"	,0,100	,370,220,160,0
	,"sn1000", "","SurgeNews","SurgeNews"	,0,1000	,470,320,160,0
	,"snc5", "","SurgeNews","SurgeNews 5 concurrent connections"		,0,0	,270,170,80,0
	,"snc15", "","SurgeNews","SurgeNews 15 concurrent connections"		,0,0	,370,220,160,0
	,"sn0", "","SurgeNews","SurgeNews"		,0,0	,670,320,160,0

	,"st0", "","SurgeTorrent","SurgeTorrent"		,0,0	,470,222,222,0

	,"fd100", "","ISyncUServer","ISyncUServer 100 User"		,0,100	,180,60,60,0
	,"fd1000", "","ISyncUServer","ISyncUServer 1000 User"	,0,1000	,360,120,120,0
	,"fd0", "","ISyncUServer","ISyncUServer Unlimited"		,0,0	,540,180,180,0

	 ,"av_5a", ""	,"avast", "SurgeMail Home etc"
		,  KF_VIRUS, 5,87,52,26,0
	 ,"av_10a", ""	,"avast", "SurgeMail "
		,  KF_VIRUS, 10,147,88,44,0
	 ,"av_100a", ""	,"avast", "SurgeMail "
		,  KF_VIRUS, 100,347,208,104,0
	 ,"av_1000a", "","avast", "SurgeMail "
		,  KF_VIRUS, 1000,447,268,134,0
	 ,"av_10000a", "","avast", "SurgeMail "
		,  KF_VIRUS, 10000,747,447,223,0
	 ,"av_100000a", ""	,"avast", "SurgeMail "
		,  KF_VIRUS, 100000,847,508,254,0
	 ,"av_infa", ""	,"avast", "SurgeMail "
		,  KF_VIRUS, 0,947,567,270		,0	
	 ,"sp_5", ""	,"SurgePlus", "SurgePlus Calender File sharing"
		,  0, 5,87,52,26,0
	 ,"sp_10", ""	,"SurgePlus", "SurgePlus Calender File sharing"
		,  0, 10,167,100,50,0
	 ,"sp_100", ""	,"SurgePlus", "SurgePlus Calender File sharing"
		,  0, 100,270,208,104,0
	 ,"sp_1000", ""	,"SurgePlus", "SurgePlus Calender File sharing"
		,  0, 1000,370,222,111,0
	 ,"sp_10000", ""	,"SurgePlus", "SurgePlus Calender File sharing"
		,  0, 10000,470,282,141,0
	 ,"sp_100000", ""	,"SurgePlus", "SurgePlus Calender File sharing"
		,  0, 100000,570,342,171,0
	 ,"sp_inf", ""	,"SurgePlus", "SurgePlus Calender File sharing"
		,  0, 0,670,402,201,0
	,"ftp1", "","SurgeFTP","SurgeFTP",0,0,670,402,201,0
	,"ftpf", "","SurgeFTP","SurgeFTP",0,1,0,0,0,0
	,"ftp10", "","SurgeFTP","SurgeFTP",0,10,170,90,81,0
	,"ftp100", "","SurgeFTP","SurgeFTP",0,100,270,162,81,0
	,"ftp1000", "","SurgeFTP","SurgeFTP",0,1000,470,282,181,0
	,"wm1", "","WebMail","WebMail",0,0,485,320,177,0
	,"swm1", "","WebMail","WebMail-Support-Updates",0,0,320,320,177,0
	,"wn1", "","WebNews","WebNews",0,0,345,230,115,0
	,"bnd1", "su_10000,db1,sp_10000,mirror","SurgeBundle1","SurgeMail 10K users + Mirror + DBabble Bundle",0,0,1424,854,427,0
	,"bnd2", "su_10000,sp_10000","SurgeBundle2","SurgeMail 10K users",0,0,570,320,160,0
	
	 ,"sb_5", ""	,"SurgeBlog", "SurgeBlog",  0, 5,0,45,0,0
	 ,"sb_10", ""	,"SurgeBlog", "SurgeBlog",  0, 10,175,105,70,0
	 ,"sb_100", ""	,"SurgeBlog", "SurgeBlog",  0, 100,470,282,188,0
	 ,"sb_1000", ""	,"SurgeBlog", "SurgeBlog",  0, 1000,570,342,228,0
	 ,"sb_10000", ""	,"SurgeBlog", "SurgeBlog",  0, 10000,670,402,268,0
	 ,"sb_100000", ""	,"SurgeBlog", "SurgeBlog",  0, 100000,770,462,308,0
	 ,"sb_inf", ""	,"SurgeBlog", "SurgeBlog",  0, 0,870,522,348,0

	 ,"con_1", ""	,"Consulting", "Consulting",  0, 0,1,0,0,0
	 ,"con_300", ""	,"Consulting", "Consulting",  0, 0,300,0,0,0
	 ,"con_500", ""	,"Consulting", "Consulting",  0, 0,500,0,0,0
	 ,"con_1000", ""	,"Consulting", "Consulting",  0, 0,1000,0,0,0
	 ,"con_2000", ""	,"Consulting", "Consulting",  0, 0,2000,0,0,0
	 ,"con_3000", ""	,"Consulting", "Consulting",  0, 0,3000,0,0,0
	 ,"con_5000", ""	,"Consulting", "Consulting",  0, 0,5000,0,0,0
	 ,"con_10000", ""	,"Consulting", "Consulting",  0, 0,10000,0,0,0
	,NULL,NULL,NULL,0,0,0
};

int keylib_support(Product *x);
int keylib_avast(Product *x);
int keylib_avast_updates(int value);
int keylib_avast_paid(int paid);

typedef struct AKEY {int regid,regdate,host,prodid,flags,ulimit,reg_day1,reg_day2; } Akey;
int keylib_prodid(char *prod);
int keylib_activate_get(char *kfile,char *prod, char *regid, char *email, char *key, char *reason);
int keylib_setdebug(int x);
int keylib_recheck(char *prod, char *regid, char *reason);
int keylib_recheck_now(char *kfile, char *reason);
int keylib_regid(void);
int keylib_check_file(char *kfile, char *product, int *ulimit, char *reason);
int keylib_check_file2(char *kfile, char *product, int *ulimit, int *regdate2, char *reason);
int keylib_isok(char *reason);
int keylib_istemp(char *reason);
int keylib_expired(void);
int keylib_get_host(char *host);
int keylib_uncache(void);
time_t keylib_regdate(void);

int keylib_init(char *path,int prodid, int (*imsg_fn)(char *s,...));
int keylib_fail(void); 
int keylib_warning(void);
int keylib_nusers(void);
int keylib_isfreelicense(void);
time_t keylib_trial_expiredate(void);
int keylib_regid(void);
char *keylib_nice(char *product);
int keylib_imsg(int (*ximsg)(const char *arg,...));
char *keylib_encode(char *in, char *tmp);

int keylib_set_key(char *keystring);
int keylib_set_reg(int regid); /* Manually set by user, -2 = give me a new one anyway  */
int keylib_set_email(char *email); 
int keylib_from_file(char *kfile,char *key, char *prod, char *regid, char *email);

int keylib_get_reg(char *reason); /* Get local regid if exists */
char *keylib_get_email(char *email); 

int keylib_fetch_reg(char *reason); /* IF more than one offer list including 'new' one */
int keylib_fetch_key(char *reason); /* Try and fetch a key for this registration number */
Product *keylib_prod_find(char *prodcode);
char *keylib_regids(void);
int keylib_install(char *prod, char *email, char *regid, char *reason, char *newspass);
int keylib_pre_install(char *fname, char *email, char *regid, char *newspass);
int keylib_ask_install(char *fname, char *prod, char *dfltemail);

char *keylib_error(void);
char *keylib_hostname(void);
char *keylib_url_change(char *newspass);
int keylib_isvirus(void);
char *keylib_avast_url(void);

int keylib_store(char *kfile, char *key, char *email, char *product, char *reason);
char *keylib_nice(char *product);
int keylib_new(char *key, int regid, int prodid, int months, char *host, time_t xtime, int ulimit, int flags);
int keylib_check(char *key, int *ulimit, char *host, int nusers, int *regid, int *flags, char *product, char *reason);
char * keylib_ctime(time_t t, char *tmp);
int keylib_decode(char *key, Akey *k, time_t *reg_time, time_t *expire_time, int *badcrc);
void keylib_fromdate(Akey *k, time_t *t, int *months);
int keylib_todate(Akey *k, time_t t, int months);
int keylib_test(void);
int keylib_pack(Akey *k, unsigned char *keybin);
int keylib_unpack(unsigned char *keybin, Akey *k);
int keylib_cur_key(char *bf);
int keylib_byuser(char *name, int ulimit, char *code);

char *keylib_url(void);
char *keylib_url_always(void);
char *keylib_email(void);

char *keylib_bintohex(char *bin, int binlen, char *out, int outlen);
char *keylib_hextobin(char *s, int *xlen, unsigned char *bf);
int keylib_nibtobin(char *s);
int keylib_ulimit_encode(int n);
int keylib_ulimit_decode(int n);
int keylib_host(char *xhost);
char *keylib_url_encrypt(void);
unsigned int keylib_crc(unsigned char *xin,int len);



#ifdef IS_KEYLIB_C
#ifndef KEYLIB_INTERNAL
#include "tcplib.h"
#define kkk_hostname tcp_hostname
#define kkk_lookup tcp_lookup
#define kkk_init tcp_init
#define kkk_new tcp_new
#define kkk_noblock tcp_noblock
#define kkk_open tcp_open
#define kkk_error tcp_error
#define kkk_free tcp_free
#define kkk_wait_write tcp_wait_write
#define kkk_waitfor tcp_waitfor
#define kkk_printf tcp_printf
#define kkk_read tcp_read

#else

#include <stdarg.h>
#ifndef WIN32
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netdb.h>
#include <sys/time.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

#define socket_close close
#define socket_open open
#define socket_read read
#define socket_ioctl ioctl
#define socket_write write
#define NEED_BCOPY TRUE
#ifndef WIN32
#ifndef SOCKET
#define SOCKET short
#endif
#endif 
#ifndef INVALID_SOCKET
#define INVALID_SOCKET -1
#endif

#else /* Windows */

#include <winsock.h>
#define socket_close closesocket
#define socket_ioctl ioctlsocket
#define socket_read(s,b,l) recv(s,b,l,0)
#define socket_write(s,b,l) send(s,b,l,0)

#endif

#define socket_shutdown shutdown



typedef struct CHAN {
	SOCKET sk;/* the socket */
	int id; /* socket's id */
	int block; /* Last state of channel (blocking true or false) */
	int noblock;/*Set(ie call kkk_noblock)before opening socket to make nonblocking socket*/
	char *inbf;
	int maxinbf;
	int inupto;/*Number of characters that have been read from the start of the channel 
	             buffer(inbf). This must be incremented or the buffer space cannot be
				 reused*/
	int inlen;/*The total number of characters in the channel buffer (inbf)*/
	int canclose;/* A flag that the socket should not be closed */
	int xerrno;/* Error number associated with last socket call */
	int lclport;/* The prefered port for the socket to bind to(set using kkk_lclport)*/
	int write_timeout; /* timeout in milliseconds for kkk_printf */
	int read_timeout; /* timeout in milliseconds for readline functions */
	char *buffer;	/* output buffering kkk_set_buffer... */
	int buffer_len;
	int isbuffer; 
	char myname[100];
	char theirname[100];
	char erradd[200];
	struct CHAN *next;/* Link your channels and make a list if you're that way inclined*/
} Chan;


/*kkk_hostname: gets the name of the local host
  Arguements: host: buffer to read name into(upto 190 chars can be read)
  Return: pointer to the buffer. 
  Remarks:returns 127.0.0.1 if error in determining host name occurs       */
char *kkk_hostname(char *host);

/*kkk_init: initiates use of socket DLL, must be called before using other tcp functions
  Arguements: vemsg: function by which to output initialization error messages
  Return: none.
  Remarks: only required on WIN32                                          */
void kkk_init(int (*vemsg)( const char *format ,...));

/*kkk_new: allocates new CHAN structure for a channel
  Arguements: c: pointer to channel to allocate structure for (*c must == NULL)
  Return: none.
  Remarks: error messages encountered are output through emsg function      */
void kkk_new(Chan **c);

/*kkk_accept: accepts an incoming connection attempt on a channel
  Arguements: listen:a channel that has been placed in a listening state
			  newchan: pointer to a new channel(*newchan must == NULL) that the new
					   connection will be made to
  Return: 1 if new connection successfully setup
          0 otherwise ( error number is returned in c->xerrno)
  Remarks: incoming connection attempts to connect at channel 'listen'. If a connection
		   attempt is detected the new channel is created and returned as newchan.											
           This is a blocking call.                                           */
int kkk_accept(Chan *listen, Chan **newchan);

/*kkk_listen: creates a new channel and places it in a state where it is listening 
			  for an incoming connection.
  Arguements: cc: pointer to new channel(*cc must == NULL) to be set in listening state
		      port: port to listen on
			  bindin: unused
			  reuse: if non zero, allow socket to be bound to a local address that
			         is already in use
  Return: 1 if socket successfully created and placed in listening state
          0 otherwise                                        					*/
int kkk_listen(Chan **cc, int port, char *bindin, int reuse);

/*kkk_lasterror: gets the last socket error that occured
  Arguements: c: c->xerrno is set to the value of the last error
  Return: value of the last socket error that occured	
  Remarks: the other functions call this when an error occurs, it is not required to
           call this function directly                    					*/
int kkk_lasterror(Chan *c);

/*kkk_release: puts channel into state where it may be closed
  Arguement: c: channel to be put into closable state
  Return: 1 if channel successfully put into state where it may be closed
          0 otherwise														*/
int kkk_release(Chan *c);

/*kkk_free: closes a channel and frees memory associated with it
  Arguements: cc: pointer to channel to be freed
  Return: 0 if cc is an invalid channel or contains and invalid socket
          1 otherwise                                                       */
int kkk_free(Chan **cc);

/*kkk_write: sends data on a connected channel
  Arguements: c:channel to send data over
              s:a buffer containing the data to be sent
			  len:length of buffer containing data
  Return: the number of bytes sent.
          This may block if len exceeds out going buffer size              */
int kkk_write(Chan *c, char *s, int len);
int kkk_write_timed(Chan *c, char *s, int len, int msecs);

/*kkk_read: reads incoming data on a channel
  Arguements: c: channel to read data from
	          s: buffer to store data
			  len: maximum number of bytes to read
  Return: the number of bytes read  
  Remarks: By default this is a blocking call.								*/
int kkk_read(Chan *c, char *s, int len);

/*kkk_read_timed: puts a time limit on an attempt to read incoming data on a channel
  Arguements: c: channel to read data from
			  s: buffer to store data
			  len: maximum number of bytes to read
			  msecs: maximum number of milliseconds to wait before receiving data
  Return:  the number of bytes read
		   -2 if the function timed out								    	*/
int kkk_read_timed(Chan *c, char *s, int len, int msecs);
/*kkk_peek_line_timed: puts a time limit on an attempt to read incoming data on a channel
                       data can be reread from subsequent calls.
  Arguements: c: channel to read data from
			  s: buffer to store data
			  len: maximum number of bytes to read
			  msecs: maximum number of milliseconds to wait before receiving data
  Return:  the number of bytes read
		   -2 if the function timed out								    	*/
int kkk_peek_line_timed(Chan *c, char *s, int len, int msecs);

/*kkk_printf: sends data on a connected channel using same format as printf
  Arguements: c: channel to send data over
              arglist: printf arguements 
  Return: 1 if data successfully sent
          0 otherwise
  Remarks: errors are output through emsg.
           All kkk_printf's are logged using emsg if kkk_setdebug(TRUE) has been called */
int kkk_printf(Chan *c, char * arg_list, ...);

/*kkk_open: opens a connection to a remote machine
  Arguements: cc: pointer to channel structure to connect with
              hostname: name of machine to connect to
			  port: port number on remote machine to connect to
			  bindout: unused
  Return: 1 if valid channel created
          0 otherwise
  Remarks: errors are variously outputed using emsg or printf               */
int kkk_open(Chan *cc, char *hostname,  int port, char *bindout);

/*kkk_readline: reads upto the first newline encountered in incoming data on a channel
Arguements: c: the channel to read from
              out: a buffer to read data into(data is also read into channel buffer)
			  len: maximum number of characters to read into out buffer(less may be read 
				   if there is insufficient room in the channel buffer)
Return: 0 if a time out was encountered before receiving a new line(data read so far
            will be in channel buffer, but not in 'out' arguement).
          1 otherwise
Remarks: This is nonblocking, but time outs may be significant if no data is queued ie
           in the order of seconds.
           The actual newline char and any directly proceding cariage returns are removed*/
int kkk_readline(Chan *c, char *out, int len);

/*kkk_error: gets a text message detailing a socket error number
  Arguements: c:channel on which a socket error has occured
              bf: buffer to read error message into
  Return: a pointer to bf                                                               */
char *kkk_error(Chan *c, char *bf);

/*kkk_getip: gets ip address of the peer to which a channel is connected
  Arguements c: connected channel from which to get the peers ip from
             ipbf: buffer to store ip address
  Return: 1 if peer ip successfully determined
          0 otherwise
  Remarks: Errors outputed through emsg                                                  */
int kkk_getip(Chan *c, char *ipbf);

/*kkk_getports: get local and remote port through which a channel is connected
  Arguements: c: connected channel
              local: buffer to store local port
			  remote: buffer to store remote port
  Return: 0 if either of the ports could not be determined
          1 otherwise
  Remarks: Error messages output through emsg										     */
int kkk_getports(Chan *c, int *local, int *remote);

/*kkk_getport: get local port through which a channel is connected
  Arguements: c: connected channel
	          local: buffer to store local port number in
  Return: 0 if port could not be determined
          1 otherwise
  Remarks: Error messages output through emsg                                            */
int kkk_getport(Chan *c, int *local);

/*kkk_isopen: determines if a channel believes it is connected
  Arguements: c: the channel to be queried
  Return: 0 if channel has invalid socket or is NULL
          1 otherwise	                                                                 */
int kkk_isopen(Chan *c);

/*kkk_nodelay: switches on/off the tcp Nagle algorithm for a given channel
  Arguements: c: the channel
              x: 1 for on, 0 for off
  Return: 1 if Nagle algorithm successfully switched on or off
          0 otherwise
  Remarks: Nagle algorithm buffers incoming data if previous data is still in transit and 
           buffers out going data until a full packet can be sent.                        */
int kkk_nodelay(Chan *c, int x);

/*kkk_getmyip: gets local ip of a channel
  Arguements: c: connected channel to get ip of
              ipbf: buffer to store ip
  Return: 1 if ip successfully determined
          0 otherwise   
  Remarks: errors outputed via emsg                                                      */
int kkk_getmyip(Chan *c, char *ipbf);

/*kkk_waitfor: wait a given length of time or until their is data queued on a socket for reading
  Arguements: sk: socket to wait on
              msec: number of millseconds to wait before timing out
  Return: 0 if times out
          1 if their is data queued to be read                                           */
int kkk_waitfor(Chan *c, int msec);

/*kkk_printf_nolog: sends data on a connected channel using same format as printf
  Arguements: c: channel to send data over
              arglist: printf arguements 
  Return: 1 if data successfully sent
          0 otherwise
  Remarks: errors are output through emsg.                                               */
int kkk_printf_nolog(Chan *c, char * arg_list, ...);

/*kkk_wait_write: waits for a channel to enter a writeable state
  Arguements: c: a connected channel
              msec: number of milliseconds to wait
  Return: 1 if check was successful
          0 if check failed or time out occured                                           */
int kkk_wait_write(Chan *c, int msec);

/*kkk_noblock: if called before openning channel, will create a non-blocking channel
  Arguements: c: the channel
  Return: 1 if channel successfully set to nonblocking
          0 otherwise                                                                     */
int kkk_noblock(Chan *c);

/*kkk_lookup: find ip address of a domain name
  Arguements: s: domain name(may contain port in name:port format)
              ip: buffer to return ip address in
  Return: 1 if ip successfully determined
          0 otherwise                                                                     */
int kkk_lookup(char *s, char *ip);

/*kkk_setdebug: adds extra debug functionality to tcp functions
  Arguements: x: 1 for debug on, 0 for off                                                */
void kkk_setdebug(int x);

/*kkk_setlclport: sets the desired port a channel should use
  Arguements: c: the channel
              x: port number
  Return: 1 if lclport successfully set
          0 otherwise	                                                                  */
int kkk_setlclport(Chan *c, int x);
int kkk_getname(char *ipnumber, char *ipname);
int kkk_open_reuse(Chan *cc, char *hostname,  int port, char *bindout);
void kkk_setlinger(Chan *c, int xon, int hunds);
int kkk_setblock(Chan *c, int t);
int kkk_handle_count(void);
int kkk_ssl_server(Chan *c, char *reason);
int kkk_waitfor(Chan *c, int msec);
int kkk_ssl_init(Chan *c, int isserver, Chan *inherit, char *reason);
int kkk_ssl_cmp(Chan *a, Chan *b);
int kkk_ssl_setkey(char *pk, char *keyfile);
char *kkk_read_dot(Chan *c, int *len, int *isend, int *isnulls, int secs, int isstart);
int kkk_readbf(Chan *c, int msec, int max);
int kkk_close_nice(Chan *c);
int kkk_wouldblock(Chan *c);
int kkk_check_open(Chan *c);
int kkk_not_connected(Chan *c);

int kkk_buffer_add(Chan *c, char *bf, int len);
void kkk_buffer_flush(Chan *c);
void kkk_buffer_set(Chan *c, int x);

int kkk_waitfor_list(Chan *first, int msec);
int kkk_set_read_timeout(Chan *c, int msec);
void kkk_init_dmsg(int (*vemsg)( const char *format ,...));

/* For reading long command lines, free vout using kkk_readline_free, max can
safely be a silly number, it's a limit not a preallocated amount */
int kkk_readline_big(Chan *c, char **vout, int max);
int kkk_readline_free(char *out);
#endif
#endif
#ifdef __cplusplus
}
#endif
#endif
