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"

Include dependency graph for app_disa.c:

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 = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, .support_level = AST_MODULE_SUPPORT_CORE, }
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 120 of file app_disa.c.

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


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 425 of file app_disa.c.

static void __unreg_module ( void   )  [static]

Definition at line 425 of file app_disa.c.

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

Definition at line 148 of file app_disa.c.

References app_opts, args, ast_answer(), AST_APP_ARG, ast_app_parse_options(), ast_callerid_split(), ast_channel_caller(), ast_channel_flags(), ast_channel_hangupcause_set(), ast_channel_lock, ast_channel_name(), ast_channel_pbx(), ast_channel_unlock, 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_LOG_NOTICE, 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_strlen_zero, ast_test_flag, ast_tvdiff_ms(), ast_tvnow(), ast_waitfor(), context, ast_frame::data, ast_pbx::dtimeoutms, exten, f, firstdigittimeout, ast_frame::frametype, ast_frame_subclass::integer, LOG_WARNING, mailbox, NOANSWER_FLAG, NULL, pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), play_dialtone(), POUND_TO_END_FLAG, ast_pbx::rtimeoutms, S_COR, ast_frame::subclass, tmp(), and ast_frame::uint32.

Referenced by load_module().

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

static int load_module ( void   )  [static]

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

Definition at line 130 of file app_disa.c.

References ast_app_has_voicemail(), ast_channel_zone(), ast_get_indication_tone(), ast_playtones_start(), ast_tone_zone_sound_unref(), ast_tonepair_start(), ast_tone_zone_sound::data, and NULL.

Referenced by disa_exec().

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

static int unload_module ( void   )  [static]

Definition at line 414 of file app_disa.c.

References ast_unregister_application().

00415 {
00416    return ast_unregister_application(app);
00417 }


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 = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, .support_level = AST_MODULE_SUPPORT_CORE, } [static]

Definition at line 425 of file app_disa.c.

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

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

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

Definition at line 425 of file app_disa.c.


Generated on Thu Apr 16 06:28:26 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6