/*

                                   _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-2006
       "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

*/

/* main.c :: Midnight Code library test and example program		*/


#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <arpa/inet.h>

#include <libmidnightcode.h>


int
main(int argc, char **argv) {
  int ret_i;
  int showBroadcast = 1;
  int vartwo = 4;
  int help = 0;
  int list_silent = 0;
  float varthr = 1.2;
  char info[64] = "\0";
  char urlstring[64];
  struct in_addr ip_addr;
  struct in_addr host;
  void * tmp_void_p;
  struct midnightcode_config_head_t * config_list_head_p;
  struct midnightcode_config_element_t * now_element, *old_element;
  struct midnightcode_interface_head_t * interface_list_head_p;
  struct midnightcode_disk_head_t * disk_list_head_p;
  struct midnightcode_resolve_domain_head_t * domain_list_head_p;
  struct midnightcode_resolve_server_head_t * server_list_head_p;
  struct midnightcode_html_document_head_t * html_list_head_p;
  struct midnightcode_disk_element_t * now_disk;
  struct midnightcode_interface_element_t * now_interface;
  struct midnightcode_interface_element_t * set_interface;
  struct midnightcode_route_head_t * route_list_head_p;
  // struct midnightcode_route_element_t * now_route;
  // u_char * uchar_p;
  // int n;
  // char serialized[32] = "s:8:\"abcd1234\";";
  // char serialized[32] = "s:14:\"S01JJ60XB08091\";";
  char serialized[32] = "s:17:\"00:13:46:78:3B:2D\";";
  unsigned char mac_address[6];
  unsigned char * uchar_p;
  char parse_buf[64];
  char base64_string[32] = "Base64 works!";
  char base64_buffer[64];



  /* SWITCHES */
  /*
  struct entry_struct_name {
    int test_val;
    midnightcode_list_entry(entry_struct_name);
  };
  */

  // struct entry_struct_name *np, *op;

  struct midnightcode_switch_t switches[] = {
    { "b", "broadcast", "Example integer value",
      MIDNIGHTCODE_PARSE_TYPE_INT, 0, 0, &showBroadcast },
    { "v", "var2", "Another example integer value",
      MIDNIGHTCODE_PARSE_TYPE_INT, 0, 0, &vartwo },
    { "v3", "var3", "A float test value",
      MIDNIGHTCODE_PARSE_TYPE_FLOAT, 0, 0, &varthr },
    { "i", "info", "An example string value",
      MIDNIGHTCODE_PARSE_TYPE_STRING, 64, 0, &info },
    { "ho", "host", "A host example that returns an IP",
      MIDNIGHTCODE_PARSE_TYPE_HOST, 0, 0, &host.s_addr },
    { "ip", "ipaddr", "An IP example that only accepts an IP",
      MIDNIGHTCODE_PARSE_TYPE_IP, 0, 0, &ip_addr.s_addr },
    { "l", "list_silent", "On/Off - Silent list render",
      MIDNIGHTCODE_PARSE_TYPE_NONE, 0, 0, &list_silent },
    { "h", "help", "Display this help/usage screen",
      MIDNIGHTCODE_PARSE_TYPE_NONE, 0, 0, &help },
    { 0 }
  };



  /* CONFIG FILE */

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

  old_element = malloc(sizeof(struct midnightcode_config_element_t));
  now_element = malloc(sizeof(struct midnightcode_config_element_t));



  /* INTERFACE STUFF */

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



  /* RESOLVE STUFF */

  midnightcode_list_init(domain_struct_head,
                         midnightcode_domain_element_t);
  tmp_void_p = (void *)&domain_struct_head;
  domain_list_head_p = tmp_void_p;

  midnightcode_list_init(server_struct_head,
                         midnightcode_server_element_t);
  tmp_void_p = (void *)&server_struct_head;
  server_list_head_p = tmp_void_p;



  /* ROUTE STUFF */

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




  /* DISK STUFF */

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





  /* HTML STUFF */

  midnightcode_list_init(html_struct_head,
                         midnightcode_html_document_element_t);
  tmp_void_p = (void *)&html_struct_head;
  html_list_head_p = tmp_void_p;




  // SWITCH PARSING TEST --------------------------------------------------

  memset(&ip_addr, 0, sizeof(struct in_addr));
  memset(&host, 0, sizeof(struct in_addr));
  if((ret_i = midnightcode_switch_process(argc, argv, switches)) != 0) {
    fprintf(stdout, "\n");
    midnightcode_logo(0,
      MIDNIGHTCODE_COLOUR_STYLE_BLOOD_MOON);
    midnightcode_license(0,
      MIDNIGHTCODE_COLOUR_STYLE_BLOOD_MOON, 
      MIDNIGHTCODE_LICENSE_TEXT_COPYRIGHT);
    fprintf(stdout, "    Error in switches, switch \"%s\" is unkown"
            " at parameter number %d.\n\n", argv[ret_i], ret_i);
    midnightcode_switch_usage(MIDNIGHTCODE_SWITCH_STYLE_SOFT,
                              argv[0], switches);
    exit(1);
  }
  if(help) {
    midnightcode_logo(0,
      MIDNIGHTCODE_COLOUR_STYLE_BLOOD_MOON);
  midnightcode_license(0,
    MIDNIGHTCODE_COLOUR_STYLE_BLOOD_MOON, 
    MIDNIGHTCODE_LICENSE_TEXT_COPYRIGHT);
    midnightcode_switch_usage(MIDNIGHTCODE_SWITCH_STYLE_SOFT,
                              argv[0], switches);
    exit(1);
  }

  /*
  fprintf(stdout, "--broadcast=[%d]\n", showBroadcast);
  fprintf(stdout, "--var2=[%d]\n", vartwo);
  fprintf(stdout, "--var3=[%f]\n", varthr);
  fprintf(stdout, "--info=[%s]\n", info);
  fprintf(stdout, "-ip=[%s]\n", inet_ntoa(ip_addr));
  fprintf(stdout, "-ho=[%s]\n", inet_ntoa(host));
  */


  fflush(stdout);



  // LOGO / LICENSE TEST --------------------------------------------------

  midnightcode_logo(0,
    MIDNIGHTCODE_COLOUR_STYLE_BLOOD_MOON);
  midnightcode_license(0,
    MIDNIGHTCODE_COLOUR_STYLE_BLOOD_MOON, 
    MIDNIGHTCODE_LICENSE_TEXT_ALL);





  // STATUS TEXT TEST -----------------------------------------------------

  // Status Title
  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_H1,
                           MIDNIGHTCODE_STATUS_STYLE_NORMAL,
                           "Welcome to %s", argv[0]);

  // Status Section
  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_H2,
                           MIDNIGHTCODE_STATUS_STYLE_SOFT,
                           "Test set for %s styles", "Logo");

  // Status
  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_TEXT,
                           MIDNIGHTCODE_STATUS_STYLE_SOFT,
                           "This is status text that is long "
                           "and c%d%dl to look at too", 0,0);
  midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_OKAY);

  // Status
  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_TEXT,
                           MIDNIGHTCODE_STATUS_STYLE_NORMAL,
                           "This is status text that is long "
                           "and c%d%dl to look at too", 0,0);
  midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_WARN);

  // Status
  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_TEXT,
                           MIDNIGHTCODE_STATUS_STYLE_STRONG,
                           "This is status text");
  midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_FAIL);

  // Status blurb
  fprintf(stdout, "\n");
  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_BLURB,
                           MIDNIGHTCODE_STATUS_STYLE_UNKNOWN,
                           "There appear to be no network card drivers loaded.");
  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_BLURB,
                           MIDNIGHTCODE_STATUS_STYLE_UNKNOWN,
                           "Your card is not supported. Please see the CHAOS");
  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_BLURB,
                           MIDNIGHTCODE_STATUS_STYLE_UNKNOWN,
                           "HOWTO or FAQ for more information or email the");
  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_BLURB,
                           MIDNIGHTCODE_STATUS_STYLE_UNKNOWN,
                           "list and provide details of this system.");
  fprintf(stdout, "\n");
  fflush(stdout);

  // Status
  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_TEXT,
                           MIDNIGHTCODE_STATUS_STYLE_UNKNOWN,
                           "This is status text");
  midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_UNKNOWN);

  fprintf(stdout, "\n\n");





  // CONFIG PARSING TEST --------------------------------------------------

  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_TEXT,
                           MIDNIGHTCODE_STATUS_STYLE_NORMAL,
                           "Config file [%s] load and parse", "test.cfg");
  if((ret_i = midnightcode_config_read("test.cfg",
                         config_list_head_p,
                         MIDNIGHTCODE_CONFIG_TYPE_NEWSET,
                         MIDNIGHTCODE_CONFIG_OPTION_AUTONEW |
                         MIDNIGHTCODE_CONFIG_OPTION_MERGEARGS |
                         MIDNIGHTCODE_CONFIG_OPTION_SILENT )) != 0) {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_FAIL);
  } else {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_OKAY);
  }







  // INTERFACE DUMP TEST --------------------------------------------------

  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_TEXT,
                           MIDNIGHTCODE_STATUS_STYLE_NORMAL,
                           "Retrieving all host interfaces");
  // if((ret_i = midnightcode_interface_byindex(interface_list_head_p, 2)) < 0) {
  if((ret_i = midnightcode_interface_list(interface_list_head_p)) < 0) {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_FAIL);
  } else {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_OKAY);
  }


  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_TEXT,
                           MIDNIGHTCODE_STATUS_STYLE_NORMAL,
                           "Writing hosts file");
  if(midnightcode_interface_writehosts("./hosts",
    interface_list_head_p) < 0) {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_FAIL);
  } else {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_OKAY);
  }




  // Resolver from Config
  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_TEXT,
                           MIDNIGHTCODE_STATUS_STYLE_NORMAL,
                           "Pulling resolver from config");
  if((ret_i = midnightcode_resolve_from_config(domain_list_head_p,
                           server_list_head_p,
                           config_list_head_p)) != 0) {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_FAIL);
  } else {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_OKAY);
  }



  // Resolver to resolv.conf file
  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_TEXT,
                           MIDNIGHTCODE_STATUS_STYLE_NORMAL,
                           "Writing resolv file");
  if(midnightcode_resolve_writeconf("./resolv.conf",
    domain_list_head_p, server_list_head_p) < 0) {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_FAIL);
  } else {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_OKAY);
  }



  // Resolver to Config
  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_TEXT,
                           MIDNIGHTCODE_STATUS_STYLE_NORMAL,
                           "Adding resolver to config");
  if((ret_i = midnightcode_resolve_to_config(domain_list_head_p,
                           server_list_head_p,
                           config_list_head_p)) != 0) {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_FAIL);
  } else {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_OKAY);
  }





  // char node_id[MIDNIGHTCODE_LICENSE_NODEID_SIZE];
  midnightcode_list_for_each(now_interface, interface_list_head_p) {
    printf("%s: %s\n", now_interface->name, now_interface->vendor_name);
  }
  /*
    memset(&node_id, 0, MIDNIGHTCODE_LICENSE_NODEID_SIZE);
    midnightcode_license_get_nodeid((char *)&node_id,
      &(now_interface->ipv4_address));
    printf("%-30.30s %s",
      now_interface->ipv4_address_s, node_id);
    printf(" # ");
    printf("%s\n", now_interface->name);
  }
  */


  /*
  midnightcode_list_for_each(now_interface, interface_list_head_p) {
    printf("Interface: %s ", now_interface->name);
    uchar_p = (u_char *)&now_interface->mac_address;
    printf("[%02x:%02x:%02x:%02x:%02x:%02x] ",
            *uchar_p, *(uchar_p + 1), *(uchar_p + 2),
            *(uchar_p + 3), *(uchar_p + 4), *(uchar_p + 5));
    printf("[%s/", inet_ntoa(now_interface->ipv4_address));
    printf("%s] ", inet_ntoa(now_interface->ipv4_mask));
    printf("[%s]\n", inet_ntoa(now_interface->ipv4_broadcast));
    printf("Interface: %s [%s] [%d] [%s/%s] [%s]\n",
        now_interface->name,
        now_interface->mac_address_s,
        now_interface->mtu,
        now_interface->ipv4_address_s,
        now_interface->ipv4_mask_s,
        now_interface->ipv4_broadcast_s);
  }
  fprintf(stdout, "\n\n");
  */

  /*
  midnightcode_list_for_each(now_interface, interface_list_head_p) {
    if(!now_interface->is_alias)
      printf("	!");
    printf("is_alias [%s] = [%s]:[%s]\n", now_interface->name,
      now_interface->name_root, now_interface->name_alias);
  }
  fprintf(stdout, "\n\n");
  */



  // Interfaces of Interest 
  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_TEXT,
                           MIDNIGHTCODE_STATUS_STYLE_NORMAL,
                           "Finding interfaces of interest");
  if((ret_i = midnightcode_interface_only(interface_list_head_p)) <= 0) {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_FAIL);
  } else {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_OKAY);
  }



  // Interface to Config
  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_TEXT,
                           MIDNIGHTCODE_STATUS_STYLE_NORMAL,
                           "Adding interfaces to config");
  if((ret_i = midnightcode_interface_to_config(interface_list_head_p,
                           config_list_head_p)) != 0) {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_FAIL);
  } else {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_OKAY);
  }


  // Configure an Interface
  set_interface = NULL;
  if(midnightcode_interface_byname(interface_list_head_p,
                               "eth0:1", &set_interface) == 1) {
    if(!set_interface)
      midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_BLURB,
                               MIDNIGHTCODE_STATUS_STYLE_UNKNOWN,
                               "!set_interface");

    snprintf(set_interface->ipv4_address_s, 31, "192.168.3.3");
    if(midnightcode_parse_strtovar((void *)&set_interface->ipv4_address,
                               set_interface->ipv4_address_s, 0, 0,
                               MIDNIGHTCODE_PARSE_TYPE_IP))
      midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_BLURB,
                               MIDNIGHTCODE_STATUS_STYLE_UNKNOWN,
                               "!midnightcode_parse_strtovar");

    snprintf(set_interface->ipv4_broadcast_s, 31, "192.168.3.255");
    if(midnightcode_parse_strtovar((void *)&set_interface->ipv4_broadcast,
                               set_interface->ipv4_broadcast_s, 0, 0,
                               MIDNIGHTCODE_PARSE_TYPE_IP))
      midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_BLURB,
                               MIDNIGHTCODE_STATUS_STYLE_UNKNOWN,
                               "!midnightcode_parse_strtovar");

    inet_ntop(AF_INET, &set_interface->ipv4_address,
      set_interface->ipv4_address_s, 31);

    midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_BLURB,
                               MIDNIGHTCODE_STATUS_STYLE_UNKNOWN,
                               "IP    [%s]->%s", set_interface->name,
                               set_interface->ipv4_address_s);
    midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_BLURB,
                               MIDNIGHTCODE_STATUS_STYLE_UNKNOWN,
                               "Bcast [%s]->%s", set_interface->name,
                               set_interface->ipv4_broadcast_s);
    if(midnightcode_ip_isprivate(set_interface->ipv4_address.s_addr)) {
      midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_BLURB,
                               MIDNIGHTCODE_STATUS_STYLE_UNKNOWN,
                               "[isPrivate]");
    }
    if(midnightcode_ip_ismulticast(set_interface->ipv4_address.s_addr)) {
      midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_BLURB,
                               MIDNIGHTCODE_STATUS_STYLE_UNKNOWN,
                               "[isMulticast]");
    }


    if(midnightcode_interface_configure(set_interface) != 0)
      midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_BLURB,
                               MIDNIGHTCODE_STATUS_STYLE_UNKNOWN,
                               "!midnightcode_interface_configure");


    /*
    if(midnightcode_interface_down(set_interface) != 0)
        printf("iface down issue\n");
    if(midnightcode_interface_up(set_interface) != 0)
        printf("iface up issue\n");
    */
  }
  fprintf(stdout, "\n");
  fflush(stdout);


  // Interface from Config
  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_TEXT,
                           MIDNIGHTCODE_STATUS_STYLE_NORMAL,
                           "Pulling interfaces from config");
  if((ret_i = midnightcode_interface_from_config(interface_list_head_p,
                           config_list_head_p)) != 0) {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_FAIL);
  } else {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_OKAY);
  }












  // ROUTE DUMP TEST ------------------------------------------------------

  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_TEXT,
                           MIDNIGHTCODE_STATUS_STYLE_NORMAL,
                           "Retrieving all host routes");
  // if((ret_i = midnightcode_route_default(route_list_head_p)) < 0) {
  if((ret_i = midnightcode_route_list(route_list_head_p)) < 0) {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_FAIL);
  } else {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_OKAY);
  }

  /*
  printf("       %-20.20s %-20.20s %-20.20s %s [%s]\n",
      "Source", "Destination", "Gateway", "Metric", "iface");
  midnightcode_list_for_each(now_route, route_list_head_p) {

    printf("Route: %-20.20s %-20.20s %-20.20s %4d [%d]\n",
        now_route->ipv4_prefsource_s,
        now_route->ipv4_destination_s,
        now_route->ipv4_gateway_s,
        now_route->metric,
        now_route->out_ifindex);

  }
  fprintf(stdout, "\n\n");
  */





  // EXEC TEST ------------------------------------------------------------

  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_TEXT,
                           MIDNIGHTCODE_STATUS_STYLE_SOFT,
                           "Exec output .. ");
  int options = 0;
  int terminal = 0;
  int pid;
  options |= MIDNIGHTCODE_PROCESS_OPTION_WAITTERM;
  options |= MIDNIGHTCODE_PROCESS_OPTION_NULLIO;
  options |= MIDNIGHTCODE_PROCESS_OPTION_EXITCODE;
  // options |= MIDNIGHTCODE_PROCESS_OPTION_GETPID;
  terminal = MIDNIGHTCODE_TERMINAL_VIRTUAL_NULL;
  if((pid = midnightcode_process("./go", options, terminal)) != 0) {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_FAIL);
  } else {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_OKAY);
  }

  fprintf(stdout, "\n\n");




  // LIST MANIPULATION TEST -----------------------------------------------

  /* 

     Note that the INDEX and LOCK extensions add up to 50%
     processing time to all list work;
  
     --- 20 Million Entries :: + 30 seconds
     # NOINDEX, NOLOCK
     real    1m12.377s
     user    0m5.086s
     sys     0m2.801s
     
     # INDEX, LOCK
     real    1m43.043s
     user    0m7.638s
     sys     0m3.319s
     
     --- 10 Million Entries :: + 2 seconds
     # NOINDEX, NOLOCK
     real    0m5.055s
     user    0m2.528s
     sys     0m0.515s
     
     # INDEX, LOCK
     real    0m7.342s
     user    0m3.840s
     sys     0m0.553s

  */

  /*
  midnightcode_list_init(list_struct_head, entry_struct_name);
  if(vartwo < 5)
    vartwo = 5;

  op = NULL;
  for(n=1; n<=vartwo; n++) {
    if(!list_silent)
      printf("Append list entry %d\n", n);
    np = malloc(sizeof(struct entry_struct_name));
    memset(np, 0, sizeof(struct entry_struct_name));
    np->test_val = n;
    midnightcode_list_append(&list_struct_head, np);
    if(n==2)
      op = np;
  }
  n = 1999;
  printf("Insert list entry %d\n", n);
  np = malloc(sizeof(struct entry_struct_name));
  np->test_val = n;
  midnightcode_list_insert(&list_struct_head, np);
  printf("List count: %d\n", (&(list_struct_head))->count);

  midnightcode_list_for_each(np, &list_struct_head) {
    if(!list_silent)
      printf("List entry: %d, index=%d\n",
        np->test_val, midnightcode_list_entry_index(np));
  }

  midnightcode_list_for_each(np, &list_struct_head) {
    if(!list_silent)
      printf("List entry: %d, index=%d\n",
        np->test_val, midnightcode_list_entry_index(np));
  }

  printf("Remove list entry 2\n");
  midnightcode_list_remove(&list_struct_head, op);
  printf("Entry 2 was ..\n");
  printf("ent2->test_val = [%d], index = [%d]\n",
    op->test_val, midnightcode_list_entry_index(op));
  free(op);
  printf("List count: %d\n", (&(list_struct_head))->count);

  midnightcode_list_for_each(np, &list_struct_head) {
    if(!list_silent)
      printf("List entry: %d, index=%d\n",
        np->test_val, midnightcode_list_entry_index(np));
  }
  np = (&(list_struct_head))->last;
  printf("Last list entry: %d\n", np->test_val);

  printf("Remove last list entry\n");
  midnightcode_list_remove(&list_struct_head, np);
  free(np);

  printf("----------------\n");

  np = (&(list_struct_head))->last;
  printf("Last: %d, index=%d\n",
    np->test_val, midnightcode_list_entry_index(np));
  np = np->MIDNIGHTCODE_LIST_ENTRIES.prev;
  printf("Last -1: %d, index=%d\n",
    np->test_val, midnightcode_list_entry_index(np));

  printf("List count: %d\n", midnightcode_list_count(&list_struct_head));
  */





  // DISK DUMP TEST -------------------------------------------------------

  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_TEXT,
                           MIDNIGHTCODE_STATUS_STYLE_NORMAL,
                           "Retrieving all disk devices");
  if((ret_i = midnightcode_disk_list(disk_list_head_p)) < 0) {
  // if((ret_i = midnightcode_disk_bytype(disk_list_head_p,
  //                                     MIDNIGHTCODE_DISK_TYPE_DISK)) < 0) {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_FAIL);
  } else {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_OKAY);
  }

  midnightcode_list_for_each(now_disk, disk_list_head_p) {
    printf("Disk Device: %s\n", now_disk->device);
    printf("  Device Type:  %s\n", now_disk->device_type_s);
    printf("  Vendor ID:    %s\n", now_disk->vendor_id);
    printf("  Product ID:   %s\n", now_disk->product_id);
    printf("  Serial No:    %s\n", now_disk->serial_no);
    printf("  Version:      %s\n", now_disk->version);
    printf("  Capacity:     %s\n", now_disk->capacity_s);
    printf("  Emulation:    %d\n", now_disk->scsi_emulation);
    printf("  Bus Type:     %d\n", now_disk->bus_type);
    if(now_disk->device_type == MIDNIGHTCODE_DISK_TYPE_WORM ||
      now_disk->device_type == MIDNIGHTCODE_DISK_TYPE_CDDVD) {
      printf("  Tray State:   %d\n", now_disk->cd_tray_state);
      printf("  Media Avail:  %d\n", now_disk->cd_media_available);
      printf("  Media Type:   %d\n", now_disk->cd_media_type);
      printf("  Media Label:  %s\n", now_disk->cd_media_label);
    }
    fprintf(stdout, "\n");
  }
  fprintf(stdout, "\n\n");

  // Disks of Interest 
  /*
  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_TEXT,
                           MIDNIGHTCODE_STATUS_STYLE_NORMAL,
                           "Finding disks of interest");
  if((ret_i = midnightcode_disk_only(disk_list_head_p, 10)) != 0) {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_FAIL);
  } else {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_OKAY);
  }
  */

  // Disk to Config
  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_TEXT,
                           MIDNIGHTCODE_STATUS_STYLE_NORMAL,
                           "Adding disks to config");
  if((ret_i = midnightcode_disk_to_config(disk_list_head_p,
                           config_list_head_p)) != 0) {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_FAIL);
  } else {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_OKAY);
  }

  midnightcode_disk_from_config(disk_list_head_p, config_list_head_p);




  // FILTER TEST ----------------------------------------------------------
/*
  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_TEXT,
                           MIDNIGHTCODE_STATUS_STYLE_SOFT,
                           "Filter testing .. ");
  int action = MIDNIGHTCODE_FILTER_ACTION_SHUTDOWN;
  if(midnightcode_filter(action, "", 0,
                     (struct midnightcode_filter_rule_head_t *)NULL,
                     (struct midnightcode_filter_chain_head_t *)NULL) != 0) { 
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_FAIL);
  } else {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_OKAY);
  }
*/
  fprintf(stdout, "\n\n");




 
  // PARSER TEST ----------------------------------------------------------
  /*
  char string_trim1[255] = "   three leading spaces, four trailing    ";
  char string_trim2[255] = "   three leading white spaces, no trailing";
  char string_trim3[255] = "no leading white spaces, four trailing    ";

  printf("Pre-trim 1:  [%s]\n", string_trim1); 
  midnightcode_parse_trim(string_trim1, strlen(string_trim1));
  printf("Post-trim 1: [%s]\n", string_trim1); 

  printf("Pre-trim 2:  [%s]\n", string_trim2); 
  midnightcode_parse_trim(string_trim2, strlen(string_trim2));
  printf("Post-trim 2: [%s]\n", string_trim2); 

  printf("Pre-trim 3:  [%s]\n", string_trim3); 
  midnightcode_parse_trim(string_trim3, strlen(string_trim3));
  printf("Post-trim 3: [%s]\n", string_trim3); 
  */







  // CONFIG PARSING TEST --------------------------------------------------

  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_TEXT,
                           MIDNIGHTCODE_STATUS_STYLE_NORMAL,
                           "Config file [%s] write to store", "out.cfg");
  if((ret_i = midnightcode_config_write("out.cfg",
                           config_list_head_p,
                           MIDNIGHTCODE_CONFIG_TYPE_NEWSET, 0)) != 0) {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_FAIL);
  } else {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_OKAY);
  }

  /*
  fprintf(stdout, "\n");
  printf("list count [%d]\n", midnightcode_list_count(config_list_head_p));
  */




  memset(parse_buf, 0, sizeof(parse_buf));
  memset(mac_address, 0, sizeof(mac_address));
  uchar_p = mac_address;
  // if(midnightcode_parse_unserialize((void *)&parse_buf, serialized,
                                    // MIDNIGHTCODE_PARSE_TYPE_STRING) < 0) {
  if(midnightcode_parse_unserialize(&mac_address, serialized,
                                    0, 0,
                                    MIDNIGHTCODE_PARSE_TYPE_HWADDR) < 0) {
    midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_BLURB,
                             MIDNIGHTCODE_STATUS_STYLE_UNKNOWN,
                             "Unserialize [%s] bombed", serialized);

  } else {
    midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_BLURB,
                             MIDNIGHTCODE_STATUS_STYLE_UNKNOWN,
                             "Unserialized [%s]", serialized);
    midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_BLURB,
                             MIDNIGHTCODE_STATUS_STYLE_UNKNOWN,
                             "To [%02X:%02X:%02X:%02X:%02X:%02X]",
                             *uchar_p, *(uchar_p + 1), *(uchar_p + 2),
                             *(uchar_p + 3), *(uchar_p + 4), *(uchar_p + 5));
  }
  if(midnightcode_parse_serialize(parse_buf, &mac_address, 32, 0,
                             MIDNIGHTCODE_PARSE_TYPE_HWADDR) < 0) {
    midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_BLURB,
                             MIDNIGHTCODE_STATUS_STYLE_UNKNOWN,
                             "Failed serial [%02X:%02X:%02X:%02X:%02X:%02X]",
                             *uchar_p, *(uchar_p + 1), *(uchar_p + 2),
                             *(uchar_p + 3), *(uchar_p + 4), *(uchar_p + 5));
  } else {
    midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_BLURB,
                             MIDNIGHTCODE_STATUS_STYLE_UNKNOWN,
                             "Serialised [%02X:%02X:%02X:%02X:%02X:%02X]",
                             *uchar_p, *(uchar_p + 1), *(uchar_p + 2),
                             *(uchar_p + 3), *(uchar_p + 4), *(uchar_p + 5));
    midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_BLURB,
                             MIDNIGHTCODE_STATUS_STYLE_UNKNOWN,
                             "To [%s]", parse_buf);
  }
  fprintf(stdout, "\n");
  fflush(stdout);





  // PCMCIA DETECTION TEST --------------------------------------------------

  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_TEXT,
                           MIDNIGHTCODE_STATUS_STYLE_NORMAL,
                           "Probing for PCMCIA bus support");
  if((ret_i = midnightcode_pcmcia_exists()) <= 0) {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_WARN);
  } else {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_OKAY);
  }





  // HTML PARSING TEST ----------------------------------------------------

  char html_sample[1024] = "<html>\n<body>\ntest this<br>"
                           "short html string\n<br><hr height=\"1\" width=20>"
                           "</body>\n</html>";
  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_TEXT,
                           MIDNIGHTCODE_STATUS_STYLE_NORMAL,
                           "Parsing sample HTML content");
  if((ret_i = midnightcode_html_parse(html_sample, strlen(html_sample),
                           html_list_head_p)) != 0) {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_FAIL);
  } else {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_OKAY);
  }





  // URL ENCODING TEST ----------------------------------------------------

  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_TEXT,
                           MIDNIGHTCODE_STATUS_STYLE_NORMAL,
                           "URL encode of string [%s]", "http://www.com/");
  if((ret_i = midnightcode_parse_strtourl(urlstring, "http://www.com/", 64))
                           < 1) {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_FAIL);
  } else {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_OKAY);
  }
  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_BLURB,
                           MIDNIGHTCODE_STATUS_STYLE_UNKNOWN,
                           "URL result [%s]", urlstring);
  fprintf(stdout, "\n");
  fflush(stdout);





  // BASE64 ENCODING TEST -------------------------------------------------


  memset(base64_buffer, 0, 64);
  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_TEXT,
                           MIDNIGHTCODE_STATUS_STYLE_NORMAL,
                           "Base64 encode of string [%s] len [%d]",
                           base64_string, strlen(base64_string));
  if((ret_i = midnightcode_base64_encode((unsigned char  *)base64_buffer,
    (unsigned char *)base64_string, 64, strlen(base64_string))) < 1) {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_FAIL);
  } else {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_OKAY);
  }
  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_BLURB,
                           MIDNIGHTCODE_STATUS_STYLE_UNKNOWN,
                           "Base64 result [%s] len [%d]",
                           base64_buffer, ret_i);


  memset(base64_string, 0, 32);
  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_TEXT,
                           MIDNIGHTCODE_STATUS_STYLE_NORMAL,
                           "Base64 decode of string [%s] len [%d]",
                           base64_buffer, strlen(base64_buffer));
  if((ret_i = midnightcode_base64_decode((unsigned char *)base64_string,
    (unsigned char *)base64_buffer, 32, strlen(base64_buffer))) < 1) {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_FAIL);
  } else {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_OKAY);
  }
  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_BLURB,
                           MIDNIGHTCODE_STATUS_STYLE_UNKNOWN,
                           "Base64 result [%s] len [%d]",
                           base64_string, ret_i);
  fprintf(stdout, "\n");
  fflush(stdout);



  /*
  char strstr_haystack[255];
  char strstr_needle[8];
  memset(strstr_haystack, 0, 255);
  memset(strstr_needle, 0, 8);
  snprintf(&(strstr_haystack[32]), 255,
    "%s", "abcdefbeeghijklmnopbeepqrstuvwxyz");
  snprintf(strstr_needle, 8, "%s", "beep");
  ret_i = midnightcode_parse_strstr(strstr_haystack, strstr_needle,
    255, strlen(strstr_needle));
  printf(" [%c][%c][%c][%c] seen an offset of [%d]\n",
    strstr_haystack[51], strstr_haystack[52],
    strstr_haystack[53], strstr_haystack[54], ret_i);
  */

  /*
  float version_f = 1.1;
  printf("v_f[%05.2f] == l_v[%05.2f] ?\n", version_f, libmidnightcode_version);
  if(version_f == libmidnightcode_version) {
    printf("matched\n");
  } else {
    printf("didn't match\n");
  }
  */





  exit(0);
}

