/* Nessus
 * Copyright (C) 1998 - 2001 Renaud Deraison
 *
 * 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 'save report' dialog.
 */


#include <includes.h>
#ifdef USE_GTK
#include <gtk/gtk.h>

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

#include "preferences.h"
#include "context.h"
#include "error_dlg.h"
#include "backend.h"
#include "html_output.h"
#include "report_utils.h"
#include "latex_output.h"
#include "text_output.h"
#include "xml_output_ng.h"
#include "html_graph_output.h"
#include "nbe_output.h"
#include "pdf_output.h"

#include "nessus_i18n.h"

#include "globals.h"

#define SAVE_NBE 	0
#define SAVE_HTML 	1
#define SAVE_TEXT 	2
#define SAVE_LATEX 	3
#define SAVE_HTML_GRAPH 4
#define SAVE_PDF 	5
#define SAVE_XML_NG 	6
#define SAVE_MAX SAVE_XML_NG


/**
 * @brief Callback for report export filename and type (nbe, html...) selection
 * widget.
 * 
 * Determines export target type and converts the backend appropriately, e.g.
 * by calling arglist_to_html.
 * 
 * @return Always 0.
 * 
 * @see arglist_to_html
 * @see backend_to_nbe
 * @see report_save_cb
 */
static int
file_save_ok_callback (GtkWidget *widget, GtkWidget *filedialog)
{
  const char *filename =
    gtk_file_selection_get_filename(GTK_FILE_SELECTION(filedialog));
  char *basename = g_path_get_basename(filename);
  char *ext = strrchr(basename, '.');
  char *fname;
  struct arglist *hosts = NULL;
  GtkWidget *menu = gtk_object_get_data(GTK_OBJECT(filedialog), "menu");
  GtkWidget *active = gtk_menu_get_active(GTK_MENU(menu));
  int type = GPOINTER_TO_SIZE(gtk_object_get_data(GTK_OBJECT(active), "type"));
  char *suffixes[] = { ".nbe", ".html", ".txt", ".tex", "", ".pdf", ".xml"};
#define MAX_SUFFIX_LEN 5 /* .html */
  char *suffix = suffixes[type];
  int be = GPOINTER_TO_SIZE(arg_get_value(arg_get_value(MainDialog, "REPORT"), "BE"));
  struct context *report_context
    = arg_get_value(arg_get_value(MainDialog, "REPORT"), "REPORT_CONTEXT");

  gboolean was_mapped = report_context->is_severity_mapped;
  report_context->is_severity_mapped = FALSE;

  gtk_widget_hide(filedialog);

  if(check_is_dir(filename))
    fname = g_build_filename(filename, basename, NULL);
  else
    fname = g_strdup(filename);

  /*
   * Add a default extension
   */
  if(suffix && (!ext || strcmp(ext, suffix)))
  {
    char *tmpname = g_strdup_printf("%s%s", fname, suffix);

    g_free(fname);
    fname = tmpname;
  }

  switch (type)
  {
    case SAVE_HTML:
      hosts = backend_convert(be);
      arglist_to_html(hosts, fname);
      break;
    case SAVE_XML_NG:
      backend_to_xml_ng(be, fname);
      break;
    case SAVE_LATEX:
      hosts = backend_convert(be);
      arglist_to_latex(hosts, fname);
      break;
    case SAVE_TEXT:
      hosts = backend_convert(be);
      arglist_to_text(hosts, fname);
      break;
#ifndef NO_GDCHART
    case SAVE_HTML_GRAPH:
      hosts = backend_convert(be);
      arglist_to_html_graph(hosts, fname);
      break;
#endif
    case SAVE_PDF:
      arglist_to_pdf(report_context, be, fname);
      break;
    case SAVE_NBE:
    default:
      backend_to_nbe(be, fname);
      break;
  }
  g_free(basename);
  g_free(fname);
  if(hosts)
    arg_free_all(hosts);
  gtk_widget_destroy(filedialog);

  report_context->is_severity_mapped = was_mapped;
  return 0;
}

/**
 * @brief Callback, opens a file and export target (nbe, xml, pdf...) selection
 * @brief widget and attempts export on click on OK.
 * 
 * Callback on OK- button is file_save_ok_callback.
 * "inspired" from the Gimp 1.2.2
 * See gimp/app/fileops.c for a cleaner function
 * @window Parent gtk widget.
 * 
 * @see file_save_ok_callback
 */
void
report_save_cb (GtkWidget *window)
{
  GtkWidget *filesave;
  GtkWidget *frame;
  GtkWidget *hbox;
  GtkWidget *label;
  GtkWidget *option_menu;
  GtkWidget *menu;
  GtkWidget *save_options;
  GtkWidget *type;

  filesave = gtk_file_selection_new(_("Export Report"));

  gtk_window_set_position(GTK_WINDOW(filesave), GTK_WIN_POS_MOUSE);

  gtk_container_border_width(GTK_CONTAINER(filesave), 2);
  gtk_container_border_width(GTK_CONTAINER(GTK_FILE_SELECTION(filesave)->
	  button_area), 2);

  g_signal_connect(GTK_FILE_SELECTION(filesave)->ok_button,
      "clicked", G_CALLBACK(file_save_ok_callback), filesave);

  g_signal_connect_swapped(GTK_FILE_SELECTION(filesave)->cancel_button,
      "clicked", G_CALLBACK(gtk_widget_destroy), filesave);

  save_options = gtk_hbox_new(TRUE, 1);

  frame = gtk_frame_new(_("Export Options"));
  gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN);
  gtk_box_pack_start(GTK_BOX(save_options), frame, TRUE, TRUE, 4);

  hbox = gtk_hbox_new(FALSE, 4);
  gtk_container_border_width(GTK_CONTAINER(hbox), 4);
  gtk_container_add(GTK_CONTAINER(frame), hbox);
  gtk_widget_show(hbox);

  label = gtk_label_new(_("Report file format : "));
  gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
  gtk_widget_show(label);

  option_menu = gtk_option_menu_new();
  gtk_box_pack_start(GTK_BOX(hbox), option_menu, TRUE, TRUE, 0);
  gtk_widget_show(option_menu);


 /*---------------------------------------------------------------*
  *	We fill the dialog with the various export formats
  *	we know about
  *---------------------------------------------------------------*/
  menu = gtk_menu_new();
  gtk_object_set_data(GTK_OBJECT(filesave), "menu", menu);

  type = gtk_menu_item_new_with_label("NBE");
  gtk_object_set_data(GTK_OBJECT(type), "type", (void *)SAVE_NBE);
  gtk_menu_append(GTK_MENU(menu), type);
  gtk_widget_show(type);

  type = gtk_menu_item_new_with_label("XML");
  gtk_object_set_data(GTK_OBJECT(type), "type", (void *)SAVE_XML_NG);
  gtk_menu_append(GTK_MENU(menu), type);
  gtk_widget_show(type);

  type = gtk_menu_item_new_with_label("HTML");
  gtk_object_set_data(GTK_OBJECT(type), "type", (void *)SAVE_HTML);
  gtk_menu_append(GTK_MENU(menu), type);
  gtk_widget_show(type);

  type = gtk_menu_item_new_with_label("LaTeX");
  gtk_object_set_data(GTK_OBJECT(type), "type", (void *)SAVE_LATEX);
  gtk_menu_append(GTK_MENU(menu), type);
  gtk_widget_show(type);

  type = gtk_menu_item_new_with_label(_("ASCII text"));
  gtk_object_set_data(GTK_OBJECT(type), "type", (void *)SAVE_TEXT);
  gtk_menu_append(GTK_MENU(menu), type);
  gtk_widget_show(type);

#ifndef NO_GDCHART
  type = gtk_menu_item_new_with_label(_("HTML with Pies and Graphs"));
  gtk_object_set_data(GTK_OBJECT(type), "type", (void *)SAVE_HTML_GRAPH);
  gtk_menu_append(GTK_MENU(menu), type);
  gtk_widget_show(type);
#endif

  type = gtk_menu_item_new_with_label("PDF");
  gtk_object_set_data(GTK_OBJECT(type), "type", (void*)SAVE_PDF);
  gtk_menu_append(GTK_MENU(menu), type);
  gtk_widget_show(type);

 /*----------------------------------------------------------------*/
  gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu), menu);
  gtk_widget_show(menu);
  gtk_widget_show(frame);

  /* pack the containing save_options hbox into the save-dialog */
  gtk_box_pack_end(GTK_BOX(GTK_FILE_SELECTION(filesave)->main_vbox),
      save_options, FALSE, FALSE, 0);
  gtk_widget_show(save_options);
  gtk_widget_show(filesave);
}

/*
 * Open a pdf file with the configured pdf viewer.
 * XXX: This function eventually should be moved into a more
 * suitable module.
 */
#ifndef CYGWIN

void
show_pdf (gchar * filename)
{
  const gchar *pdfviewer = prefs_get_string(Global, "pdfviewer");

  if (!check_is_file(filename))
  {
    show_warning(_("PDF file %s not found."), filename);
    return;
  }

  if (!pdfviewer)
  {
    show_warning(_("You haven't configured a PDF viewer."
                   "\nThe report was saved as %s so you can manually open it."),
                 filename);
    return;
  }

  {
  gchar *cmd = g_strdup_printf("'%s' '%s'", pdfviewer, filename);

  /* start PDF viewer */
  if(!g_spawn_command_line_async(cmd, NULL))
    show_error(_("Can't launch PDF viewer: %s"), pdfviewer);
  g_free(cmd);
  }
}

#else /* CYGWIN */

/* The cygwin version uses always the system default.
 * A bit complicated, but it works. Nicer solution
 * appreciated.
 */
void
show_pdf (gchar * filename)
{
  char win32path[MAX_PATH];
  HINSTANCE rc;
  cygwin_conv_to_win32_path(filename, win32path);
  rc = ShellExecute((HWND)0, NULL, win32path, NULL, NULL, SW_SHOWNORMAL);
  if (rc <= (HINSTANCE)32)
  {
    char *s_buf;
    DWORD error = GetLastError();
    int len = FormatMessage( /* API error */
                            FORMAT_MESSAGE_ALLOCATE_BUFFER |
                            FORMAT_MESSAGE_FROM_SYSTEM |
                            FORMAT_MESSAGE_IGNORE_INSERTS,
                            NULL, /* no message source */
                            error,
                            MAKELANGID(LANG_NEUTRAL,
                            SUBLANG_DEFAULT),
                            (LPTSTR) &s_buf,
                            0, /* size not used */
                            NULL); /* no args */
    show_error(_("Can't open PDF file: %s:\n%s"), filename, s_buf);
    LocalFree(s_buf);
  }
}

#endif /* CYGWIN */

void
report_open_pdf (GtkWidget *menuitem,  gpointer ctrls)
{
  int be = GPOINTER_TO_SIZE(arg_get_value(arg_get_value(ctrls, "REPORT"), "BE"));
  struct context *report_context
    = arg_get_value(arg_get_value(ctrls, "REPORT"), "REPORT_CONTEXT");
  gchar *basename = g_path_get_basename (Context->dir);
  gchar *fname    = g_strdup_printf ("%s.pdf", basename);
  gchar *filename = g_build_filename (Context->dir, fname, NULL);

  g_free (basename);
  g_free (fname);

  arglist_to_pdf (report_context, be, filename);

  show_pdf (filename);
  g_free (filename);
}

#endif
