/*

                                   _JNJ`                        
                               .JNMH`                           
                              JMMF`       `;.                   
                            .NMM)          `MN.                 
                            MMM)            (MML                
                           (MMM`             MMML               
                     M  I  D  N  I  G  H  T    C  o  D  E       
                           (NMMF             MHNH               
                            NMML            .MMM                
                             NMML          .NMH                 
                              4MMNL       .#F                   
                               `4HNNL_   `                      
                                   `"""`                        

                          Copyright (C) 2004-2007
       "Ian (Larry) Latter" <ian dot latter at midnightcode dot org>

    Midnight Code is a registered trademark of Ian Latter.

    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, and mirrored at the Midnight Code web
    site; as at version 2 of the License only.
  
    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
    (version 2) along with this program; if not, write to the Free
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA, or see http://midnightcode.org/gplv2.txt

*/

/* cgi.c :: Midnight Code web interface example program			*/


#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <errno.h>

#include <libmidnightcode.h>
#include "cgic.h"

#define MAKE_STRING(x) #x
#define CONCAT(x,y) x##y
// #define CONCAT(x,y) MAKE_STRING(x##y)

enum page_t
{
  PAGE_ADMIN_DEFAULT = 0,
  PAGE_ADMIN_SYSTEM = 1,
  PAGE_ADMIN_NETWORK = 2,
  PAGE_ADMIN_DISK = 3,
  PAGE_ADMIN_STATUS = 4
};

struct midnightcode_webint_menu_t menu[] = {
  { 0, "/", "Home" },
  { 0, "/?page=1", "System" },
  { 0, "/?page=2", "Network" },
  { 0, "/?page=3", "Disk" },
  { 0, "/?page=4", "Status" },
  { 0 }
};

struct midnightcode_webint_message_t message;

struct midnightcode_config_head_t * config_list_head_p;
struct midnightcode_disk_head_t * config_disk_list_head_p;
struct midnightcode_interface_head_t * config_interface_list_head_p;

struct midnightcode_disk_head_t * disk_list_head_p;
struct midnightcode_interface_head_t * interface_list_head_p;
struct midnightcode_route_head_t * route_list_head_p;
struct midnightcode_resolve_domain_head_t * nsdomain_list_head_p;
struct midnightcode_resolve_server_head_t * nsserver_list_head_p;

struct midnightcode_disk_element_t * disk;
struct midnightcode_interface_element_t * interface;
struct midnightcode_route_element_t * route;
struct midnightcode_resolve_domain_element_t * nsdomain;
struct midnightcode_resolve_server_element_t * nsserver;


char title[32] = "Administration Console";
int input_page;
int input_action;



int
config_get(struct midnightcode_socket_element_t * socket) {
  char * buffer;
  int buffer_size;
  struct midnightcode_webint_message_t message;
  struct midnightcode_webint_message_t * message_p;
  int ret_i;


  ret_i = 0;
  message_p = &message;

  memset(message_p, 0, sizeof(struct midnightcode_webint_message_t));
  message_p->query = MIDNIGHTCODE_WEBINT_QUERY_GET;
  message_p->type = 0;
  if(midnightcode_webint_membrane(MIDNIGHTCODE_WEBINT_MEMBRANE_ENCODE,
    &buffer, &buffer_size, &message_p) == 0) {
    if(midnightcode_socket_write_block(socket, buffer,
      buffer_size, MIDNIGHTCODE_SOCKET_IO_BLOCKING) <= 0) {
      fprintf(cgiOut, "%s", "Failed to send config query\n");
      ret_i = -1;
    }
    free(buffer);
    buffer = NULL;
  }
  buffer_size = 0;

  if(midnightcode_socket_read_block(socket, &buffer, &buffer_size, 1,
    MIDNIGHTCODE_SOCKET_IO_BLOCKING) > 0) {
    if(midnightcode_webint_membrane(MIDNIGHTCODE_WEBINT_MEMBRANE_DECODE,
      &buffer, &buffer_size, &message_p) == 0) {
      if(message_p->buffer[message_p->buffer_size] != '\0') {
        ret_i = -1;
      } else {
        if(midnightcode_config_read(config_list_head_p,
          (char *)message_p->buffer, message_p->buffer_size,
          MIDNIGHTCODE_CONFIG_TYPE_NEWSET,
          MIDNIGHTCODE_CONFIG_OPTION_AUTONEW |
          MIDNIGHTCODE_CONFIG_OPTION_MERGEARGS |
          MIDNIGHTCODE_CONFIG_OPTION_SILENT ) != 0) {
          fprintf(cgiOut, "%s", "Failed to parse config response\n");
          ret_i = -1;
        }
      }
      free(buffer);
      buffer = NULL;
    } else {
      fprintf(cgiOut, "%s", "Failed to get config response\n");
      ret_i = -1;
    }
    buffer_size = 0;
  } else {
    fprintf(cgiOut, "%s", "Failed to receive data\n");
    ret_i = -1;
  }

  memset(message_p, 0, sizeof(struct midnightcode_webint_message_t));
  message_p->query = MIDNIGHTCODE_WEBINT_QUERY_ACK;
  message_p->type = 0;
  if(midnightcode_webint_membrane(MIDNIGHTCODE_WEBINT_MEMBRANE_ENCODE,
    &buffer, &buffer_size, &message_p) == 0) {
    if(midnightcode_socket_write_block(socket, buffer,
      buffer_size, MIDNIGHTCODE_SOCKET_IO_BLOCKING) <= 0) {
      fprintf(cgiOut, "%s", "Failed to send config ack\n");
      ret_i = -1;
    }
    free(buffer);
    buffer = NULL;
  }
  buffer_size = 0;

  midnightcode_socket_close(socket);


  return ret_i;
}



int
page_admin_default(char ** buffer,
                   struct midnightcode_socket_element_t * socket) {
  int buffer_size;

  struct midnightcode_webint_page_t page[] = {
    { "Home", "Welcome Administrator" },
    { 0 }
  };

  struct midnightcode_webint_content_t content[] = {
    { "", "Long-winded log entry content .. etc." },
    { 0 }
  };


  cgiHeaderContentType("text/html");
  config_get(socket);

  menu[PAGE_ADMIN_DEFAULT].active = 1;
  buffer_size = midnightcode_webint_buffer(buffer,
    title, menu, page, content, 0, MIDNIGHTCODE_WEBINT_LAYOUT_ALL);
  if(*buffer == NULL)
    return 0;
  if(buffer_size <= 0) {
    if(*buffer)
      free(*buffer);
    return 0;
  }

  return buffer_size;
}



int
page_admin_system(char ** buffer,
                   struct midnightcode_socket_element_t * socket) {
  int buffer_size;

  struct midnightcode_webint_page_t page[] = {
    { "System", "Configure basic NAS features" },
    { 0 }
  };

  struct midnightcode_webint_content_t content[] = {
    { "Name", "Various fields and hoohar" },
    { "DNS", "Various fields and hoohar" },
    { "Time", "Various fields and hoohar" },
    { "Syslog", "Various fields and hoohar" },
    { 0 }
  };


  cgiHeaderContentType("text/html");
  config_get(socket);

  midnightcode_resolve_from_config(nsdomain_list_head_p,
    nsserver_list_head_p, config_list_head_p);
  midnightcode_list_for_each(nsserver, nsserver_list_head_p) {
    fprintf(cgiOut, "nameserver: %s<br>\n",
      nsserver->ipv4_address_s);
    fflush(cgiOut);
  }


  menu[PAGE_ADMIN_SYSTEM].active = 1;
  buffer_size = midnightcode_webint_buffer(buffer,
    title, menu, page, content, 0, MIDNIGHTCODE_WEBINT_LAYOUT_ALL);
  if(*buffer == NULL)
    return 0;
  if(buffer_size <= 0) {
    if(*buffer)
      free(*buffer);
    return 0;
  }

  return buffer_size;
}



int
page_admin_lan(char ** buffer,
                   struct midnightcode_socket_element_t * socket) {
  int buffer_size;

  struct midnightcode_webint_page_t page[] = {
    { "Network", "Configure NAS network connectivity" },
    { 0 }
  };

  struct midnightcode_webint_content_t content[] = {
    { "Interfaces", "Various fields and hoohar" },
    { "Static Routes", "Various fields and hoohar" },
    { 0 }
  };


  cgiHeaderContentType("text/html");
  config_get(socket);



  // TODO: If action = apply
  //         process form
  //         send changes / state

  // NOTE: Query init for Interfaces
  if(midnightcode_interface_from_config(interface_list_head_p,
    config_list_head_p) == 0) {
    midnightcode_interface_only(interface_list_head_p);
  }
  midnightcode_list_for_each(interface, interface_list_head_p) {
    fprintf(cgiOut, "%s: %s<br>\n",
      interface->name, interface->vendor_name);
    fflush(cgiOut);
  }


  // NOTE: Query init for Routes
  midnightcode_route_from_config(route_list_head_p,
    config_list_head_p);
  midnightcode_list_for_each(route, route_list_head_p) {
    printf("Route: %-20.20s %-20.20s %-20.20s %4d [%d]<br>\n",
      route->ipv4_prefsource_s,
      route->ipv4_destination_s,
      route->ipv4_gateway_s,
      route->metric,
      route->out_ifindex);
  }



  menu[PAGE_ADMIN_NETWORK].active = 1;
  buffer_size = midnightcode_webint_buffer(buffer,
    title, menu, page, content, 0, MIDNIGHTCODE_WEBINT_LAYOUT_ALL);
  if(*buffer == NULL)
    return 0;
  if(buffer_size <= 0) {
    if(*buffer)
      free(*buffer);
    return 0;
  }

  return buffer_size;
}



int
page_admin_disk(char ** buffer,
                   struct midnightcode_socket_element_t * socket) {
  int buffer_size;

  struct midnightcode_webint_page_t page[] = {
    { "Disk", "Configure NAS storage environment" },
    { 0 }
  };

  struct midnightcode_webint_content_t content[] = {
    { "General", "Various fields and hoohar" },
    { "Disks", "Various fields and hoohar" },
    { 0 }
  };


  cgiHeaderContentType("text/html");
  config_get(socket);

  // NOTE: Query init for Interfaces
  if(midnightcode_disk_from_config(disk_list_head_p,
    config_list_head_p) == 0) {
    midnightcode_disk_only(disk_list_head_p, 10);
  }
  midnightcode_list_for_each(disk, disk_list_head_p) {
    fprintf(cgiOut, "%s: %s<br>\n",
      disk->device, disk->capacity_s);
    fflush(cgiOut);
  }

  menu[PAGE_ADMIN_DISK].active = 1;
  buffer_size = midnightcode_webint_buffer(buffer,
    title, menu, page, content, 0, MIDNIGHTCODE_WEBINT_LAYOUT_ALL);
  if(*buffer == NULL)
    return 0;
  if(buffer_size <= 0) {
    if(*buffer)
      free(*buffer);
    return 0;
  }

  return buffer_size;
}



int
page_admin_status(char ** buffer,
                   struct midnightcode_socket_element_t * socket) {
  int buffer_size;

  struct midnightcode_webint_page_t page[] = {
    { "Status", "Current NAS state and recent log data" },
    { 0 }
  };

  struct midnightcode_webint_content_t content[] = {
    { "Usage", "Various fields and hoohar" },
    { "Capacity", "Various fields and hoohar" },
    { "Logs", "Various fields and hoohar" },
    { 0 }
  };


  cgiHeaderContentType("text/html");
  config_get(socket);

  menu[PAGE_ADMIN_STATUS].active = 1;
  buffer_size = midnightcode_webint_buffer(buffer,
    title, menu, page, content, 0, MIDNIGHTCODE_WEBINT_LAYOUT_ALL);
  if(*buffer == NULL)
    return 0;
  if(buffer_size <= 0) {
    if(*buffer)
      free(*buffer);
    return 0;
  }

  return buffer_size;
}



int
cgiMain() {
  struct midnightcode_socket_head_t * sockets;
  struct midnightcode_socket_element_t * socket;
  void * tmp_void_p;
  int ret_i;
  char * buffer;

  ret_i = 0;
  buffer = NULL;

  /* NOTE: Initialise permanent structures */
  midnightcode_list_init(socket_struct_head, midnightcode_socket_element_t);
  tmp_void_p = (void *)&socket_struct_head;
  sockets = tmp_void_p;

  midnightcode_list_init(config_struct_head, midnightcode_config_element_t);
  tmp_void_p = (void *)&config_struct_head;
  config_list_head_p = tmp_void_p;

  midnightcode_list_init(config_disk_struct_head, midnightcode_disk_element_t);
  tmp_void_p = (void *)&config_disk_struct_head;
  config_disk_list_head_p = tmp_void_p;

  midnightcode_list_init(config_interface_struct_head,
    midnightcode_interface_element_t);
  tmp_void_p = (void *)&config_interface_struct_head;
  config_interface_list_head_p = tmp_void_p;

  midnightcode_list_init(disk_struct_head, midnightcode_disk_element_t);
  tmp_void_p = (void *)&disk_struct_head;
  disk_list_head_p = tmp_void_p;

  midnightcode_list_init(interface_struct_head,
    midnightcode_interface_element_t);
  tmp_void_p = (void *)&interface_struct_head;
  interface_list_head_p = tmp_void_p;

  midnightcode_list_init(route_struct_head, midnightcode_route_element_t);
  tmp_void_p = (void *)&route_struct_head;
  route_list_head_p = tmp_void_p;

  midnightcode_list_init(nsdomain_struct_head, midnightcode_domain_element_t);
  tmp_void_p = (void *)&nsdomain_struct_head;
  nsdomain_list_head_p = tmp_void_p;

  midnightcode_list_init(nsserver_struct_head, midnightcode_server_element_t);
  tmp_void_p = (void *)&nsserver_struct_head;
  nsserver_list_head_p = tmp_void_p;



  if(midnightcode_socket_initialise(sockets) < 0) {
    cgiHeaderContentType("text/html");
    fprintf(cgiOut, "Unable to initialise socket library\n");
    fflush(cgiOut);
    fclose(cgiOut);
    exit(1);
  }

  // MIDNIGHTCODE_SOCKET_CONTROL_MIDNIGHTCODE,
  if(midnightcode_socket_open(&socket,
    MIDNIGHTCODE_SOCKET_CONTROL_MIDNIGHTCODE,
    MIDNIGHTCODE_SOCKET_DPD_DISABLE,
    0, MIDNIGHTCODE_SOCKET_DIR_INITIATE,
    MIDNIGHTCODE_SOCKET_PROTOCOL_TCP,
    "127.0.0.1", MIDNIGHTCODE_WEBINT_PORT) < 0) {
    cgiHeaderContentType("text/html");
    fprintf(cgiOut, "Unable to initialise client socket\n");
    fflush(cgiOut);
    fclose(cgiOut);
    exit(1);
  }


  cgiFormInteger("page", &input_page, 0);
  cgiFormInteger("action", &input_action, 0);

  switch(input_page) {

    case PAGE_ADMIN_DEFAULT:
      if(page_admin_default(&buffer, socket)) {
        fprintf(cgiOut, "%s", buffer);
        free(buffer);
      }
      break;

    case PAGE_ADMIN_SYSTEM:
      if(page_admin_system(&buffer, socket)) {
        fprintf(cgiOut, "%s", buffer);
        free(buffer);
      }
      break;

    case PAGE_ADMIN_NETWORK:
      if(page_admin_lan(&buffer, socket)) {
        fprintf(cgiOut, "%s", buffer);
        free(buffer);
      }
      break;

    case PAGE_ADMIN_DISK:
      if(page_admin_disk(&buffer, socket)) {
        fprintf(cgiOut, "%s", buffer);
        free(buffer);
      }
      break;

    case PAGE_ADMIN_STATUS:
      if(page_admin_status(&buffer, socket)) {
        fprintf(cgiOut, "%s", buffer);
        free(buffer);
      }
      break;

    default:
      cgiHeaderContentType("text/html");
      break;

  }


  fflush(cgiOut);
  fclose(cgiOut);

  midnightcode_socket_shutdown(sockets);


  exit(ret_i);
}

