/* 
 * Copyright (C) 2007  Martin J. Muench <mjm@codito.de>
 *
 * Some small hacked wrapper functions
 */

#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <ctype.h>
#include <errno.h>

#include "wrap.h"
#include "debug.h"

/* malloc() wrapper */
void *Malloc(size_t size) {
  void *buffer;

  buffer = malloc(size);

  if(buffer == NULL) {
    fprintf(stderr, "malloc() failed: %s\n", strerror(errno));
    exit(EXIT_FAILURE);
  }

  memset(buffer, 0, size);

  return(buffer);
}

/* realloc() wrapper */
void *Realloc(void *buffer, size_t size) {

  buffer = realloc(buffer, size);

  if(buffer == NULL) {
    fprintf(stderr, "realloc() failed: %s\n", strerror(errno));
    exit(EXIT_FAILURE);
  }

  return(buffer);
}

/* convert string to array */
char **stringtoarray(char *string, char delimiter, int *size)
{
  char **array = NULL;
  char *ptr, *oldptr;
  int flag = 1;
  int count;

  *size = 0;
  ptr = string;

  for(count=0 ; flag ; count++) {
    for (oldptr=ptr;*ptr&&*ptr!=delimiter;*ptr++)
      ;
    if (!*ptr) flag = 0;
    *ptr++ = 0x00;
    (*size)++;

    array = realloc(array, (count+1)*sizeof(char *));
    array[count] = strdup(oldptr);
  }
  return array;
}

/* read input from stdin */
void get_string_input(char *outbuf, size_t outbuf_len, const char *fmt, ...)
{
  char msg[128];
  va_list ap;

  memset(msg, 0, sizeof(msg));
  va_start(ap, fmt);
  vsnprintf(msg, sizeof(msg)-1, fmt, ap);
  va_end(ap);

  do {
    printf("%s", msg);
    fflush(stdout);
  } while(!fgets(outbuf, outbuf_len, stdin));

  /* Remove newline */
  if(outbuf[strlen(outbuf)-1] == 0x0d)
    outbuf[strlen(outbuf)-1] = 0x00;

  return;
}

/* check whether buffer contains binary characters */
int is_binary(const unsigned char *buffer, size_t len) {
    int i;

    for(i = 0; i < len ; i++) {
	if(!isascii(buffer[i]))
	    return 1;
    }

    return 0;
}

/* init bin 2 hex table */
void init_bin2hex(char bin2hex_table[256][2])
{
    unsigned i=0;

    for(i=0;i<256;i++) {
	bin2hex_table[i][0] = ( ((i >> 4) & 0x0F) <= 0x09) ? (((i >> 4) & 0x0F) + '0') : (((i >> 4) & 0x0F) + 'a' - 10);
	bin2hex_table[i][1] = ( ((i)      & 0x0F) <= 0x09) ? (((i)      & 0x0F) + '0') : (((i)      & 0x0F) + 'a' - 10);
    }

    return;
}

/* convert bin to hex */
void bin_to_hex(char bin2hex_table[256][2],
		const unsigned char *bin_buffer,
		size_t bin_buffer_size,
		char * hex_buffer,
		size_t hex_buffer_size)
{
    unsigned i;

    for(i=0;i<bin_buffer_size; ++i) {
	hex_buffer[i*2  ] = bin2hex_table[bin_buffer[i]][0];
	hex_buffer[i*2+1] = bin2hex_table[bin_buffer[i]][1];
    }

    hex_buffer[bin_buffer_size*2] = 0x00;

    return;
}

/* write login data struct to dump file */
void write_login_data(login_t *data, const char *file)
{
    FILE *lfile;

    debug(("write_login_data() %s", file));

    if((lfile = fopen(file, "a")) == NULL) {
	fprintf(stderr, "* Cannot open dump file: %s\n", strerror(errno));
	return;
    }

    fprintf(lfile, "%s\"%s\"%s\"%s\"%s\"%s\"%s\"%s\"%s\"%s\"%s\"%s\n",
	    data->server,
	    data->client,
	    data->user,
	    data->realm,
	    data->method,
	    data->uri,
	    data->nonce,
            data->cnonce,
            data->nonce_count,
            data->qop,
	    data->algorithm,
	    data->hash);

    fclose(lfile);

    debug(("write_login_data() done"));

    return;
}

/* Update line in dump file with password */
void update_login_data(login_t *data, const char *pw, const char *file) {
  FILE *login_file, *temp_file;
  char buffer[1024], orig_string[1024];
  char *tempfile;
  size_t tempfile_len;

  debug(("update_login_data(): %s", file));

  tempfile_len = (strlen(file) + strlen(".tmp") + 1);
  tempfile     = (char *)Malloc(tempfile_len);

  snprintf(tempfile, tempfile_len, "%s.tmp", file);

  if((login_file = fopen(file, "r")) == NULL) {
    fprintf(stderr, "* Cannot open dump file: %s\n", strerror(errno));
    free(tempfile);
    return;
  }

  if((temp_file = fopen(tempfile, "w")) == NULL) {
    fprintf(stderr, "* Cannot open temp file: %s\n", strerror(errno));
    fclose(login_file);
    free(tempfile);
    return;
  }

  snprintf(orig_string, sizeof(orig_string), "%s\"%s\"%s\"%s\"%s\"%s\"%s\"%s\"%s\"%s\"%s\"%s\n",
           data->server,
           data->client,
           data->user,
           data->realm,
           data->method,
           data->uri,
           data->nonce,
           data->cnonce,
           data->nonce_count,
           data->qop,
           data->algorithm,
           data->hash);

  while((fgets(buffer, sizeof(buffer), login_file)) != NULL) {
    if(!strncmp(buffer, orig_string, sizeof(buffer))) {
      fprintf(temp_file, "%s\"%s\"%s\"%s\"%s\"%s\"%s\"%s\"%s\"%s\"%s\"%s\n",
	      data->server,
	      data->client,
	      data->user,
	      data->realm,
	      data->method,
	      data->uri,
	      data->nonce,
              data->cnonce,
              data->nonce_count,
              data->qop,
	      "PLAIN",
	      pw);
    }
    else {
      fprintf(temp_file, "%s", buffer);
    }
  }

  fclose(login_file);
  fclose(temp_file);

  /* rename */
  if(rename(tempfile, file) < 0) {
    fprintf(stderr, "* Cannot rename tempfile to dump file: %s\n", strerror(errno));
    free(tempfile);
    return;
  }

  free(tempfile);

  debug(("update_login_data() done"));
}

/* find value in buffer */
int find_value(const char *value, const char *buffer, char *outbuf, size_t outbuf_len)
{
    char *ptr1, *tempbuf;
    int i, b;

    /* debug(("find_value() %s", value)); */

    ptr1 = strstr(buffer, value);
    if(ptr1 == NULL) return -1;
    ptr1 += strlen(value);

    b = strlen(ptr1);
    tempbuf = Malloc(b + 1);

    /* value is quoted */
    if(ptr1[0] == '"') {
	for(i = 1 ; i < b ; i++) {
	    ptr1++;
	    if(ptr1[0] == '"') break;
	    tempbuf[i-1]=ptr1[0];
	}
    }
    /* copy till ',', '\r' or '\n' */
    else {
	for(i = 0 ; i < b ; i++) {
	  if(ptr1[0] == ',' || ptr1[0] == 0x0d || ptr1[0] == 0x0a) break;
	  tempbuf[i]=ptr1[0];
	  ptr1++;
	}
    }

    memset(outbuf, 0, sizeof(outbuf));
    strncpy(outbuf, tempbuf, outbuf_len - 1);
    free(tempbuf);

    debug(("find_value: %s'%s'", value, outbuf)); 
    
    return 0;
}

void Toupper(char *buffer, size_t buffer_len)
{
  int i;

  for(i = 0 ; i < buffer_len ; i++)
    buffer[i] = toupper(buffer[i]);

  return;
}

void extract_method(char *out, const char *in, size_t out_len) 
{
  int i;

  debug(("extract_method() begin"));

  for(i = 0 ; i < out_len ; i++) {
    if(in[i] == ' ') break;
    out[i] = in[i];
  }

  out[i]=0x00;

  debug(("extract_method(): %s", out));

  return;
}
