Wed Aug 18 22:33:58 2010

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

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 __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "DISA (Direct Inward System Access) Application" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "a9c98e5d177805051735cb5b0b16b0a0" , .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
static char * descrip
enum { ... }  option_flags
static char * synopsis = "DISA (Direct Inward System Access)"


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

00093      {
00094    NOANSWER_FLAG = (1 << 0),
00095    POUND_TO_END_FLAG = (1 << 1),
00096 } option_flags;


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 375 of file app_disa.c.

static void __unreg_module ( void   )  [static]

Definition at line 375 of file app_disa.c.

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

Definition at line 116 of file app_disa.c.

References ast_channel::_state, app_opts, ast_answer(), AST_APP_ARG, ast_app_parse_options(), ast_clear_flag, AST_CONTROL_HANGUP, ast_copy_string(), ast_debug, AST_DECLARE_APP_ARGS, ast_exists_extension(), AST_FLAG_END_DTMF_ONLY, AST_FRAME_CONTROL, AST_FRAME_DTMF, ast_frfree, ast_ignore_pattern(), ast_log(), ast_matchmore_extension(), AST_MAX_EXTENSION, ast_playtones_stop(), ast_read(), ast_set_flag, AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_tvdiff_ms(), ast_tvnow(), ast_waitfor(), chan, ast_channel::cid, ast_callerid::cid_num, ast_channel::context, context, ast_pbx::dtimeoutms, exten, f, firstdigittimeout, ast_flags::flags, ast_channel::hangupcause, LOG_WARNING, mailbox, ast_channel::name, NOANSWER_FLAG, ast_channel::pbx, play_dialtone(), POUND_TO_END_FLAG, and ast_pbx::rtimeoutms.

Referenced by load_module().

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

static int load_module ( void   )  [static]

Definition at line 369 of file app_disa.c.

References AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_register_application, and disa_exec().

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

Definition at line 103 of file app_disa.c.

References ast_app_has_voicemail(), ast_get_indication_tone(), ast_playtones_start(), ast_tonepair_start(), chan, tone_zone_sound::data, and ast_channel::zone.

Referenced by disa_exec().

00104 {
00105    const struct tone_zone_sound *ts = NULL;
00106    if(ast_app_has_voicemail(mailbox, NULL))
00107       ts = ast_get_indication_tone(chan->zone, "dialrecall");
00108    else
00109       ts = ast_get_indication_tone(chan->zone, "dial");
00110    if (ts)
00111       ast_playtones_start(chan, 0, ts->data, 0);
00112    else
00113       ast_tonepair_start(chan, 350, 440, 0, 0);
00114 }

static int unload_module ( void   )  [static]

Definition at line 364 of file app_disa.c.

References ast_unregister_application().

00365 {
00366    return ast_unregister_application(app);
00367 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "DISA (Direct Inward System Access) Application" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, } [static]

Definition at line 375 of file app_disa.c.

char* app = "DISA" [static]

Definition at line 48 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 101 of file app_disa.c.

Referenced by app_exec(), disa_exec(), record_exec(), and softhangup_exec().

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 375 of file app_disa.c.

char* descrip [static]

Definition at line 52 of file app_disa.c.

enum { ... } option_flags

char* synopsis = "DISA (Direct Inward System Access)" [static]

Definition at line 50 of file app_disa.c.


Generated on Wed Aug 18 22:33:58 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7