/**************************************************
OpengateM - MAC address authentication system 
   module for local work database (SQLite3)

Copyright (C) 2011 Opengate Project Team
Written by Yoshiaki Watanabe

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.

Email: watanaby@is.saga-u.ac.jp
**************************************************/
#include "opengatemmng.h"
#include <sqlite3.h>

static int sqliteBusyTimeout=100;  /* value used in sqite3_busy_timeout() */

/********************************************************************/
/* set static variable for sqlite-busy-timeout defined in conf file */
/********************************************************************/
int setupSqliteBusyTimeoutValue(void){

  char *str;
  
  /* if set in conf, use the value. if not, use the above default. */
  str=GetConfValue("SqliteBusyTimeout");
  if(str!=NULL) sqliteBusyTimeout=atoi(str);

  return sqliteBusyTimeout;
}

/**********************************************/
/* initialize work db implemented with sqlite */
/**********************************************/
int initWorkDb(void){
  char *pErrMsg=NULL;
  sqlite3 *db;

  char *createCmd1="CREATE TABLE IF NOT EXISTS maccheck "
    "(macAddress TEXT PRIMARY KEY, "
    "ipv4 TEXT DEFAULT '', ipv6 TEXT DEFAULT '', "
    " pid INTEGER DEFAULT 0, ruleIpv4 INTEGER DEFAULT 0, "
    " ruleIpv6 INTEGER DEFAULT 0, detectTime INTEGER DEFAULT 0)";

  char *createCmd2="CREATE TABLE IF NOT EXISTS cookietable "
    "(cookie TEXT PRIMARY KEY, "
    " saveTime INTEGER DEFAULT 0,"
    " userId TEXT DEFAULT '',"
    " extraId TEXT DEFAULT '',"
    " userType INTEGER DEFAULT 0,"
    " mailDefault TEXT DEFAULT '',"
    " macAddress TEXT DEFAULT '')";

  char *createCmd3="CREATE TABLE IF NOT EXISTS sessionmd "
    "(ipAddress TEXT PRIMARY KEY, "
    "userId TEXT, extraId TEXT, openTime INTEGER, checkTime INTEGER, "
    "macAddress TEXT, ruleNumber INTEGER)";

  char *createCmd4="CREATE TABLE IF NOT EXISTS macinfo "
    "(macAddress TEXT PRIMARY KEY ON CONFLICT REPLACE, "
    "detectTime INTEGER, ttl INTEGER, isNat INTEGER)";

  /* setup static variable value for SqLite3_busy_timeout from conf */
  SetupSqliteBusyTimeoutValue();

  /* Open sqlite for opengateMmng */
  if(sqlite3_open(GetConfValue("SqliteDbMmng"),&db)!=SQLITE_OK){
    err_msg("ERR at %s#%d: sqlite3_open",__FILE__,__LINE__);
    sqlite3_close(db);
    terminateProg(0);
  }
  sqlite3_busy_timeout(db, sqliteBusyTimeout);

  /* create table1 (maccheck table in opengateMmng) */
  if(sqlite3_exec(db, createCmd1, NULL, NULL, &pErrMsg)!=SQLITE_OK){
    err_msg("ERR at %s#%d: sqlite3_exec: %s",__FILE__,__LINE__,pErrMsg);
    terminateProg(0);
  }

  /* create table2 (cookietable in opengateMmng) */
  if(sqlite3_exec(db, createCmd2, NULL, NULL, &pErrMsg)!=SQLITE_OK){
    err_msg("ERR at %s#%d: sqlite3_exec: %s",__FILE__,__LINE__,pErrMsg);
    terminateProg(0);
  }

  /* close opengateMmng */
  sqlite3_close(db);

  /* Open sqlite for opengateMd */
  if(sqlite3_open(GetConfValue("SqliteDbMd"),&db)!=SQLITE_OK){
    err_msg("ERR at %s#%d: sqlite3_open",__FILE__,__LINE__);
    sqlite3_close(db);
    terminateProg(0);
  }
  sqlite3_busy_timeout(db, sqliteBusyTimeout);

  /* create table3 (sessionmd table in opengateMd) */
  if(sqlite3_exec(db, createCmd3, NULL, NULL, &pErrMsg)!=SQLITE_OK){
    err_msg("ERR at %s#%d: sqlite3_exec: %s",__FILE__,__LINE__,pErrMsg);
    terminateProg(0);
  }

  /* create table4 (macinfo table in opengateMd) */
  if(sqlite3_exec(db, createCmd4, NULL, NULL, &pErrMsg)!=SQLITE_OK){
    err_msg("ERR at %s#%d: sqlite3_exec: %s",__FILE__,__LINE__,pErrMsg);
    terminateProg(0);
  }

  /* close opengateMd */
  sqlite3_close(db);
  return TRUE;
}

/********************************************/
/* create temporary table for mac checking  */
/* (gather mac addresses from arp and ndp)  */
/********************************************/
int createMacCheckTableInWorkDb(void){

  char *pErrMsg=NULL;
  sqlite3 *db;

  char *delCmd="DELETE FROM maccheck";

  /* Open sqlite */
  if(sqlite3_open(GetConfValue("SqliteDbMmng"),&db)!=SQLITE_OK){
    err_msg("ERR at %s#%d: sqlite3_open",__FILE__,__LINE__);
    sqlite3_close(db);
    terminateProg(0);
  }
  sqlite3_busy_timeout(db, sqliteBusyTimeout);

  /* renew mac check table */
   if(sqlite3_exec(db, delCmd, NULL, NULL, &pErrMsg)!=SQLITE_OK){
     err_msg("ERR at %s#%d: sqlite3_exec: %s",__FILE__,__LINE__,pErrMsg);
     terminateProg(0);
   }

  /* get arp entry and add to mac check table */
  Initqueue();
  GetMacAddrListFromArp(GetConfValue("Device"));
  AddIpv4ToMacCheckTable();
  
  /* get ndp entry and add to mac check table */
  Initqueue();
  GetMacAddrListFromNdp(GetConfValue("Device"));
  AddIpv6ToMacCheckTable();
  Freequeue();

  sqlite3_close(db);
  return TRUE;
}

/********************************************************/
/* add mac-ipv4 pair to mac check table                 */
/* execute both of update and insert commands           */
/* because the mac address exists or not exist in table */
/********************************************************/
int addIpv4ToMacCheckTable(void){

  int rc;
  sqlite3 *db;
  char *pErrMsg=NULL;
  char macAddr[ADDRMAXLN];
  char ipAddr[ADDRMAXLN];
  char* serverAddr="";
  int detectTime=0;

  /* SQL COMMAND, where %x is replaced in snprintf */
  char *insertFormat="INSERT INTO maccheck "
    " (ipv4, macAddress, detectTime) values ('%s','%s', %d)";

  char *insertCmd;
  int resultFlag=TRUE;

  /* get server and remote client address */
  serverAddr=getenv("SERVER_ADDR");

  /* Open sqlite */
  if(sqlite3_open(GetConfValue("SqliteDbMmng"),&db)!=SQLITE_OK){
    err_msg("ERR at %s#%d: sqlite3_open",__FILE__,__LINE__);
    sqlite3_close(db);
    terminateProg(0);
  }
  sqlite3_busy_timeout(db, sqliteBusyTimeout);

  /* get queued items */
  while(Dequeue(macAddr, ipAddr)){

    /* if server addr (localhost addr), ignore */
    if(strcmp(serverAddr,ipAddr)==0)continue;

    /* get detect time from md.db */
    detectTime=GetDetectTimeFromMacinfoTable(macAddr);

     /* execute insert command */
    insertCmd=sqlite3_mprintf(insertFormat, ipAddr, macAddr, detectTime);
    if((rc=sqlite3_exec(db, insertCmd, NULL, NULL, &pErrMsg))!=SQLITE_OK){
      resultFlag=FALSE;
      err_msg("ERR at %s#%d: sqlite3_exec: %s",__FILE__,__LINE__,pErrMsg);
    }
    sqlite3_free(insertCmd);
  }
  sqlite3_close(db);
  return resultFlag;
}

/********************************************************/
/* add mac-ipv6 pair to mac check table                 */
/* execute both of update and insert commands           */
/* because the mac address exists or not exist in table */
/********************************************************/
int addIpv6ToMacCheckTable(void){

  int rc;
  sqlite3 *db;
  char *pErrMsg=NULL;
  char macAddr[ADDRMAXLN];
  char ipAddr[ADDRMAXLN];
  char* serverAddr="";
  int detectTime=0;

  /* get server and remote client address */
  serverAddr=getenv("SERVER_ADDR");

  /* SQL COMMAND, where %x is replaced in snprintf */
  char *updateFormat="UPDATE maccheck "
    " SET ipv6='%s',detectTime=%d where macAddress='%s'";
  char *insertFormat="INSERT INTO maccheck "
    " (ipv6, macAddress, detectTime) values ('%s','%s', %d)";

  char *updateCmd;
  char *insertCmd;
  int resultFlag=TRUE;

  /* Open sqlite */
  if(sqlite3_open(GetConfValue("SqliteDbMmng"),&db)!=SQLITE_OK){
    err_msg("ERR at %s#%d: sqlite3_open",__FILE__,__LINE__);
    sqlite3_close(db);
    terminateProg(0);
  }
  sqlite3_busy_timeout(db, sqliteBusyTimeout);

  /* get queued items */
  while(Dequeue(macAddr, ipAddr)){

    /* if server addr, ignore */
    if(strcmp(serverAddr,ipAddr)==0)continue;

    /* get detect time from md.db */
    detectTime=GetDetectTimeFromMacinfoTable(macAddr);

    /* execute update command */
    updateCmd=sqlite3_mprintf(updateFormat, ipAddr, detectTime, macAddr);
    if((rc=sqlite3_exec(db, updateCmd, NULL, NULL, &pErrMsg))!=SQLITE_OK){

      /* if failed, execute insert command */
      insertCmd=sqlite3_mprintf(insertFormat, ipAddr, macAddr, detectTime);
      if((rc=sqlite3_exec(db, insertCmd, NULL, NULL, &pErrMsg))!=SQLITE_OK){
	resultFlag=FALSE;
	err_msg("ERR at %s#%d: sqlite3_exec: %s",__FILE__,__LINE__,pErrMsg);
      }
      sqlite3_free(insertCmd);
    }
    sqlite3_free(updateCmd);
  }
  sqlite3_close(db);
  return resultFlag;
}


/***********************************************************************/
/* get maccheck table row                                              */
/* at first call, query is done and the first row is returned          */
/* and from second call, next row of previous query is returned        */
/* this function should be called continuously until false is returned */
/***********************************************************************/
int getNextRowInMacCheckTable(char* macAddress, char* ipv4, char* ipv6){

  static sqlite3_stmt *stmt=NULL;
  static sqlite3 *db;

  /* SQL SELECT COMMAND, where %x is replaced in snprintf */
  /* get info order by detecting time */
  char *selectCmd="SELECT macAddress,ipv4,ipv6 "
    " FROM maccheck order by detectTime desc ";
  int resultFlag=TRUE;

  /* set default */
  *macAddress='\0';
  *ipv4='\0';
  *ipv6='\0';

  /* execute at the first call of this func */
  /* from second call, query is not done and query result in first call is used */  
  if(stmt==NULL){

    /* Open sqlite */
    if(sqlite3_open(GetConfValue("SqliteDbMmng"),&db)!=SQLITE_OK){
      err_msg("ERR at %s#%d: sqlite3_open",__FILE__,__LINE__);
      sqlite3_close(db);
      terminateProg(0);
    }
    sqlite3_busy_timeout(db, sqliteBusyTimeout);

    /* compile to internal statement */
    if(sqlite3_prepare(db, selectCmd, BUFFMAXLN, &stmt, NULL)!=SQLITE_OK){
      resultFlag=FALSE;
      err_msg("ERR at %s#%d: sqlite3_prepare",__FILE__,__LINE__);
      
      /* finalize */
      sqlite3_finalize(stmt);
      sqlite3_close(db);
      terminateProg(0);
    }
  }

  /* get a record (the query result is held until next call of this func) */
  if(sqlite3_step(stmt)==SQLITE_ROW){
    strlcpy(macAddress, (char*)sqlite3_column_text(stmt, 0), ADDRMAXLN);
    strlcpy(ipv4, (char*)sqlite3_column_text(stmt, 1), ADDRMAXLN);
    strlcpy(ipv6, (char*)sqlite3_column_text(stmt, 2), ADDRMAXLN);
    resultFlag=TRUE;
  }
  
  /* if not get record, clear the query result and return false */
  else{
    sqlite3_finalize(stmt);
    sqlite3_close(db);
    resultFlag=FALSE;
  }

  return resultFlag;
}

/*******************************************************/
/* get info from db input=macAddress, output=ipv4,ipv6 */
/*******************************************************/
int getIpFromMacCheckTable(char* macAddress, char* ipv4, char* ipv6){

  sqlite3_stmt *stmt=NULL;
  sqlite3 *db;

  /* SQL SELECT COMMAND, where %x is replaced in snprintf */
  char* selectFormat="SELECT ipv4,ipv6 "
    " FROM maccheck where macAddress='%s'";
  int resultFlag=TRUE;
  char* selectCmd; 

  /* set default */
  *ipv4='\0';
  *ipv6='\0';

  /* Open sqlite */
  if(sqlite3_open(GetConfValue("SqliteDbMmng"),&db)!=SQLITE_OK){
    err_msg("ERR at %s#%d: sqlite3_open",__FILE__,__LINE__);
    sqlite3_close(db);
    terminateProg(0);
  }
  sqlite3_busy_timeout(db, sqliteBusyTimeout);

  /* prepare execute command */
  selectCmd=sqlite3_mprintf(selectFormat, macAddress);

  /* compile to internal statement */
  if(sqlite3_prepare(db, selectCmd, BUFFMAXLN, &stmt, NULL)!=SQLITE_OK){
    resultFlag=FALSE;
    err_msg("ERR at %s#%d: sqlite3_prepare",__FILE__,__LINE__);
    
    /* finalize */
    sqlite3_free(selectCmd);
    sqlite3_finalize(stmt);
    sqlite3_close(db);
    return FALSE;
  }

  /* get a record */
  if(sqlite3_step(stmt)==SQLITE_ROW){
    strlcpy(ipv4, (char*)sqlite3_column_text(stmt, 0), ADDRMAXLN);
    strlcpy(ipv6, (char*)sqlite3_column_text(stmt, 1), ADDRMAXLN);
    resultFlag=TRUE;
  }
  
  /* if not get record, return false */
  else{
    resultFlag=FALSE;
  }

  /* finalize */
  sqlite3_free(selectCmd);
  sqlite3_finalize(stmt);
  sqlite3_close(db);
  return resultFlag;
}

/*****************************************************/
/* get pid and rule number from maccheck table in db */
/* macAddress:(input),pid,ruleIpv4,ruleIpv6:(output) */
/*****************************************************/
int getPidFromMacCheckTable(char* macAddress, int* pid, int* ruleIpv4, int* ruleIpv6){
  sqlite3_stmt *stmt=NULL;
  sqlite3 *db;

  /* SQL SELECT COMMAND, where %x is replaced in snprintf */
  char* selectFormat="SELECT pid,ruleIpv4,ruleIpv6 "
    " FROM maccheck where macAddress='%s'";
  int resultFlag=TRUE;
  char* selectCmd; 

  /* set default */
  *pid=0;
  *ruleIpv4=0;
  *ruleIpv6=0;

  /* Open sqlite */
  if(sqlite3_open(GetConfValue("SqliteDbMmng"),&db)!=SQLITE_OK){
    err_msg("ERR at %s#%d: sqlite3_open",__FILE__,__LINE__);
    sqlite3_close(db);
    terminateProg(0);
  }
  sqlite3_busy_timeout(db, sqliteBusyTimeout);

  /* prepare execute command */
  selectCmd=sqlite3_mprintf(selectFormat, macAddress);

  /* compile to internal statement */
  if(sqlite3_prepare(db, selectCmd, BUFFMAXLN, &stmt, NULL)!=SQLITE_OK){
    resultFlag=FALSE;
    err_msg("ERR at %s#%d: sqlite3_prepare",__FILE__,__LINE__);
    
    /* finalize */
    sqlite3_free(selectCmd);
    sqlite3_finalize(stmt);
    sqlite3_close(db);
    return FALSE;
  }

  /* get a record */
  if(sqlite3_step(stmt)==SQLITE_ROW){
    *pid = (int)sqlite3_column_int(stmt, 0);
    *ruleIpv4 = (int)sqlite3_column_int(stmt, 1);
    *ruleIpv6 = (int)sqlite3_column_int(stmt, 2);
    resultFlag=TRUE;
  }
  
  /* if not get record, return false */
  else{
    resultFlag=FALSE;
  }

  /* finalize */
  sqlite3_free(selectCmd);
  sqlite3_finalize(stmt);
  sqlite3_close(db);
  return resultFlag;
}

/****************************************************/
/* save pid and rule number to maccheck table in db */
/****************************************************/
int savePidToMacCheckTable(char* macAddress, int pid, int ruleIpv4, int ruleIpv6){
  int rc;
  sqlite3 *db;
  char *pErrMsg=NULL;

  /* SQL COMMAND, where %x is replaced in snprintf */
  char *updateFormat="UPDATE maccheck "
    " SET pid=%d, ruleIpv4=%d, ruleIpv6=%d where macAddress='%s'";
  char *updateCmd;
  int resultFlag=TRUE;

  /* Open sqlite */
  if(sqlite3_open(GetConfValue("SqliteDbMmng"),&db)!=SQLITE_OK){
    err_msg("ERR at %s#%d: sqlite3_open",__FILE__,__LINE__);
    sqlite3_close(db);
    terminateProg(0);
  }
  sqlite3_busy_timeout(db, sqliteBusyTimeout);

  /* prepare execute update command */
  updateCmd=sqlite3_mprintf(updateFormat, pid,
			    ruleIpv4, ruleIpv6, macAddress);
  if((rc=sqlite3_exec(db, updateCmd, NULL, NULL, &pErrMsg))!=SQLITE_OK){
    resultFlag=FALSE;
    err_msg("ERR at %s#%d: sqlite3_exec: %s",__FILE__,__LINE__,pErrMsg);
  }

  /* finalize */
  sqlite3_free(updateCmd);
  sqlite3_close(db);
  return resultFlag;
}

/****************************************************/
/* get detect time of mac from macinfo table in db  */
/****************************************************/
int getDetectTimeFromMacinfoTable(char* macAddress){

  sqlite3_stmt *stmt=NULL;
  sqlite3 *db;
  int detectTime=0;

  /* SQL SELECT COMMAND, where %x is replaced in snprintf */
  char* selectFormat="SELECT detectTime "
    " FROM macinfo where macAddress='%s'";
  int resultFlag=TRUE;
  char* selectCmd; 

  /* Open sqlite */
  if(sqlite3_open(GetConfValue("SqliteDbMd"),&db)!=SQLITE_OK){
    err_msg("ERR at %s#%d: sqlite3_open",__FILE__,__LINE__);
    sqlite3_close(db);
    return 0;
  }
  sqlite3_busy_timeout(db, sqliteBusyTimeout);

  /* prepare execute command */
  selectCmd=sqlite3_mprintf(selectFormat, macAddress);

  /* compile to internal statement */
  if(sqlite3_prepare(db, selectCmd, BUFFMAXLN, &stmt, NULL)!=SQLITE_OK){
    resultFlag=FALSE;
    err_msg("ERR at %s#%d: sqlite3_prepare",__FILE__,__LINE__);
    
    /* finalize */
    sqlite3_free(selectCmd);
    sqlite3_finalize(stmt);
    sqlite3_close(db);
    return FALSE;
  }

  /* get a record */
  if(sqlite3_step(stmt)==SQLITE_ROW){
    detectTime = (int)sqlite3_column_int(stmt, 0);
  }

  /* finalize */
  sqlite3_free(selectCmd);
  sqlite3_finalize(stmt);
  sqlite3_close(db);
  return detectTime;
}

/*********************************************/
/* the cookie is found in db or not found    */
/* in: cookie, userType; out: userId,extraId */
/*********************************************/
int isCookieFoundInWorkDb(char* cookie, char* userId, char* extraId, int userType){
  sqlite3_stmt *stmt=NULL;
  sqlite3 *db;

  /* SQL SELECT COMMAND, where %x is replaced in snprintf */
  char* selectFormat="SELECT userId,extraId "
    " FROM cookietable WHERE cookie='%s' and userType=%d" ;
  int resultFlag=TRUE;
  char* selectCmd; 

  /* Open sqlite */
  if(sqlite3_open(GetConfValue("SqliteDbMmng"),&db)!=SQLITE_OK){
    err_msg("ERR at %s#%d: sqlite3_open",__FILE__,__LINE__);
    sqlite3_close(db);
    return FALSE;
  }
  sqlite3_busy_timeout(db, sqliteBusyTimeout);

  /* prepare execute command */
  selectCmd=sqlite3_mprintf(selectFormat, cookie, userType);

  /* compile to internal statement */
  if(sqlite3_prepare(db, selectCmd, BUFFMAXLN, &stmt, NULL)!=SQLITE_OK){
    resultFlag=FALSE;
    err_msg("ERR at %s#%d: sqlite3_prepare",__FILE__,__LINE__);
    
    /* finalize */
    sqlite3_free(selectCmd);
    sqlite3_finalize(stmt);
    sqlite3_close(db);
    return FALSE;
  }

  /* get a record */
  if(sqlite3_step(stmt)==SQLITE_ROW){
    strlcpy(userId, (char*)sqlite3_column_text(stmt, 0), USERMAXLN);
    strlcpy(extraId, (char*)sqlite3_column_text(stmt, 1), USERMAXLN);
    resultFlag=TRUE;
  }
  else resultFlag=FALSE;

  /* finalize */
  sqlite3_free(selectCmd);
  sqlite3_finalize(stmt);
  sqlite3_close(db);
  return resultFlag;
}

/***************************************************/
/* is session for the mac found in table sessionmd */
/***************************************************/
int isSessionFoundInSessionTable(char* macAddress){

  sqlite3_stmt *stmt=NULL;
  sqlite3 *db;
  int  count=0;

  /* SQL SELECT COMMAND, where %x is replaced in snprintf */
  char* selectFormat="SELECT count(*) "
    " FROM sessionmd where macAddress='%s' limit 1";
  int resultFlag=TRUE;
  char* selectCmd; 

  /* Open sqlite */
  if(sqlite3_open(GetConfValue("SqliteDbMd"),&db)!=SQLITE_OK){
    err_msg("ERR at %s#%d: sqlite3_open",__FILE__,__LINE__);
    sqlite3_close(db);
    return 0;
  }
  sqlite3_busy_timeout(db, sqliteBusyTimeout);

  /* prepare execute command */
  selectCmd=sqlite3_mprintf(selectFormat, macAddress);

  /* compile to internal statement */
  if(sqlite3_prepare(db, selectCmd, BUFFMAXLN, &stmt, NULL)!=SQLITE_OK){
    resultFlag=FALSE;
    err_msg("ERR at %s#%d: sqlite3_prepare",__FILE__,__LINE__);
    
    /* finalize */
    sqlite3_free(selectCmd);
    sqlite3_finalize(stmt);
    sqlite3_close(db);
    return 0;
  }

  /* get a record */
  if(sqlite3_step(stmt)==SQLITE_ROW){
    count = (int)sqlite3_column_int(stmt, 0);
  }

  /* finalize */
  sqlite3_free(selectCmd);
  sqlite3_finalize(stmt);
  sqlite3_close(db);
  return count;
}


/*******************************************************/
/* save cookie(sended to client) to cookie table in db */ 
/*******************************************************/
int saveCookieToWorkDb(char* cookie, char* userId, char* extraId, int userType){
  int rc;
  sqlite3 *db;
  char *pErrMsg=NULL;

  /* SQL COMMAND */
  char* delFormat="DELETE FROM cookietable where saveTime < %d";
  char* delCmd;
  char* insertFormat="INSERT INTO cookietable "
    " (cookie, saveTime, userId, extraId, userType) "
    " values ('%s', %d, '%s', '%s', %d)";
  char* insertCmd;
  int resultFlag=TRUE;

  /* Open sqlite */
  if(sqlite3_open(GetConfValue("SqliteDbMmng"),&db)!=SQLITE_OK){
    err_msg("ERR at %s#%d: sqlite3_open",__FILE__,__LINE__);
    sqlite3_close(db);
    terminateProg(0);
  }
  sqlite3_busy_timeout(db, sqliteBusyTimeout);

  /* execute delete command to delete items before 24 hours */
  delCmd=sqlite3_mprintf(delFormat, time(NULL)-(60*60*24));
  if((rc=sqlite3_exec(db, delCmd, NULL, NULL, &pErrMsg))!=SQLITE_OK){
    resultFlag=FALSE;
    err_msg("ERR at %s#%d: sqlite3_exec: %s",__FILE__,__LINE__,pErrMsg);
  }

  /* execute insert command */
  insertCmd=sqlite3_mprintf(insertFormat, cookie, time(NULL), userId, extraId, userType);
  if((rc=sqlite3_exec(db, insertCmd, NULL, NULL, &pErrMsg))!=SQLITE_OK){
    resultFlag=FALSE;
    err_msg("ERR at %s#%d: sqlite3_exec: %s",__FILE__,__LINE__,pErrMsg);
  }

  /* finalize */
  sqlite3_free(delCmd);
  sqlite3_free(insertCmd);
  sqlite3_close(db);
  return resultFlag;
}

/********************************************/
/* save mac address corresponding to cookie */
/* to cookie table in db                    */
/********************************************/
int saveMacForCookieToWorkDb(char* cookie, char* macAddress){
  int rc;
  sqlite3 *db;
  char *pErrMsg=NULL;

  /* SQL COMMAND */
  char* updateFormat="UPDATE cookietable "
    " SET macAddress='%s' where cookie='%s'";
  char* updateCmd;
  int resultFlag=TRUE;

  /* Open sqlite */
  if(sqlite3_open(GetConfValue("SqliteDbMmng"),&db)!=SQLITE_OK){
    err_msg("ERR at %s#%d: sqlite3_open",__FILE__,__LINE__);
    sqlite3_close(db);
    terminateProg(0);
  }
  sqlite3_busy_timeout(db, sqliteBusyTimeout);

  /* execute update command */
  updateCmd=sqlite3_mprintf(updateFormat, macAddress, cookie);
  if((rc=sqlite3_exec(db, updateCmd, NULL, NULL, &pErrMsg))!=SQLITE_OK){
    resultFlag=FALSE;
    err_msg("ERR at %s#%d: sqlite3_exec: %s",__FILE__,__LINE__,pErrMsg);
  }

  /* finalize */
  sqlite3_free(updateCmd);
  sqlite3_close(db);
  return resultFlag;
}

/*****************************************************/
/* save mail address default corresponding to cookie */
/* to cookie table in db                             */
/*****************************************************/
int saveMailDefalutForCookieToWorkDb(char* cookie, char* mailDefault){
  int rc;
  sqlite3 *db;
  char *pErrMsg=NULL;

  /* SQL COMMAND */
  char* updateFormat="UPDATE cookietable "
    " SET mailDefault='%s' where cookie='%s'";
  char* updateCmd;
  int resultFlag=TRUE;

  /* Open sqlite */
  if(sqlite3_open(GetConfValue("SqliteDbMmng"),&db)!=SQLITE_OK){
    err_msg("ERR at %s#%d: sqlite3_open",__FILE__,__LINE__);
    sqlite3_close(db);
    terminateProg(0);
  }
  sqlite3_busy_timeout(db, sqliteBusyTimeout);

  /* execute update command */
  updateCmd=sqlite3_mprintf(updateFormat, mailDefault, cookie);
  if((rc=sqlite3_exec(db, updateCmd, NULL, NULL, &pErrMsg))!=SQLITE_OK){
    resultFlag=FALSE;
    err_msg("ERR at %s#%d: sqlite3_exec: %s",__FILE__,__LINE__,pErrMsg);
  }

  /* finalize */
  sqlite3_free(updateCmd);
  sqlite3_close(db);
  return resultFlag;
}

/*******************************************/
/* get maildefault corresponding to cookie */
/* from cookie table in db                 */
/*******************************************/
int getMailDefaultFromWorkDb(char* cookie, char* mailDefault){
  sqlite3_stmt *stmt=NULL;
  sqlite3 *db;

  /* SQL SELECT COMMAND, where %x is replaced in snprintf */
  char* selectFormat="SELECT mailDefault "
    " FROM cookietable WHERE cookie='%s'" ;
  int resultFlag=TRUE;
  char* selectCmd; 

  /* Open sqlite */
  if(sqlite3_open(GetConfValue("SqliteDbMmng"),&db)!=SQLITE_OK){
    err_msg("ERR at %s#%d: sqlite3_open",__FILE__,__LINE__);
    sqlite3_close(db);
    return FALSE;
  }
  sqlite3_busy_timeout(db, sqliteBusyTimeout);

  /* prepare execute command */
  selectCmd=sqlite3_mprintf(selectFormat, cookie);

  /* compile to internal statement */
  if(sqlite3_prepare(db, selectCmd, BUFFMAXLN, &stmt, NULL)!=SQLITE_OK){
    resultFlag=FALSE;
    err_msg("ERR at %s#%d: sqlite3_prepare",__FILE__,__LINE__);
    
    /* finalize */
    sqlite3_free(selectCmd);
    sqlite3_finalize(stmt);
    sqlite3_close(db);
    return FALSE;
  }

  /* get a record */
  if(sqlite3_step(stmt)==SQLITE_ROW){
    strlcpy(mailDefault, (char*)sqlite3_column_text(stmt, 0), USERMAXLN);
    resultFlag=TRUE;
  }
  else resultFlag=FALSE;

  /* finalize */
  sqlite3_free(selectCmd);
  sqlite3_finalize(stmt);
  sqlite3_close(db);
  return resultFlag;
}

/************************************************/
/* read mac address corresponding to cookie     */
/* in cookie table in work db                   */
/************************************************/
int loadMacForCookieFromWorkDb(char* cookie, char* macAddress){
  sqlite3_stmt *stmt=NULL;
  sqlite3 *db;

  /* SQL SELECT COMMAND, where %x is replaced in snprintf */
  char* selectFormat="SELECT macAddress "
    " FROM cookietable WHERE cookie='%s'" ;
  int resultFlag=TRUE;
  char* selectCmd; 

  /* Open sqlite */
  if(sqlite3_open(GetConfValue("SqliteDbMmng"),&db)!=SQLITE_OK){
    err_msg("ERR at %s#%d: sqlite3_open",__FILE__,__LINE__);
    sqlite3_close(db);
    return FALSE;
  }
  sqlite3_busy_timeout(db, sqliteBusyTimeout);

  /* prepare execute command */
  selectCmd=sqlite3_mprintf(selectFormat, cookie);

  /* compile to internal statement */
  if(sqlite3_prepare(db, selectCmd, BUFFMAXLN, &stmt, NULL)!=SQLITE_OK){
    resultFlag=FALSE;
    err_msg("ERR at %s#%d: sqlite3_prepare",__FILE__,__LINE__);
    
    /* finalize */
    sqlite3_free(selectCmd);
    sqlite3_finalize(stmt);
    sqlite3_close(db);
    return FALSE;
  }

  /* get a record */
  if(sqlite3_step(stmt)==SQLITE_ROW){
    strlcpy(macAddress, (char*)sqlite3_column_text(stmt, 0), USERMAXLN);
    resultFlag=TRUE;
  }
  else resultFlag=FALSE;

  sqlite3_free(selectCmd);
  sqlite3_finalize(stmt);
  sqlite3_close(db);
  return resultFlag;
}



/**********************************************/
/* is the mac address NAT                     */
/* (suspected info is in macinfo table in db) */
/*  *if db access fails, return false*        */
/**********************************************/
int isNatSuspectedInWorkDb(char* macAddr){

  sqlite3 *db;
  sqlite3_stmt *stmt;
  int isNat;
 
  /* SQL SELECT COMMAND, where %x is replaced in snprintf */
  char *selectFormat="SELECT isNat "
 "FROM macinfo WHERE macAddress='%s'";
  char *selectCmd;
  int resultFlag;

  /* open sqlite */
  if(sqlite3_open(GetConfValue("SqliteDbMd"),&db)!=SQLITE_OK){
    err_msg("ERR at %s#%d: sqlite3_open",__FILE__,__LINE__);
    sqlite3_close(db);
    return FALSE;
  }
  sqlite3_busy_timeout(db, sqliteBusyTimeout);

  /* prepare command string */
  selectCmd=sqlite3_mprintf(selectFormat, macAddr);
  
  /* compile to internal statement */
  if(sqlite3_prepare(db, selectCmd, BUFFMAXLN, &stmt, NULL)!=SQLITE_OK){
    err_msg("ERR at %s#%d: sqlite3_prepare",__FILE__,__LINE__);

    /* finalize */
    sqlite3_free(selectCmd);
    sqlite3_finalize(stmt);
    sqlite3_close(db);
    return FALSE;
  }

  /* get first record */
  if(sqlite3_step(stmt)==SQLITE_ROW){
    isNat=(int)sqlite3_column_int(stmt, 0);
    resultFlag=isNat;
  }else{
    resultFlag=FALSE;
  }

  /* finalize */
  sqlite3_free(selectCmd);
  sqlite3_finalize(stmt);
  sqlite3_close(db);
  
  return resultFlag;
}


/*******************************************************************/
/* is active session for Opengate(not OpengateM) found for the mac */ 
/*******************************************************************/
int isActiveSessionFoundInOpengateSessionTable(char* macAddress){

  sqlite3_stmt *stmt=NULL;
  sqlite3 *db;
  int  count=0;

  /* SQL SELECT COMMAND, where %x is replaced in snprintf */
  char* selectFormat="SELECT count(*) "
    " FROM session where (clientAddr4='%s' or clientAddr6='%s') "
    " and closeTime='-' limit 1";
  int resultFlag=TRUE;
  char* selectCmd; 

  /* Open sqlite (failed if no opengate usage) */
  if(sqlite3_open(GetConfValue("SqliteDb"),&db)!=SQLITE_OK){
    sqlite3_close(db);
    return 0;
  }
  sqlite3_busy_timeout(db, sqliteBusyTimeout);

  /* prepare execute command */
  selectCmd=sqlite3_mprintf(selectFormat, macAddress, macAddress);

  /* compile to internal statement */
  if(sqlite3_prepare(db, selectCmd, BUFFMAXLN, &stmt, NULL)!=SQLITE_OK){
    resultFlag=FALSE;
    err_msg("ERR at %s#%d: sqlite3_prepare",__FILE__,__LINE__);
    
    /* finalize */
    sqlite3_free(selectCmd);
    sqlite3_finalize(stmt);
    sqlite3_close(db);
    return 0;
  }

  /* get a record */
  if(sqlite3_step(stmt)==SQLITE_ROW){
    count = (int)sqlite3_column_int(stmt, 0);
  }

  /* finalize */
  sqlite3_free(selectCmd);
  sqlite3_finalize(stmt);
  sqlite3_close(db);
  return count;
}


/*********************************************************
 routines for debugging output
*********************************************************/
int SetupSqliteBusyTimeoutValue(void){
  int ret;
  if(debug>1) err_msg("DEBUG:=>setupSqliteBusyTimeoutValue()");
  ret=setupSqliteBusyTimeoutValue();
  if(debug>1) err_msg("DEBUG:(%d)<=setupSqliteBusyTimeoutValue()",ret);
  return ret;
}

int InitWorkDb(void){
  int ret;
  if(debug>1) err_msg("DEBUG:=>initWorkDb( )");
  ret = initWorkDb();
  if(debug>1) err_msg("DEBUG:(%d)<=initWorkDb( )",ret);
  return ret;
}

int CreateMacCheckTableInWorkDb(void){
  int ret;
  if(debug>1) err_msg("DEBUG:=>createmacChecktableinWorkDb( )");
  ret = createMacCheckTableInWorkDb();
  if(debug>1) err_msg("DEBUG:(%d)<=createMacCheckTableInWorkDb()", ret);
  return ret;
}

int AddIpv4ToMacCheckTable(void){
  int ret;
  if(debug>1) err_msg("DEBUG:=> addIpv4ToMacCheckTable( )");
  ret = addIpv4ToMacCheckTable();
  if(debug>1) err_msg("DEBUG:(%d)<= addIpv4ToMacCheckTable( )", ret);
  return ret;
}

int AddIpv6ToMacCheckTable(void){
  int ret;
  if(debug>1) err_msg("DEBUG:=>addIpv6ToMacCheckTable( )");
  ret = addIpv6ToMacCheckTable();
  if(debug>1) err_msg("DEBUG:(%d)<=addIpv6ToMacCheckTable( )", ret);
  return ret;
}

int GetNextRowInMacCheckTable(char* macAddress, char* ipv4, char* ipv6){
  int ret;
  if(debug>1) err_msg("DEBUG:=>getNextRowInMacCheckTable( )");
  ret = getNextRowInMacCheckTable(macAddress, ipv4, ipv6);
  if(debug>1) err_msg("DEBUG:(%d)<=getNextRowInMacCheckTable(%s,%s,%s)",
		      ret,macAddress,ipv4,ipv6);
  return ret;
}

int GetIpFromMacCheckTable(char* macAddress, char* ipv4, char* ipv6){
  int ret;
  if(debug>1) err_msg("DEBUG:=>getIpFromMacCheckTable(%s)",macAddress);
  ret = getIpFromMacCheckTable(macAddress, ipv4, ipv6);
  if(debug>1) err_msg("DEBUG:(%d)<=getIpFromMacCheckTable(,%s,%s)",
		      ret,ipv4,ipv6);
  return ret;
}
int GetPidFromMacCheckTable(char* macAddress, int* pid, int* ruleIpv4, int* ruleIpv6){
  int ret;
  if(debug>1) err_msg("DEBUG:=>getPidFromMacCheckTable(%s)",macAddress);
  ret = getPidFromMacCheckTable(macAddress, pid, ruleIpv4, ruleIpv6);
  if(debug>1) err_msg("DEBUG:(%d)<=getPidFromMacCheckTable(,%d,%d,%d)",
		      ret,*pid,*ruleIpv4,*ruleIpv6);
  return ret;
}
int SavePidToMacCheckTable(char* macAddress, int pid, int ruleIpv4, int ruleIpv6){
  int ret;
  if(debug>1) err_msg("DEBUG:=>savePidToMacCheckTable(%s,%d,%d,%d)",
		      macAddress, pid, ruleIpv4, ruleIpv6);
  ret = savePidToMacCheckTable(macAddress, pid, ruleIpv4, ruleIpv6);
  if(debug>1) err_msg("DEBUG:(%d)<=savePidToMacCheckTable( )",ret);
  return ret;
}

int GetDetectTimeFromMacinfoTable(char* macAddress){
  int ret;
  if(debug>1) err_msg("DEBUG:=>getDetectTimeFromMacinfoTable(%s)",macAddress);
  ret = getDetectTimeFromMacinfoTable(macAddress);
  if(debug>1) err_msg("DEBUG:(%d)<=getDetectTimeFromMacinfoTable( )",ret);
  return ret;
}
int IsSessionFoundInSessionTable(char* macAddress){
  int ret;
  if(debug>1) err_msg("DEBUG:=>isSessionFoundInSessionTable(%s)",macAddress);
  ret = isSessionFoundInSessionTable(macAddress);
  if(debug>1) err_msg("DEBUG:(%d)<=isSessionFoundInSessionTable( )",ret);
  return ret;
}

int SaveCookieToWorkDb(char* cookie, char* userId, char* extraId, int userType){
  int ret;
  if(debug>1) err_msg("DEBUG:=>saveCookieToWorkDb(%s,%s,%s,%d)",cookie,userId,extraId,userType);
  ret = saveCookieToWorkDb(cookie,userId,extraId,userType);
  if(debug>1) err_msg("DEBUG:(%d)<=saveCookieToWorkDb( )",ret);
  return ret;
}

int IsCookieFoundInWorkDb(char* cookie, char* userId, char* extraId, int userType){
  int ret;
  if(debug>1) err_msg("DEBUG:=> isCookieFoundInWorkDb(%s,%d)",cookie, userType);
  ret = isCookieFoundInWorkDb(cookie,userId,extraId,userType);
  if(debug>1) err_msg("DEBUG:(%d)<=isCookieFoundInWorkDb(%s,%s)",ret, userId,extraId);
  return ret;
}

int GetMailDefaultFromWorkDb(char* cookie, char* mailDefault){
  int ret;
  if(debug>1) err_msg("DEBUG:=> getMailDefaultFromWorkDb(%s)",cookie);
  ret = getMailDefaultFromWorkDb(cookie,mailDefault);
  if(debug>1) err_msg("DEBUG:(%d)<=getMailDefaultFromWorkDb(%s)",ret,mailDefault);
  return ret;
}

int IsNatSuspectedInWorkDb(char* macAddr){
  int ret;
  if(debug>1) err_msg("DEBUG:=>isNatSuspectedInWorkDb(%s)", macAddr);
  ret = isNatSuspectedInWorkDb(macAddr);
  if(debug>1) err_msg("DEBUG:(%d)<=isNatSuspectedInWorkDb( )", ret);
  return ret;
}

int SaveMacForCookieToWorkDb(char* cookie, char* macAddress){
  int ret;
  if(debug>1) err_msg("DEBUG:=>saveMacForCookieToWorkDb(%s,%s)", cookie,macAddress);
  ret = saveMacForCookieToWorkDb(cookie,macAddress);
  if(debug>1) err_msg("DEBUG:(%d)<=saveMacForCookieToWorkDb( )", ret);
  return ret;
}

int SaveMailDefalutForCookieToWorkDb(char* cookie, char* mailDefault){
  int ret;
  if(debug>1) err_msg("DEBUG:=>saveMailDefalutForCookieToWorkDb(%s,%s)", cookie,mailDefault);
  ret = saveMailDefalutForCookieToWorkDb(cookie,mailDefault);
  if(debug>1) err_msg("DEBUG:(%d)<=saveMailDefalutForCookieToWorkDb( )", ret);
  return ret;
}


int LoadMacForCookieFromWorkDb(char* cookie, char* macAddress){
  int ret;
  if(debug>1) err_msg("DEBUG:=>loadMacForCookieFromWorkDb(%s)", cookie);
  ret = loadMacForCookieFromWorkDb(cookie,macAddress);
  if(debug>1) err_msg("DEBUG:(%d)<=loadMacForCookieFromWorkDb(%s)", ret, macAddress);
  return ret;
}

int IsActiveSessionFoundInOpengateSessionTable(char* macAddress){
  int ret;
  if(debug>1) err_msg("DEBUG:=>isActiveSessionFoundInOpengateSessionTable(%s)", macAddress);
  ret = isActiveSessionFoundInOpengateSessionTable(macAddress);
  if(debug>1) err_msg("DEBUG:(%d)<=isActiveSessionFoundInOpengateSessionTable( )", ret);
  return ret;
}
