/* Nessus
 * Copyright (C) 1998 - 2001 Renaud Deraison
 * Copyright (C) 2004 Intevation GmbH
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2,
 * as published by the Free Software Foundation
 *
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * In addition, as a special exception, Renaud Deraison
 * gives permission to link the code of this program with any
 * version of the OpenSSL library which is distributed under a
 * license identical to that listed in the included COPYING.OpenSSL
 * file, and distribute linked combinations including the two.
 * You must obey the GNU General Public License in all respects
 * for all of the code used other than OpenSSL.  If you modify
 * this file, you may extend this exception to your version of the
 * file, but you are not obligated to do so.  If you do not wish to
 * do so, delete this exception statement from your version.
 *
 * This code deals with the PDF report output.
 */
 
#include <includes.h>

#ifdef CYGWIN
#include <sys/cygwin.h>
#endif /* CYGWIN */

#include "report.h"
#include "report_utils.h"
#include "html_output.h"
#include "error_dlg.h"
#include "globals.h"
#include "preferences.h"
#include "backend.h"
#include "data_mining.h"
#include "nessus_plugin.h"

#include "nessus_i18n.h"

/**
 * \file
 * PDF export currently works with an intermediate html export.
 * The intermediate html file is then used to create a pdf, calling the external
 * tool "htmldoc".
 */


int arglist_to_plainhtml(struct context *, int, char *);
void pdf_summary_to_file(FILE *, int, struct arglist *);
static void print_appendix(FILE *, GHashTable*);


/**
 * Print the utf8 strings as locale strings to file.
 * Obviously this is not an elegant implementation, but I am currently
 * unsure how and how far this method should/must be extended to other
 * modules.
 * Once it is going to be generalized, the implementation should be
 * made more clever.
 */
#define PRINT(file, x) { char * s = _2l(x); fprintf(file, s); g_free(s); }
#define PRINT1(file, x, v) { char * s = _2l(x); fprintf(file, s, v); g_free(s); }

/**
 * Convert the UTF-8 String to what locale is set to.
 * Unfortunately this is required htmldoc does not honor
 * the UTF-8 encoding setting in the html file.
 */
char *
_2l (char * utfstr)
{
  char * localestr;
  gsize bytes_read, bytes_written;
  GError * error;

  localestr = g_locale_from_utf8(utfstr, -1, &bytes_read,
                                 &bytes_written, &error);

  return localestr;
}

/**
 * Print format string 'fmt' to file with one %s
 * replaced with first timestamp of type = 'type'
 * (optionally host = 'host') from backend 'be'.
 * Doesn't print anything if no timestamp is found.
 *
 * TODO: Format timestamp according to locale settings.
 */
static void
PRINT_timestamp (FILE * file, int be, const char *fmt, const char *type,
                 const char *host)
{
 struct subset *s;
 char *query;

 if(host)
   query = g_strdup_printf("SELECT date FROM timestamps WHERE "
       "type = '%s' and host = '%s'", type, host);
 else
   query = g_strdup_printf("SELECT date FROM timestamps WHERE "
       "type = '%s'", type);

 s = query_backend(be, query);
 g_free(query);
 if(s && subset_size(s))
 {
  char *output = g_strdup_printf(fmt, subset_value(s));

  PRINT(file, output);
  g_free(output);
 }
 subset_free(s);
}

/**
 * Writes html table rows with information about a found security issue, 
 * containing a link to the plugin (in the appendix or online).
 * The security class (currently in use: Informational, Warning and 
 * Vulnerability) will be highlighted in a specific color (colorcode parameter).
 * 
 * @param file The file to write to.
 * @param reportplugin The plugin of which to extract description etc.
 * @param colorcode Colorcode to be used for highlighting the class string.
 * @param class Class of security issue (currently in use: Informational, 
 *              Warning and Vulnerability).
 * @param include_plugins If TRUE the link will be internal (appendix).
 */
static void html_print_plugin_box (FILE* file, struct arglist* reportplugin,
                                   char* colorcode, char* class,
                                   gboolean include_plugins)
{
  char* desc = html_output_convert_cr_to_html(reportplugin->value);
  fprintf(file, "\t<tr bgcolor=\"%s\">\n", colorcode);
  fprintf(file, "\t\t<td valign=\"top\">");
  PRINT(file, class);
  fprintf(file, "\t\t</td");
  fprintf(file, "\t</tr>\n");
  fprintf(file, "\t<tr>\n");
  fprintf(file, "\t\t<td>\n");
  html_output_print_data_with_links(file, desc, reportplugin->name, include_plugins);
  fprintf(file, "\n\t\t</td>\t</tr>\n");
  efree(&desc);
}

static int
exec_htmldoc (char ** argv)
{
 int ret;
 int pid;


 pid = fork();
 if ( pid == 0 )
 {
   int i;
   for ( i = 3 ; i < getdtablesize(); i++ ) close(i);
   ret = execvp(argv[0], argv);
   if ( ret ) exit(127);
   else exit(0);
 }
 if ( pid < 0 ) show_error(_("Could not fork (out of memory?)"));

 for ( ;; )
 {
  int e;
  errno = 0; 
  e =  waitpid(pid, &ret, 0);
  if ( e < 0 && errno == EINTR ) continue; 
  else break;
 }

 return WEXITSTATUS(ret);
}

// TODO replace argv handling and exec_htmldoc with glib functions.
char**
append_argv (char **argv, char   *opt)
{
  int argc, n ;
  
  /* special case */
  if (opt == 0) {
    if (argv == 0) 
      (argv = emalloc(sizeof (char*))) [0] = 0 ;
    return argv ;
  }
  
  if (argv == 0) {
    argc = 1 ;
    argv = emalloc(2 * sizeof (char*));
  } else {

    /* calculate dim (argv) - 1 */
    argc = 0 ;
    while (argv [argc ++] != 0)
      ;

    /* append one more item */
    n = (++ argc) * sizeof (char*) ;
    argv = erealloc(argv, n) ;
    argv [-- argc] = 0 ;
  }

  /* append one duplicated item before the NULL entry */
  argv [-- argc] = estrdup(opt);
  return argv ;
}

void
destroy_argv (char **argv)
{
  int argc ;
  if (argv == 0)
    return ;
  for (argc = 0; argv [argc] != 0; argc ++)
    efree (&argv [argc]) ;
  efree (&argv);
}


/**
 * Exports arglist to html (temporarily creates report.html!), then calls 
 * htmldoc to produce a pdf file.
 * 
 * @param be The backend index.
 * @param filename Filename to write to.
 * 
 * @return Returns always 0.
 * 
 * @see exec_htmldoc
 * @see arglist_to_plainhtml
 */
int
arglist_to_pdf (struct context * context, int be, char * filename)
{
 char tmpfname[PATH_MAX];
 char * cwd = emalloc(PATH_MAX * sizeof(char));
 int cwd_max = PATH_MAX-1;
 int htmldoc_ret;
 char ** argv = NULL;

#ifdef CYGWIN
 char w32name[PATH_MAX];

 /* On Windows we need the specific location of the htmldoc program and
  * its data files.
  * By default it is assumed it is installed as part of
  * NessusClient installation.
  */
 char * htmldoc_datadir = g_win32_get_package_installation_subdirectory(NULL,
                            NULL, "share\\htmldoc");
 char * htmldoc_program = g_win32_get_package_installation_subdirectory(NULL,
                            NULL, "bin\\htmldoc.exe");
#endif /* CYGWIN */

 const char *nessus_dir = estrdup(prefs_get_string(Global, "nessus_dir"));

 snprintf(tmpfname, PATH_MAX, "%s/.openvas_%d_pdf", nessus_dir, getpid());
 
 while (!getcwd(cwd, cwd_max))
 {	cwd_max=cwd_max+PATH_MAX;
	cwd = erealloc(cwd, (cwd_max+1) * sizeof(char));
 }
 mkdir(tmpfname,0700);
 chdir(tmpfname);

 /* Write the arglist to plain HTML suitable to be processed by HTMLDoc */
 arglist_to_plainhtml(context, be, "report.html");

#ifndef CYGWIN
 argv = append_argv(argv,  "htmldoc");
#else
 argv = append_argv(argv,  htmldoc_program);
 argv = append_argv(argv,  "--datadir");
 argv = append_argv(argv,  htmldoc_datadir);
#endif /* CYGWIN */
 argv = append_argv(argv,  "--firstpage");
 argv = append_argv(argv,  "p1");
 argv = append_argv(argv,  "--footer");
 argv = append_argv(argv,  "./c");
 argv = append_argv(argv,  "--header");
 argv = append_argv(argv,  "..t");
 argv = append_argv(argv,  "--fontsize");
 argv = append_argv(argv,  "10");
 argv = append_argv(argv,  "--quiet");
 argv = append_argv(argv,  "--webpage");
 argv = append_argv(argv,  "-f");
#ifndef CYGWIN
 argv = append_argv(argv,  filename);
#else
 cygwin_conv_to_win32_path(filename, w32name);
 argv = append_argv(argv,  w32name);
#endif /* CYGWIN */
 argv = append_argv(argv,  "report.html");
 htmldoc_ret = exec_htmldoc(argv);

 if (htmldoc_ret != 0) {
   if ( htmldoc_ret == 127 )
   	show_error(_("PDF report export failed!\nMaybe HTMLDoc (required for PDF export) is not installed or in search path."));
   else
   	 show_error(_("PDF report export failed! (htmldoc exit code: %d)"), htmldoc_ret);

   htmldoc_ret = 0;
 }
 /* Clean up */
 unlink("report.html");
 chdir(cwd);
 rmdir(tmpfname);
 efree(&cwd);

#ifdef CYGWIN
 g_free(htmldoc_datadir);
 g_free(htmldoc_program);
#endif /* CYGWIN */
 argv = append_argv(argv, NULL);
 destroy_argv (argv);
 return(htmldoc_ret);
}

/* As pdf export works via intermediate html export, it might be worth looking
   at arglist_html (html_output.c), refactor and merge. */
/**
 * Exports a backend into plain html to be converted to a pdf using htmldoc.
 * 
 * @param be Index of backend to use.
 * @param filename Filename of file to export to or "-" to print to stdout.
 * @return 0 on success, -1 on error.
 */
int
arglist_to_plainhtml (struct context * context, int be, char *filename)
{
 FILE *file;
 struct arglist *hosts;
 GHashTable * appendix_plugins = NULL;
 int include_plugins = (prefs_get_int(Global, "report_plugin_details_in_pdf")
     && context->plugins != NULL);

 if(!strcmp(filename, "-")) file = stdout;
 else file = fopen(filename, "w");
 if(!file){
 	show_error(_("Could not create this file !"));
	perror("fopen ");
	return(-1);
	}

 if (include_plugins)
   appendix_plugins = g_hash_table_new(g_str_hash, g_str_equal);

 hosts = backend_convert(be);

 /* Print the Style Sheet Opts and Report Summary */
 pdf_summary_to_file(file, be, hosts);

 fprintf(file, "\n<p>&nbsp;</p>\n<h2>");
 PRINT(file, _("Reports per Host"));
 fprintf(file, "</h2>\n");
 
 /* Loop through hosts and print out their problems "Host List"*/
 while(hosts && hosts->next)
 {
  char * hostname;
  char * port;
  struct arglist * ports;
  char * href;
  char * name;
  hostname = hosts->name;

  href = html_output_portname_to_ahref(NULL, hostname);
  fprintf(file, "\n<h3>%s</h3>\n<a name=\"%s\"></a>\n", hostname, href);
  name = html_output_portname_to_ahref("toc", hostname);
  fprintf(file, "<a name=\"%s\"></a>\n", name);
  efree(&name);

  PRINT_timestamp(file, be, _("Scan of this host started at: %s<br>\n"),
      "host_start", hostname);
  PRINT_timestamp(file, be, _("Scan of this host finished at: %s<br>\n"),
      "host_end", hostname);

//  fprintf(file, "\n<h4>Analysis of Host %s</h4>\n", hostname);
  fprintf(file, "<table border=1 bordercolor=\"#c1c1c1\" width=\"100%%\"\n");
  fprintf(file, "       cellpadding=2 cellspacing=0>\n");

  fprintf(file, "\t<tr bgcolor=\"#A2B5CD\">\n");
//  fprintf(file, "\t\t<td width=\"20%%\">Adress of Host</td>\n");
  fprintf(file, "\t\t<td width=\"40%%\">");
  PRINT(file, _("Service (Port)"));
  fprintf(file, "</td>\n");
  fprintf(file, "\t\t<td width=\"60%%\">");
  PRINT(file, _("Issue regarding port"));
  fprintf(file, "</td>\n");
  fprintf(file, "\t</tr>\n");

  ports = arg_get_value(hosts->value, "PORTS");
  if(ports)
  {
     struct arglist * open = ports;
     if(open->next)
     {
        while(open && open->next){
          name = html_output_portname_to_ahref(open->name, hostname);
	  if(name)
	  {
	      if(arg_get_value(open->value, "REPORT") ||
	         arg_get_value(open->value, "INFO") ||
	         arg_get_value(open->value, "FALSE") ||
	         arg_get_value(open->value, "NOTE")) 
	      {
	             fprintf(file, "\t<tr>\n");
	             fprintf(file, "\t\t<td><a href=\"#%s\">%s</a></td>\n",
	   				name, open->name);
	             if(arg_get_value(open->value, "REPORT")) {
		     	fprintf(file, "\t\t<td><font color=red>");
			PRINT(file, _("Security hole(s) found"));
			fprintf(file, "</font></td>\n");
		     }
	             else if(arg_get_value(open->value, "INFO")) {
			fprintf(file, "\t\t<td>");
		     	PRINT(file, _("Security warning(s) found"));
			fprintf(file, "</td>\n");
		     }
	             else if(arg_get_value(open->value, "FALSE")) {
			fprintf(file, "\t\t<td>");
		     	PRINT(file, _("False positive(s) found"));
			fprintf(file, "</td>\n");
		     }
	             else {
			fprintf(file, "\t\t<td>");
		     	PRINT(file, _("Security note(s) found"));
			fprintf(file, "</td>\n");
		     	fprintf(file, "\t</tr>");
		     }
	      }
	        else {	// Not port, info or note
		     fprintf(file, "\t<tr>\n");
		     fprintf(file, "\t\t<td>%s</td>\n", open->name);
		     fprintf(file, "\t\t<td>");
		     PRINT(file, _("No Information"));
		     fprintf(file, "</td>\n\t</tr>");
	      }
	      efree(&name);
	  }
	  else { // No port name
	      fprintf(file, "\t<tr>\n");
              fprintf(file, "\t\t<td>%s</td>\n", open->name);
	      fprintf(file, "\t\t<td>");
	      PRINT(file, _("No Information"));
	      fprintf(file, "</td>\n\t</tr>");
	    }
	  open = open->next;
       }
     }
  }
  fprintf(file, "</table>\n");
  fprintf(file, "<font size=-2><a href=\"#_summary\">");
  PRINT(file, _("[ return to summary ]"));
  fprintf(file, "</a></font><br><br>\n");

  fprintf(file, "\n<h4>");
  PRINT1(file, _("Security Issues and Fixes - Host %s"), hostname);
  fprintf(file, "</h4>\n");

  /*
   * Write the summary of the open ports here
   */
   while(ports && ports->next)
   {
    struct arglist * report;
    struct arglist * info;
    struct arglist * note;
    struct arglist * false_positive;

    port = ports->name;

    name = html_output_portname_to_ahref(ports->name, hostname);

    report = arg_get_value(ports->value, "REPORT");
    info = arg_get_value(ports->value, "INFO");
    note = arg_get_value(ports->value, "NOTE");
    false_positive = arg_get_value(ports->value, "FALSE");

    if (report || info || note || false_positive)
    {
    fprintf(file, "<h4><a name=\"%s\"></a>%s - %s</h4>\n", name, hostname, port);
    fprintf(file, "<table border=1 bordercolor=\"#c1c1c1\" width=\"100%%\"\n");
    fprintf(file, "       cellpadding=2 cellspacing=0>\n");

    while(report && report->next)
     {
     if(strlen(report->value))
       {
       // Print info about plugins, eventually add to appendix
       html_print_plugin_box(file, report, "#FF5050", "Vulnerability", 
                        include_plugins);
       if(include_plugins)
         g_hash_table_insert(appendix_plugins, report->name, context);
       }
     report = report->next;
     }

    while(info && info->next)
     {
     if(strlen(info->value))
       {
        name = html_output_portname_to_ahref(ports->name, hostname);
        html_print_plugin_box(file, info, "#FFFFA0", "Warning", 
                        include_plugins);
        if (include_plugins)
          g_hash_table_insert(appendix_plugins, info->name, context);
       }
     info = info->next;
    }

   while(note && note->next)
    {
     if(strlen(note->value))
     {
     char * name;
     //desc = emalloc(strlen(note->value)+1);
     //strncpy(desc, note->value, strlen(note->value));
     /* Convert the \n to <br>, make "<",">" html- safe */
     name = html_output_portname_to_ahref(ports->name, hostname);
     html_print_plugin_box(file, note, "#ABABE1", "Informational", 
                        include_plugins);
     if (include_plugins)
       g_hash_table_insert(appendix_plugins, note->name, context);
     }
     note = note->next;
    }

    while(false_positive && false_positive->next)
    {
     if(strlen(false_positive->value))
     {
       char * name;
       name = html_output_portname_to_ahref(ports->name, hostname);
       html_print_plugin_box(file, false_positive, "#ABABE1", "False Positive", 
			  include_plugins);
       if (include_plugins)
	 g_hash_table_insert(appendix_plugins, false_positive->name, context);
     }
     false_positive = false_positive->next;
    }

    fprintf(file, "\t</table>\n");
    fprintf(file, "<font size=-2><a href=\"#%s\">", href);
    PRINT1(file, _("[ return to %s ]"), hostname);
    fprintf(file, "</a></font><br><br>\n");
    efree(&name);
    }
    ports = ports->next;
   }

  hosts = hosts->next;
  efree(&href);
 }

 if (include_plugins && g_hash_table_size(appendix_plugins) > 0)
 {
   fprintf(file, "<hr>\n\n");
   print_appendix(file, appendix_plugins);
 }

 fprintf(file, "<hr>\n<i>");
 PRINT(file, 
	_("This file was generated by <a href=\"http://www.openvas.org\">"
          "OpenVAS</a>, the free security scanner."));
 fprintf(file, "</i></BODY>\n");
 fprintf(file, "</HTML>\n");
 fclose(file);

 if (appendix_plugins)
   g_hash_table_destroy(appendix_plugins);

 if(hosts)
   arg_free_all(hosts);
 return(0);
}


void pdf_summary_to_file (FILE *file, int be, struct arglist *hosts)
{
 struct arglist * dummy = hosts;

 fprintf(file, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Transitional//EN\">\n");
 fprintf(file, "<HTML>\n");
 fprintf(file, " <HEAD>\n");
 fprintf(file, " <TITLE>");
 PRINT(file, _("OpenVAS Scan Report"));
 fprintf(file, "</TITLE>\n");
 fprintf(file, " <meta http-equiv=\"Content-Type\" content=\"text/html; ");
 fprintf(file, "       charset=\"iso-8859-1\"\">\n");
 fprintf(file, "</HEAD>\n");
 fprintf(file, "<BODY>\n");

 /*
  * Write a (small) summary Hosts that are up, holes/warnings ect.
  */
 fprintf(file, "<h2>");
 PRINT(file, _("Summary"));
 fprintf(file, "</h2>\n");
 fprintf(file, "<a name=\"_summary\">\n");

 PRINT(file, _("This report gives details on hosts that were tested and issues that were found. "));
 PRINT(file, _("Please follow the recommended steps and procedures to eradicate these threats.\n"));
 fprintf(file, "\t<p>\n");
 fprintf(file, "\n");

 PRINT_timestamp(file, be, _("Scan started at: %s<br>\n"), "scan_start", NULL);
 PRINT_timestamp(file, be, _("Scan finished at: %s<br>\n"), "scan_end", NULL);

 fprintf(file, "\n<table border=1 bordercolor=\"#c1c1c1\" \n");
 fprintf(file, "       cellpadding=2 cellspacing=0>\n");
 fprintf(file, "\t<tr bgcolor=\"#A2B5CD\">\n");
 fprintf(file, "\t\t<td width=\"16%%\">");
 PRINT(file, _("Host"));
 fprintf(file, "</td>\n");
 fprintf(file, "\t\t<td width=\"32%%\">");
 PRINT(file, _("Possible Issues"));
 fprintf(file, "</td>\n");
 fprintf(file, "\t\t<td width=\"13%%\">");
 PRINT(file, _("Holes"));
 fprintf(file, "</td>\n");
 fprintf(file, "\t\t<td width=\"13%%\">");
 PRINT(file, _("Warnings"));
 fprintf(file, "</td>\n");
 fprintf(file, "\t\t<td width=\"13%%\">");
 PRINT(file, _("Notes"));
 fprintf(file, "</td>\n");
 fprintf(file, "\t\t<td width=\"13%%\">");
 PRINT(file, _("False Positives"));
 fprintf(file, "</td>\n");
 while (dummy && dummy->next) {
  	int result;
  	char * href = html_output_portname_to_ahref(NULL, dummy->name);

	/* The host name */
	fprintf(file, "\t<tr>\n");
	fprintf(file, "\t\t<td><a href=\"#%s\">%s</a></td>\n", href, 
							       dummy->name);
  	efree(&href);
			
	/* The maximal issue found for this host */
  	result = is_there_any_hole(dummy->value);
  	if(result == HOLE_PRESENT) {
 		fprintf(file, "\t\t<td><font color=red>");
		PRINT(file, _("Security hole(s) found"));
		fprintf(file, "</font></td>\n");
	}
  	else if(result == WARNING_PRESENT) {
		fprintf(file, "\t\t<td>");
		PRINT(file, _("Security warning(s) found"));
		fprintf(file, "</td>\n");
	}
  	else if(result == NOTE_PRESENT) {
		fprintf(file, "\t\t<td>");
		PRINT(file, _("Security note(s) found"));
		fprintf(file, "</td>\n");
	}
  	else if(result == FALSE_PRESENT) {
		fprintf(file, "\t\t<td>");
		PRINT(file, _("False positive(s) found"));
		fprintf(file, "</td>\n");
	}
  	else {
		fprintf(file, "\t\t<td>");
		PRINT(file, _("No noticeable information found"));
		fprintf(file, "</td>\n");
	}
				
	/* The numbers of holes, warnings and notes for this host */
	fprintf(file, "\t\t<td align=\"center\">%d</td>\n",
	       	number_of_holes_by_host(dummy->value)); 	
	fprintf(file, "\t\t<td align=\"center\">%d</td>\n",
		number_of_warnings_by_host(dummy->value));
	fprintf(file, "\t\t<td align=\"center\">%d</td>\n",
	       	number_of_notes_by_host(dummy->value));
	fprintf(file, "\t\t<td align=\"center\">%d</td>\n",
	       	number_of_false_positives_by_host(dummy->value));
	fprintf(file, "\t</tr>\n");
	dummy = dummy->next;
 }
 fprintf(file, "\t<tr>\n");

 /* Sum up the numbers ... */
 fprintf(file, "\t\t<td>");
 PRINT(file, _("Total"));
 fprintf(file, ": %d</td>\n\t\t<td>&nbsp;</td>\n",
	arglist_length(hosts)); 
 fprintf(file, "\t\t<td align=\"center\">%d</td>\n",
	number_of_holes(hosts));	
 fprintf(file, "\t\t<td align=\"center\">%d</td>\n",
	number_of_warnings(hosts));
 fprintf(file, "\t\t<td align=\"center\">%d</td>\n",
       	number_of_notes(hosts));
 fprintf(file, "\t\t<td align=\"center\">%d</td>\n",
       	number_of_false_positives(hosts));
 fprintf(file, "\t</tr>\n");
 fprintf(file, "</table>\n");
}


static void
print_plugin_table_row (FILE *file, char *fieldname, char *text)
{
  char *html = html_output_convert_cr_to_html(text);
  fprintf(file, "\t<tr><td align=\"right\" valign=\"top\"><b>%s</b></td>"
      "<td>%s</td></tr>\n", fieldname, html);
  efree(&html);
}


static void
print_prefs_row (FILE *file, char *pref, char *text)
{
  char *pref_html = html_output_convert_cr_to_html(pref);
  char *text_html = html_output_convert_cr_to_html(text);
    fprintf(file, "\t<tr><td><b>%s</b></th><td>%s</td></tr>\n",
	pref_html, text_html);
  efree(&text_html);
  efree(&pref_html);
}


/**
 * Prints names and trust level of signatures of a NVT in an unordered list in
 * a table row with two cells (left hand cell will contain "Signed by:").
 * Uses non-conform html list item tags not nested in a list, to force htmldoc 
 * to insert bullets for them.
 * 
 * @param file File to write to.
 * @param nvt Pointer to plugin as nessus_plugin struct.
 * @param context The context used to retrieve certificate information.
 */
static void
print_plugin_information_signatures (FILE* file, struct nessus_plugin* nvt, 
                                     struct context* context)
{
  int idx = 0;
  gchar** fprs;

  if( nvt->sign_key_ids == NULL
      || strcmp(nvt->sign_key_ids, "") == 0
      || strcmp(nvt->sign_key_ids, "NOSIGNKEYS") == 0)
    {
    print_plugin_table_row(file, _("Signed by"), _("not signed"));
    }
  else if (context->signer_fp_certificates == NULL)
  {
    print_plugin_table_row(file, _("Signed by"), 
                                 _("unknown signature(s)"));
  }
  else
    {
    /* fprs contains (comma separated) fingerprint(s) that are keys in 
       the contexts hashtable. extract and look up */
    fprs = g_strsplit_set(nvt->sign_key_ids, ",", -1);
    // Start table row
    fprintf(file, "\t<tr><td align=\"right\" valign=\"top\"><b>%s</b></td>"
                  "<td align=\"left\">", _("Signed by"));

    while (fprs[idx] != NULL)
      {
      openvas_certificate* cert = 
                g_hash_table_lookup(context->signer_fp_certificates, fprs[idx]);
      if(cert != NULL)
        {
        const char* trust = (cert->trusted == TRUE) ? _("trusted")
                                              : _("not trusted");
        char* text = g_strdup_printf ("%s (%s)", cert->ownername, trust);
        // Print ownername and trustlevel in good (trusted, green) or bad color
        fprintf(file, "<li><font color=\"%s\">%s</font></li>", 
                      (cert->trusted == TRUE) ? "#006600" : "#660000", text);
        g_free(text);
        }
      else
        {
        // Certificate not found in hashtable
        fprintf(file, "<li><font color=\"%s\">%s</font></li>", 
                                         "#660000", _("unknown signature"));
        }
      idx++;
      }
    // End the unordered list and table row 
    fprintf(file, "\n\t</td></tr>\n");
    g_strfreev(fprs);
    }
}

static void
print_plugin_information(gpointer key, gpointer value, gpointer userdata)
{
  struct context *context = value;
  FILE *file = userdata;
  char *plugin_oid = key;
  struct nessus_plugin *plugin;
  char *description;
  char *html_description;

  plugin = nessus_plugin_get_by_oid(context->plugins, plugin_oid);
  if (plugin == NULL)
    plugin = nessus_plugin_get_by_oid(context->scanners, plugin_oid);

  if (plugin == NULL)
  {
    fprintf(stderr, "print_plugin_information: no plugin with oid %s\n",
	plugin_oid);
    return;
  }

  fprintf(file, "<H3><a name=\"nvt%s\">NVT %s: %s</a></H3>\n\n",
      plugin_oid, plugin_oid, plugin->name);

  fprintf(file, "<table>\n");
  print_plugin_table_row(file, _("Summary"), plugin->summary);
  print_plugin_table_row(file, _("Category"), plugin->category);
  print_plugin_table_row(file, _("Family"), plugin->family);
  print_plugin_table_row(file, _("Version"), plugin->version);
  if(plugin->cve != NULL && strcmp(plugin->cve, "NOCVE") != 0)
    print_plugin_table_row(file, _("CVE"), plugin->cve);
  if(plugin->bid != NULL &&  strcmp(plugin->bid, "NOBID") != 0)
    print_plugin_table_row(file, _("BID"), plugin->bid);
  if(plugin->xrefs != NULL &&  strcmp(plugin->xrefs, "NOXREF") != 0)
    print_plugin_table_row(file, _("XRefs"), plugin->xrefs);
  print_plugin_information_signatures(file, plugin, context);
  fprintf(file, "</table>");

  description = nessus_plugin_get_description(plugin);
  html_description = html_output_convert_cr_to_html(description);
  PRINT1(file, "<p></p>\n<h4>%s</h4>\n", _("Description"));
  fputs(html_description, file);
  efree(&html_description);

  fprintf(file, "\n<p>\n");

  if (plugin->plugin_prefs)
  {
    struct arglist *prefs = plugin->plugin_prefs;

    PRINT1(file, "<p></p>\n<h4>%s</h4>\n<table>\n", _("Parameters"));

    while (prefs && prefs->next)
    {
      if (prefs->type == ARG_ARGLIST)
      {
	print_prefs_row(file, prefs->name,
	    (char*)arg_get_value(prefs->value, "value"));
      }
      else
	fprintf(stderr,
	    "print_plugin_information: plugin_prefs is not ARG_ARGLIST\n");

      prefs = prefs->next;
    }

    fputs("</table>\n<p>", file);
  }
}


/**
 * Writes plugin information tables (in html) for a number of plugins.
 * @param file The html file to write to.
 * @param hash HashTable containing the nessus_plugins.
 * @see print_plugin_information
 */
static void
print_appendix(FILE *file, GHashTable *hash)
{
  PRINT1(file, "<H2>%s</H2>\n\n", _("Appendix: NVT Information"));

  g_hash_table_foreach(hash, print_plugin_information, file);
}
