/*
 * This program is free software, distributed under the terms of
 * the GNU General Public License Version 2. See the LICENSE file
 * at the top of the source tree.
 */

/*! \file
 * 
 * \brief Connect with Serval Distributed Numbering Architecture for Mesh Calling
 *
 * Paul Gardner-Stephen (paul@servalproject.org)
 *
 * \ingroup applications
 */

#include "asterisk.h"

ASTERISK_FILE_VERSION(__FILE__, "$Revision: Serval $")

#include <sys/types.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <pthread.h>


#include "asterisk/utils.h"
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/callerid.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/features.h"
#include "asterisk/options.h"
#include "asterisk/cli.h"
#include "asterisk/config.h"
#include "asterisk/say.h"
#include "asterisk/localtime.h"
#include "asterisk/cdr.h"
#include "asterisk/options.h"

#include "serval.c"

#undef inet_ntoa
#define inet_ntoa ast_inet_ntoa

static char *sdnalookup_descrip = 
  "  SDNALookup(): Resolves a telephone number into SIP address via Serval Distributed Numbering Architecture\n";

static char *sdnalookup_app = "SDNALookup";
static char *sdnalookup_synopsis = "Resolve DID into SIP address via Serval DNA";

static char *handle_cli_sdnalookup(int fd, int argc, char *argv[])
{
  char *did=NULL;
  char *sid=NULL;
  unsigned char buffer[65535];
  int len=0;
  int instance=0;

   if (argc != 4) {
        ast_cli(fd, "You did not provide an argument to serval dna lookup\n\n");
        return RESULT_FAILURE;
    }

   did=argv[3];

   if (requestItem(did,sid,"locations",instance,buffer,sizeof(buffer),&len,NULL))
     {
       ast_cli(fd,"Serval DNA Lookup: requestItem() failed (len=%d).\n\n",len);
       return RESULT_FAILURE;
     }
   
   buffer[len]=0;
   ast_cli(fd,"%s resolves to %s (len=%d)\n",did,buffer,len);
   return RESULT_SUCCESS;
}

static char *handle_cli_sdnapeers(int fd, int argc, char *argv[])
{
  int i;

   if (argc != 3) {
        ast_cli(fd, "serval dna peers does not argue about arguments.\n\n");
        return RESULT_FAILURE;
    }

   getPeerList();
   ast_cli(fd,"%d peers reachable:\n",peer_count);
   for(i=0;i<peer_count;i++)
     {
       unsigned char *c=(unsigned char *)&peers[i];
       ast_cli(fd,"  %d.%d.%d.%d\n",c[0],c[1],c[2],c[3]);
     }
   return RESULT_SUCCESS;
}


static char *handle_cli_sdnagate(int fd, int argc, char *argv[])
{
   unsigned char buffer[65535];
   int len=0;
   int instance=0;

   if (gatewayspec) free(gatewayspec);
   gatewayspec=NULL;
   if (argc == 3 ) {
       ast_cli(fd,"Serval DNA Gateway Function OFF.\n\n",len);
       return RESULT_SUCCESS;
   } 
   if (argc != 4) {
        ast_cli(fd, "You did not provide an argument to serval dna gateway\n\n");
        return RESULT_FAILURE;
    }

   gatewayspec=strdup(argv[3]);

   ast_cli(fd,"Serval DNA Gateway Function ON (trunk spec is %s).\n\n",gatewayspec);
   return RESULT_SUCCESS;
}

static char *handle_cli_sdnadebug(int fd, int argc, char *argv[])
{
   if (argc != 3) {
        ast_cli(fd, "You did not provide an argument to serval debug\n\n");
        return RESULT_FAILURE;
    }

   debug=atoi(argv[2]);

   ast_cli(fd,"Serval debug level set to %d\n",debug);
   return RESULT_SUCCESS;
}


static char sdnalookup_usage[]=
  "Usage: serval dna lookup <did>\n"
  "       Attempt to resolve a DID into a SIP address via Serval DNA.\n"
  "Examples:\n"
  "       serval dna lookup 0427679796\n";

static char sdnapeers_usage[]=
  "Usage: serval dna peers\n"
  "       Ask DNA to list the peers currently reachable on the mesh.\n"
  "Examples:\n"
  "       serval dna peers\n";

static char sdnadebug_usage[]=
  "Usage: serval debug <debug level>\n"
  "       Set Serval debug level (0-3 are useful values).\n"
  "Examples:\n"
  "       serval debug 3\n";

static char sdnagate_usage[]=
  "Usage: serval dna gateway [gateway uri]\n"
  "       Offer Serval DNA gateway services to allow other BatPhones to use our SIP trunk.\n"
  "Examples:\n"
  "       serval dna gateway 4000@10.130.1.101\n";


static struct ast_cli_entry cli_sdnalookup[] = {
  { { "serval","dna","lookup" }, handle_cli_sdnalookup,
    "Resolve a telephone number via Serval DNA", sdnalookup_usage },
  { { "serval","dna","peers" }, handle_cli_sdnapeers,
    "Ask DNA to list peers reachable on the mesh", sdnapeers_usage },
  { { "serval","debug" }, handle_cli_sdnadebug,
    "Set Serval debug level", sdnadebug_usage },
  { { "serval","dna","gateway" }, handle_cli_sdnagate,
    "Enable DNA Gateway ", sdnagate_usage },
};

static int sdnalookup_exec(struct ast_channel *chan, void *data)
{
  char *did=data;
  char *sid=NULL;
  unsigned char buffer[65535];
  int len=0;
  int instance=0;

  char status[256] = "INVALIDARGS";

  /* Clear Serval DNA set variables */
  pbx_builtin_setvar_helper(chan, "SDNADID", "");
  pbx_builtin_setvar_helper(chan, "SDNASID", "");
  pbx_builtin_setvar_helper(chan, "SDNALOCATION", "");
  pbx_builtin_setvar_helper(chan, "SDNASIG", "");

  if (ast_strlen_zero(data)) {
    ast_log(LOG_WARNING, "SDNALookup requires an argument (number)\n");
    pbx_builtin_setvar_helper(chan, "SDNASTATUS", status);
    if (debug) fprintf(stderr,"SDNASTATUS=%s (a)\n",status);
    return -1;
  }

  /* XXX - Simple version for now.  Should really use a derivation of the core code from the function below to:
     (a) provide more meaningful errors;
     (b) retrieve the SID for the DID for further use
     (c) fetch the voicesig as well if requested 
  */
  if (requestItem(did,sid,"locations",instance,buffer,sizeof(buffer),&len,NULL))
    {
      pbx_builtin_setvar_helper(chan,"SNASTATUS","FAILED");
      if (debug) fprintf(stderr,"SDNASTATUS=FAILED\n");
      return -1;
    }

  /* It worked, so set appropriate variables and return happily */
  pbx_builtin_setvar_helper(chan,"SNADID",did);
  if (debug) fprintf(stderr,"SNADID=%s\n",did);
  if (sid) {
    pbx_builtin_setvar_helper(chan,"SNASID",sid);
    if (debug) fprintf(stderr,"SNASID=%s\n",sid);
  }
  if (len) {
    buffer[len]=0;
    pbx_builtin_setvar_helper(chan,"SDNALOCATION",(char*)buffer);
    if (debug) fprintf(stderr,"SNALOCATION=%s\n",buffer);
  }
  return 0;
}

static int unload_module(void)
{
  int res;

  ast_cli_unregister_multiple(cli_sdnalookup, ARRAY_LEN(cli_sdnalookup));
  res = ast_unregister_application(sdnalookup_app);

  return res;
}

static int load_module(void)
{
  batman_peerfile=NULL;
  ast_cli_register_multiple(cli_sdnalookup, ARRAY_LEN(cli_sdnalookup));
  return ast_register_application(sdnalookup_app, sdnalookup_exec, sdnalookup_synopsis, sdnalookup_descrip);
}

#define AST_MODULE "app_serval"

AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Serval Mesh Telephony Adapter and Serval DNA Resolver");