Thu Apr 28 2011 17:15:27

Asterisk developer's documentation


app_disa.c File Reference

DISA -- Direct Inward System Access Application. More...

#include "asterisk.h"
#include <math.h>
#include <sys/time.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/app.h"
#include "asterisk/indications.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/ulaw.h"
#include "asterisk/callerid.h"
#include "asterisk/stringfields.h"
Include dependency graph for app_disa.c:

Go to the source code of this file.

Enumerations

enum  { NOANSWER_FLAG = (1 << 0), POUND_TO_END_FLAG = (1 << 1) }

Functions

static void __reg_module (void)
static void __unreg_module (void)
static int disa_exec (struct ast_channel *chan, void *data)
static int load_module (void)
static void play_dialtone (struct ast_channel *chan, char *mailbox)
static int unload_module (void)

Variables

static struct ast_module_info
__MODULE_INFO_SECTION 
__mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "DISA (Direct Inward System Access) Application" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, }
static char * app = "DISA"
static struct ast_app_option app_opts [128] = { [ 'n' ] = { .flag = NOANSWER_FLAG }, [ 'p' ] = { .flag = POUND_TO_END_FLAG },}
static struct ast_module_infoast_module_info = &__mod_info
enum { ... }  option_flags

Detailed Description

DISA -- Direct Inward System Access Application.

Author:
Jim Dixon <jim@lambdatel.com>

Definition in file app_disa.c.


Enumeration Type Documentation

anonymous enum
Enumerator:
NOANSWER_FLAG 
POUND_TO_END_FLAG 

Definition at line 115 of file app_disa.c.

     {
   NOANSWER_FLAG = (1 << 0),
   POUND_TO_END_FLAG = (1 << 1),
} option_flags;

Function Documentation

static void __reg_module ( void  ) [static]

Definition at line 402 of file app_disa.c.

static void __unreg_module ( void  ) [static]

Definition at line 402 of file app_disa.c.

static int disa_exec ( struct ast_channel chan,
void *  data 
) [static]

Definition at line 143 of file app_disa.c.

References ast_channel::_state, accountcode, app_opts, ast_answer(), AST_APP_ARG, ast_app_parse_options(), ast_callerid_split(), AST_CDR_FLAG_POSTED, ast_cdr_reset(), ast_clear_flag, AST_CONTROL_CONGESTION, AST_CONTROL_HANGUP, ast_copy_string(), ast_debug, AST_DECLARE_APP_ARGS, ast_exists_extension(), ast_explicit_goto(), AST_FLAG_END_DTMF_ONLY, AST_FRAME_CONTROL, AST_FRAME_DTMF, ast_frfree, ast_ignore_pattern(), ast_indicate(), ast_log(), ast_matchmore_extension(), AST_MAX_EXTENSION, ast_playtones_stop(), ast_read(), ast_safe_sleep(), ast_set_callerid(), ast_set_flag, AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_string_field_set, ast_strlen_zero(), ast_test_flag, ast_tvdiff_ms(), ast_tvnow(), ast_waitfor(), ast_channel::cdr, ast_channel::cid, ast_callerid::cid_num, ast_channel::context, context, ast_frame::data, ast_pbx::dtimeoutms, exten, f, firstdigittimeout, ast_flags::flags, ast_frame::frametype, ast_channel::hangupcause, LOG_WARNING, mailbox, ast_channel::name, NOANSWER_FLAG, ast_channel::pbx, pbx_builtin_setvar_helper(), play_dialtone(), POUND_TO_END_FLAG, ast_pbx::rtimeoutms, ast_frame::subclass, and ast_frame::uint32.

Referenced by load_module().

{
   int i = 0, j, k = 0, did_ignore = 0, special_noanswer = 0;
   int firstdigittimeout = (chan->pbx ? chan->pbx->rtimeoutms : 20000);
   int digittimeout = (chan->pbx ? chan->pbx->dtimeoutms : 10000);
   struct ast_flags flags;
   char *tmp, exten[AST_MAX_EXTENSION] = "", acctcode[20]="";
   char pwline[256];
   char ourcidname[256],ourcidnum[256];
   struct ast_frame *f;
   struct timeval lastdigittime;
   int res;
   FILE *fp;
   AST_DECLARE_APP_ARGS(args,
      AST_APP_ARG(passcode);
      AST_APP_ARG(context);
      AST_APP_ARG(cid);
      AST_APP_ARG(mailbox);
      AST_APP_ARG(options);
   );

   if (ast_strlen_zero(data)) {
      ast_log(LOG_WARNING, "DISA requires an argument (passcode/passcode file)\n");
      return -1;
   }

   ast_debug(1, "Digittimeout: %d\n", digittimeout);
   ast_debug(1, "Responsetimeout: %d\n", firstdigittimeout);

   tmp = ast_strdupa(data);

   AST_STANDARD_APP_ARGS(args, tmp);

   if (ast_strlen_zero(args.context))
      args.context = "disa";
   if (ast_strlen_zero(args.mailbox))
      args.mailbox = "";
   if (!ast_strlen_zero(args.options))
      ast_app_parse_options(app_opts, &flags, NULL, args.options);

   ast_debug(1, "Mailbox: %s\n",args.mailbox);

   if (!ast_test_flag(&flags, NOANSWER_FLAG)) {
      if (chan->_state != AST_STATE_UP) {
         /* answer */
         ast_answer(chan);
      }
   } else special_noanswer = 1;

   ast_debug(1, "Context: %s\n",args.context);

   if (!strcasecmp(args.passcode, "no-password")) {
      k |= 1; /* We have the password */
      ast_debug(1, "DISA no-password login success\n");
   }

   lastdigittime = ast_tvnow();

   play_dialtone(chan, args.mailbox);

   ast_set_flag(chan, AST_FLAG_END_DTMF_ONLY);

   for (;;) {
        /* if outa time, give em reorder */
      if (ast_tvdiff_ms(ast_tvnow(), lastdigittime) > ((k&2) ? digittimeout : firstdigittimeout)) {
         ast_debug(1,"DISA %s entry timeout on chan %s\n",
            ((k&1) ? "extension" : "password"),chan->name);
         break;
      }

      if ((res = ast_waitfor(chan, -1) < 0)) {
         ast_debug(1, "Waitfor returned %d\n", res);
         continue;
      }

      if (!(f = ast_read(chan))) {
         ast_clear_flag(chan, AST_FLAG_END_DTMF_ONLY);
         return -1;
      }

      if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP)) {
         if (f->data.uint32)
            chan->hangupcause = f->data.uint32;
         ast_frfree(f);
         ast_clear_flag(chan, AST_FLAG_END_DTMF_ONLY);
         return -1;
      }

      /* If the frame coming in is not DTMF, just drop it and continue */
      if (f->frametype != AST_FRAME_DTMF) {
         ast_frfree(f);
         continue;
      }

      j = f->subclass;  /* save digit */
      ast_frfree(f);

      if (!i) {
         k |= 2; /* We have the first digit */
         ast_playtones_stop(chan);
      }

      lastdigittime = ast_tvnow();

      /* got a DTMF tone */
      if (i < AST_MAX_EXTENSION) { /* if still valid number of digits */
         if (!(k&1)) { /* if in password state */
            if (j == '#') { /* end of password */
                 /* see if this is an integer */
               if (sscanf(args.passcode,"%30d",&j) < 1) { /* nope, it must be a filename */
                  fp = fopen(args.passcode,"r");
                  if (!fp) {
                     ast_log(LOG_WARNING,"DISA password file %s not found on chan %s\n",args.passcode,chan->name);
                     ast_clear_flag(chan, AST_FLAG_END_DTMF_ONLY);
                     return -1;
                  }
                  pwline[0] = 0;
                  while(fgets(pwline,sizeof(pwline) - 1,fp)) {
                     if (!pwline[0])
                        continue;
                     if (pwline[strlen(pwline) - 1] == '\n')
                        pwline[strlen(pwline) - 1] = 0;
                     if (!pwline[0])
                        continue;
                      /* skip comments */
                     if (pwline[0] == '#')
                        continue;
                     if (pwline[0] == ';')
                        continue;

                     AST_STANDARD_APP_ARGS(args, pwline);

                     ast_debug(1, "Mailbox: %s\n",args.mailbox);

                     /* password must be in valid format (numeric) */
                     if (sscanf(args.passcode,"%30d", &j) < 1)
                        continue;
                      /* if we got it */
                     if (!strcmp(exten,args.passcode)) {
                        if (ast_strlen_zero(args.context))
                           args.context = "disa";
                        if (ast_strlen_zero(args.mailbox))
                           args.mailbox = "";
                        break;
                     }
                  }
                  fclose(fp);
               }
               /* compare the two */
               if (strcmp(exten,args.passcode)) {
                  ast_log(LOG_WARNING,"DISA on chan %s got bad password %s\n",chan->name,exten);
                  goto reorder;

               }
                /* password good, set to dial state */
               ast_debug(1,"DISA on chan %s password is good\n",chan->name);
               play_dialtone(chan, args.mailbox);

               k|=1; /* In number mode */
               i = 0;  /* re-set buffer pointer */
               exten[sizeof(acctcode)] = 0;
               ast_copy_string(acctcode, exten, sizeof(acctcode));
               exten[0] = 0;
               ast_debug(1,"Successful DISA log-in on chan %s\n", chan->name);
               continue;
            }
         } else {
            if (j == '#') { /* end of extension .. maybe */
               if (i == 0 && 
                     (ast_matchmore_extension(chan, args.context, "#", 1, chan->cid.cid_num) ||
                      ast_exists_extension(chan, args.context, "#", 1, chan->cid.cid_num)) ) {
                  /* Let the # be the part of, or the entire extension */
               } else {
                  break;
               }
            }
         }

         exten[i++] = j;  /* save digit */
         exten[i] = 0;
         if (!(k&1))
            continue; /* if getting password, continue doing it */
         /* if this exists */

         /* user wants end of number, remove # */
         if (ast_test_flag(&flags, POUND_TO_END_FLAG) && j == '#') {
            exten[--i] = 0;
            break;
         }

         if (ast_ignore_pattern(args.context, exten)) {
            play_dialtone(chan, "");
            did_ignore = 1;
         } else
            if (did_ignore) {
               ast_playtones_stop(chan);
               did_ignore = 0;
            }

         /* if can do some more, do it */
         if (!ast_matchmore_extension(chan,args.context,exten,1, chan->cid.cid_num)) {
            break;
         }
      }
   }

   ast_clear_flag(chan, AST_FLAG_END_DTMF_ONLY);

   if (k == 3) {
      int recheck = 0;
      struct ast_flags cdr_flags = { AST_CDR_FLAG_POSTED };

      if (!ast_exists_extension(chan, args.context, exten, 1, chan->cid.cid_num)) {
         pbx_builtin_setvar_helper(chan, "INVALID_EXTEN", exten);
         exten[0] = 'i';
         exten[1] = '\0';
         recheck = 1;
      }
      if (!recheck || ast_exists_extension(chan, args.context, exten, 1, chan->cid.cid_num)) {
         ast_playtones_stop(chan);
         /* We're authenticated and have a target extension */
         if (!ast_strlen_zero(args.cid)) {
            ast_callerid_split(args.cid, ourcidname, sizeof(ourcidname), ourcidnum, sizeof(ourcidnum));
            ast_set_callerid(chan, ourcidnum, ourcidname, ourcidnum);
         }

         if (!ast_strlen_zero(acctcode))
            ast_string_field_set(chan, accountcode, acctcode);

         if (special_noanswer) cdr_flags.flags = 0;
         ast_cdr_reset(chan->cdr, &cdr_flags);
         ast_explicit_goto(chan, args.context, exten, 1);
         return 0;
      }
   }

   /* Received invalid, but no "i" extension exists in the given context */

reorder:
   /* Play congestion for a bit */
   ast_indicate(chan, AST_CONTROL_CONGESTION);
   ast_safe_sleep(chan, 10*1000);

   ast_playtones_stop(chan);

   return -1;
}
static void play_dialtone ( struct ast_channel chan,
char *  mailbox 
) [static]

Definition at line 125 of file app_disa.c.

References ast_app_has_voicemail(), ast_get_indication_tone(), ast_playtones_start(), ast_tone_zone_sound_unref(), ast_tonepair_start(), ast_tone_zone_sound::data, and ast_channel::zone.

Referenced by disa_exec().

{
   struct ast_tone_zone_sound *ts = NULL;

   if (ast_app_has_voicemail(mailbox, NULL)) {
      ts = ast_get_indication_tone(chan->zone, "dialrecall");
   } else {
      ts = ast_get_indication_tone(chan->zone, "dial");
   }

   if (ts) {
      ast_playtones_start(chan, 0, ts->data, 0);
      ts = ast_tone_zone_sound_unref(ts);
   } else {
      ast_tonepair_start(chan, 350, 440, 0, 0);
   }
}
static int unload_module ( void  ) [static]

Definition at line 391 of file app_disa.c.

References ast_unregister_application().


Variable Documentation

struct ast_module_info __MODULE_INFO_SECTION __mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "DISA (Direct Inward System Access) Application" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, } [static]

Definition at line 402 of file app_disa.c.

char* app = "DISA" [static]

Definition at line 113 of file app_disa.c.

struct ast_app_option app_opts[128] = { [ 'n' ] = { .flag = NOANSWER_FLAG }, [ 'p' ] = { .flag = POUND_TO_END_FLAG },} [static]

Definition at line 123 of file app_disa.c.

Referenced by disa_exec().

Definition at line 402 of file app_disa.c.

enum { ... } option_flags