Mon Aug 31 12:30:14 2015

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"

Go to the source code of this file.

Enumerations

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

Functions

 AST_APP_OPTIONS (app_opts,{AST_APP_OPTION('n', NOANSWER_FLAG), AST_APP_OPTION('p', POUND_TO_END_FLAG),})
 AST_MODULE_INFO_STANDARD (ASTERISK_GPL_KEY,"DISA (Direct Inward System Access) Application")
static int disa_exec (struct ast_channel *chan, const char *data)
static int load_module (void)
static void play_dialtone (struct ast_channel *chan, char *mailbox)
static int unload_module (void)

Variables

static const char app [] = "DISA"

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 119 of file app_disa.c.

00119      {
00120    NOANSWER_FLAG = (1 << 0),
00121    POUND_TO_END_FLAG = (1 << 1),
00122 };


Function Documentation

AST_APP_OPTIONS ( app_opts   ) 
AST_MODULE_INFO_STANDARD ( ASTERISK_GPL_KEY  ,
"DISA (Direct Inward System Access) Application"   
)
static int disa_exec ( struct ast_channel chan,
const char *  data 
) [static]

Definition at line 147 of file app_disa.c.

References ast_channel::_state, accountcode, args, 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_FLAGS_ALL, 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::caller, ast_channel::cdr, context, ast_frame::data, ast_pbx::dtimeoutms, exten, f, firstdigittimeout, ast_flags::flags, ast_frame::frametype, ast_channel::hangupcause, ast_party_caller::id, ast_frame_subclass::integer, LOG_WARNING, mailbox, NOANSWER_FLAG, ast_party_id::number, ast_channel::pbx, pbx_builtin_setvar_helper(), play_dialtone(), POUND_TO_END_FLAG, ast_pbx::rtimeoutms, S_COR, ast_party_number::str, ast_frame::subclass, ast_frame::uint32, and ast_party_number::valid.

Referenced by load_module().

00148 {
00149    int i = 0, j, k = 0, did_ignore = 0, special_noanswer = 0;
00150    int firstdigittimeout = (chan->pbx ? chan->pbx->rtimeoutms : 20000);
00151    int digittimeout = (chan->pbx ? chan->pbx->dtimeoutms : 10000);
00152    struct ast_flags flags;
00153    char *tmp, exten[AST_MAX_EXTENSION] = "", acctcode[20]="";
00154    char pwline[256];
00155    char ourcidname[256],ourcidnum[256];
00156    struct ast_frame *f;
00157    struct timeval lastdigittime;
00158    int res;
00159    FILE *fp;
00160    AST_DECLARE_APP_ARGS(args,
00161       AST_APP_ARG(passcode);
00162       AST_APP_ARG(context);
00163       AST_APP_ARG(cid);
00164       AST_APP_ARG(mailbox);
00165       AST_APP_ARG(options);
00166    );
00167 
00168    if (ast_strlen_zero(data)) {
00169       ast_log(LOG_WARNING, "DISA requires an argument (passcode/passcode file)\n");
00170       return -1;
00171    }
00172 
00173    ast_debug(1, "Digittimeout: %d\n", digittimeout);
00174    ast_debug(1, "Responsetimeout: %d\n", firstdigittimeout);
00175 
00176    tmp = ast_strdupa(data);
00177 
00178    AST_STANDARD_APP_ARGS(args, tmp);
00179 
00180    if (ast_strlen_zero(args.context))
00181       args.context = "disa";
00182    if (ast_strlen_zero(args.mailbox))
00183       args.mailbox = "";
00184    if (!ast_strlen_zero(args.options)) {
00185       ast_app_parse_options(app_opts, &flags, NULL, args.options);
00186    } else {
00187       /* Coverity - This uninit_use should be ignored since this macro initializes the flags */
00188       ast_clear_flag(&flags, AST_FLAGS_ALL);
00189    }
00190 
00191 
00192    ast_debug(1, "Mailbox: %s\n",args.mailbox);
00193 
00194    if (!ast_test_flag(&flags, NOANSWER_FLAG)) {
00195       if (chan->_state != AST_STATE_UP) {
00196          /* answer */
00197          ast_answer(chan);
00198       }
00199    } else special_noanswer = 1;
00200 
00201    ast_debug(1, "Context: %s\n",args.context);
00202 
00203    if (!strcasecmp(args.passcode, "no-password")) {
00204       k |= 1; /* We have the password */
00205       ast_debug(1, "DISA no-password login success\n");
00206    }
00207 
00208    lastdigittime = ast_tvnow();
00209 
00210    play_dialtone(chan, args.mailbox);
00211 
00212    ast_set_flag(chan, AST_FLAG_END_DTMF_ONLY);
00213 
00214    for (;;) {
00215         /* if outa time, give em reorder */
00216       if (ast_tvdiff_ms(ast_tvnow(), lastdigittime) > ((k&2) ? digittimeout : firstdigittimeout)) {
00217          ast_debug(1,"DISA %s entry timeout on chan %s\n",
00218             ((k&1) ? "extension" : "password"),chan->name);
00219          break;
00220       }
00221 
00222       if ((res = ast_waitfor(chan, -1) < 0)) {
00223          ast_debug(1, "Waitfor returned %d\n", res);
00224          continue;
00225       }
00226 
00227       if (!(f = ast_read(chan))) {
00228          ast_clear_flag(chan, AST_FLAG_END_DTMF_ONLY);
00229          return -1;
00230       }
00231 
00232       if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer == AST_CONTROL_HANGUP)) {
00233          if (f->data.uint32)
00234             chan->hangupcause = f->data.uint32;
00235          ast_frfree(f);
00236          ast_clear_flag(chan, AST_FLAG_END_DTMF_ONLY);
00237          return -1;
00238       }
00239 
00240       /* If the frame coming in is not DTMF, just drop it and continue */
00241       if (f->frametype != AST_FRAME_DTMF) {
00242          ast_frfree(f);
00243          continue;
00244       }
00245 
00246       j = f->subclass.integer;  /* save digit */
00247       ast_frfree(f);
00248 
00249       if (!i) {
00250          k |= 2; /* We have the first digit */
00251          ast_playtones_stop(chan);
00252       }
00253 
00254       lastdigittime = ast_tvnow();
00255 
00256       /* got a DTMF tone */
00257       if (i < AST_MAX_EXTENSION) { /* if still valid number of digits */
00258          if (!(k&1)) { /* if in password state */
00259             if (j == '#') { /* end of password */
00260                  /* see if this is an integer */
00261                if (sscanf(args.passcode,"%30d",&j) < 1) { /* nope, it must be a filename */
00262                   fp = fopen(args.passcode,"r");
00263                   if (!fp) {
00264                      ast_log(LOG_WARNING,"DISA password file %s not found on chan %s\n",args.passcode,chan->name);
00265                      ast_clear_flag(chan, AST_FLAG_END_DTMF_ONLY);
00266                      return -1;
00267                   }
00268                   pwline[0] = 0;
00269                   while(fgets(pwline,sizeof(pwline) - 1,fp)) {
00270                      if (!pwline[0])
00271                         continue;
00272                      if (pwline[strlen(pwline) - 1] == '\n')
00273                         pwline[strlen(pwline) - 1] = 0;
00274                      if (!pwline[0])
00275                         continue;
00276                       /* skip comments */
00277                      if (pwline[0] == '#')
00278                         continue;
00279                      if (pwline[0] == ';')
00280                         continue;
00281 
00282                      AST_STANDARD_APP_ARGS(args, pwline);
00283 
00284                      ast_debug(1, "Mailbox: %s\n",args.mailbox);
00285 
00286                      /* password must be in valid format (numeric) */
00287                      if (sscanf(args.passcode,"%30d", &j) < 1)
00288                         continue;
00289                       /* if we got it */
00290                      if (!strcmp(exten,args.passcode)) {
00291                         if (ast_strlen_zero(args.context))
00292                            args.context = "disa";
00293                         if (ast_strlen_zero(args.mailbox))
00294                            args.mailbox = "";
00295                         break;
00296                      }
00297                   }
00298                   fclose(fp);
00299                }
00300                /* compare the two */
00301                if (strcmp(exten,args.passcode)) {
00302                   ast_log(LOG_WARNING,"DISA on chan %s got bad password %s\n",chan->name,exten);
00303                   goto reorder;
00304 
00305                }
00306                 /* password good, set to dial state */
00307                ast_debug(1,"DISA on chan %s password is good\n",chan->name);
00308                play_dialtone(chan, args.mailbox);
00309 
00310                k|=1; /* In number mode */
00311                i = 0;  /* re-set buffer pointer */
00312                exten[sizeof(acctcode)] = 0;
00313                ast_copy_string(acctcode, exten, sizeof(acctcode));
00314                exten[0] = 0;
00315                ast_debug(1,"Successful DISA log-in on chan %s\n", chan->name);
00316                continue;
00317             }
00318          } else {
00319             if (j == '#') { /* end of extension .. maybe */
00320                if (i == 0
00321                   && (ast_matchmore_extension(chan, args.context, "#", 1,
00322                      S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))
00323                      || ast_exists_extension(chan, args.context, "#", 1,
00324                         S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) ) {
00325                   /* Let the # be the part of, or the entire extension */
00326                } else {
00327                   break;
00328                }
00329             }
00330          }
00331 
00332          exten[i++] = j;  /* save digit */
00333          exten[i] = 0;
00334          if (!(k&1))
00335             continue; /* if getting password, continue doing it */
00336          /* if this exists */
00337 
00338          /* user wants end of number, remove # */
00339          if (ast_test_flag(&flags, POUND_TO_END_FLAG) && j == '#') {
00340             exten[--i] = 0;
00341             break;
00342          }
00343 
00344          if (ast_ignore_pattern(args.context, exten)) {
00345             play_dialtone(chan, "");
00346             did_ignore = 1;
00347          } else
00348             if (did_ignore) {
00349                ast_playtones_stop(chan);
00350                did_ignore = 0;
00351             }
00352 
00353          /* if can do some more, do it */
00354          if (!ast_matchmore_extension(chan, args.context, exten, 1,
00355             S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
00356             break;
00357          }
00358       }
00359    }
00360 
00361    ast_clear_flag(chan, AST_FLAG_END_DTMF_ONLY);
00362 
00363    if (k == 3) {
00364       int recheck = 0;
00365       struct ast_flags cdr_flags = { AST_CDR_FLAG_POSTED };
00366 
00367       if (!ast_exists_extension(chan, args.context, exten, 1,
00368          S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
00369          pbx_builtin_setvar_helper(chan, "INVALID_EXTEN", exten);
00370          exten[0] = 'i';
00371          exten[1] = '\0';
00372          recheck = 1;
00373       }
00374       if (!recheck
00375          || ast_exists_extension(chan, args.context, exten, 1,
00376             S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
00377          ast_playtones_stop(chan);
00378          /* We're authenticated and have a target extension */
00379          if (!ast_strlen_zero(args.cid)) {
00380             ast_callerid_split(args.cid, ourcidname, sizeof(ourcidname), ourcidnum, sizeof(ourcidnum));
00381             ast_set_callerid(chan, ourcidnum, ourcidname, ourcidnum);
00382          }
00383 
00384          if (!ast_strlen_zero(acctcode))
00385             ast_string_field_set(chan, accountcode, acctcode);
00386 
00387          if (special_noanswer) cdr_flags.flags = 0;
00388          ast_cdr_reset(chan->cdr, &cdr_flags);
00389          ast_explicit_goto(chan, args.context, exten, 1);
00390          return 0;
00391       }
00392    }
00393 
00394    /* Received invalid, but no "i" extension exists in the given context */
00395 
00396 reorder:
00397    /* Play congestion for a bit */
00398    ast_indicate(chan, AST_CONTROL_CONGESTION);
00399    ast_safe_sleep(chan, 10*1000);
00400 
00401    ast_playtones_stop(chan);
00402 
00403    return -1;
00404 }

static int load_module ( void   )  [static]
static void play_dialtone ( struct ast_channel chan,
char *  mailbox 
) [static]

Definition at line 129 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().

00130 {
00131    struct ast_tone_zone_sound *ts = NULL;
00132 
00133    if (ast_app_has_voicemail(mailbox, NULL)) {
00134       ts = ast_get_indication_tone(chan->zone, "dialrecall");
00135    } else {
00136       ts = ast_get_indication_tone(chan->zone, "dial");
00137    }
00138 
00139    if (ts) {
00140       ast_playtones_start(chan, 0, ts->data, 0);
00141       ts = ast_tone_zone_sound_unref(ts);
00142    } else {
00143       ast_tonepair_start(chan, 350, 440, 0, 0);
00144    }
00145 }

static int unload_module ( void   )  [static]

Definition at line 406 of file app_disa.c.

References ast_unregister_application().

00407 {
00408    return ast_unregister_application(app);
00409 }


Variable Documentation

const char app[] = "DISA" [static]

Definition at line 117 of file app_disa.c.


Generated on 31 Aug 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1