Sun Aug 6 15:03:17 2006

Asterisk developer's documentation


Main Page | Modules | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

app_directory.c File Reference

Provide a directory of extensions. More...

#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include "asterisk.h"
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/config.h"
#include "asterisk/say.h"
#include "asterisk/utils.h"

Include dependency graph for app_directory.c:

Go to the source code of this file.

Defines

#define NUMDIGITS   3
#define VOICEMAIL_CONFIG   "voicemail.conf"

Functions

static char * convert (char *lastname)
char * description (void)
 Provides a description of the module.
static int directory_exec (struct ast_channel *chan, void *data)
static int do_directory (struct ast_channel *chan, struct ast_config *cfg, char *context, char *dialcontext, char digit, int last)
char * key ()
 Returns the ASTERISK_GPL_KEY.
int load_module (void)
 Initialize the module.
static int play_mailbox_owner (struct ast_channel *chan, char *context, char *dialcontext, char *ext, char *name)
static struct ast_configrealtime_directory (char *context)
int unload_module (void)
 Cleanup all module structures, sockets, etc.
int usecount (void)
 Provides a usecount.

Variables

static char * app = "Directory"
static char * descrip
 LOCAL_USER_DECL
 STANDARD_LOCAL_USER
static char * synopsis = "Provide directory of voicemail extensions"
static char * tdesc = "Extension Directory"


Detailed Description

Provide a directory of extensions.

Definition in file app_directory.c.


Define Documentation

#define NUMDIGITS   3
 

Definition at line 84 of file app_directory.c.

Referenced by convert(), and do_directory().

#define VOICEMAIL_CONFIG   "voicemail.conf"
 

Definition at line 81 of file app_directory.c.

Referenced by load_config(), load_module(), and realtime_directory().


Function Documentation

static char* convert char *  lastname  )  [static]
 

Definition at line 185 of file app_directory.c.

References malloc, and NUMDIGITS.

Referenced by do_directory().

00186 {
00187    char *tmp;
00188    int lcount = 0;
00189    tmp = malloc(NUMDIGITS + 1);
00190    if (tmp) {
00191       while((*lastname > 32) && lcount < NUMDIGITS) {
00192          switch(toupper(*lastname)) {
00193          case '1':
00194             tmp[lcount++] = '1';
00195             break;
00196          case '2':
00197          case 'A':
00198          case 'B':
00199          case 'C':
00200             tmp[lcount++] = '2';
00201             break;
00202          case '3':
00203          case 'D':
00204          case 'E':
00205          case 'F':
00206             tmp[lcount++] = '3';
00207             break;
00208          case '4':
00209          case 'G':
00210          case 'H':
00211          case 'I':
00212             tmp[lcount++] = '4';
00213             break;
00214          case '5':
00215          case 'J':
00216          case 'K':
00217          case 'L':
00218             tmp[lcount++] = '5';
00219             break;
00220          case '6':
00221          case 'M':
00222          case 'N':
00223          case 'O':
00224             tmp[lcount++] = '6';
00225             break;
00226          case '7':
00227          case 'P':
00228          case 'Q':
00229          case 'R':
00230          case 'S':
00231             tmp[lcount++] = '7';
00232             break;
00233          case '8':
00234          case 'T':
00235          case 'U':
00236          case 'V':
00237             tmp[lcount++] = '8';
00238             break;
00239          case '9':
00240          case 'W':
00241          case 'X':
00242          case 'Y':
00243          case 'Z':
00244             tmp[lcount++] = '9';
00245             break;
00246          }
00247          lastname++;
00248       }
00249       tmp[lcount] = '\0';
00250    }
00251    return tmp;
00252 }

char* description void   ) 
 

Provides a description of the module.

Returns:
a short description of your module

Definition at line 635 of file app_directory.c.

References tdesc.

00636 {
00637    return tdesc;
00638 }

static int directory_exec struct ast_channel chan,
void *  data
[static]
 

Definition at line 526 of file app_directory.c.

References ast_answer(), ast_config_destroy(), AST_DIGIT_ANY, ast_log(), AST_STATE_UP, ast_stopstream(), ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_variable_retrieve(), ast_waitfordigit(), ast_waitstream(), cfg, context, dialcontext, do_directory(), last, LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_WARNING, and realtime_directory().

Referenced by load_module().

00527 {
00528    int res = 0;
00529    struct localuser *u;
00530    struct ast_config *cfg;
00531    int last = 1;
00532    char *context, *dialcontext, *dirintro, *options;
00533 
00534    if (ast_strlen_zero(data)) {
00535       ast_log(LOG_WARNING, "Directory requires an argument (context[,dialcontext])\n");
00536       return -1;
00537    }
00538 
00539    LOCAL_USER_ADD(u);
00540 
00541    context = ast_strdupa(data);
00542    dialcontext = strchr(context, '|');
00543    if (dialcontext) {
00544       *dialcontext = '\0';
00545       dialcontext++;
00546       options = strchr(dialcontext, '|');
00547       if (options) {
00548          *options = '\0';
00549          options++; 
00550          if (strchr(options, 'f'))
00551             last = 0;
00552       }
00553    } else   
00554       dialcontext = context;
00555 
00556    cfg = realtime_directory(context);
00557    if (!cfg) {
00558       LOCAL_USER_REMOVE(u);
00559       return -1;
00560    }
00561 
00562    dirintro = ast_variable_retrieve(cfg, context, "directoryintro");
00563    if (ast_strlen_zero(dirintro))
00564       dirintro = ast_variable_retrieve(cfg, "general", "directoryintro");
00565    if (ast_strlen_zero(dirintro)) {
00566       if (last)
00567          dirintro = "dir-intro"; 
00568       else
00569          dirintro = "dir-intro-fn";
00570    }
00571 
00572    if (chan->_state != AST_STATE_UP) 
00573       res = ast_answer(chan);
00574 
00575    for (;;) {
00576       if (!res)
00577          res = ast_streamfile(chan, dirintro, chan->language);
00578       if (!res)
00579          res = ast_waitstream(chan, AST_DIGIT_ANY);
00580       ast_stopstream(chan);
00581       if (!res)
00582          res = ast_waitfordigit(chan, 5000);
00583       if (res > 0) {
00584          res = do_directory(chan, cfg, context, dialcontext, res, last);
00585          if (res > 0) {
00586             res = ast_waitstream(chan, AST_DIGIT_ANY);
00587             ast_stopstream(chan);
00588             if (res >= 0) {
00589                continue;
00590             }
00591          }
00592       }
00593       break;
00594    }
00595    ast_config_destroy(cfg);
00596    LOCAL_USER_REMOVE(u);
00597    return res;
00598 }

static int do_directory struct ast_channel chan,
struct ast_config cfg,
char *  context,
char *  dialcontext,
char  digit,
int  last
[static]
 

Definition at line 406 of file app_directory.c.

References ast_goto_if_exists(), ast_log(), ast_readstring(), ast_streamfile(), ast_strlen_zero(), ast_variable_browse(), ast_channel::context, convert(), free, ast_channel::language, LOG_WARNING, ast_channel::macrocontext, ast_variable::name, name, ast_variable::next, NUMDIGITS, play_mailbox_owner(), strcasestr(), strdup, strsep(), and ast_variable::value.

Referenced by directory_exec().

00407 {
00408    /* Read in the first three digits..  "digit" is the first digit, already read */
00409    char ext[NUMDIGITS + 1];
00410    char name[80] = "";
00411    struct ast_variable *v;
00412    int res;
00413    int found=0;
00414    int lastuserchoice = 0;
00415    char *start, *pos, *conv,*stringp=NULL;
00416 
00417    if (ast_strlen_zero(context)) {
00418       ast_log(LOG_WARNING,
00419          "Directory must be called with an argument "
00420          "(context in which to interpret extensions)\n");
00421       return -1;
00422    }
00423    if (digit == '0') {
00424       if (!ast_goto_if_exists(chan, chan->context, "o", 1) ||
00425           (!ast_strlen_zero(chan->macrocontext) &&
00426            !ast_goto_if_exists(chan, chan->macrocontext, "o", 1))) {
00427          return 0;
00428       } else {
00429          ast_log(LOG_WARNING, "Can't find extension 'o' in current context.  "
00430             "Not Exiting the Directory!\n");
00431          res = 0;
00432       }
00433    }  
00434    if (digit == '*') {
00435       if (!ast_goto_if_exists(chan, chan->context, "a", 1) ||
00436           (!ast_strlen_zero(chan->macrocontext) &&
00437            !ast_goto_if_exists(chan, chan->macrocontext, "a", 1))) {
00438          return 0;
00439       } else {
00440          ast_log(LOG_WARNING, "Can't find extension 'a' in current context.  "
00441             "Not Exiting the Directory!\n");
00442          res = 0;
00443       }
00444    }  
00445    memset(ext, 0, sizeof(ext));
00446    ext[0] = digit;
00447    res = 0;
00448    if (ast_readstring(chan, ext + 1, NUMDIGITS - 1, 3000, 3000, "#") < 0) res = -1;
00449    if (!res) {
00450       /* Search for all names which start with those digits */
00451       v = ast_variable_browse(cfg, context);
00452       while(v && !res) {
00453          /* Find all candidate extensions */
00454          while(v) {
00455             /* Find a candidate extension */
00456             start = strdup(v->value);
00457             if (start && !strcasestr(start, "hidefromdir=yes")) {
00458                stringp=start;
00459                strsep(&stringp, ",");
00460                pos = strsep(&stringp, ",");
00461                if (pos) {
00462                   ast_copy_string(name, pos, sizeof(name));
00463                   /* Grab the last name */
00464                   if (last && strrchr(pos,' '))
00465                      pos = strrchr(pos, ' ') + 1;
00466                   conv = convert(pos);
00467                   if (conv) {
00468                      if (!strcmp(conv, ext)) {
00469                         /* Match! */
00470                         found++;
00471                         free(conv);
00472                         free(start);
00473                         break;
00474                      }
00475                      free(conv);
00476                   }
00477                }
00478                free(start);
00479             }
00480             v = v->next;
00481          }
00482 
00483          if (v) {
00484             /* We have a match -- play a greeting if they have it */
00485             res = play_mailbox_owner(chan, context, dialcontext, v->name, name);
00486             switch (res) {
00487                case -1:
00488                   /* user pressed '1' but extension does not exist, or
00489                    * user hungup
00490                    */
00491                   lastuserchoice = 0;
00492                   break;
00493                case '1':
00494                   /* user pressed '1' and extensions exists;
00495                      play_mailbox_owner will already have done
00496                      a goto() on the channel
00497                    */
00498                   lastuserchoice = res;
00499                   break;
00500                case '*':
00501                   /* user pressed '*' to skip something found */
00502                   lastuserchoice = res;
00503                   res = 0;
00504                   break;
00505                default:
00506                   break;
00507             }
00508             v = v->next;
00509          }
00510       }
00511 
00512       if (lastuserchoice != '1') {
00513          if (found) 
00514             res = ast_streamfile(chan, "dir-nomore", chan->language);
00515          else
00516             res = ast_streamfile(chan, "dir-nomatch", chan->language);
00517          if (!res)
00518             res = 1;
00519          return res;
00520       }
00521       return 0;
00522    }
00523    return res;
00524 }

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 647 of file app_directory.c.

References ASTERISK_GPL_KEY.

00648 {
00649    return ASTERISK_GPL_KEY;
00650 }

int load_module void   ) 
 

Initialize the module.

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.

Definition at line 611 of file app_directory.c.

References app, ast_config_destroy(), ast_config_load(), ast_log(), ast_register_application(), ast_variable_retrieve(), cfg, descrip, directory_exec(), LOG_WARNING, synopsis, vmfmts, and VOICEMAIL_CONFIG.

00612 {
00613 #ifdef USE_ODBC_STORAGE
00614    struct ast_config *cfg = ast_config_load(VOICEMAIL_CONFIG);
00615    char *tmp;
00616 
00617    if (cfg) {
00618       if ((tmp = ast_variable_retrieve(cfg, "general", "odbcstorage"))) {
00619          ast_copy_string(odbc_database, tmp, sizeof(odbc_database));
00620       }
00621       if ((tmp = ast_variable_retrieve(cfg, "general", "odbctable"))) {
00622          ast_copy_string(odbc_table, tmp, sizeof(odbc_table));
00623       }
00624       if ((tmp = ast_variable_retrieve(cfg, "general", "format"))) {
00625          ast_copy_string(vmfmts, tmp, sizeof(vmfmts));
00626       }
00627       ast_config_destroy(cfg);
00628    } else
00629       ast_log(LOG_WARNING, "Unable to load " VOICEMAIL_CONFIG " - ODBC defaults will be used\n");
00630 #endif
00631 
00632    return ast_register_application(app, directory_exec, synopsis, descrip);
00633 }

static int play_mailbox_owner struct ast_channel chan,
char *  context,
char *  dialcontext,
char *  ext,
char *  name
[static]
 

Definition at line 259 of file app_directory.c.

References ast_config_AST_SPOOL_DIR, AST_DIGIT_ANY, ast_filedelete(), ast_fileexists(), ast_goto_if_exists(), ast_log(), ast_say_character_str(), ast_stopstream(), ast_streamfile(), ast_strlen_zero(), ast_waitfordigit(), ast_waitstream(), ast_channel::language, and LOG_WARNING.

Referenced by do_directory().

00259                                                                                                                  {
00260    int res = 0;
00261    int loop = 3;
00262    char fn[256];
00263    char fn2[256];
00264 
00265    /* Check for the VoiceMail2 greeting first */
00266    snprintf(fn, sizeof(fn), "%s/voicemail/%s/%s/greet",
00267       (char *)ast_config_AST_SPOOL_DIR, context, ext);
00268 #ifdef USE_ODBC_STORAGE
00269    retrieve_file(fn);
00270 #endif
00271 
00272    /* Otherwise, check for an old-style Voicemail greeting */
00273    snprintf(fn2, sizeof(fn2), "%s/vm/%s/greet",
00274       (char *)ast_config_AST_SPOOL_DIR, ext);
00275 #ifdef USE_ODBC_STORAGE
00276    retrieve_file(fn2);
00277 #endif
00278 
00279    if (ast_fileexists(fn, NULL, chan->language) > 0) {
00280       res = ast_streamfile(chan, fn, chan->language);
00281       if (!res) {
00282          res = ast_waitstream(chan, AST_DIGIT_ANY);
00283       }
00284       ast_stopstream(chan);
00285    } else if (ast_fileexists(fn2, NULL, chan->language) > 0) {
00286       res = ast_streamfile(chan, fn2, chan->language);
00287       if (!res) {
00288          res = ast_waitstream(chan, AST_DIGIT_ANY);
00289       }
00290       ast_stopstream(chan);
00291    } else {
00292       res = ast_say_character_str(chan, !ast_strlen_zero(name) ? name : ext,
00293                AST_DIGIT_ANY, chan->language);
00294    }
00295 #ifdef USE_ODBC_STORAGE
00296    ast_filedelete(fn, NULL);  
00297    ast_filedelete(fn2, NULL); 
00298 #endif
00299 
00300    while (loop) {
00301       if (!res) {
00302          res = ast_streamfile(chan, "dir-instr", chan->language);
00303       }
00304       if (!res) {
00305          res = ast_waitstream(chan, AST_DIGIT_ANY);
00306       }
00307       if (!res) {
00308          res = ast_waitfordigit(chan, 3000);
00309       }
00310       ast_stopstream(chan);
00311    
00312       if (res > -1) {
00313          switch (res) {
00314             case '1':
00315                /* Name selected */
00316                loop = 0;
00317                if (ast_goto_if_exists(chan, dialcontext, ext, 1)) {
00318                   ast_log(LOG_WARNING,
00319                      "Can't find extension '%s' in context '%s'.  "
00320                      "Did you pass the wrong context to Directory?\n",
00321                      ext, dialcontext);
00322                   res = -1;
00323                }
00324                break;
00325    
00326             case '*':   
00327                /* Skip to next match in list */
00328                loop = 0;
00329                break;
00330    
00331             default:
00332                /* Not '1', or '*', so decrement number of tries */
00333                res = 0;
00334                loop--;
00335                break;
00336          } /* end switch */
00337       } /* end if */
00338       else {
00339          /* User hungup, so jump out now */
00340          loop = 0;
00341       }
00342    } /* end while */
00343 
00344    return(res);
00345 }

static struct ast_config* realtime_directory char *  context  )  [static]
 

Definition at line 347 of file app_directory.c.

References ast_category_append(), ast_category_browse(), ast_category_get(), ast_category_new(), ast_config_destroy(), ast_config_load(), ast_load_realtime_multientry(), ast_log(), ast_variable_append(), ast_variable_new(), ast_variable_retrieve(), cfg, LOG_WARNING, mailbox, var, and VOICEMAIL_CONFIG.

Referenced by directory_exec().

00348 {
00349    struct ast_config *cfg;
00350    struct ast_config *rtdata;
00351    struct ast_category *cat;
00352    struct ast_variable *var;
00353    char *mailbox;
00354    char *fullname;
00355    char *hidefromdir;
00356    char tmp[100];
00357 
00358    /* Load flat file config. */
00359    cfg = ast_config_load(VOICEMAIL_CONFIG);
00360 
00361    if (!cfg) {
00362       /* Loading config failed. */
00363       ast_log(LOG_WARNING, "Loading config failed.\n");
00364       return NULL;
00365    }
00366 
00367    /* Get realtime entries, categorized by their mailbox number
00368       and present in the requested context */
00369    rtdata = ast_load_realtime_multientry("voicemail", "mailbox LIKE", "%", "context", context, NULL);
00370 
00371    /* if there are no results, just return the entries from the config file */
00372    if (!rtdata)
00373       return cfg;
00374 
00375    /* Does the context exist within the config file? If not, make one */
00376    cat = ast_category_get(cfg, context);
00377    if (!cat) {
00378       cat = ast_category_new(context);
00379       if (!cat) {
00380          ast_log(LOG_WARNING, "Out of memory\n");
00381          ast_config_destroy(cfg);
00382          return NULL;
00383       }
00384       ast_category_append(cfg, cat);
00385    }
00386 
00387    mailbox = ast_category_browse(rtdata, NULL);
00388    while (mailbox) {
00389       fullname = ast_variable_retrieve(rtdata, mailbox, "fullname");
00390       hidefromdir = ast_variable_retrieve(rtdata, mailbox, "hidefromdir");
00391       snprintf(tmp, sizeof(tmp), "no-password,%s,hidefromdir=%s",
00392           fullname ? fullname : "",
00393           hidefromdir ? hidefromdir : "no");
00394       var = ast_variable_new(mailbox, tmp);
00395       if (var)
00396          ast_variable_append(cat, var);
00397       else
00398          ast_log(LOG_WARNING, "Out of memory adding mailbox '%s'\n", mailbox);
00399       mailbox = ast_category_browse(rtdata, mailbox);
00400    }
00401    ast_config_destroy(rtdata);
00402 
00403    return cfg;
00404 }

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 600 of file app_directory.c.

References app, ast_unregister_application(), and STANDARD_HANGUP_LOCALUSERS.

00601 {
00602    int res;
00603 
00604    res = ast_unregister_application(app);
00605 
00606    STANDARD_HANGUP_LOCALUSERS;
00607 
00608    return res;
00609 }

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 640 of file app_directory.c.

References STANDARD_USECOUNT.

00641 {
00642    int res;
00643    STANDARD_USECOUNT(res);
00644    return res;
00645 }


Variable Documentation

char* app = "Directory" [static]
 

Definition at line 56 of file app_directory.c.

char* descrip [static]
 

Definition at line 59 of file app_directory.c.

LOCAL_USER_DECL
 

Definition at line 88 of file app_directory.c.

STANDARD_LOCAL_USER
 

Definition at line 86 of file app_directory.c.

char* synopsis = "Provide directory of voicemail extensions" [static]
 

Definition at line 58 of file app_directory.c.

char* tdesc = "Extension Directory" [static]
 

Definition at line 55 of file app_directory.c.


Generated on Sun Aug 6 15:03:19 2006 for Asterisk - the Open Source PBX by  doxygen 1.4.2