/* aide, Advanced Intrusion Detection Environment
 *
 * Copyright (C) 1999 Rami Lehti
 *
 * 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
 */
 

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include "db.h"
#include "db_file.h"
#include "db_config.h"
#include "report.h"
#include "be.h"

#ifdef WITH_MHASH
#include <mhash.h>
#endif

#include "base64.h"
#include "util.h"
#include "aide.h"

db_line* db_char2line(char** ss,db_config* conf);
long readint(char* s,char* err);
long readoct(char* s,char* err);

time_t base64totime_t(char*);
int db_init(db_config* conf,int inout)
{
  
  error(200,"db_init %i\n",inout);

  if(inout==1){
    conf->db_in=be_init(1,conf->db_in_url);
    if(conf->db_in==NULL) {
      return RETFAIL;
    }
    return RETOK;
  }
  if(inout==0){
    conf->db_out=be_init(0,conf->db_out_url);
    if(conf->db_out==NULL){
      error(200,"db_out is null\n");
      return RETFAIL;
    }
    error(200,"db_out is nonnull %s\n",conf->db_out_url->value);
    return RETOK;
  }
  return RETFAIL;
}

db_line* db_readline(db_config* conf){
  db_line* s=NULL;
  int i=0;

  switch (conf->db_in_url->type) {
  case url_stdin:
  case url_fd:
  case url_file: {
    /* Should set errno */
    /* Please FIXME */
    if (conf->db_in!=NULL) {
      char** ss=db_readline_file(conf);
      if (ss!=NULL){
	s=db_char2line(ss,conf);

	for(i=0;i<conf->db_in_size;i++){
	  if(ss[conf->db_in_order[i]]!=NULL){
	    free(ss[conf->db_in_order[i]]);
	    ss[conf->db_in_order[i]]=NULL;
	  }
	}
	free(ss);
	
      }
    }
      
    break;
  }
  default : {
    error(0,"db_readline():Url-type backend not implemented\n");
    return NULL;
  }
  }
  
  return s;
  
}

byte* base64tobyte(char* src,int len)
{
  if(strcmp(src,"0")!=0){
    return decode_base64(src,len);
  }
  return NULL;
}


db_line* db_char2line(char** ss,db_config* conf){

  int i;
  db_line* line=(db_line*)malloc(sizeof(db_line)*1);

  line->md5=NULL;
  line->sha1=NULL;
  line->rmd160=NULL;
  line->tiger=NULL;
#ifdef WITH_MHASH
  line->crc32=NULL;
  line->crc32b=NULL;
  line->haval=NULL;
  line->rmd128=NULL;
  line->snefru=NULL;
  line->gost=NULL;
#endif
  line->perm=0;
  line->uid=0;
  line->gid=0;
  line->atime=0;
  line->ctime=0;
  line->mtime=0;
  line->inode=0;
  line->nlink=0;
  line->bcount=0;
  line->size=0;
  line->filename=NULL;
  line->attr=0;

  for(i=0;i<conf->db_in_size;i++){
    switch (conf->db_in_order[i]) {
    case db_filename : {
      if(ss[conf->db_in_order[i]]!=NULL){
	decode_string(ss[conf->db_in_order[i]]);
	line->filename=strdup(ss[conf->db_in_order[i]]);
      } else {
	error(0,"db_char2line():Error while reading database\n");
	abort();
      }
      break;
    }
    case db_mtime : {
      line->mtime=base64totime_t(ss[conf->db_in_order[i]]);
      break;
    }
    case db_bcount : {
      line->bcount=readint(ss[conf->db_in_order[i]],"bcount");
      break;
    }
    case db_atime : {
      line->atime=base64totime_t(ss[conf->db_in_order[i]]);
      break;
    }
    case db_ctime : {
      line->ctime=base64totime_t(ss[conf->db_in_order[i]]);
      break;
    }
    case db_inode : {
      line->inode=readint(ss[conf->db_in_order[i]],"inode");
      break;
    }

    case db_uid : {
      line->uid=readint(ss[conf->db_in_order[i]],"uid");
      break;
    }
    case db_gid : {
      line->gid=readint(ss[conf->db_in_order[i]],"gid");
      break;
    }
    case db_size : {
      line->size=readint(ss[conf->db_in_order[i]],"size");
      break;
    }
    case db_md5 : {
      line->md5=base64tobyte(ss[conf->db_in_order[i]],
			     strlen(ss[conf->db_in_order[i]]));
      break;
    }
    case db_sha1 : {
      line->sha1=base64tobyte(ss[conf->db_in_order[i]],
			      strlen(ss[conf->db_in_order[i]]));
      break;
    }
    case db_rmd160 : {
      line->rmd160=base64tobyte(ss[conf->db_in_order[i]],
				strlen(ss[conf->db_in_order[i]]));
      break;
    }
    case db_tiger : {
      line->tiger=base64tobyte(ss[conf->db_in_order[i]],
			       strlen(ss[conf->db_in_order[i]]));
      break;
    }
#ifdef WITH_MHASH
    case db_crc32 : {
      line->crc32=base64tobyte(ss[conf->db_in_order[i]],
			       strlen(ss[conf->db_in_order[i]]));
      break;
    }
    case db_gost : {
      line->gost=base64tobyte(ss[conf->db_in_order[i]],
			       strlen(ss[conf->db_in_order[i]]));
      break;
    }
    case db_haval : {
      line->haval=base64tobyte(ss[conf->db_in_order[i]],
			       strlen(ss[conf->db_in_order[i]]));
      break;
    }
    case db_rmd128 : {
      line->rmd128=base64tobyte(ss[conf->db_in_order[i]],
			       strlen(ss[conf->db_in_order[i]]));
      break;
    }
    case db_snefru : {
      line->snefru=base64tobyte(ss[conf->db_in_order[i]],
			       strlen(ss[conf->db_in_order[i]]));
      break;
    }
    case db_crc32b : {
      line->crc32b=base64tobyte(ss[conf->db_in_order[i]],
			       strlen(ss[conf->db_in_order[i]]));
      break;
    }
#endif
    case db_perm : {
      line->perm=readoct(ss[conf->db_in_order[i]],"permissions");
      break;
    }
    
    case db_lnkcount : {
      line->nlink=readint(ss[conf->db_in_order[i]],"nlink");
      break;
    }
    
    default : {
      error(0,"Not implemented in db_char2line %i \n",conf->db_in_order[i]);
      return NULL;
    }
    
    }
    
  }

  return line;
}

time_t base64totime_t(char* s){
  
  byte* b=decode_base64(s,strlen(s));
  char* endp;
  
  if (b==NULL||strcmp(s,"0")==0) {
    
    /* Should we print error here? */
    free(b);
    
    return 0;
  } else {
    time_t t = strtol(b,&endp,10);
    
    if (endp[0]!='\0') {
      error(0,"Error converting base64\n");
      free(b);
      return 0;
    }
    free(b);
    return t;
  }
  
  
}

long readint(char* s,char* err){
  long i;
  char* e;
  i=strtol(s,&e,10);
  if (e[0]!='\0') {
    error(0,"Could not read %s from database",err);
  }
  return i;
}

long readoct(char* s,char* err){
  long i;
  char* e;
  i=strtol(s,&e,8);
  if (e[0]!='\0') {
    error(0,"Could not read %s from database. String %s \n",err,s);
  }
  return i;
}


int db_writespec(db_config* conf)
{
  switch (conf->db_out_url->type) {
  case url_stdout:
  case url_stderr:
  case url_fd:
  case url_file: {
    if(conf->db_out!=NULL){
      if(db_writespec_file(conf)==RETOK){
	return RETOK;
      }
    }
    break;
  }
  default:{
    error(0,"Unknown output in db out.\n");    
    return RETFAIL;
  }
  }
  return RETFAIL;
}


int db_writeline(db_line* line,db_config* conf){

  if (line==NULL||conf==NULL) return 0;
  
  switch (conf->db_out_url->type) {
  case url_stdout:
  case url_stderr:
  case url_fd:
  case url_file: {
    if (conf->db_out!=NULL) {
      if (db_writeline_file(line,conf)==RETOK) {
	return RETOK;
      }
    };
    return RETFAIL;
    break;
  }
  default : {
    error(0,"Unknown output in db out.\n");    
    return RETFAIL;
  } 
  }
  
  
  return RETFAIL;
}

/* Please FIXME */
int db_close(db_config* conf)
{
  return RETFAIL;
}
