#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include "lprintf.h"
typedef unsigned char uuchar;
char *new_make(int months, int users, int flags, char *host);
int new_test(char *k, char *host, int *users, int *flags, char *expires);
int db_rcheck(char *kin, char *host, int *users, int *flags, char *expires);
int new_hash_upr(char *x, int flags);
int new_hash_lwr2(char *x, int flags);
int new_hash(char *x, int flags);
int new_crc(unsigned char *x, int len);
char *strtobin(char *s, int *xlen);
char *bintostr(char *s, int len);
int hextobin(char *s);
void swap_nibs(char *s, int len);
void swap_nib(char *bb1, char *bb2);
int new_hash_lwr(char *x, int flags);

#ifndef TRUE
#define FALSE 0
#define TRUE (!FALSE)
#endif
#ifdef TEST
void main()
{
 	char name[100];
	char month[100],users[100];
	char tmp[200],ex[200];
	int u;

again:
	printf("Enter Host "); gets(name);
	printf("Enter Months "); gets(month);
	printf("Enter users "); gets(users);
	strcpy(tmp,new_make(atoi(month),atoi(users),2,name));
	printf("xxx {%s} \n",tmp);
	printf("Enter Name "); gets(name);
	if (new_test(tmp,name,&u,ex)) {
		printf("License matched\n");
	}
	printf("message {%s}\n",ex);
	goto again;
}
#endif

void long_to_char(int in, char *out)
{
 	*out++ = in & 255;
	in = in >> 8;
 	*out++ = in & 255;
}
int char_to_long(char *inn)
{
	unsigned char *in = (unsigned char *) inn;
	int r = 0;
	r = in[1];
	r = r << 8;
	r += in[0];
	return r;
}
char *new_make(int months, int users, int flags, char *host)
{
	char xxx[20];
	time_t t;
	struct tm *tt;
	static char rslt[200];

	time(&t);
	tt = localtime(&t);
	xxx[0] = (months) + (flags << 4);
	xxx[1] = users;
	xxx[2] = tt->tm_year;
	xxx[3] = tt->tm_mon;
	long_to_char(new_hash(host,flags),xxx+4);
	long_to_char(new_crc((unsigned char *) xxx,6),xxx+6);
	swap_nibs(xxx,8);
	strcpy(rslt,bintostr(xxx,8));
	return rslt;
}
#define xfail(xx) {isok = FALSE; strcpy(expires,xx);}				       
static char *months[]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
int new_test(char *kin, char *host, int *users, int *flags, char *expires)
{
 	int len;
 	char *k = strtobin(kin,&len);
 	int m,mon,year,xhost,xcrc,rcrc;
	int isok = TRUE;
	time_t t;
	struct tm *tt;
	static char rslt[200];

	strcpy(expires,"");
	swap_nibs(k,len);
	time(&t);
	tt = localtime(&t);
	m = k[0] & 15;
	*flags = (k[0] >> 4) & 15;
	*users = k[1];
	year = k[2];
	mon = k[3];
	xhost = char_to_long(k+4);
	xcrc = char_to_long(k+6);	
	rcrc = new_crc((unsigned char *) k,6);
	if (tt->tm_year < year) xfail("Futuristic Key Year");
	if (tt->tm_year == year) 
	  if (tt->tm_mon < mon) xfail("Futuristic Key Month");
	if (isok) if (m>0) {
		mon += m;
		if (mon>11) {year++; mon -= 11;}
		if (mon>0 && mon<12) lprintf(expires,200,"Temporary license expires after %s-%d",months[mon],year+1900);
		if (year < tt->tm_year) xfail("Key expired last year");
		if (year == tt->tm_year) 
		  if (mon < tt->tm_mon) xfail("Key expired last month");
	}
	if (xhost!=0) if (  (xhost != new_hash(host,*flags)) && (xhost != new_hash_lwr(host,*flags)) && (xhost != new_hash_upr(host,*flags)) && (xhost != new_hash_lwr2(host,*flags)) ) xfail("Key for wrong computer");
	if (xcrc != rcrc) xfail("Bad Bit Length");

	return isok;
}
char *strtobin(char *s, int *xlen)
{
	static unsigned char bf[200];
 	int i,len;
	unsigned char *out = bf;
	len = strlen(s);
	for (i=0;i<len;i+=2,s+=2) {
		*out++ = hextobin(s);	
	}
	*xlen = len/2;
	return (char *) bf;
}
char *bintostr(char *s, int len)
{
	static char bf[200];
	char tmp[200];
	int xlen;
	int i;
	strcpy(bf,"");
 	for (i=0; i<len; i++,s++) {
	 	lprintf(tmp,200-1,"%02x",(unsigned int) *s);
		xlen = strlen(tmp);
		if (xlen>=2) xlen -=2;
		strcat(bf,tmp+xlen);
	}
	return bf;	
}
int hextobin(char *s)
{
 	int t,i;
	if (isdigit(*s)) i = *s-'0';
	else i = *s-'a'+10;
	t = i*16; s++;
	if (isdigit(*s)) i = *s-'0';
	else i = *s-'a'+10;
	t += i;

	return t;
}
int new_hash_lwr(char *x, int flags)
{
	static char bf[800];
	strcpy(bf,x);
	strlwr(bf);
	return new_hash(bf,flags);
}
int new_hash_lwr2(char *x, int flags)
{
	static char bf[800];
	char *s;
	strcpy(bf,x);
	strlwr(bf);
	s = strchr(bf,':');
	if (s!=NULL) *s = 0;
	return new_hash(bf,flags);
}
int new_hash_upr(char *x, int flags)
{
	static char bf[800];
	char *s;
	strcpy(bf,x);
	strupr(bf);
	s = strchr(bf,':');
	if (s!=NULL) *s = 0;
	return new_hash(bf,flags);
}
int new_hash(char *x, int flags)
{
	char *s;
	int n;
	static char bf[400];
	if (strcmp(x,"*")==0) return 0;
       	strcpy(bf,x);
	s = strchr(bf,':');
	if (s!=NULL) {
		if (flags==9) *s = 0;
		else if (flags==8) *s = 0;
		else {
		  for (n=0;*s!=0;s++) {
		 	if (*s=='.') n++;
			if (n>=2) {*s=0; break;}
		  }
		}
	}
	return new_crc((unsigned char *) bf,strlen(bf));
}
int new_crc(unsigned char *x, int len)
{
	int crc=0;
	int i;
 	for (i=0; i<len; i++) {
	 	crc = (crc << 1) + x[i]*i;
		crc = crc % 32000;
	}
	return crc % 32000;
}
void swap_nibs(char *s, int len)
{
	int i;
	for (i=0; i<len; i+=2,s+=2) swap_nib(s,s+1);
}
void swap_nib(char *bb1, char *bb2) 
{
	char b1 = *bb1;
	char b2 = *bb2;
	*bb1 = (b1 & 0x55) | (b2 & 0xaa);
	*bb2 = (b2 & 0x55) | (b1 & 0xaa);
}

int db_rcheck(char *kin, char *host, int *users, int *flags, char *expires)
{
 	int len;
 	char *k = strtobin(kin,&len);
 	int m,mon,year,xhost,xcrc,rcrc;
	int isok = TRUE;
	time_t t;
	struct tm *tt;
	static char rslt[200];


	strcpy(expires,"");

	swap_nibs(k,len);
	time(&t);
	tt = localtime(&t);
	m = k[0] & 15;
	*flags = (k[0] >> 4) & 15;
	*users = k[1];
	year = k[2];
	mon = k[3];
	xhost = char_to_long(k+4);
	xcrc = char_to_long(k+6);	
	rcrc = new_crc((unsigned char *) k,6);
	if (tt->tm_year < year) xfail("Futuristic Key Year");
	if (tt->tm_year == year) 
	  if (tt->tm_mon < mon) xfail("Futuristic Key Month");
	if (m>0) {
	 	mon += m;
		if (mon>11) {year++; mon -= 11;}
		if (mon>0 && mon<12) lprintf(expires,200,"Temporary license expires after %s-%d",months[mon],year+1900);
		if (year < tt->tm_year) xfail("Key expired last year");
		if (year == tt->tm_year) 
		  if (mon < tt->tm_mon) xfail("Key expired last month");
	}
	if (xcrc != rcrc) xfail("Bad Bit Length");
	if (xhost!=0) if (  (xhost != new_hash(host,*flags)) && (xhost != new_hash_lwr(host,*flags)) && (xhost != new_hash_upr(host,*flags)) && (xhost != new_hash_lwr2(host,*flags)) ) xfail("Key for wrong computer");

	return isok;
}
