Wed Apr 6 11:29:49 2011

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, 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 struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, }
static const 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


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.

00115      {
00116    NOANSWER_FLAG = (1 << 0),
00117    POUND_TO_END_FLAG = (1 << 1),
00118 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 408 of file app_disa.c.

static void __unreg_module ( void   )  [static]

Definition at line 408 of file app_disa.c.

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

Definition at line 143 of file app_disa.c.

References ast_channel::_state, app_opts, args, 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(), ast_channel::caller, context, ast_pbx::dtimeoutms, exten, f, firstdigittimeout, ast_flags::flags, ast_channel::hangupcause, ast_party_caller::id, LOG_WARNING, mailbox, ast_channel::name, NOANSWER_FLAG, ast_party_id::number, ast_channel::pbx, play_dialtone(), POUND_TO_END_FLAG, ast_pbx::rtimeoutms, S_COR, ast_party_number::str, and ast_party_number::valid.

Referenced by load_module().

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

static int load_module ( void   )  [static]

Definition at line 402 of file app_disa.c.

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

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().

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

static int unload_module ( void   )  [static]

Definition at line 397 of file app_disa.c.

References ast_unregister_application().

00398 {
00399    return ast_unregister_application(app);
00400 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, } [static]

Definition at line 408 of file app_disa.c.

const 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.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 408 of file app_disa.c.


Generated on Wed Apr 6 11:29:49 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7