/**************************************************
OpengateM - MAC address authentication system 
 module for Communication through CGI 

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

Programmed by Yoshiaki WATANABE
**************************************************/

#include	"opengatemmng.h"

/* convert one-char-hex "a" to one-number 0Xa */
#define hex2num(x)  ((x)>='A' ? ((x) & 0XDF) - 'A' +10 : ((x) - '0'))

void split(char content[], char *name[], char *value[], char *next[]);
void decode(char *string);

char macAddress[ADDRMAXLN]="";

/********************************************/
/* get Post data sent from the client       */
/********************************************/
int getPostData(char *content, int contentMaxLength){
  int contentLen;

  /* get content sent from web input */
  if(isNull(getenv("CONTENT_LENGTH"))) return FALSE;
  contentLen=atoi(getenv("CONTENT_LENGTH"));
  contentLen++; /* for terminate ch */

  /* if larger than buffer, cut off */
  if(contentLen > contentMaxLength) contentLen=contentMaxLength;
  if(fgets(content, contentLen, stdin) == NULL){
    content[0]='\0';
  }

  return TRUE;
}

/****************************************************/
/* get language form query string (in url lang=ja)  */
/****************************************************/
int getLangFromQueryString(char* language){

  int found=FALSE;
  char queryStr[BUFFMAXLN];
  char *name[1];
  char *value[1];
  char *next[1];
  char *ptr;

  /* get default language at the top of lang list */
  sscanf(GetConfValue("HtmlLangs"), "%s", language);

  /* if no string, return default */
  if(isNull(getenv("QUERY_STRING"))) return FALSE;

  /* get html access parameter string */
  strlcpy(queryStr, getenv("QUERY_STRING"), BUFFMAXLN);

  /* split language in string [....&lang=ja&.....] */
  ptr=queryStr;
  while(ptr!=NULL){
    split(ptr, name, value, next);
    if(strstr(name[0], "lang")!=NULL){
      if(!isNull(value[0])) strlcpy(language, value[0], WORDMAXLN);
      found=TRUE;
    }
    ptr=next[0];
  }
  return found;
}

/*********************************************************************/
/* get redirected url form query string (in url redirectedurl=xxxxx) */
/*********************************************************************/
int getRedirectedUrlFromQueryString(char* redirectedUrl){

  int found=FALSE;
  char queryStr[BUFFMAXLN];
  char *name[1];
  char *value[1];
  char *next[1];
  char *ptr;

  /* default is null */
  redirectedUrl[0]='\0';

  /* if no string, return default */
  if(isNull(getenv("QUERY_STRING"))) return FALSE;

  /* get html access parameter string */
  strlcpy(queryStr, getenv("QUERY_STRING"), BUFFMAXLN);

  /* split language in string [....&redirectedurl=xxxx&.....] */
  ptr=queryStr;
  while(ptr!=NULL){
    split(ptr, name, value, next);
    if(strstr(name[0], "redirectedurl")!=NULL){
      if(!isNull(value[0])) strlcpy(redirectedUrl, value[0], BUFFMAXLN);
      found=TRUE;
    }
    ptr=next[0];
  }
  return found;
}

/*************************************************************/
/* get mac address form query string (in url macaddr=xxxxx)  */
/*************************************************************/
int getMacAddrFromQueryString(char* macAddress){

  int found=FALSE;
  char queryStr[BUFFMAXLN];
  char *name[1];
  char *value[1];
  char *next[1];
  char *ptr;

  /* set default */
  macAddress[0]='\0';

  /* if no string returns, return default */
  if(isNull(getenv("QUERY_STRING"))) return FALSE;

  /* get html access parameter string */
  strlcpy(queryStr, getenv("QUERY_STRING"), BUFFMAXLN);

  /* split in string [....&macaddr=xxxxx&.....] */
  ptr=queryStr;
  while(ptr!=NULL){
    split(ptr, name, value, next);
    if(strstr(name[0], "macaddr")!=NULL){
      strlcpy(macAddress, value[0], WORDMAXLN);
      found=TRUE;
    }
    ptr=next[0];
  }
  decode(macAddress);
  return found;

}

/**************************************************/
/* get userid from environment variable           */
/*  long userid: "userid@extraid" is set in env   */
/**************************************************/
int getUserIdFromEnv(char *userid){

  int ret=FALSE;
  char* pEnv=NULL;

  /* if shibboleth or httpbasic, get uid from environment var */
  /*** case of shibboleth */
  if(strcmp(GetConfValue("AuthServer/Protocol"), "shibboleth")==0){

    /* get data from env-variables for uid and org attribute, if env-var exists */
    pEnv=getenvEx(GetConfValue("AuthServer/UidAttribute"),TRUE,TRUE); 
    if(!isNull(pEnv)){
      strlcpy(userid, pEnv, USERMAXLN);

      /* if orp string can be get from env-var, concatenate it as uid@org */
      pEnv=getenvEx(GetConfValue("AuthServer/OrgAttribute"),TRUE,TRUE);
      if(!isNull(pEnv)){
	strlcat(userid, GetConfValue("UserIdSeparator"), USERMAXLN);
	strlcat(userid, pEnv, USERMAXLN);
      } 
      ret=TRUE;
    }

    /* else, get name from env-variable for EPPN(edu person principal name) attribute */
    else{
      pEnv=getenvEx(GetConfValue("AuthServer/EppnAttribute"),TRUE,FALSE);
      if(!isNull(pEnv)){
	strlcat(userid, pEnv, USERMAXLN);
	ret=TRUE;
      }
    }

    /* if not get, error exit */
    if(ret==FALSE){
      err_msg("ERR at %s#%d: Cannot get user info from shibboleth",__FILE__,__LINE__);
      PutMessageToClient("Cannot get user info from shibboleth<br>Check shibboleth setting in .htaccess, conf and others");
      exit(0);
    }    
  }

  /*** case of httpbasic */
  else if(strcmp(GetConfValue("AuthServer/Protocol"), "httpbasic")==0){
    if(!isNull(getenv("REMOTE_USER"))){
      strlcpy(userid,getenv("REMOTE_USER"),USERMAXLN);
      ret=TRUE;
    }else{
      err_msg("ERR at %s#%d: Cannot get user info from httpbasic",__FILE__,__LINE__);
      ret=FALSE;
      PutMessageToClient("Cannot get user info from http basic<br>Check http-basic setting in .htaccess and other");
      exit(0);
    }
  }
  return ret;
}

/********************************************/
/* get userid and password from post string */
/********************************************/
int getUserIdFromPostData(char* requestStr, char* userid, char* password){

  char *name[1];
  char *value[1];
  char *next[1];
  char *ptr;
  int ret=FALSE;
  char content[BUFFMAXLN];

  /* if null string, return */
  if(isNull(requestStr)) return FALSE;

  /* copy it to work area */
  strlcpy(content, requestStr, BUFFMAXLN);

  /* split request item and pick up userid and password */
  ptr=content;
  while(ptr!=NULL){

    /* pick up next item */
    split(ptr, name, value, next);
    
    /* copy to var */
    if(strcmp(name[0], "userid")==0){
      strlcpy(userid, value[0], USERMAXLN);
      decode(userid);
      ret=TRUE;
    }
    else if(strcmp(name[0], "password")==0){
      strlcpy(password, value[0], USERMAXLN);
      decode(password);
    }
    
    /* shift pointer to next item */
    ptr=next[0];
  }

  /* if password is found in request string, clear the string */
  if(!isNull(password)) requestStr[0]='\0';

  return ret;
}

/*********************************************/
/* analyze request from mac check page       */
/* content: (input) request string           */
/* status: (output) OPEN(1)/CLOSE(0)/NONE(-1)*/
/* macAddress: (output) mac addr             */
/*********************************************/
int analyzeCheckRequest(char *content, int* status, char* macAddress){
  char *name[1];
  char *value[1];
  char *next[1];
  char *ptr;

  /* set default */
  *status=NONE;
  *macAddress='\0';

  /* split request item and pick up status(open/close) and macAddress */
  ptr=content;
  while(!isNull(ptr)){

    /* pick up next item */
    split(ptr, name, value, next);

    /* if item =status */
    if(strcmp(name[0], "status")==0){
      if(strcmp(value[0], "open")==0) *status=OPEN;
      if(strcmp(value[0], "close")==0) *status=CLOSE;
    }

    /* if item = macaddr */
    else if(strcmp(name[0], "macaddr")==0){
      strlcpy(macAddress, value[0], ADDRMAXLN);
      decode(macAddress);
    }
    
    /* shift pointer to next item */
    ptr=next[0];
  }

  return TRUE;
}

/********************************************/
/* analyze request from mac register page   */
/********************************************/
int analyzeRegisterRequest(char *content, char* macAddress, char* deviceName, char* mailAddress){
  char *name[1];
  char *value[1];
  char *next[1];
  char *ptr;

  /* if null request, return false */
  if(isNull(content)) return FALSE;
  
  /* set default */
  *macAddress='\0';
  *deviceName='\0';
  *mailAddress='\0';

  /*** split item in request and pick up macAddress,deviceName,mailAddress */
  /* scan the content string of request */
  ptr=content;
  while(!isNull(ptr)){

    /* pick up next item */
    split(ptr, name, value, next);

    /* if item = macaddr */
    if(strcmp(name[0], "macaddr")==0){
      strlcpy(macAddress, value[0], ADDRMAXLN);
      decode(macAddress);

    }
    else if(strcmp(name[0], "device")==0){
      strlcpy(deviceName, value[0], WORDMAXLN);
      decode(deviceName);
    }
    else if(strcmp(name[0], "mailaddr")==0){
      strlcpy(mailAddress, value[0], BUFFMAXLN);
      decode(mailAddress);
    }

    /* shift pointer to next item */
    ptr=next[0];
  }

  /* if null or illegal device name, return false */
  if(*deviceName=='\0'){
    SetMessage(EmptyDeviceName); 
    return FALSE;
  }
  if(!IsSafeString(deviceName, WORDMAXLN)){
    SetMessage(IllegalCharInDevice);
    return FALSE;
  }

  /* if illegal mail address, return false */
  /* (null mail address is permitted) */
  if(*mailAddress!='\0'){
    if(!IsSafeString(mailAddress, BUFFMAXLN)){
      SetMessage(IllegalCharInMailAddr);
      return FALSE;
    }
  }

  /* if illegal mac address, return false */
  if(!ConvertMacAddr(macAddress)) return FALSE;

  /* if already registered in db, return false */
  if(IsMacAddrFoundInMngDb(macAddress)){
    SetMessage(ExistentMacAddr);
    return FALSE;
  }
  
  return TRUE;
}
  
/*****************************************/
/* convert mac address to regular format */
/*  [01:23:45:67:89:0a]                  */
/* (colon separate, lower case letters)  */
/*****************************************/
int convertMacAddr(char* macAddr){

  int m[6]; /* mac address sequence 6-bytes */
  int i;

  /* normal form is hex:hex:hex:hex:hex:hex */
  /*             or hex-hex-hex-hex-hex-hex */
  /* and hex<256 */
  if((sscanf(macAddr, "%x:%x:%x:%x:%x:%x", 
	     &m[0],&m[1],&m[2],&m[3],&m[4],&m[5])!=6)
     && (sscanf(macAddr, "%x-%x-%x-%x-%x-%x", 
		&m[0],&m[1],&m[2],&m[3],&m[4],&m[5])!=6)){
    SetMessage(IllegalMacAddrForm);
    return FALSE;
  }
  for(i=0;i<6;i++){
    if(m[i]>255){
      SetMessage(IllegalMacAddr);
      return FALSE;
    }
  }

  /* format to [01:23:45:67:89:0a] */
  snprintf(macAddr, ADDRMAXLN, "%02x:%02x:%02x:%02x:%02x:%02x",
	   m[0],m[1],m[2],m[3],m[4],m[5]);

  return TRUE;
}

/********************************/
/* check safe characters string */
/********************************/
int isSafeString(char* str, int length){
  char allowableChar[]=" !#$&*+,-./:=?[]^_{|}@";
  int i;
  char ch;

  /* scan all char in str */
  for(i=0; i<length; i++){
    ch=str[i];
    
    /* if reached to the end of string, break loop */
    if(ch=='\0') break;

    /* if char is alpha or numeric, goto next char */
    if(isalnum(ch)) continue;

    /* if char is control or non-ascii, return false */
    if( (unsigned)ch < 0x20|| 0x7f < (unsigned)ch) return FALSE;
    
    /* if char is not allowable, return false */
    if(strchr(allowableChar, ch)==NULL) return FALSE;
  }

  /* all char is safe */
  return TRUE;
}

/*********************************************/
/* put auth request page to client           */
/*********************************************/
int putAuthRequestPageToClient(char *language, char* cgiName, char* docName, char* redirectedUrl){
  char authdoc[BUFFMAXLN];
  FILE *fp;
  char buff[BUFFMAXLN];

  /* make directory path to the auth page document template file */
  snprintf(authdoc, BUFFMAXLN, "%s%s/%s/%s",GetConfValue("DocumentRoot"),
	  GetConfValue("OpengateDir"),language,docName);

  /* replace keyword and send out the file */
  printf("Content-type: text/html\r\n\r\n");

  /* open the template file */
  if((fp=fopen(authdoc, "r"))==NULL){
    err_msg("ERR at %s#%d: cannot find file %s",__FILE__,__LINE__, authdoc);
    return FALSE;
  }

  /* read line from template file, replace variables, and write to client */
  while(fgets(buff,BUFFMAXLN,fp)!=NULL){
    HtmlReplace(buff, "%%CGINAME%%", cgiName);
    HtmlReplace(buff, "%%REDIRECTEDURL%%", redirectedUrl);
    if(strstr(buff, "%%ERRORLIST%%")!=NULL){
      InsertMessageToPage(language);
    }else{
      printf("%s",buff);    
    }
  }
  fclose(fp);
  return TRUE;
}

/*****************************************/
/* deny message page to the client       */
/*****************************************/
int putDenyToClient(char *language){
  char denydoc[BUFFMAXLN];
  FILE *fp;
  char buff[BUFFMAXLN];

  /* make read in path to the deny document */
  snprintf(denydoc, BUFFMAXLN, "%s%s/%s/%s",GetConfValue("DocumentRoot"),
	  GetConfValue("OpengateDir"),language,GetConfValue("DenyDoc"));

  /* replace keyword and send out the file */
  printf("Content-type: text/html\r\n\r\n");

  /* open the template file */
  if((fp=fopen(denydoc, "r"))==NULL){
    err_msg("ERR at %s#%d: cannot find file %s",__FILE__,__LINE__, denydoc);
    return FALSE;
  }

  /* read line from template file, replace variables, and write to client */
  while(fgets(buff,BUFFMAXLN,fp)!=NULL){
    if(strstr(buff, "%%ERRORLIST%%")!=NULL){
      InsertMessageToPage(language);
    }else{
      printf("%s",buff);
    }
  }
  fclose(fp);
  return TRUE;
}

/*****************************************/
/* put mac address check page to client  */
/* the page includes detected mac list   */ 
/*****************************************/
int putCheckPageToClient(char *language, char* userId, char* extraId){
  char responsedoc[BUFFMAXLN];
  FILE *fp;
  char buff[BUFFMAXLN];
  char cookie[SIDMAXLN];
  char* chkCgi=GetConfValue("CheckCgi");
  char* regCgi=GetConfValue("RegisterCgi");
  char* timeout=GetConfValue("OpenTimeout");

  /* make read in path to the document */
  snprintf(responsedoc, BUFFMAXLN, "%s%s/%s/%s",GetConfValue("DocumentRoot"),
	  GetConfValue("OpengateDir"),language,GetConfValue("CheckDoc"));

  /* send header */
  printf("Content-type: text/html\r\n");

  /* if no cookie, make, send, and save cookie */
  if(!GetHttpCookie(cookie,GetConfValue("AuthAdminCookie"))){
    CreateCookie(cookie);
    printf("Set-Cookie: %s=%s;path=/;\r\n", GetConfValue("AuthAdminCookie"), cookie);
    SaveCookieToWorkDb(cookie,userId, extraId, ADMINUSER);
  }

  /* end of http header */
  printf("\r\n");

  /* open the template file */
  if((fp=fopen(responsedoc, "r"))==NULL){
    err_msg("ERR at %s#%d: cannot find file %s",__FILE__,__LINE__, responsedoc);
    return FALSE;
  }

  /* read line from template file, replace variables, and write to client */
  while(fgets(buff,BUFFMAXLN,fp)!=NULL){
    HtmlReplace(buff, "%%CHECKCGI%%", chkCgi);
    HtmlReplace(buff, "%%REGISTERCGI%%", regCgi);
    HtmlReplace(buff, "%%TIMEOUT%%", timeout);
    HtmlReplace(buff, "%%USERID%%", userId);

    if(strstr(buff, "%%MACCHECKLIST%%")!=NULL){
      PutMacCheckListToClient();
    }
    else if(strstr(buff, "%%ERRORLIST%%")!=NULL){
      InsertMessageToPage(language);
    }
    else{
      printf("%s",buff);    
    }
  }
  fclose(fp);
  return TRUE;
}
/***********************************************************/
/* put mac register page to client                         */
/* ownReg:1=the page is controlled by owner, 0=under admin */
/***********************************************************/
int putRegisterPageToClient(char *language, char* macAddress, char* deviceName, char* mailAddress, char* userId, char* extraId, int ownReg, char* redirectedUrl){
  char responsedoc[BUFFMAXLN];
  FILE *fp;
  char buff[BUFFMAXLN];
  char cookie[SIDMAXLN];
  char* regCgi="";
  char* regDoc="";
  char* maxDevicesStr;

  /* get Maximum count of devices for an user from conf file */
  maxDevicesStr=GetConfValue("MaxDevices");

  /* setup cgi and doc */
  if(ownReg){
    regCgi=GetConfValue("OwnCgi");
    regDoc=GetConfValue("OwnRegisterDoc");
  }else{
    regCgi=GetConfValue("RegisterCgi");
    regDoc=GetConfValue("RegisterDoc");
  }
  if(isNull(regCgi) || isNull(regDoc)){
    err_msg("ERR at %s#%d: cannot find cgi/doc for reg in conf",__FILE__,__LINE__);
    return FALSE;
  }

  /* make path to the document template file */
  snprintf(responsedoc, BUFFMAXLN, "%s%s/%s/%s",GetConfValue("DocumentRoot"),
	  GetConfValue("OpengateDir"),language,regDoc);

  /* send header */
  printf("Content-type: text/html\r\n");

  /* if no cookie, make, send, and save cookie */
  if(!GetHttpCookie(cookie, GetConfValue("AuthUserCookie"))){
    CreateCookie(cookie);
    printf("Set-Cookie: %s=%s;path=/;\r\n", GetConfValue("AuthUserCookie"), cookie);
    SaveCookieToWorkDb(cookie, userId, extraId, NORMALUSER);
    SaveMailDefalutForCookieToWorkDb(cookie, mailAddress);
  }

  /* end of http header */
  printf("\r\n");

  /* open the template file */
  if((fp=fopen(responsedoc, "r"))==NULL){
    err_msg("ERR at %s#%d: cannot find file %s",__FILE__,__LINE__, responsedoc);
    return FALSE;
  }

  /* read line from template file, replace variables, and write to client */
  while(fgets(buff,BUFFMAXLN,fp)!=NULL){
    HtmlReplace(buff, "%%REGISTERCGI%%", regCgi);
    HtmlReplace(buff, "%%MACADDR%%", macAddress);
    HtmlReplace(buff, "%%DEVICE%%", deviceName);
    HtmlReplace(buff, "%%MAILADDR%%", mailAddress);
    HtmlReplace(buff, "%%USERID%%", userId);
    HtmlReplace(buff, "%%REDIRECTEDURL%%", redirectedUrl);
    HtmlReplace(buff, "%%MAXDEVICES%%", maxDevicesStr);

    if(strstr(buff, "%%MACREGLIST%%")!=NULL){
      PutMacRegListToClient(userId, extraId);
    }
    else if(strstr(buff, "%%ERRORLIST%%")!=NULL){
      InsertMessageToPage(language);
    }
    else{
      printf("%s",buff);    
    }
  }
  fclose(fp);
  return TRUE;
}

/********************************************************/
/* put mac-check table in mac-check page                */
/* mac-check table is prepared in work db with arp/ndp  */
/* it is used for candidates of mac to register         */
/* (at registration by admin)                           */
/********************************************************/
void putMacCheckListToClient(void){

  char macAddress[ADDRMAXLN];
  char vendor[WORDMAXLN];
  char ipv4[ADDRMAXLN];
  char ipv6[ADDRMAXLN];
  int firstRow=TRUE;
  int inUse=FALSE;
  int foundOnDb=FALSE;

  /* get mac list from db and insert into html table */
  while(GetNextRowInMacCheckTable(macAddress, ipv4, ipv6)){

    /* get nic vendor from management db */
    GetNicVendorFromMngDb(macAddress, vendor, WORDMAXLN);

    /* is the terminal in use */
    if(IsSessionFoundInSessionTable(macAddress) ||
       IsActiveSessionFoundInOpengateSessionTable(macAddress)) inUse=TRUE;
    else inUse = FALSE;
    
    /* is the terminal's MAC is registered in DB */
    foundOnDb = IsMacAddrFoundInMngDb(macAddress);

    /* print out table row */
    /* the row is colored, if it is a candidate for registering */
    /* the terminals inUse/foundInDb is probably not the candidate */
    if(inUse || foundOnDb){
      printf("<tr align=middle>\n");
    }else{
      printf("<tr style='background-color: rgb(255,255,204);' align=middle>\n");
    }

    /* show radio button, checked on first row */ 
    if(firstRow){
      printf("<td><input type='radio' name='macaddr' value='%s' checked></td>\n", macAddress);
      firstRow=FALSE;
    }else{
      printf("<td><input type='radio' name='macaddr' value='%s'></td>\n", macAddress);
    }

    /* show macAddress, vendor, ipv4,ipv6 */
    printf("<td>%s</td>\n", macAddress);
    printf("<td>%s</td>\n",vendor);
    printf("<td>%s</td>\n",ipv4);
    printf("<td>%s</td>\n",ipv6);

    /* show flags for inUse/foundInDb */
    if(inUse) printf("<td>*</td>\n");
    else  printf("<td><br></td>\n");
    if(foundOnDb) printf("<td>*</td>\n");
    else  printf("<td><br></td>\n");
    printf("</tr>\n");
  }
}

/************************************************/
/* put list of mac address regisitered in db    */
/************************************************/
void putMacRegListToClient(char* userId, char* extraId){

  char deviceName[WORDMAXLN]="";
  char entryDate[WORDMAXLN]="";
  char limitDate[WORDMAXLN]="";
  char status[WORDMAXLN]="";
  char macAddress[ADDRMAXLN]="";
  char mailAddress[BUFFMAXLN]="";

  /* get registered mac list form db and insert */
  while(GetNextMacAddrFromMngDb(userId,extraId,macAddress,deviceName,
				entryDate,limitDate,status,mailAddress)){

    printf("<tr align=middle>\n");
    printf("<td>%s</td>\n", macAddress);
    printf("<td>%s</td>\n",deviceName);
    printf("<td>%s</td>\n",entryDate);
    printf("<td>%s</td>\n",limitDate);
    printf("<td>%s</td>\n",status);
    printf("<td>%s</td>\n",mailAddress);
    printf("</tr>\n");
  }
}

/*********************************************/
/* put some message to the client            */
/*********************************************/
void putMessageToClient(char *message)
{
  printf("Content-type: text/html\r\n\r\n");
  printf("<HTML><HEAD><TITLE>OpengateMsg</TITLE></HEAD> \r\n");
  printf("<BODY>\r\n");
  printf("%s\r\n",     message);
  printf("</BODY></HTML> \r\n\r\n");
}

/*************************************************/
/* send page that auto-returns to redirectedUrl  */
/* after delay (ReturnWaitTime is in conf)       */
/*************************************************/
void returnToRedirectedPage(char* redirectedUrl, char* language){
  
  char returndoc[BUFFMAXLN];
  FILE *fp;
  char buff[BUFFMAXLN];
  char* waitTime="10";
 
  /* make read in path to the document */
  snprintf(returndoc, BUFFMAXLN, "%s%s/%s/%s",GetConfValue("DocumentRoot"),
	  GetConfValue("OpengateDir"),language,GetConfValue("ReturnDoc"));

  /* send header */
  printf("Content-type: text/html\r\n\r\n");

  /* open the template file */
  if((fp=fopen(returndoc, "r"))==NULL){
    err_msg("ERR at %s#%d: cannot find file %s",__FILE__,__LINE__, returndoc);
    printf("Error! \r\n\r\n");
    return;
  }

  /* get return wait time from conf */
  /* (it is inserted as Refresh time in the page) */
  if(!isNull(GetConfValue("ReturnWaitTime"))){
    waitTime=GetConfValue("ReturnWaitTime");
  }
  
  /* read line from template file, replace variables, and write to client */
  while(fgets(buff,BUFFMAXLN,fp)!=NULL){
    HtmlReplace(buff, "%%WAITTIME%%", waitTime);
    HtmlReplace(buff, "%%REDIRECTEDURL%%", redirectedUrl);
    printf("%s",buff);    
  }
  fclose(fp);
}

/*************************************************************/
/* split name and value in content such as "name=value&..."  */
/*  input:content, output:name,value,next                    */
/*************************************************************/
void split(char content[], char *name[], char *value[], char *next[]){
  char *pstr;
  
  /* set default */
  name[0]=content;
  value[0]=content+strlen(content);
  next[0]=value[0];

  /* set name end */
  if((pstr=strchr(name[0],(int)'='))==NULL){
    next[0]=NULL;
    return;
  }
  *pstr='\0';
  
  /* set value start */
  pstr++;
  value[0]=pstr;
  
  /* set value end */
  if((pstr=strchr(value[0],'&'))==NULL){
    next[0]=NULL;
    return;
  }
  *pstr='\0';

  /* set next start */
  pstr++;
  next[0]=pstr;

  return;
}

/*****************************************/
/* decode text coding in web post        */
/* eg. "+%21" => " !"(space,exclamation) */
/* string: input and output              */
/*****************************************/
void decode(char *string)
{
  char *pcheck, *pinsert;

  pcheck=pinsert=string;
  while(*pcheck != '\0'){
    if(*pcheck == '+'){
      *pinsert = ' ';
    }else if(*pcheck == '%'){
      *pinsert=(char)(hex2num(*(pcheck+1))*16 + hex2num(*(pcheck+2)));
      pcheck+=2;
    }else{
      *pinsert=*pcheck;
    }
    pcheck++;
    pinsert++;
  }
  *pinsert=*pcheck;
}


/********************************************/
/* replace beforeStr to afterStr in buff    */
/* buff: input and output                   */
/* beforeStr,afterStr: input                */
/* if afterStr is too long, tail is cut-off */
/********************************************/
int htmlReplace(char* buff,char *beforeStr,char *afterStr){
  char *pBuff , *pNext;
  char tempBuff[BUFFMAXLN];
  
  if(buff==NULL) return 1;

  strlcpy(tempBuff, buff, BUFFMAXLN);
  strlcpy(buff,"",BUFFMAXLN);
  
  for(pBuff = tempBuff;
      (pNext=StrSplit(pBuff, beforeStr)) != NULL;
      pBuff = pNext){
    strlcat(buff,pBuff,BUFFMAXLN);
    strlcat(buff,afterStr,BUFFMAXLN);
  }
  strlcat(buff,pBuff,BUFFMAXLN);
  
  return 0;
}

/*****************************************************/
/* split a str at delimStr and return next pointer   */
/*  str: input and output                            */
/*  delimStr: input                                  */
/* eg. IN: str="abcdefghijk" delimStr="def"          */
/*    OUT: str="abc###ghijk"    '#' means null(\0)   */
/*                    |________ pointer returned     */
/*****************************************************/
char* strSplit(char* str, const char* delimStr){
    char* delimPoint = strstr(str,delimStr);
    const size_t delimLen = strlen(delimStr);

    if(delimPoint == NULL) return NULL;
    else{
        *delimPoint = '\0';
        delimPoint += delimLen; 
    }
    return delimPoint;
}


/**********************/
/* get HTTP-Cookie    */
/**********************/
/********************************************************/
/*cookie is picked out from the cookie string such as   */
/*  "OpengateMmng=de..ac1&Userid=user1"                 */
/*  "OpengateMmng=de..ac1&Userid=user1; xxx=..; yyy=.." */
/*  "xxx=..; yyy=..; OpengateMmng=de..ac1&Userid=user1" */
/*  cookieName:(input) "OpengateMmng" defined in conf   */
/*  cookie:(output) value of above cookie name          */
/********************************************************/
int getHttpCookie(char *cookie, char* cookieName){
  char content[BUFFMAXLN];
  char *name[1];
  char *value[1];
  char *next[1];
  char *ptr=NULL;
  char *ptrNext=NULL;

  /* reset buffer */
  cookie[0]='\0';

 /* if exist cookie, copy it to work area */
  if(isNull(getenv("HTTP_COOKIE"))) return FALSE;
  strlcpy(content, getenv("HTTP_COOKIE"), BUFFMAXLN);
  ptr=content;

  /* search 'OpengateMmng' cookie string (terminated by ; or \0) */
  while(ptr!=NULL){
    if((ptrNext=strstr(ptr, "; "))==NULL) break;          /* search "; " */
    *ptrNext='\0';                               /* overwrite string end */
    ptrNext++;                                 /* pointer to next string */
    while(!isNull(ptrNext)&&*ptrNext==' ') ptrNext++;     /* skip spaces */
    if(strstr(ptr, cookieName)==ptr) break;          /* exit at matching */
    ptr=ptrNext;                                    /* check next string */
  }

  /* get valuses of cookie from "OpengateMmng=de..ac1" */
  while(ptr!=NULL){
    split(ptr, name, value, next);

    if(strstr(name[0], cookieName)!=NULL){
      strlcpy(cookie, value[0], SIDMAXLN);
    }
    ptr=next[0];
  }
  
  if(isNull(cookie)) return FALSE;
  else return TRUE;
}

/*****************************************************/
/* compare received cookie with previously saved one */
/*****************************************************/
int isCorrectCookie(char* cookie, int userType){
  char userId[USERMAXLN];
  char extraId[USERMAXLN];

  /* compare http received cookie and DB readin cookie */
  switch(userType){
  case NORMALUSER:
    GetHttpCookie(cookie, GetConfValue("AuthUserCookie"));
    if(IsCookieFoundInWorkDb(cookie,userId,extraId,NORMALUSER)) return TRUE;
    else return FALSE;
  case ADMINUSER:
    GetHttpCookie(cookie, GetConfValue("AuthAdminCookie"));
    if(IsCookieFoundInWorkDb(cookie,userId,extraId,ADMINUSER)) return TRUE;
    else return FALSE;
  }
  return FALSE;
}

/************************************************/
/* analyze update request and execute request   */
/************************************************/
int analyzeUpdateRequestAndExecute(char *requestStr, char* userId, char* extraId){
  char *name[1];
  char *value[1];
  char *next[1];
  char *ptr;
  char macAddr[ADDRMAXLN];
  int modified=FALSE;    /* status of database modification */
  int ret;
  char content[BUFFMAXLN];
  char deviceName[WORDMAXLN]="";
  char mailAddress[BUFFMAXLN]="";

  /* if null string, return false */
  if(isNull(requestStr)) return FALSE;

  /* copy request string to work area */
  strlcpy(content, requestStr, BUFFMAXLN);

  /*** split item and execute the request(from following input forms) */
  /* <input type=radio name=11:22:33:44:55:66 value=extend> */
  /* <input type=radio name=11:22:33:44:55:66 value=pause> */
  /* <input type=radio name=11:22:33:44:55:66 value=delete> */
  /* <input type=hidden name=11:22:33:44:55:66 value=mail:wata@foo.bar> */
  /* <input type=hidden name=11:22:33:44:55:66 value=name:iPhone01> */

  /* point to the head of string and scan the string to the tail */
  ptr=content;
  while(ptr!=NULL){

    /* pick up next item */
    split(ptr, name, value, next);
    
    /* if item=delete, execute delete */
    if(strcmp(value[0], "delete")==0){
      strlcpy(macAddr, name[0], ADDRMAXLN); /* copy mac to work area */
      decode(macAddr);                      /* decode html encoding */
      if(ConvertMacAddr(macAddr)){          /* convert to colon & lower-char str */
	ret=DelMacAddrFromMngDb(macAddr);   /* remove mac from db */
	if(ret){
	  modified=TRUE;
	  PutMacModifyLogToMngDb(userId, extraId, macAddr, 'D'); /* save change log */
	  PutMacAddressToServers(macAddr);  /* send mac to opengatemd daemons */
	}
      }
    }

    /* if item = extend, execute extend */
    else if(strcmp(value[0], "extend")==0){
      strlcpy(macAddr, name[0], ADDRMAXLN);
      decode(macAddr);
      if(ConvertMacAddr(macAddr)){
	ret=RenewMacAddrInMngDb(macAddr);
	if(ret){
	  modified=TRUE;
	  PutMacModifyLogToMngDb(userId, extraId, macAddr, 'E');
	  PutMacAddressToServers(macAddr);
	}
      }
    }

    /* if item = pause, execute pause */
    else if(strcmp(value[0], "pause")==0){
      strlcpy(macAddr, name[0], ADDRMAXLN);
      decode(macAddr);
      if(ConvertMacAddr(macAddr)){
	ret=PauseMacAddrInMngDb(macAddr);
	if(ret){
	  modified=TRUE;
	  PutMacModifyLogToMngDb(userId, extraId, macAddr, 'P');
	  PutMacAddressToServers(macAddr);
	}
      }
    }

    /* if item = name xxxx, execute renaming the device name */
    else if(strstr(value[0], "name+")==value[0]){
      strlcpy(macAddr, name[0], ADDRMAXLN);
      decode(macAddr);
      if(ConvertMacAddr(macAddr)){

	/* when value=name xxxx, rename device-name to xxxx */
	/* copy limitted length and decode */
	strlcpy(deviceName, value[0]+5, WORDMAXLN);
	decode(deviceName);

	/* if illegal device name, return */
	if(*deviceName=='\0'){
	  SetMessage(EmptyDeviceName); 
	  return FALSE;
	}
	if(!IsSafeString(deviceName, WORDMAXLN)){
	  SetMessage(IllegalCharInDevice);
	  return FALSE;
	}

	/* update the device name in db */
	RenameDeviceNameInMngDb(macAddr, deviceName);
      }
    }

    /* if item = mail xxxx, execute renaming the mail address */
    else if(strstr(value[0], "mail+")==value[0]){
      strlcpy(macAddr, name[0], ADDRMAXLN);
      decode(macAddr);
      if(ConvertMacAddr(macAddr)){

	/* when value=mail xxxx, rename mail-address to xxxx */
	/* copy limitted length and decode */
	strlcpy(mailAddress, value[0]+5, BUFFMAXLN);
	decode(mailAddress);

	/* if illegal mail address, return */
	if(*mailAddress!='\0'){
	  if(!IsSafeString(mailAddress, BUFFMAXLN)){
	    SetMessage(IllegalCharInMailAddr);
	    return FALSE;
	  }
	}
	
	/* update the device name in db */
	RenameMailAddressInMngDb(macAddr, mailAddress);
      }
    }
    
    /* shift pointer to next item */
    ptr=next[0];
  }

  return modified;
}

/**********************************************************/
/* put update page to client                              */
/* ownUpdate:1=page is controlled by owner, 0=under admin */
/**********************************************************/
int putUpdatePageToClient(char *language, char* userId, char* extraId, int ownUpdate, char* redirectedUrl){
  char responsedoc[BUFFMAXLN];
  FILE *fp;
  char buff[BUFFMAXLN];
  char cookie[SIDMAXLN];
  char* updateCgi="";
  char* updateDoc="";
  char mailDefault[BUFFMAXLN];

  /* select update page for owner or administrator */
  if(ownUpdate){
    updateCgi=GetConfValue("OwnCgi");
    updateDoc=GetConfValue("OwnUpdateDoc");
  }else{
    updateCgi=GetConfValue("UpdateCgi");
    updateDoc=GetConfValue("UpdateDoc");
  }
  if(isNull(updateCgi) || isNull(updateDoc)){
    err_msg("ERR at %s#%d: cannot find cgi/doc for update in conf",__FILE__,__LINE__);
    return FALSE;
  }

  /* make read in path to the retry document */
  snprintf(responsedoc, BUFFMAXLN, "%s%s/%s/%s",GetConfValue("DocumentRoot"),
	  GetConfValue("OpengateDir"),language,updateDoc);

  /* send header */
  printf("Content-type: text/html\r\n");

  /* if no cookie, make, send, and save cookie */
  if(!GetHttpCookie(cookie, GetConfValue("AuthUserCookie"))){
    CreateCookie(cookie);
    printf("Set-Cookie: %s=%s;path=/;\r\n", GetConfValue("AuthUserCookie"), cookie);
    SaveCookieToWorkDb(cookie,userId, extraId, NORMALUSER);
    MakeMailDefault(userId, extraId, mailDefault);
    SaveMailDefalutForCookieToWorkDb(cookie, mailDefault);
  }

  /* end of http header */
  printf("\r\n");

  /* open the template file */
  if((fp=fopen(responsedoc, "r"))==NULL){
    err_msg("ERR at %s#%d: cannot find file %s",__FILE__,__LINE__, responsedoc);
    return FALSE;
  }

  /* read line from template file, replace variables, and write to client */
  while(fgets(buff,BUFFMAXLN,fp)!=NULL){
    HtmlReplace(buff, "%%CGINAME%%", updateCgi);
    HtmlReplace(buff, "%%USERID%%", userId);
    HtmlReplace(buff, "%%REDIRECTEDURL%%", redirectedUrl);

    if(strstr(buff, "%%MACLIST%%")!=NULL){
      PutMacListToClient(userId,extraId);
    }
    else if(strstr(buff, "%%USAGELOG%%")!=NULL){
      PutUsageLogToClient(userId, extraId, language);
    }
    else if(strstr(buff, "%%ERRORLIST%%")!=NULL){
      InsertMessageToPage(language);
    }
    else{
      printf("%s",buff);    
    }
  }
  fclose(fp);
  return TRUE;
}


/*********************************************/
/* put mac list for the user to the client   */
/*********************************************/
void putMacListToClient(char* userId, char* extraId){

  char deviceName[WORDMAXLN];
  char entryDate[WORDMAXLN];
  char limitDate[WORDMAXLN];
  char status[WORDMAXLN];
  char macAddr[ADDRMAXLN];
  char mailAddress[BUFFMAXLN];

  /*** make html-table for deletion and extending the registration   */
  /* following code inserts table row of a mac address for the user  */
  /* (table skeleton is prepared in in template file)                */
  /* --example of the row--                                          */
  /* <tr align=middle>                                               */
  /* <td><input type=radio name=11:22:33:44:55:66 value=extend></td> */
  /* <td><input type=radio name=11:22:33:44:55:66 value=pause></td>  */
  /* <td><input type=radio name=11:22:33:44:55:66 value=delete></td> */
  /* <td>11:22:33:44:55:66</td>                                      */
  /* <td>onclick="editstring('11:22:33:44:55:66','name',this)">iPhone1</td>      */
  /* <td>onclick="editstring('11:22:33:44:55:66','mail',this)">wata@foo.bar</td> */
  /* <td>2000/01/03 01:23:45</td>                                    */
  /* <td>2000/02/01 00:00:00</td>                                    */
  /* <td>A</td>                                                      */
  /* </tr>                                                           */
  /* ----                                                            */
  /* editstring is a javascript function to edit string in html-item */

  /* get registered mac form db */
  while(GetNextMacAddrFromMngDb(userId,extraId,macAddr,deviceName,
				entryDate,limitDate,status,mailAddress)){

    /* put out a html table row to the client */
    printf("<tr align=middle>\n");
    if((status[0]=='A')||(status[0]=='P')){
      printf("<td><input type=radio name=%s value=extend checked></td>\n",
	     macAddr);
      printf("<td><input type=radio name=%s value=pause></td>\n",macAddr);
      printf("<td><input type=radio name=%s value=delete></td>\n",macAddr);
    }else{
      printf("<td>-</td>\n");
      printf("<td>-</td>\n");
      printf("<td>-</td>\n");
    }
    printf("<td>%s</td>\n", macAddr);
    printf("<td onclick=\"editstring('%s','name',this)\">%s</td>\n",
	   macAddr,deviceName);
    printf("<td onclick=\"editstring('%s','mail',this)\">%s</td>\n",
	   macAddr,mailAddress);
    printf("<td>%s</td>\n",entryDate);
    printf("<td>%s</td>\n",limitDate);
    printf("<td>%s</td>\n",status);
    printf("</tr>\n");
  }
}

/*********************************************/
/* put usage log to the client            */
/*********************************************/
void putUsageLogToClient(char *userId, char* extraId, char* language){

  char macAddr[ADDRMAXLN]="";
  char deviceName[WORDMAXLN]="";
  char openTime[WORDMAXLN]="";
  char closeTime[WORDMAXLN]="";
  char gatewayName[WORDMAXLN]="";
  char beginTime[WORDMAXLN]="";
  char endTime[WORDMAXLN]="";
  int dateCount=0;
  char* p;
  int count=0;

  /*** get usage log and insert it to html doc as JSON format */
  /* get one log form management db */
  while(GetNextUsageLogFromMngDb(userId,extraId,macAddr,deviceName,
				 openTime,closeTime,gatewayName)){

    /* split hostname only (opengate01.example.com -> opengate01) */
    if((p=strchr(gatewayName,'.'))!=NULL) *p='\0';

    /* put out the log as a JSON item */
    /* table skeleton is prepared in template file */
    printf("\t %d:{\n", count);
    printf("\t\t macAddress: '%s',\n", macAddr);
    printf("\t\t device: '%s',\n",deviceName);
    printf("\t\t openTime: '%s',\n",openTime);
    printf("\t\t closeTime: '%s',\n",closeTime);
    printf("\t\t gateway: '%s'\n",gatewayName);
    printf("\t },\n");

    /* increment log counter */
    count++;
  }

  /* put out the JSON item for summary info of the list */
  GetTimeRangeToShowLog(beginTime, endTime, &dateCount);
  printf("\t info:{\n");
  printf("\t\t beginTime: '%s',\n", beginTime);
  printf("\t\t endTime: '%s',\n", endTime);
  printf("\t\t listCount: %d,\n", count);
  printf("\t\t dateCount: %d\n", dateCount);
  printf("\t }\n");
}

/********************************************************/
/* the client is an allowable http-user-agent or not    */
/* the allowable http-user-agent can be defined in conf */
/* (if no definition, all agents are allowed)           */
/* the agent is described with Regular Expression       */
/********************************************************/
int isAccessedFromAllowableAgent(void){

  char* pAgent=NULL;
  char* pRegExPattern=NULL;
  int found=FALSE;

  /* get agent string. if not, return false */
  if( isNull(pAgent=getenv("HTTP_USER_AGENT")) ) return FALSE;

  /* get first reg expression in conf. if not, return true(not define=allow all) */
  if(isNull(pRegExPattern=GetFirstConfValue("AllowableAgentPattern"))){
    return TRUE;
  }

  /* loop for patterns in conf */
  while(!isNull(pRegExPattern)){

    /* if agent is matched to reg ex, return true. */
    /* last-arg 1 means case sensitive */
    if(RegExMatch(pAgent, pRegExPattern, 1)){
      found=TRUE;
      break;
    }

    /* get next reg expression in conf */
    pRegExPattern=GetNextConfValue();
  }

  /* if fail, print message */
  if(!found){
    err_msg("ERR at %s#%d: http-agent[%s] is not allowed in conf file",__FILE__,__LINE__, pAgent);
  }

  return found;
}

/*******************************/
/*******************************/

int GetPostData(char *content, int contentMaxLength){
  int ret;
  if(debug>1) err_msg("DEBUG:=>getPostData(%d)", contentMaxLength);
  ret=getPostData(content, contentMaxLength);
  if(debug>1) err_msg("DEBUG:%d<=getPostData(..)",ret);
  return ret;
}

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

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

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

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

int AnalyzeRegisterRequest(char *content, char* macAddress, char* deviceName, char* mailAddress){
  int ret;
  if(debug>1) err_msg("DEBUG:=>analyzeRegisterRequest(%s)", content);
  ret=analyzeRegisterRequest(content, macAddress, deviceName, mailAddress);
  if(debug>1) err_msg("DEBUG:%d<=analyzeRegisterRequest(%s,%s,%s)",ret, macAddress, deviceName, mailAddress);
  return ret;
}

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

int PutCheckPageToClient(char *language, char* userId, char* extraId){
  int ret;
  if(debug>1) err_msg("DEBUG:=>putCheckPageToClient(%s,%s,%s)", 
		      language,userId,extraId);
  ret=putCheckPageToClient(language,userId,extraId);
  if(debug>1) err_msg("DEBUG:(%d)<=putCheckPageToClient( )",ret);
  return ret;
}

int PutRegisterPageToClient(char *language, char* macAddress, char* deviceName, char* mailAddress, char* userId, char* extraId, int ownReg, char* redirectedUrl){
  int ret;
  if(debug>1) err_msg("DEBUG:=>putRegisterPageToClient(%s,%s,%s,%s,%s,%s,%d,%s)", language,macAddress,deviceName,mailAddress,userId,extraId,ownReg, redirectedUrl);
  ret=putRegisterPageToClient(language, macAddress, deviceName, mailAddress, userId, extraId, ownReg, redirectedUrl);
  if(debug>1) err_msg("DEBUG:(%d)<=putRegisterPageToClient( )",ret);
  return ret;
}

void PutMacCheckListToClient(void){
  if(debug>1) err_msg("DEBUG:=>putMacCheckListToClient( )");
  putMacCheckListToClient();
  if(debug>1) err_msg("DEBUG:<=putMacCheckListToClient( )");
}

void PutMacRegListToClient(char* userId, char* extraId){
  if(debug>1) err_msg("DEBUG:=>putMacRegListToClient( )");
  putMacRegListToClient(userId, extraId);
  if(debug>1) err_msg("DEBUG:<=putMacRegListToClient( )");
}

void PutMessageToClient(char *message){
  if(debug>1) err_msg("DEBUG:=>putMessageToClient(%s)",message);
  putMessageToClient(message);
  if(debug>1) err_msg("DEBUG:<=putMessageToClient( )");
}

void ReturnToRedirectedPage(char* redirectedUrl, char* language){
  if(debug>1) err_msg("DEBUG:=>returnToRedirectedPage(%s,%s)",redirectedUrl,language);
  returnToRedirectedPage(redirectedUrl, language);
  if(debug>1) err_msg("DEBUG:<=returnToRedirectedPage( )");
}

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

int IsSafeString(char* str, int length){
  int ret;
  if(debug>1) err_msg("DEBUG:=>isSafeString(%s,%d)",str,length);
  ret=isSafeString(str,length);
  if(debug>1) err_msg("DEBUG:(%d)<=isSafeString( )",ret);
  return ret;
}

int HtmlReplace(char* buff,char *beforeStr,char *afterStr){
  int ret;
  if(debug>2) err_msg("DEBUG:=>htmlReplace(%s,%s,%s)",buff,beforeStr,afterStr);
  ret = htmlReplace(buff, beforeStr, afterStr);
  if(debug>2) err_msg("DEBUG:(%d)<=htmlReplace( )",ret);
  return ret;
}

char* StrSplit(char* str,const char* delimStr){
  char* ret;
  if(debug>2) err_msg("DEBUG:=>strSplit(%s,%s)",str,delimStr);
  ret = strSplit(str, delimStr);
  if(debug>2) err_msg("DEBUG:(%s)<=strSplit( )",ret);
  return ret;
}

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

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

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

int GetUserIdFromPostData(char* requestStr, char* userid, char* password){
  int ret;
  if(debug>1) err_msg("DEBUG:=>getUserIdFromPostData(..)");
  ret = getUserIdFromPostData(requestStr,userid,password);
  if(debug>1) err_msg("DEBUG:(%d)<=getUserIdFromPostData(,%s,password)",ret,userid);
  return ret;
}

int PutAuthRequestPageToClient(char *language, char* cgiName, char* docName, char* redirectedUrl){
  int ret;
  if(debug>1) err_msg("DEBUG:=>putAuthRequestPageToClient(%s,%s,%s)",language,cgiName, docName, redirectedUrl);
  ret=putAuthRequestPageToClient(language,cgiName, docName, redirectedUrl);
  if(debug>1) err_msg("DEBUG:(%d)<=putAuthRequestPageToClient( )",ret);
  return ret;
}

int AnalyzeUpdateRequestAndExecute(char *content, char* userId, char* extraId){
  int ret;

  if(debug>1) err_msg("DEBUG:=>analyzeUpdateRequestAndExecute(%s,%s,%s)", content,userId,extraId);
  ret=analyzeUpdateRequestAndExecute(content,userId,extraId);
  if(debug>1) err_msg("DEBUG:%d<=analyzeUpdateRequestAndExecute( )",ret);
  return ret;
}

int PutUpdatePageToClient(char *language, char* userId, char* extraId, int ownUpdate, char* redirectedUrl){
  int ret;
  if(debug>1) err_msg("DEBUG:=>putUpdatePageToClient(%s,%s,%s,%d,%s)", 
		      language,userId,extraId,ownUpdate,redirectedUrl);
  ret=putUpdatePageToClient(language,userId,extraId,ownUpdate,redirectedUrl);
  if(debug>1) err_msg("DEBUG:(%d)<=putUpdatePageToClient( )",ret);
  return ret;
}

void PutMacListToClient(char *userId, char* extraId){
  if(debug>1) err_msg("DEBUG:=>putMacListToClient(%s,%s)",userId,extraId);
  putMacListToClient(userId,extraId);
  if(debug>1) err_msg("DEBUG:<=putMacListToClient( )");
}

void PutUsageLogToClient(char *userId, char* extraId, char* language){
  if(debug>1) err_msg("DEBUG:=>putUsageLogToClient(%s,%s,%s)",userId,extraId,language);
  putUsageLogToClient(userId,extraId,language);
  if(debug>1) err_msg("DEBUG:<=putUsageLogToClient( )");
}

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