Fri Jun 19 12:09:56 2009

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

static void __unreg_module ( void   )  [static]

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

static int load_module ( void   )  [static]

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

References ast_unregister_application().

00366 {
00367    return ast_unregister_application(app);
00368 }


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 376 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 376 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 Fri Jun 19 12:09:56 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7