Thu Jul 9 13:40:44 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 = "068e67f60f50dd9ee86464c05884a49d" , .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 const 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 373 of file app_disa.c.

static void __unreg_module ( void   )  [static]

Definition at line 373 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::dtimeout, exten, f, firstdigittimeout, ast_flags::flags, LOG_WARNING, mailbox, ast_channel::name, NOANSWER_FLAG, ast_channel::pbx, play_dialtone(), POUND_TO_END_FLAG, and ast_pbx::rtimeout.

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

static int load_module ( void   )  [static]

Definition at line 368 of file app_disa.c.

References ast_register_application, and disa_exec().

00369 {
00370    return ast_register_application(app, disa_exec, synopsis, descrip);
00371 }

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

References ast_unregister_application().

00364 {
00365    return ast_unregister_application(app);
00366 }


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 = "068e67f60f50dd9ee86464c05884a49d" , .load = load_module, .unload = unload_module, } [static]

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

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 373 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 Thu Jul 9 13:40:44 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7