Asterisk.org: Developer Documentation (28 Oct 2009)

Wed Oct 28 15:48:03 2009

## Asterisk developer's documentation

# app_disa.c File Reference

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

`#include <string.h>`
`#include <stdlib.h>`
`#include <stdio.h>`
`#include <math.h>`
`#include <sys/time.h>`
`#include "asterisk.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 dependency graph for app_disa.c:

Go to the source code of this file.

## Functions

char * | description (void)
| Provides a description of the module.
static int | disa_exec (struct ast_channel *chan, void *data)
char * | key (void)
| Returns the ASTERISK_GPL_KEY.
int | load_module (void)
| Initialize the module.
static void | play_dialtone (struct ast_channel *chan, char *mailbox)
int | unload_module (void)
| Cleanup all module structures, sockets, etc.
int | usecount (void)
| Provides a usecount.

## Variables

static char * | app = "DISA"
static char * | descrip
| LOCAL_USER_DECL
| STANDARD_LOCAL_USER
static char * | synopsis = "DISA (Direct Inward System Access)"
static char * | tdesc = "DISA (Direct Inward System Access) Application"

## Detailed Description

DISA -- Direct Inward System Access Application.

Author:
  Jim Dixon <jim@lambdatel.com>

Definition in file app_disa.c.

## Function Documentation

char* description | ( | void |  | ) |

Provides a description of the module.

Returns:
  a short description of your module

Definition at line 397 of file app_disa.c.

    00398 {
    00399    return tdesc;
    00400 }

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

Definition at line 115 of file app_disa.c.

References ast_channel::_state, ast_channel::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_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_strlen_zero(), ast_waitfor(), ast_channel::cdr, ast_channel::cid, ast_callerid::cid_num, ast_channel::context, context, ast_pbx::dtimeout, exten, firstdigittimeout, ast_frame::frametype, LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_DEBUG, LOG_ERROR, LOG_WARNING, mailbox, ast_channel::name, ast_channel::pbx, pbx_builtin_setvar_helper(), play_dialtone(), ast_pbx::rtimeout, and ast_frame::subclass.

Referenced by load_module().

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

char* key | ( | void |  | ) |

Returns the ASTERISK_GPL_KEY.

This returns the ASTERISK_GPL_KEY, signifiying that you agree to the terms of the GPL stated in the ASTERISK_GPL_KEY. Your module will not load if it does not return the EXACT message:

     char *key(void) {
             return ASTERISK_GPL_KEY;
     }

Returns:
  ASTERISK_GPL_KEY

Definition at line 409 of file app_disa.c.

References ASTERISK_GPL_KEY.

    00410 {
    00411    return ASTERISK_GPL_KEY;
    00412 }

int load_module | ( | void |  | ) |

Initialize the module.

This function is called at module load time. Put all code in here that needs to set up your module's hardware, software, registrations, etc.

Returns:
  This function should return 0 on success and non-zero on failure. If the module is not loaded successfully, Asterisk will call its unload_module() function.

Initialize the Agents module. This function is being called by Asterisk when loading the module. Among other thing it registers applications, cli commands and reads the cofiguration file.

Returns:
  int Always 0.

TE STUFF END

Definition at line 392 of file app_disa.c.

References ast_register_application(), and disa_exec().

    00393 {
    00394    return ast_register_application(app, disa_exec, synopsis, descrip);
    00395 }

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

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

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

int unload_module | ( | void |  | ) |

Cleanup all module structures, sockets, etc.

This is called at exit. Any registrations and memory allocations need to be unregistered and free'd here. Nothing else will do these for you (until exit).

Returns:
  Zero on success, or non-zero on error.

Definition at line 381 of file app_disa.c.

References ast_unregister_application(), and STANDARD_HANGUP_LOCALUSERS.

    00382 {
    00383    int res;
    00384
    00385    res = ast_unregister_application(app);
    00386
    00387    STANDARD_HANGUP_LOCALUSERS;
    00388
    00389    return res;
    00390 }

int usecount | ( | void |  | ) |

Provides a usecount.

This function will be called by various parts of asterisk. Basically, all it has to do is to return a usecount when called. You will need to maintain your usecount within the module somewhere. The usecount should be how many channels provided by this module are in use.

Returns:
  The module's usecount.

Definition at line 402 of file app_disa.c.

References STANDARD_USECOUNT.

    00403 {
    00404    int res;
    00405    STANDARD_USECOUNT(res);
    00406    return res;
    00407 }

## Variable Documentation

char* app = "DISA"`[static]`

Definition at line 53 of file app_disa.c.

char* descrip`[static]`

Definition at line 57 of file app_disa.c.

LOCAL_USER_DECL

Definition at line 100 of file app_disa.c.

STANDARD_LOCAL_USER

Definition at line 98 of file app_disa.c.

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

Definition at line 55 of file app_disa.c.

char* tdesc = "DISA (Direct Inward System Access) Application"`[static]`

Definition at line 51 of file app_disa.c.