Tue Sep 30 01:19:41 2008

Asterisk developer's documentation


app_disa.c File Reference

DISA -- Direct Inward System Access Application. More...

#include "asterisk.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <sys/time.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.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.

Functions

 AST_MODULE_INFO_STANDARD (ASTERISK_GPL_KEY,"DISA (Direct Inward System Access) Application")
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 char * app = "DISA"
static char * descrip
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.


Function Documentation

AST_MODULE_INFO_STANDARD ( ASTERISK_GPL_KEY  ,
"DISA (Direct Inward System Access) Application"   
)

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

Definition at line 112 of file app_disa.c.

References ast_channel::_state, accountcode, ast_answer(), AST_APP_ARG, ast_callerid_split(), AST_CDR_FLAG_POSTED, ast_cdr_reset(), AST_CONTROL_CONGESTION, AST_CONTROL_HANGUP, AST_DECLARE_APP_ARGS, ast_exists_extension(), ast_explicit_goto(), AST_FORMAT_ULAW, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_VOICE, ast_frfree, ast_ignore_pattern(), ast_indicate(), ast_log(), ast_matchmore_extension(), AST_MAX_EXTENSION, ast_module_user_add, ast_module_user_remove, ast_playtones_stop(), ast_read(), ast_set_callerid(), ast_set_read_format(), ast_set_write_format(), AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_string_field_set, ast_strlen_zero(), ast_waitfor(), ast_channel::cdr, ast_channel::cid, ast_callerid::cid_num, ast_channel::context, context, ast_pbx::dtimeout, exten, f, firstdigittimeout, ast_flags::flags, ast_frame::frametype, LOG_DEBUG, LOG_WARNING, mailbox, ast_channel::pbx, pbx_builtin_setvar_helper(), play_dialtone(), ast_pbx::rtimeout, and ast_frame::subclass.

Referenced by load_module().

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

static int load_module ( void   )  [static]

Definition at line 388 of file app_disa.c.

References ast_register_application(), and disa_exec().

00389 {
00390    return ast_register_application(app, disa_exec, synopsis, descrip);
00391 }

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

Definition at line 99 of file app_disa.c.

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

Referenced by disa_exec().

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

static int unload_module ( void   )  [static]

Definition at line 377 of file app_disa.c.

References ast_module_user_hangup_all, and ast_unregister_application().

00378 {
00379    int res;
00380 
00381    res = ast_unregister_application(app);
00382 
00383    ast_module_user_hangup_all();
00384 
00385    return res;
00386 }


Variable Documentation

char* app = "DISA" [static]

Definition at line 52 of file app_disa.c.

char* descrip [static]

Definition at line 56 of file app_disa.c.

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

Definition at line 54 of file app_disa.c.


Generated on Tue Sep 30 01:19:41 2008 for Asterisk - the Open Source PBX by  doxygen 1.5.6