/*
 * Copyright (c) 2003-2014
 * Distributed Systems Software.  All rights reserved.
 * See the file LICENSE for redistribution information.
 */

/*****************************************************************************
 * COPYRIGHT AND PERMISSION NOTICE
 * 
 * Copyright (c) 2001-2003 The Queen in Right of Canada
 * 
 * All rights reserved.
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation 
 * the rights to use, copy, modify, merge, publish, distribute, and/or sell
 * copies of the Software, and to permit persons to whom the Software is 
 * furnished to do so, provided that the above copyright notice(s) and this
 * permission notice appear in all copies of the Software and that both the
 * above copyright notice(s) and this permission notice appear in supporting
 * documentation.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE 
 * BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES,
 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 
 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 
 * SOFTWARE.
 * 
 * Except as contained in this notice, the name of a copyright holder shall not
 * be used in advertising or otherwise to promote the sale, use or other
 * dealings in this Software without prior written authorization of the
 * copyright holder.
 ***************************************************************************/

/*
 * Utility/CGI program to print its environment, arguments, and CGI parameters
 *
 * If a CGI parameter called "FORMAT" is set to "HTML", then the output
 * format is HTML rather than text.
 */

#ifndef lint
static const char copyright[] =
"Copyright (c) 2003-2014\n\
Distributed Systems Software.  All rights reserved.";
static const char revid[] =
  "$Id: prenv.c 2676 2014-03-16 15:51:46Z brachman $";
#endif

#include "dacs.h"

#include <sys/utsname.h>

static MAYBE_UNUSED char *log_module_name = "dacs_prenv";

static int just_dump_stdin = 0;

extern char **environ;

static char *
fmt_kwv(int is_html, char *name, char *name_s, char *value, char *value_s)
{
  Ds ds;

  ds_init(&ds);
  if (is_html) {
	ds_asprintf(&ds, "<span class=\"%s\">%s</span>", name_s, name);
	ds_asprintf(&ds, "=");
	ds_asprintf(&ds, "<span class=\"%s\">%s</span>", value_s, value);
	ds_asprintf(&ds, "\n");
  }
  else
	ds_asprintf(&ds, "%s=%s\n", name, value);

  return(ds_buf(&ds));
}

static int
compar(const void *ap, const void *bp)
{
  const char *a, *b;

  a = *(const char **) ap;
  b = *(const char **) bp;

  return(strcmp(a, b));
}

int
main(int argc, char **argv)
{
  int xargc, emit_html, i, st;
  char **xargv, *errmsg, *qs;
  Dsvec *dsv;
  Kwv *kwv;
  Kwv_pair *v;
  struct utsname uts;
  Html_header_conf *hc;

  xargc = argc;
  xargv = argv;
  emit_html = 0;
  hc = emit_html_header_conf(NULL);
  errmsg = NULL;

  st = dacs_init(DACS_STANDALONE_SERVICE, &argc, &argv, NULL, &errmsg);

  /*
   * Always check for this flag, and before emitting anything.
   */
  for (i = 1; i < argc; i++) {
	if (strcaseeq(argv[i], "-html")) {
	  emit_html = 1;
	  break;
	}
  }

  if (st == -1) {
	emit_html ? emit_html_header(stdout, NULL) : emit_plain_header(stdout);
	if (errmsg != NULL)
	  printf("dacs_init() failed: %s\n", errmsg);
	else
	  printf("dacs_init() failed\n");
	emit_html ? emit_html_trailer(stdout) : emit_plain_trailer(stdout);

	exit(1);
  }

  if ((kwv = kwv_init(INIT_CGI_KWV)) == NULL) {
	emit_html ? emit_html_header(stdout, NULL) : emit_plain_header(stdout);
	printf("kwv_init failed\n");
	emit_html ? emit_html_trailer(stdout) : emit_plain_trailer(stdout);

	exit(1);
  }
  kwv_set_mode(kwv, "+d");

  qs = getenv("QUERY_STRING");
  if (just_dump_stdin || (qs != NULL && streq(qs, "just_dump_stdin"))) {
	char buf[1024];

	emit_html ? emit_html_header(stdout, NULL) : emit_plain_header(stdout);
	while (fgets(buf, sizeof(buf), stdin) != NULL)
	  printf("%s", buf);
	emit_html ? emit_html_trailer(stdout) : emit_plain_trailer(stdout);

	exit(1);
  }

  if (cgiparse(stdin, qs, kwv, NULL) == -1) {
	emit_html ? emit_html_header(stdout, NULL) : emit_plain_header(stdout);
	printf("cgiparse() failed\n");
	emit_html ? emit_html_trailer(stdout) : emit_plain_trailer(stdout);

	exit(1);
  }

  if ((v = kwv_lookup(kwv, "FORMAT")) != NULL && strcaseeq(v->val, "HTML"))
	emit_html = 1;

  if (emit_html) {
	if (conf_val(CONF_CSS_PATH) != NULL)
	  hc->css = ds_xprintf("%s/dacs_prenv.css", conf_val(CONF_CSS_PATH));
	else
	  hc->css = CSS_DIR/**/"/dacs_prenv.css";
	hc->title = "Output of dacs_prenv";

	emit_html_header(stdout, hc);
  }
  else
	emit_plain_header(stdout);

  if (emit_html)
	printf("<h1>Command line arguments:</h1><pre>\n");
  else
	printf("Command line arguments:\n");

  for (i = 0; i < xargc; i++) {
	printf("%s", fmt_kwv(emit_html,
						 ds_xprintf("argv[%d]", i), "argname",
						 ds_xprintf("\"%s\"", xargv[i]), "argvalue"));
  }

  if (emit_html) printf("</pre><p>");
  printf("\n");

  if (emit_html)
	printf("<h1>Environment variables:</h1><pre>");
  else
	printf("Environment variables:\n");

  /* Let's do it this way, just because... */
  dsv = NULL;
  dsvec_set(dsv, environ, char *, 0);
  dsvec_sort(dsv, compar);

  for (i = 0; i < dsvec_len(dsv); i++) {
	char *p, *q, *name, *v, *value;

	p = (char *) dsvec_ptr_index(dsv, i);
	env_parse(p, &name, &value);

	if (streq(name, "SERVER_SIGNATURE")) {
	  /* Why does someone think that marking this up is a good idea? */
	  v = strdup(value);
	  if ((q = strcaseprefix(v, "<address>")) != NULL) {
		v = q;
		if ((q = strcasesuffix(v, strlen(v), "</address>\n")) != NULL) {
		  *q = '\0';
		  value = v;
		}
	  }
	}

	printf("%s", fmt_kwv(emit_html, name, "envname",
						 ds_xprintf("\"%s\"", value), "envvalue"));
  }

  if (emit_html) printf("</pre><p>");
  printf("\n");

  if (uname(&uts) == 0) {
	if (emit_html)
	  printf("<h1>Platform:</h1><pre>");
	else
	  printf("Platform:\n");

	printf("%s%s%s%s%s",
		   fmt_kwv(emit_html, "sysname", "envname",
				   ds_xprintf("\"%s\"", uts.sysname), "envvalue"),
		   fmt_kwv(emit_html, "nodename", "envname",
				   ds_xprintf("\"%s\"", uts.nodename), "envvalue"),
		   fmt_kwv(emit_html, "release", "envname",
				   ds_xprintf("\"%s\"", uts.release), "envvalue"),
		   fmt_kwv(emit_html, "version", "envname",
				   ds_xprintf("\"%s\"", uts.version), "envvalue"),
		   fmt_kwv(emit_html, "machine", "envname",
				   ds_xprintf("\"%s\"", uts.machine), "envvalue"));
	if (emit_html)
	  printf("</pre><p>");
  }

  printf("\n");

  if (emit_html)
	printf("<h1>CGI parameters:</h1><pre>");
  else
	printf("CGI parameters:\n");
	
  for (i = 0; i < kwv->nused; i++) {
	long len;

	for (v = kwv->pairs[i]; v != NULL; v = v->next) {
	  len = (long) strlen(v->val);
	  printf("%s", fmt_kwv(emit_html,
						   "Name", "envname",
						   ds_xprintf("\"%s\"", v->name), "envvalue"));

	  printf("%s", fmt_kwv(emit_html,
						   ds_xprintf("Value (%ld byte%s)",
									  len, len == 1 ? "" : "s"), "envname",
						   ds_xprintf("\"%s\"", v->val), "envvalue"));
	}
  }

  if (emit_html) printf("</pre>");

  emit_html ? emit_html_trailer(stdout) : emit_plain_trailer(stdout);

  exit(0);
}
