/*
---------------------------------------------------------------------------
 xml_tun.c,v 1.6 2004/02/11 04:52:54 blanchet Exp
---------------------------------------------------------------------------
* This source code copyright (c) Hexago Inc. 2002-2004.
* 
* This program is free software; you can redistribute it and/or modify it 
* under the terms of the GNU General Public License (GPL) Version 2, 
* June 1991 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; see the file GPL_LICENSE.txt. If not, write 
* to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
* MA 02111-1307 USA
---------------------------------------------------------------------------
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include "platform.h"

#include "xmlparse.h"

#define   XMLTUN
#include "xml_tun.h"

#define TEST 0

/*
 * Here are declarations of the appropriate treatment functions, taking care
 * of the content of the nodes parsed. This is required to insure binding to the
 * procedures in the node structure.
 *
 * Use the PROC macro to help insure proper declaration.
 */
 
PROC(tunnel);

PROC(server);
PROC(client);
PROC(broker);

PROC(address);
PROC(dns_server);
PROC(router);
PROC(prefix);
PROC(as);
PROC(keepalive);

/*
 * Here we define a simple node structure containing only one entry
 * corresponding to the root node.
 *
 * Such a structure must be created for each level of information that
 * is part of the expected xml content.
 */
 
tNode Root[] =

  STARTLIST
    NODE(tunnel) ATTR(action) ATTR(type) ATTR(lifetime) ATTR(proxy) ATTR(mtu) ENDNODE
  ENDLIST

tNode Tunnel[] =

  STARTLIST
    NODE(server)                  ENDNODE
    NODE(client)                  ENDNODE
    NODE(broker)                  ENDNODE
  ENDLIST

tNode Server[] =

  STARTLIST
    NODE(address) ATTR(type)      ENDNODE
    NODE(router)  ATTR(protocol)  ENDNODE
  ENDLIST

tNode Client[] =

  STARTLIST
    NODE(address) ATTR(type)      ENDNODE
    NODE(router)  ATTR(protocol)  ENDNODE
    NODE(keepalive) ATTR(interval) ENDNODE
  ENDLIST

tNode Router[] =

  STARTLIST
    NODE(prefix)     ATTR(length) ENDNODE
    NODE(dns_server) ATTR(type)   ENDNODE
    NODE(as)         ATTR(number) ENDNODE
  ENDLIST

tNode DNSServer[] =

  STARTLIST
    NODE(address) ATTR(type)      ENDNODE
  ENDLIST

tNode Broker[] =

  STARTLIST
    NODE(address) ATTR(type) ENDNODE
  ENDLIST

tNode Keepalive[] =

  STARTLIST
    NODE(address) ATTR(type) ENDNODE
  ENDLIST

/*
 * Support functions
 */

static int Assign(char *str, char **toStr)
{
  char *tol;
  
  if (str == NULL) return 0;

  /* turn answer to lower case */
  /* should help homogenize    */
  /* scripting				   */

  tol = str;
  while (*tol != '\0') {
	  *tol = tolower(*tol);
	  tol++;
  }

  *toStr = (char *) malloc(strlen(str) + 1);

  if (*toStr == NULL) {
    printf("Assign: Mewmory allocation error!\n");
    return -1;
  }

  strcpy(*toStr, str);

  return 0;
}

static int AssignToList(char *str, tLinkedList **toList)
{
  tLinkedList *ll;

  if (str == NULL) return 0;

  ll = (tLinkedList *) malloc(sizeof(tLinkedList));
  if (ll == NULL) {
    printf("AssignToList: Memory allocation error!\n");
    return -1;
  }

  ll->Value = (char *) malloc(strlen(str) + 1);

  if (ll->Value == NULL) {
    printf("AssignToList: Memory allocation error!\n");
    return -1;
  }

  strcpy(ll->Value, str);

  ll->next = *toList;
  *toList  = ll;

  return 0;
}
    
/*
 * Here are defined every treatment functions required. use the PROC
 * macro to help insure proper declaration.
 *
 * These event functions update the contain of the tTunnel instance with the
 * information that is part of the XML structure.
 */

static tTunnel *theTunnelInfo;

static int 
  client,
  server,
  router,
  dns_server,
  broker,
  keepalive;
 
PROC(default)
{
  printf("Found <%s>%.10s%s</%s>\n", n->name, content, strlen(content) > 10 ? "..." : "", n->name);
  return 0;
}

PROC(tunnel)
{
  Assign(n->attributes[0].value, &theTunnelInfo->action  );
  Assign(n->attributes[1].value, &theTunnelInfo->type    );
  Assign(n->attributes[2].value, &theTunnelInfo->lifetime);
  Assign(n->attributes[3].value, &theTunnelInfo->proxy   );
  Assign(n->attributes[4].value, &theTunnelInfo->mtu	 );
  
  return XMLParse(content, Tunnel);
}

PROC(server) 
{
  int res;

  server = 1; 
  res = XMLParse(content, Server); 
  server = 0;
  return res;
}

PROC(broker)
{
  int res;

  broker = 1;
  res = XMLParse(content, Broker);
  broker = 0;
  return res;
}

PROC(client)
{
  int res;

  client = 1;
  res = XMLParse(content, Client);
  client = 0;

  return res;
} 

PROC(dns_server)
{
  int res;

  dns_server = 1; 
  res = XMLParse(content, DNSServer); 
  dns_server = 0; 

  return res;
}

PROC(router)
{
  int res;

  router = 1; 
  Assign(n->attributes[0].value, &theTunnelInfo->router_protocol); 
  res = XMLParse(content, Router);
  router = 0;

  return res;
}

PROC(as)
{
  if (client) {
    Assign(n->attributes[0].value, &theTunnelInfo->client_as);
  } else if (server) {
    Assign(n->attributes[0].value, &theTunnelInfo->server_as);
  }
  return 0;
}

PROC(keepalive)
{
  int res;
  Assign(n->attributes[0].value, &theTunnelInfo->keepalive_interval);
  keepalive = 1;
  res = XMLParse(content, Keepalive);
  keepalive = 0;
  return res;
}


PROC(prefix) {
  Assign(n->attributes[0].value, &theTunnelInfo->prefix_length);
  Assign(content, &theTunnelInfo->prefix);
  return 0;
}

PROC(address)
{
  if (client) {
    if (keepalive) {
      if (!strcmp(n->attributes[0].value, "ipv6")) {
	Assign(content, &theTunnelInfo->keepalive_address_ipv6);
      }      
    }
    else if (router) {
      if (dns_server) {
        if (!strcmp(n->attributes[0].value, "ipv4")) {
          AssignToList(content, &theTunnelInfo->dns_server_address_ipv4);
        } else if (!strcmp(n->attributes[0].value, "ipv6")) {
          AssignToList(content, &theTunnelInfo->dns_server_address_ipv6);
        }
      }
    } else {
      if (!strcmp(n->attributes[0].value, "ipv4")) {
        Assign(content, &theTunnelInfo->client_address_ipv4);
      } else if (!strcmp(n->attributes[0].value, "ipv6")) {
        Assign(content, &theTunnelInfo->client_address_ipv6);
      } else if (!strcmp(n->attributes[0].value, "dn")) {
        Assign(content, &theTunnelInfo->client_dns_name);
      }
    }
  } else if (server) {
    if (!strcmp(n->attributes[0].value, "ipv4")) {
      Assign(content, &theTunnelInfo->server_address_ipv4);
    } else if (!strcmp(n->attributes[0].value, "ipv6")) {
      Assign(content, &theTunnelInfo->server_address_ipv6);
    }
  } else if (broker) {
    if (!strcmp(n->attributes[0].value, "ipv4") || !strcmp(n->attributes[0].value, "dn")) {
      AssignToList(content, &theTunnelInfo->broker_address_ipv4);
    }
  }
  return 0;
}

/* Put here any relevant code... */

void tspFree(char *var)
{
  if (var) free(var);
}

void tspFreeLinkedList(tLinkedList *list)
{
  if(list) {
    if(list->next) {
      tspFreeLinkedList(list->next);
      free(list->next);
      list->next = NULL;
    }
    if(list->Value) {
      free(list->Value);
      list->Value = NULL;
    }
  }
}

void tspClearTunnelInfo(tTunnel *Tunnel)
{
  if (Tunnel) {
    tspFree(Tunnel->action);
    tspFree(Tunnel->type);
    tspFree(Tunnel->lifetime);
    tspFree(Tunnel->proxy);
    tspFree(Tunnel->mtu);
    tspFree(Tunnel->client_address_ipv4);
    tspFree(Tunnel->client_address_ipv6);
    tspFree(Tunnel->client_dns_name);
    tspFree(Tunnel->server_address_ipv4);
    tspFree(Tunnel->server_address_ipv6);
    tspFree(Tunnel->router_protocol);
    tspFree(Tunnel->prefix_length);
    tspFree(Tunnel->prefix);
    tspFree(Tunnel->client_as);
    tspFree(Tunnel->server_as);
    tspFree(Tunnel->keepalive_interval);
    tspFree(Tunnel->keepalive_address_ipv6);
    tspFreeLinkedList(Tunnel->dns_server_address_ipv4);
    tspFreeLinkedList(Tunnel->dns_server_address_ipv6);
    tspFreeLinkedList(Tunnel->broker_address_ipv4);
  }
}

void ShowList(tLinkedList *l)
{
  int first = 1;

  while (l != NULL) {
    if (!first) printf(", ");
    if (l->Value != NULL) printf("%s", l->Value);
    l = l->next;
    first = 0;
  }
}

void tspXMLShowInfo(tTunnel *Tunnel)
{
  printf("Parsed Info:\n\n");

  printf("  action                         = [%s]\n", Tunnel->action              == NULL ? "" : Tunnel->action             );
  printf("  type                           = [%s]\n", Tunnel->type                == NULL ? "" : Tunnel->type               );
  printf("  lifetime                       = [%s]\n", Tunnel->lifetime            == NULL ? "" : Tunnel->lifetime           );
  printf("  proxy                          = [%s]\n", Tunnel->proxy               == NULL ? "" : Tunnel->proxy              );
  printf("  mtu                            = [%s]\n", Tunnel->mtu                 == NULL ? "" : Tunnel->mtu                );  
  printf("  client address ipv4            = [%s]\n", Tunnel->client_address_ipv4 == NULL ? "" : Tunnel->client_address_ipv4);
  printf("  client address ipv6            = [%s]\n", Tunnel->client_address_ipv6 == NULL ? "" : Tunnel->client_address_ipv6);
  printf("  client dns name                = [%s]\n", Tunnel->client_dns_name     == NULL ? "" : Tunnel->client_dns_name    );
  printf("  server address ipv4            = [%s]\n", Tunnel->server_address_ipv4 == NULL ? "" : Tunnel->server_address_ipv4);
  printf("  server address ipv6            = [%s]\n", Tunnel->server_address_ipv6 == NULL ? "" : Tunnel->server_address_ipv6);
  printf("  router protocol                = [%s]\n", Tunnel->router_protocol     == NULL ? "" : Tunnel->router_protocol    );
  printf("  prefix length                  = [%s]\n", Tunnel->prefix_length       == NULL ? "" : Tunnel->prefix_length      );
  printf("  prefix                         = [%s]\n", Tunnel->prefix              == NULL ? "" : Tunnel->prefix             );
  printf("  client as number               = [%s]\n", Tunnel->client_as           == NULL ? "" : Tunnel->client_as          );
  printf("  server as number               = [%s]\n", Tunnel->server_as           == NULL ? "" : Tunnel->server_as          );
  printf("  keepalive interval             = [%s]\n", Tunnel->keepalive_interval  == NULL ? "" : Tunnel->keepalive_interval );
  printf("  keepalive address              = [%s]\n", Tunnel->keepalive_address_ipv6 == NULL ? "" : Tunnel->keepalive_address_ipv6);
  printf("  dns server addresse(s) ipv4    = ["); ShowList(Tunnel->dns_server_address_ipv4); printf("]\n");
  printf("  dns server addresse(s) ipv6    = ["); ShowList(Tunnel->dns_server_address_ipv6); printf("]\n");
  printf("  broker addresse(s) ipv4        = ["); ShowList(Tunnel->broker_address_ipv4);     printf("]\n");
}

int tspXMLParse(char *Data, tTunnel *Tunnel)
{
  tspClearTunnelInfo(Tunnel);

  client = server = router = dns_server = broker = 0;

  theTunnelInfo = Tunnel;

  return XMLParse(Data, Root);
}

#if TEST

char *testData =
" <tunnel action=\"info\" type=\"v6v4\" lifetime=\"1440\" proxy=\"yes\" mtu=\"1280\">\n"
"  <server>\n"
"   <address type=\"ipv4\">206.123.31.114</address>\n"
"   <address type=\"ipv6\">3ffe:b00:c18:ffff:0000:0000:0000:0000</address>\n"
"   <router protocol=\"bgp\">\n"
"    <as number=\"23456\"/>\n"
"   </router>\n"
"  </server>\n"
"  <client>\n"
"   <address type=\"ipv4\">1.1.1.1</address>\n"
"   <address type=\"ipv6\">3ffe:b00:c18:ffff::0000:0000:0000:0001</address>\n"
"   <address type=\"dn\">userid.domain</address>\n"
"   <router protocol=\"bgp\">\n"
"    <prefix length=\"48\">3ffe:0b00:c18:1234::</prefix>\n"
"    <as number=\"12345\"/>\n"
"    <dns_server>\n"
"     <address type=\"ipv4\">2.3.4.5</address>\n"
"     <address type=\"ipv4\">2.3.4.6</address>\n"
"     <address type=\"ipv6\">3ffe:0c00::1</address>\n"
"    </dns_server>\n"
"   </router>\n"
"   <keepalive interval=\"30\"><address type=\"ipv6\">::</address></keepalive>\n"
"  </client>\n"
" </tunnel>\n";

main()
{
  tTunnel t;
  static char string[5000];
  int res;

  printf("Start....\n");

  memset(&t, 0, sizeof(t));  
  strcpy(string, testData);
  
  res = tspXMLParse(string, &t);

  if (res != 0) {
    printf("Result = %d\n", res);
  }

  tspXMLShowInfo(&t);

  return 0;
}

#endif

/*----- xmltsp.c -----------------------------------------------------------------------*/

