/** BEGIN COPYRIGHT BLOCK
 * Copyright (C) 2001 Sun Microsystems, Inc.  Used by permission.
 * Copyright (C) 2005 Red Hat, Inc.
 * All rights reserved.
 *
 * 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; version 2
 * of the License.
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 * END COPYRIGHT BLOCK **/
/*
 * viewlog.c:  View various log files in HTML Admin interface.
 * 
 * Initial version: 3/11/99 by Adam Prishtina
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <prtypes.h>

#include "libadminutil/resource.h"
#include "libadminutil/distadm.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <signal.h>
#include <sys/types.h>
#include "libadmin/libadmin.h"

#include "config.h"
#include "libadmsslutil/psetcssl.h"
#include "libadmsslutil/admsslutil.h"

#include "cgicommon.h"


#define MY_PAGE "viewlog.html"
#define DEF_SIZE "25"

#define LOGDIRATTR "nslogdir"
#define ERRORLOGATTR "nserrorlog"

/*
 * i18n conversions defines and function;
 * properties file  = "viewlog.properties"
 */
#define RESOURCE_FILE "viewlog"
#define resource_key(a,b)   a b

#define DBT_INV_NUMBER                      resource_key(RESOURCE_FILE, "1")
#define DBT_INV_NUMBER_DESC                 resource_key(RESOURCE_FILE, "2")
#define DBT_SUBTITLE                        resource_key(RESOURCE_FILE, "3")
#define DBT_WITH                            resource_key(RESOURCE_FILE, "4")
#define DBT_NO_DIR                          resource_key(RESOURCE_FILE, "5")
#define DBT_NO_DIR_DESC                     resource_key(RESOURCE_FILE, "6")
#define DBT_NO_FILE                         resource_key(RESOURCE_FILE, "7")
#define DBT_NO_FILE_DESC                    resource_key(RESOURCE_FILE, "8")
#define DBT_NO_DIR_FOUND                    resource_key(RESOURCE_FILE, "9")
#define DBT_NO_ID                           resource_key(RESOURCE_FILE, "10")
#define DBT_NO_ID_DESC                      resource_key(RESOURCE_FILE, "11")
#define DBT_INV_NOHTML                      resource_key(RESOURCE_FILE, "12")
#define DBT_INV_NOHTML_DESC                 resource_key(RESOURCE_FILE, "13")

/* html resource */
#define DBT_DISPLAY_LOGFILE_SELECT_BEGIN    resource_key(RESOURCE_FILE, "20")
#define DBT_DISPLAY_LOGFILE_VALUE_SELECTED  resource_key(RESOURCE_FILE, "21")
#define DBT_DISPLAY_LOGFILE_SELECT_VALUE    resource_key(RESOURCE_FILE, "22")
#define DBT_DISPLAY_LOGFILE_NO_LOG          resource_key(RESOURCE_FILE, "23")
#define DBT_DISPLAY_LOGFILE_SELECT_END      resource_key(RESOURCE_FILE, "24")
#define DBT_MAIN_HIDDEN_TRACK               resource_key(RESOURCE_FILE, "25")
#define DBT_MAIN_ID_TITLE                   resource_key(RESOURCE_FILE, "26")
#define DBT_MAIN_WIDTH                      resource_key(RESOURCE_FILE, "27")
#define DBT_MAIN_TABLE                      resource_key(RESOURCE_FILE, "28")
#define DBT_MAIN_TABLE_FONT                 resource_key(RESOURCE_FILE, "29")
#define DBT_MAIN_TABLE_FONT_CLOSE           resource_key(RESOURCE_FILE, "30")

static  char *acceptLanguage = (char*)"en";
static  Resource *i18nResource = NULL;
static  Resource *i18nResource_common = NULL;

static char*
getResourceString(char *key) {
  if (key && !strncmp(key, COMMON_RESOURCE_FILE, strlen(COMMON_RESOURCE_FILE))) {
    return (char *)(res_getstring(i18nResource_common, key, acceptLanguage, NULL, 0, NULL));
  } else {
    return (char *)(res_getstring(i18nResource, key, acceptLanguage, NULL, 0, NULL));
  }
}

void search_file(FILE *cmd, int num, char *str) {

  int replace, count, temp;
  char line[BIG_LINE];
  char **buffer = NULL; /* buffer to store log matches */
  char **tmp = NULL;
  int i = 0;

  if(num <= 0) return;

  replace=0;
  count=0;
  while(fgets(line, sizeof(line), cmd)) {
    if(strncmp(line, "format=", 7)) 
      if((!str) || (strstr(line, str))) {
        count++;
        if(count<=num) {
          if(!buffer) {
            buffer = (char **)MALLOC(sizeof(char *));
            if (!buffer) {
              /* Malloc failed.  Bail. */
              return;
            }
          } else {
            tmp = (char **)REALLOC(buffer, count*(sizeof(char *)));
            if (!tmp) {
              /* Realloc failed.  Free and bail. */
              for (i=0; i<(count-1); i++) {
                FREE(buffer[i]);
              }
              FREE(buffer);
              return;
            }
            buffer = tmp;
          }
        } else {
          FREE(buffer[replace]);
        }

        temp = strlen(line);
        line[temp-1] = ' ';
        line[temp] = '\n';
        line[temp+1] = '\0';
        buffer[replace] = STRDUP(line);
        if(replace == (num-1))
          replace=0;
        else replace++;
      }
  }
  if(count < num) { /* could not find num entries */
    replace=0;
  }
  else count=num;
  
  /* replace is at the first entry to output */
  for(temp=0; temp<count; temp++) {
    fputs(buffer[replace], stdout);
    FREE(buffer[replace]);
    if(replace == (num-1))
      replace=0;
    else replace++;
  }
  if(buffer)
    FREE(buffer);
}

static void i18nInit() {
    i18nResource = res_find_and_init_resource(PROPERTYDIR, RESOURCE_FILE);
    i18nResource_common = res_find_and_init_resource(PROPERTYDIR, COMMON_RESOURCE_FILE);

    if (getenv("HTTP_ACCEPT_LANGUAGE")) {
        acceptLanguage = getenv("HTTP_ACCEPT_LANGUAGE");
    }
}


void display_logfiles(char *logdir, char *default_logfile)
{
    int  x; 
    char *seps = "/";
    char *token; 
    char *curlog = NULL;
    char **logfiles;
    int at_least_one=0;

    if (default_logfile != NULL) {
      token = strtok(default_logfile, seps);
      while(token != NULL) {
        curlog = token;
        token = strtok(NULL, seps);
      }
    }
    fprintf(stdout, "%s", getResourceString(DBT_DISPLAY_LOGFILE_SELECT_BEGIN));

    logfiles = list_directory(logdir, 0);
      
    for(x=0; logfiles && logfiles[x]; x++) {
      if (curlog && !strcmp(curlog, logfiles[x])) {
        fprintf(stdout, getResourceString(DBT_DISPLAY_LOGFILE_VALUE_SELECTED),
                logfiles[x], logfiles[x]);
      }
      else {
        fprintf(stdout, getResourceString(DBT_DISPLAY_LOGFILE_SELECT_VALUE),
                logfiles[x], logfiles[x]);
      }
      at_least_one = 1;
    }

    if(!at_least_one)
      fprintf(stdout, "%s", getResourceString(DBT_DISPLAY_LOGFILE_NO_LOG));

    fprintf(stdout, "%s", getResourceString(DBT_DISPLAY_LOGFILE_SELECT_END));

}

/*
 * With the FHS work, plus the injunction against
 * paths in CGI parameters, we should get the
 * logdir from the server config, using the pset interface
 */
static char *
getLogDir(AdmldapInfo info, const char *id)
{
  int rval = 0;
  char *logdir = NULL;
  PsetHndl pset;
  char *configdir = util_get_conf_dir();

  if (!PL_strncasecmp(id, "admin-serv", strlen("admin-serv"))) {
    return PL_strdup(util_get_log_dir()); /* same as admin server log dir */
  }

  /* Log dir for the DS */
  /* create pset with this dn */
  pset = psetCreateSSL((char *)id, configdir, NULL, NULL, &rval);
  if (pset && ((rval == PSET_OP_OK) || (rval == PSET_LOCAL_OPEN_FAIL))) { /* only admin-serv uses local file */
    if (util_psetHasObjectClass(pset, DSOBJECTCLASS)) {
      char *host = psetGetAttrSingleValue(pset, "serverHostName", &rval);
      char *sport = psetGetAttrSingleValue(pset, "nsServerPort", &rval);
      char *ssecport = psetGetAttrSingleValue(pset, "nsSecureServerPort", &rval);
      char *ssecurity = psetGetAttrSingleValue(pset, "nsServerSecurity", &rval);
      int port, security;
      char *user = NULL;
      char *binddn = NULL;
      char *bindpw = admldapGetSIEPWD(info);
      int freebindpw = 1;
      char *p;

      ADM_GetUserDNString(&rval, &user);
      if (!user) {
        ADM_GetCurrentUsername(&rval, &user);
      }
      /* if user is just attr val, get dn */
      binddn = admldapGetUserDN(info, user);
      if (!bindpw) {
        freebindpw = 0;
        ADM_GetCurrentPassword(&rval, &bindpw);
      }
      security = (ssecurity && !PL_strcasecmp(ssecurity, "on")) ? 1 : 0;
      if (security) {
        if (ssecport) {
          port = atoi(ssecport);
        } else {
          port = 636;
        }
      } else {
        if (sport) {
          port = atoi(sport);
        } else {
          port = 389;
        }
      }

      psetDelete(pset);
      pset = psetRealCreateSSL(info, host, port, security, DSCONFIGENTRY,
                               binddn, bindpw, NULL, &rval);
      if (!pset) {
#ifdef LDAP_DEBUG
          char buf[BUFSIZ];
          fprintf(stderr, "Error: could not open pset to [%s:%d] dn (%s) as (%s): %d (%s)\n",
                  host, port, DSCONFIGENTRY, binddn, rval,
                  psetErrorString(rval, acceptLanguage, buf, sizeof(buf), NULL));
#endif
          goto done;
      }
      logdir = psetGetAttrSingleValue(pset, DSERRORLOGDIR, &rval);
      if (!logdir) {
#ifdef LDAP_DEBUG
          char buf[BUFSIZ];
          fprintf(stderr, "Error: could not read logdir from [%s:%d] dn (%s) as (%s): %d (%s)\n",
                  host, port, DSCONFIGENTRY, binddn, rval,
                  psetErrorString(rval, acceptLanguage, buf, sizeof(buf), NULL));
#endif
          goto done;
      }
      p = strstr(logdir, "/errors");
      if (p) {
          *p = '\0';
      }

done:
      PL_strfree(host);
      PL_strfree(sport);
      PL_strfree(ssecport);
      PL_strfree(ssecurity);
      PL_strfree(binddn);
      if (freebindpw) {
        memset(bindpw, 0, strlen(bindpw));
        PL_strfree(bindpw);
        bindpw = NULL;
      }
    }
  }
  psetDelete(pset);

  return logdir;
}

int main(int argc, char *argv[])
{

    int _ai = ADMUTIL_Init();
    char *qs = NULL;
    char line[BIG_LINE];
    FILE *html = open_html_file(MY_PAGE);
    char *method = NULL;
    char *nohtml = NULL;
    char *num=NULL;
    char *str=NULL;
    char *file;
    char *logdir = NULL;
    char *id;
    char tmp[BIG_LINE];
    int x;
    int print_html = 1;
    int proceed = 0;
    char msg[BUFSIZ];
    AdmldapInfo ldapInfo = NULL; /* our config */
    int rc = 0;
    char *configdir = NULL;

    (void)_ai; /* get rid of unused variable warning */
    i18nInit();

    fprintf(stdout, "Content-type: text/html;charset=utf-8\n\n");

    method = getenv("REQUEST_METHOD");
    if(method) {
        if(!strcmp(method, "GET")) {
            qs = getenv("QUERY_STRING");
            if(qs && *qs) {
                get_begin(qs);
                proceed = 1;
            }
        } else if(!strcmp(method, "POST")) {
            post_begin(stdin);
            proceed = 1;
        }
    }

    if(!proceed)
    {
        rpt_err(INCORRECT_USAGE,
              getResourceString(DBT_NO_ID),
              getResourceString(DBT_NO_ID_DESC), NULL);
    }

    num=get_cgi_var("num", NULL, NULL);
    str=get_cgi_var("str", NULL, NULL);
    file=get_cgi_var("file", NULL, NULL);
    id=get_cgi_var("id", NULL, NULL);
    nohtml=get_cgi_var("nohtml", NULL, NULL);

    if(!id)
        rpt_err(INCORRECT_USAGE,
                getResourceString(DBT_NO_ID),
                getResourceString(DBT_NO_ID_DESC), NULL);

    if(num)  {
        for(x=0; num[x]; x++)  {
            if(!isdigit(num[x]))
                rpt_err(INCORRECT_USAGE, getResourceString(DBT_INV_NUMBER), 
                        getResourceString(DBT_INV_NUMBER_DESC), NULL);
        }
    }

    if(!num) num=DEF_SIZE;

    configdir = util_get_conf_dir();
    ldapInfo = admldapBuildInfoOnly(configdir, &rc);
    if (rc || !ldapInfo) {
        PR_snprintf(line, sizeof(line), 
                    getResourceString(CMN_CONFIGPROBLEM),
                    configdir ? configdir : "(null)", rc);
        rpt_err(APP_ERROR, line, NULL, NULL);
    } else {
        const char *secdir = util_get_security_dir();
        if(ADMSSL_InitSimple((char *)configdir, (char *)secdir, 1)) {
            PR_snprintf(line, sizeof(line), getResourceString(CMN_SSL_INIT_ERROR),
                        secdir ? secdir : "(null)", PR_GetError(),
                        SSL_Strerror(PR_GetError()) ? SSL_Strerror(PR_GetError()) : "unknown");
            rpt_err(SYSTEM_ERROR, line, NULL, NULL);
        }

        logdir = getLogDir(ldapInfo, id);
        if(!logdir) {
            PR_snprintf(msg, sizeof(msg), 
                        getResourceString(DBT_NO_DIR_FOUND), id);
            rpt_err(INCORRECT_USAGE, getResourceString(DBT_NO_DIR), msg, NULL);
        }
    }

    if(nohtml) {
        for(x=0; nohtml[x]; x++) {
            if(!isdigit(nohtml[x]))
               rpt_err(INCORRECT_USAGE, getResourceString(DBT_INV_NUMBER),
                       getResourceString(DBT_INV_NUMBER_DESC), NULL);
        }

        if (atoi(nohtml) > 0) {
            /* print raw log content only */
            print_html = 0; 
        }
    }

    if (print_html ) {
        while(next_html_line(html, line))  {
            if(parse_line(line, NULL))  {
                if(directive_is(line, "LOG_TO_VIEW"))  {
                    display_logfiles(logdir, file);
                }
                else if(directive_is(line, "NUM_TO_VIEW"))  {
                    output_input("text", "num", num, NULL);
                }
                else if(directive_is(line, "STRING_TO_VIEW"))  {
                    output_input("text", "str", str, NULL);
                }
                else if(directive_is(line, "HIDDEN_ID"))  {
                    /* keep hidden track of what the current id are */
                    fprintf(stdout, (const char*)getResourceString(DBT_MAIN_HIDDEN_TRACK), id);
                }
                else if(directive_is(line, "ID_TITLE"))  {
                    fprintf(stdout, (const char*)getResourceString(DBT_MAIN_ID_TITLE), id);
                }
                else if(directive_is(line, "ACCESS_LOG"))  {
                    FILE *cmd;
                    char full_path[PATH_MAX];

#ifdef AIX
                    fflush(stdout);
#endif
                    if (!file || !*file ||
                        !util_is_valid_path_string(file) ||
                        !util_verify_file_or_dir(logdir, PR_FILE_DIRECTORY, file, -1, PR_FILE_FILE)) {
                        continue;
                    }

                    PR_snprintf(full_path, sizeof(full_path), "%s%c%s", logdir, FILE_PATHSEP, file);
                    cmd = fopen(full_path, "r");
                    fprintf(stdout, "%s", getResourceString(DBT_MAIN_WIDTH));
                    PR_snprintf(tmp, sizeof(tmp), getResourceString(DBT_SUBTITLE), num, file, (str)? getResourceString(DBT_WITH) : "",
                        (str)? str : "");

                    fprintf(stdout, (const char*)getResourceString(DBT_MAIN_TABLE), tmp);

                    fprintf(stdout, "%s", getResourceString(DBT_MAIN_TABLE_FONT));
                    /* begin search */
                    if(cmd) {
                        search_file(cmd, atoi(num), str);
                        fclose(cmd);
                    }
                    fprintf(stdout, "%s", getResourceString(DBT_MAIN_TABLE_FONT_CLOSE));
                } else {
                    fputs(line, stdout);
                }
            }  
        }
    } else {
        /* only print the raw log content */
        FILE *cmd;
        char full_path[PATH_MAX];

#ifdef AIX
        fflush(stdout);
#endif
        if (file && *file && util_is_valid_path_string(file) && 
            util_verify_file_or_dir(logdir, PR_FILE_DIRECTORY, file, -1, PR_FILE_FILE)) {
            PR_snprintf(full_path, sizeof(full_path), "%s%c%s", logdir, FILE_PATHSEP, file);
            cmd = fopen(full_path, "r");

            /* begin search */
            if(cmd) {
                search_file(cmd, atoi(num), str);
                fclose(cmd);
            }
        }
    }

    return 0;
}
