/* Code style: -*- linux-c -*- */
/* File : xfw/find/first.c */

/* this program is simply to create a random tree something like this

  <-down  up->
  start  --> *---*----*-----*  u
  ^   |    |        p
  |   |    `-----*  |
  d   |    |        v
  o   |    `-----*
  w   |    |     |
  n   |    *     *
  *

  this is *NOT* a standard binary tree as more than two elements may be at
  any level

  */


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include "range.h"

#include <Xm/Xm.h>
#include <Xm/Label.h>
#include <Xm/PushB.h>
#include <Xm/ScrolledW.h>
#include "Tree.h"


/* yea gads! hide yer grannies folks, were going on a pointer binge! */

struct node * add_new_node_to_current(Widget parent, Widget super_node,
                               struct node *new_node, struct node *current)
{
       /* ok, we know where the last info is held and we assume that we have a memory space */
       int loop=-1, dupe=0;
       struct node add_node, *new_ptr;
       Widget w;             /* tree node */
       char   buf[200];      /* text to stuff in widget label */


       new_ptr = (struct node *) calloc(1,sizeof(struct node)); /* allocate memeory for new node */

#ifdef DEBUG
       printf("Size of structure to be used in add_new_node_to_current is (%d)\n",
              sizeof(add_node));
#endif

       /* Naughty!!! */
       memcpy(new_ptr, new_node, (sizeof(add_node)));

       /* ok string it together */


       /* sanity checks time */
       /* are we adding to ourselves? */
       /* ie is the current pointers ip the same as the one we are trying to add ? */
       /* ip's are unique so we can test that */
       if (new_node->ip == current->ip) {
               printf("Dulicate ip found - attempt to add identical info to same node ignored\n");
               dupe = -999;
       }

       /* now search for entries that may point to the same information we are trying to add */
       for (loop = 0 ; loop < MAXROUTER ; loop++) {
               if (current->out[loop] != NULL) {
                       if (current->out[loop]->ip == new_node->ip) {
                               printf("Looks like a dulicate entry to me jim.... ignoring this entry\n");
                               dupe = -1 - loop; /* zero is a valid case that would overlap unless we did this */
                       }
               }
       }


       /* next, can we actually add it to the list? */
       loop=-1;
       while(current->out[++loop] != NULL); /* find an empty slot */
       if (loop > MAXROUTER) {
               perror("In add_new_node_to_current, no spare routes out! (increase MAXROUTER)");
       }


       /* *FINALLY* we get to add the node */

       if (dupe >= 0) {
               new_ptr->face = current; /* pass the address of the last member */
               current->out[loop] = new_ptr;

       /* Add in Widget, I'm unclear as to how the X11 memory allocation works here someone */
       /* might wish to clear it up (thanks in advance if you do 8) ) */

               sprintf (buf, "IP: %s", ip_to_str(current->ip) );
               w = XtVaCreateManagedWidget (buf, xmPushButtonWidgetClass,
                       parent,
                       XmNsuperNode, super_node,
                       NULL );
               new_ptr->w = w ; /* link the node tree with the X11 tree */

              return (new_ptr);
       }

       /* though if we were trying to add a recursive loop,... */
       if (dupe == -999) {
               return (current); /* all details preserved */
       }

       /* and if the information already existed, move the pointer forward */
       if (dupe < 0 ) {
               return (current->out[(-1 - dupe)]); /* zero is a valid case that would overlap */
       }

       return(NULL);
}

void dummy_test(Widget first, struct node * start)
{
       /* simply add a set of dummy address routes */
       /* ok we are going to call a routine down here for to add a node */
       /* this means passing the current address of the curr_chain_ptr */
       /* along with some details to add in a copy of the node structure */


       /*
          This routine creates the following link list structure

          *0-----------*1------*2------*3------*4      (164.11.X.0)
          ^            |\              |
          |            | *5----*6      *7------*8      (200.1.X.0)
          |            |
          start        *9-----*10------*11             (100.5.X.0)


          0    164.11.100.10
          1    164.11.101.1
          2    164.11.102.1
          3    164.11.103.1
          4    164.11.104.1

          5    200.1.10.1
          6    200.1.55.1

          7    200.1.211.1
          8    200.1.212.1

          9    100.5.21.1
          10   100.5.27.1
          11   100.5.31.1
          */


       struct node size, *curr_position_ptr, *new_node_data;
       int size_array=0;
       Widget curr;

       curr_position_ptr = start;

       size_array = sizeof(size); /* what a crap way to find out the size of an array */

       printf("Dummy routine about to build tree using structures (%d) bytes long\n", size_array);

       /* NODE 0 */

       /* create some memory storage space */
       new_node_data = (struct node *) calloc(1, size_array);

       new_node_data->ip = encode_ip("164.11.100.10");
       new_node_data->netmask = encode_ip("255.255.255.224");
       new_node_data->broadcast = encode_ip("164.11.100.63");
       memcpy(new_node_data->local_cell.other_hosts, dummy_create_hosts(new_node_data), 255);
       new_node_data->last_updated = curr_time();
/**********************/
       curr_position_ptr = add_new_node_to_current(first, first, new_node_data, curr_position_ptr);

       /* NODE 1 */

       curr_position_ptr = start; /* whee! */

       /* create some memory storage space */
       new_node_data = (struct node *) calloc(1, size_array);

       new_node_data->ip = encode_ip("164.11.101.1");
       new_node_data->netmask = encode_ip("255.255.255.224");
       new_node_data->broadcast = encode_ip("164.11.101.63");
       memcpy(new_node_data->local_cell.other_hosts, dummy_create_hosts(new_node_data), 255);
       new_node_data->last_updated = curr_time();

       curr_position_ptr = add_new_node_to_current(first, curr_position_ptr->out[0]->w, new_node_data, curr_position_ptr);

       /* NODE 2 */

       /* create some memory storage space */
       new_node_data = (struct node *) calloc(1, size_array);

       new_node_data->ip = encode_ip("164.11.102.222");
       new_node_data->netmask = encode_ip("255.255.255.240");
       new_node_data->broadcast = encode_ip("164.11.102.15");
       memcpy(new_node_data->local_cell.other_hosts, dummy_create_hosts(new_node_data), 255);
       new_node_data->last_updated = curr_time();
       curr_position_ptr = add_new_node_to_current(first, curr_position_ptr->out[0]->w, new_node_data, curr_position_ptr);


       /* NODE 3 */

       /* create some memory storage space */
       new_node_data = (struct node *) calloc(1, size_array);

       new_node_data->ip = encode_ip("164.11.103.1");
       new_node_data->netmask = encode_ip("255.255.255.224");
       new_node_data->broadcast = encode_ip("164.11.103.63");
       memcpy(new_node_data->local_cell.other_hosts, dummy_create_hosts(new_node_data), 255);
       new_node_data->last_updated = curr_time();

       curr_position_ptr = add_new_node_to_current(first, curr_position_ptr->out[0]->w, new_node_data, curr_position_ptr);


       /* NODE 4 */

       /* create some memory storage space */
       new_node_data = (struct node *) calloc(1, size_array);

       new_node_data->ip = encode_ip("164.11.104.129");
       new_node_data->netmask = encode_ip("255.255.255.224");
       new_node_data->broadcast = encode_ip("164.11.100.63");
       memcpy(new_node_data->local_cell.other_hosts, dummy_create_hosts(new_node_data), 255);
       new_node_data->last_updated = curr_time();

       curr_position_ptr = add_new_node_to_current(first, curr_position_ptr->out[0]->w, new_node_data, curr_position_ptr);


       /* NODE 5 */
       curr_position_ptr = start; /* known referance point */
       curr_position_ptr = curr_position_ptr->out[0]; /* move to node 1 */

       /* create some memory storage space */
       new_node_data = (struct node *) calloc(1, size_array);

       new_node_data->ip = encode_ip("200.1.10.1");
       new_node_data->netmask = encode_ip("255.255.255.0");
       new_node_data->broadcast = encode_ip("200.1.10.255");
       memcpy(new_node_data->local_cell.other_hosts, dummy_create_hosts(new_node_data), 255);
       new_node_data->last_updated = curr_time();

       curr_position_ptr = add_new_node_to_current(first, curr_position_ptr->out[1]->w, new_node_data, curr_position_ptr);


       /* NODE 6 */

       /* create some memory storage space */
       new_node_data = (struct node *) calloc(1, size_array);

       new_node_data->ip = encode_ip("200.1.55.122");
       new_node_data->netmask = encode_ip("255.255.255.240");
       new_node_data->broadcast = encode_ip("200.1.55.15");
       memcpy(new_node_data->local_cell.other_hosts, dummy_create_hosts(new_node_data), 255);
       new_node_data->last_updated = curr_time();

       curr_position_ptr = add_new_node_to_current(first, curr_position_ptr->out[0]->w, new_node_data, curr_position_ptr);


       /* NODE 7 */
       curr_position_ptr = start; /* known referance point */
       curr_position_ptr = curr_position_ptr->out[0]->out[0]->out[0]; /* NODE 3 */

       /* create some memory storage space */
       new_node_data = (struct node *) calloc(1, size_array);

       new_node_data->ip = encode_ip("200.1.211.1");
       new_node_data->netmask = encode_ip("255.255.255.0");
       new_node_data->broadcast = encode_ip("200.1.211.255");
       memcpy(new_node_data->local_cell.other_hosts, dummy_create_hosts(new_node_data), 255);
       new_node_data->last_updated = curr_time();

       curr_position_ptr = add_new_node_to_current(first, curr_position_ptr->out[1]->w, new_node_data, curr_position_ptr);


       /* NODE 8 */

       /* create some memory storage space */
       new_node_data = (struct node *) calloc(1, size_array);

       new_node_data->ip = encode_ip("200.1.212.1");
       new_node_data->netmask = encode_ip("255.255.255.224");
       new_node_data->broadcast = encode_ip("200.1.212.63");
       memcpy(new_node_data->local_cell.other_hosts, dummy_create_hosts(new_node_data), 255);
       new_node_data->last_updated = curr_time();

       curr_position_ptr = add_new_node_to_current(first, curr_position_ptr->out[0]->w, new_node_data, curr_position_ptr);


       /* NODE 9 */

       curr_position_ptr = start; /* known referance point */
       curr_position_ptr = curr_position_ptr->out[0]; /* move to node 1 */

       /* create some memory storage space */
       new_node_data = (struct node *) calloc(1, size_array);

       new_node_data->ip = encode_ip("100.5.21.1");
       new_node_data->netmask = encode_ip("255.255.255.0");
       new_node_data->broadcast = encode_ip("100.5.21.255");
       memcpy(new_node_data->local_cell.other_hosts, dummy_create_hosts(new_node_data), 255);
       new_node_data->last_updated = curr_time();

       curr_position_ptr = add_new_node_to_current(first, curr_position_ptr->out[2]->w, new_node_data, curr_position_ptr);


       /* NODE 10 */

       /* create some memory storage space */
       new_node_data = (struct node *) calloc(1, size_array);

       new_node_data->ip = encode_ip("100.5.27.1");
       new_node_data->netmask = encode_ip("255.255.255.240");
       new_node_data->broadcast = encode_ip("100.5.27.15");
       memcpy(new_node_data->local_cell.other_hosts, dummy_create_hosts(new_node_data), 255);
       new_node_data->last_updated = curr_time();

       curr_position_ptr = add_new_node_to_current(first, curr_position_ptr->out[0]->w, new_node_data, curr_position_ptr);


       /* NODE 11 */

       /* create some memory storage space */
       new_node_data = (struct node *) calloc(1, size_array);

       new_node_data->ip = encode_ip("100.5.31.18");
       new_node_data->netmask = encode_ip("255.255.255.248");
       new_node_data->broadcast = encode_ip("100.5.31.7");
       memcpy(new_node_data->local_cell.other_hosts, dummy_create_hosts(new_node_data), 255);
       new_node_data->last_updated = curr_time();

       curr_position_ptr = add_new_node_to_current(first, curr_position_ptr->out[0]->w, new_node_data, curr_position_ptr);

       /* END OF TEST TREE */

}



char * dummy_create_hosts(struct node *node)
{
       /* This routine will create an encoded string which contains the state of */
       /* the local hosts */
       /* we pass in the node structure as this provides the netmask and the ip */
       /* from which we can work out what range of ips we should operate on */
       /* to see this working we set all hosts in the range as active (0xAA) */


       struct range size_block, *block;
       unsigned int start, finish, loop;
       char txt_start[20]="", txt_finish[20]="";
       static unsigned char buffer[255]="";

       memset(buffer, 0, 255);

       /* be safe, not sorry */
#ifdef DEBUG
       printf("dummy_create_hosts: sizeof block is (%d) bytes\n", sizeof(block));
#endif

       block = (struct range *) calloc(1,sizeof(size_block)); /* be safe, NEVER trust memory */

       block = calc(node->ip, node->netmask, node->broadcast);

       start = block->start;
       finish = block->finish;

       translate(txt_start, start);
       translate(txt_finish, finish);
       printf("Worked range is %-14s  ---  %-14s\n", txt_start, txt_finish);

       /* ok what we would in real life do is search through the range for */
       /* hosts we should verify */


       for(loop = start +1 ; loop < finish; loop++) {

#ifdef DEBUG
               /* reuse txt_finish */
               translate(txt_finish, loop);
               printf("(FALSE) tested/detected ip (%s) with ping packet\n", txt_finish);
#endif

               buffer[((loop - start) + (unsigned int) decode(start, CLASS_D))] = 0xAA; /* it's life jim, but not as we know it */
       }


       return ((char *)buffer);
}


int main(int argc, char *argv[])
{
       /* theory, I have a structure that can handle a number of routers at it's own level
          and a way of finding the last router down */

       struct sigaction s;
       struct ip_chain *capture_list;
       struct node *start_chain_ptr, *curr_chain_ptr, *new_ptr; /* new chain */
       int size_node;

       /* Create the X11 shells */
       Widget        shell, tree;
       XtAppContext  app;

       /*
        * Initialize Xt.
        */
       shell = XtAppInitialize ( &app, "TreeDump", NULL, 0,
                                &argc, argv, NULL, NULL, 0 );

       /*
        * Create a scrolled tree.
        */

       tree = XsCreateScrolledTree ( shell, "tree", NULL, 0 );

       XtManageChild ( tree );


       /* first off lets generate the starting sentenal */
       /* god I hate pointers,.... */

       size_node = sizeof(struct node);

       /* we use calloc to fill out the struture with NULL's (bit of a dirty trick) */
       start_chain_ptr = (struct node *) calloc(1, size_node); /* allocate starting point */
       capture_list = (struct ip_chain *) calloc(1, sizeof(struct ip_chain));

       /* oh, and get a memory area for the temporary structure */
       new_ptr = (struct node *) calloc(1, size_node);

       printf("Size of each element will be (%d) bytes\n", size_node);

       /* This is the prime starting point in the tree, as such it has to be */
       /* filled in, in a slightly different way to most other nodes */
       /* first off fill out the structure, as calloc has zeroed the whole thing */


       new_ptr = if_setup();

       start_chain_ptr->ip        = new_ptr->ip;
       start_chain_ptr->netmask   = new_ptr->netmask;
       start_chain_ptr->broadcast = new_ptr->broadcast;


       printf("Welcome, you are running this program on a machine whose IP config is\n");
       printf("IP:\t\t%s\n", ip_to_str(start_chain_ptr->ip));
       printf("Netmask:\t%s\n", ip_to_str(start_chain_ptr->netmask));
       printf("Broadcast:\t%s\n", ip_to_str(start_chain_ptr->broadcast));
       printf("Eth0 has been switched to promiscious mode\n\n");

       curr_chain_ptr = start_chain_ptr;

       /* from here on, curr_chain_ptr
          is what we manipulate */


       /* yea ha! started the list, now create a dummy list */

       dummy_test(tree, curr_chain_ptr);

       printf("A dummy network tree has been generated\n\n");

       printf("Start tree dump\n");


/*      dump_tree(tree, start_chain_ptr, NULL); */
       XtRealizeWidget ( shell );

       printf("End of tree dump\n\n");
       XtAppMainLoop( app);

       /* Snoop for a while, and create a table of external ip's */
       /* these ip's are semi sorted to remove any ip's from the local network */
       /* and to then remove ip's we know how to get to */
       /* at this point, we have a table of ip's we can fire into a traceroute */
       /* like routine */


       do {

               /* I suppose select() could have been used but I'm not familiar with it's use */

               s.sa_handler = alarm_catcher;
               sigemptyset(&s.sa_mask);
               s.sa_flags = 0;
               sigaction(SIGALRM, &s, NULL);
               alarm (TIME_DELAY); /* for the next 30 seconds */



               /* Oh, this is neat 8), the grab_ips_from_net() function grabs as */
               /* many ip's it sees drifting by the network and stores them in */
               /* a linked list, when the alarm goes off, the linked list is read */
               /* by process_captured(), which simply navagates the linked list */
               /* when grab_ips_from_net() is then recalled, it clears down the structure */
               /* before adding to it again */

               if (rang) {
                       printf("processing captured list\n");
                       sleep(5);
                       /*                      process_captured(capture_list); */
               } else {
                       printf("Gone to capture a list\n");
                       sleep(5);
                       /*                      grab_ips_from_net(capture_list); */
               }

       } while (1 == 1);


       /* we pass the ip's in one at a time (slow, but avoids network loads) */
       /* the list of routes the packet returns by is fed into add_node */
       /* any points that it tries to re-add the same router, the program will ignore */
       /* it simply follows the current structure until it needs to add a point */
       /* (this logic is in add_new_node_to_current()) */



       return (0);
}


void alarm_catcher(int sig)
{
       if (sig == SIGALRM)
               rang = 1 - rang; /* toggle state */
       printf("alarm_catcher: called (%d)\n", rang);
       alarm (TIME_DELAY);     /* move to process_captured at some point */
}