/*
 	util.c
 
 	Auxiliar functions of 'sks' project
 	
	Copyright (C) 2004-2007  Manuel Pancorbo Castro

	This program 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.

	This program 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 this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

	Manuel Pancorbo Castro <mpancorbo@gmail.com>
 
*/


#include <unistd.h>

#include "mycrypt.h"
#include "binasc.h"
#include "sks.h"


#ifdef LINUX
#define ECHO_OFF    "stty -echo"
#define ECHO_ON     "stty echo"

#elif defined WIN32
#include "conio.h"
/*#define ECHO_OFF    "echo off"
#define ECHO_ON     "echo on"*/
#else
#error "WIN32 or LINUX must be defined"
#endif


void burn_stack(unsigned long len)
{
   unsigned char buf[32];
   zeromem(buf, sizeof(buf));
   if (len > (unsigned long)sizeof(buf))
      burn_stack(len - sizeof(buf));
}

ERROR get_text(FILE *inp, char *frase, const char *msg)
{
	char last;
	
	assert((inp != NULL) && (frase != NULL));
	
	if(inp == stdin){
		fputs(msg, stderr);
		fgets(frase, PASSWD_SIZE, inp);
#if 0
		fputs("\n", stderr);
#endif
	}
	else{
		fgets(frase, PASSWD_SIZE, inp);
	}
	last = frase[strlen(frase)-1];
	if((last == '\n') || last == '\r')	frase[strlen(frase)-1] = 0;
	last = frase[strlen(frase)-1];
	if((last == '\n') || last == '\r')	frase[strlen(frase)-1] = 0;

    return 0;    
}

#ifdef WIN32	
ERROR get_secret_text(char *pass, int n, const char *msg)
{
	int i, x;
	
	_cputs(msg);
	for(i = 0; i < n; ++i){
		x = (_getch() & 0xff);
		if ( (x == '\n') || (x == '\r')){
			pass[i] = 0;
			break;
		}
		if(x == '\b'){
			_putch(x);
			_putch(' ');
			_putch(x);
			i--;
			i = (i < 0)? 0: i;
			pass[i--] = 0;
			/*_getch();*/
		}
		else{
			pass[i] = (x & 0xff);
			_putch( '*' );
		}
	}
	_putch( '\n' );
	return 0;
}

#endif

ERROR get_privkey(FILE *inp,  PrivKey p, const char *msg)
{

	char frase[PASSWD_SIZE];
	ERROR err;

	memset(frase, 0, PASSWD_SIZE);
#ifdef LINUX

	system(ECHO_OFF);
	if((err = get_text(inp, frase, msg))) return err;
	system(ECHO_ON);
	fputs("\n", stderr);
	
#elif defined WIN32
	get_secret_text(frase, PASSWD_SIZE, msg);
	
#endif
	
	if((err = hash_password( frase, p))) return err;
	memset(frase, 0, PASSWD_SIZE);

	return 0;
}

void write_longint(FILE *ptr, unsigned long int x, int binmode)
/**		In UTF-like stile: data are input in 7-bit chunks; 8th bit
		shows if more data should be read **/	
{
	int out, base = 1 << 7;
	while(1){
		out = x % base;
		x /= base;
		if(x) {fputcPlus(out | 0x80, ptr, binmode);}
		else{
			fputcPlus(out, ptr, binmode);
			return;
		}
	}
}

int read_longint(FILE *ptr, unsigned long int *x, int binmode)
{
	int i = 0 ;
	unsigned char c;
	
	*x = 0;
	while(1){
		freadPlus(&c, 1, 1, ptr, binmode);
		*x += ((unsigned long int) (c & 0x7f)) << 7*i;
		++i;
		if(!(c & 0x80)) break;
		
	}
	
	return i;
}

ERROR write_signature(FILE *ptr, sgPair *sig)
{
	
	int  binmode = 0;

	fwritePlus(sig->r, 1, KEY_SIZE, ptr, binmode);
	fwritePlus(sig->s, 1, KEY_SIZE, ptr, binmode);
	
	if(!binmode) flushArmour(ptr);
	
	return 0;
}

ERROR read_signature(FILE *ptr, sgPair *sig, int binmode)
{
	if(freadPlus(sig->r, 1, KEY_SIZE, ptr, binmode) != KEY_SIZE)
		return -1;
	
	if(freadPlus(sig->s, 1, KEY_SIZE, ptr, binmode) != KEY_SIZE)
		return -1;
	
	if(!binmode) burnBinasc();
	return 0;
}


int position(FILE  * f_inp, /*FILE *f_out,*/ const char *pattern) /* scan ascii file for pattern */
{
  while(!feof(f_inp))
  {
      char buffer[SMALL_BUF];
      fgets(buffer, SMALL_BUF, f_inp);
      if(!strncasecmp(buffer, pattern, strlen(pattern))) break;
	  /*if(f_out != NULL){
	  	fputs(buffer, f_out);
		fputc('\n', f_out);
	}*/
  }
  if(feof(f_inp))
  {

    return -1;
  }
  return 0;
}

int str_match(char *s1, char *s2)
/** Looks for matching substring in main string **/
/** Returns 1 if match and 0 if not **/
{
	int i, s1_len, s2_len, main_len, sub_len;
	char *main_str, *sub_str;

	s1_len = strlen(s1);
	s2_len = strlen(s2);

	if(s1_len == s2_len)
		return !strcasecmp(s1, s2);
	else if(s1_len > s2_len){
		main_str = s1;
		sub_str = s2;
		main_len = s1_len;
		sub_len = s2_len;
	}
	else /*if(s2__len > s1_len)*/{
		main_str = s2;
		sub_str = s1;
		main_len = s2_len;
		sub_len = s1_len;
	}

	for(i = 0; i <= main_len - sub_len; ++i){
		if(!strncasecmp(main_str + i, sub_str, sub_len))
			return 1;
	}
	return 0;
}

ERROR
fputs_base36(PubKey a, FILE *out)
{
	vl_number b;
	PubKey hsh;
	int i = 0;
	char buf[40], x, *p;
		
	hash_binary(hsh, a, GF_SIZE);
//	vlOpen(b); 
	gfZero(b);
	vlUnpack(b, hsh);
	gf_toradix(b, buf, 36);
	p = buf + strlen(buf) - 30;
	for(i = 0; i < 30; ++i){
		if( (x = p[i]) == 'O') {fputc('o', out);}
		else {fputc(x, out);}
		if( !((i+1) % 5) ) fputc(' ', out);
	}
	vlClear(b); 
	return 0;
}

int char_set_conversion = 0;

void test_charset()
{
	#ifdef LINUX
	#include <unistd.h>
 	char_set_conversion = !str_match(getenv("LANG"), "UTF-8");
//	char_set_conversion = 0;
	#else
	char_set_conversion = 1;
	#endif
	/*fprintf(stderr, "Consersión: %d\n", char_set_conversion);*/
}

static char dest[1024];
 
char * utf8_to_latin1( char *source)
{
 	assert(source != NULL);
	if(!char_set_conversion) return source;
 	int i, j, in, out, len;
	#ifdef WIN32
	unsigned char lat1[] = {225, 233, 237, 243, 250, 252, 241, 231, 193, 
		201, 205, 211, 218, 220, 209, 199, 161, 191};
	unsigned char oem[] =  {160, 130, 161, 162, 163, 129, 164, 135, 181,
		144, 214, 224, 233, 154, 165, 128, 173, 168,   32};
	#endif
	
	len = strlen(source);
	memset(dest, 0, len + 1);
	for(i = j =0; i < len; ++i){
		if((in = source[i]) >= 0x80){
			out = (in & 0x1F);
			if(((in & 0xE0) != 0xC0) || (out > 3)){
				fprintf(stderr, "No válido: c1 = 0x%02x\n", in);
				continue;
			}
			in = source[++i];
			if(((in & 0xC0) != 0x80)){
				fprintf(stderr, "No válido: c2 = 0x%02x\n", in);
				continue;
			}
			out <<= 6;
			out += in & 0x3f;
			#ifdef WIN32
			/*** CP851 transform ***/
			int k;
			for(k = 0; k< sizeof(lat1); ++k)
				if(out == lat1[k]) break;
			out = oem[k];
			#endif
		}
		else out = in;
		
		dest[j++] = out;
		if(!out) break;
	}
	
	return dest;
}

