Wed Oct 28 15:48:02 2009

Asterisk developer's documentation


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, int fromappvm)
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, int fromappvm)
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 643 of file app_directory.c.

00644 {
00645    return tdesc;
00646 }

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

Definition at line 531 of file app_directory.c.

References ast_channel::_state, 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(), ast_channel::language, last, LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_WARNING, and realtime_directory().

Referenced by load_module().

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

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

Definition at line 411 of file app_directory.c.

References ast_goto_if_exists(), ast_log(), ast_readstring(), ast_streamfile(), ast_strlen_zero(), ast_variable_browse(), 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().

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

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

References ASTERISK_GPL_KEY.

00656 {
00657    return ASTERISK_GPL_KEY;
00658 }

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

References ast_config_destroy(), ast_config_load(), ast_log(), ast_register_application(), ast_variable_retrieve(), cfg, directory_exec(), LOG_WARNING, and VOICEMAIL_CONFIG.

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

static int play_mailbox_owner ( struct ast_channel chan,
char *  context,
char *  dialcontext,
char *  ext,
char *  name,
int  fromappvm 
) [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::exten, 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 (fromappvm) {
00318                   /* We still want to set the exten */
00319                   ast_copy_string(chan->exten, ext, sizeof(chan->exten));
00320                } else {
00321                   if (ast_goto_if_exists(chan, dialcontext, ext, 1)) {
00322                      ast_log(LOG_WARNING,
00323                         "Can't find extension '%s' in context '%s'.  "
00324                         "Did you pass the wrong context to Directory?\n",
00325                         ext, dialcontext);
00326                      res = -1;
00327                   }
00328                }
00329                break;
00330    
00331             case '*':   
00332                /* Skip to next match in list */
00333                loop = 0;
00334                break;
00335    
00336             default:
00337                /* Not '1', or '*', so decrement number of tries */
00338                res = 0;
00339                loop--;
00340                break;
00341          } /* end switch */
00342       } /* end if */
00343       else {
00344          /* User hungup, so jump out now */
00345          loop = 0;
00346       }
00347    } /* end while */
00348 
00349    return(res);
00350 }

static struct ast_config* realtime_directory ( char *  context  )  [static, read]

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

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

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

References ast_unregister_application(), and STANDARD_HANGUP_LOCALUSERS.

00609 {
00610    int res;
00611 
00612    res = ast_unregister_application(app);
00613 
00614    STANDARD_HANGUP_LOCALUSERS;
00615 
00616    return res;
00617 }

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

References STANDARD_USECOUNT.

00649 {
00650    int res;
00651    STANDARD_USECOUNT(res);
00652    return res;
00653 }


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.

Definition at line 88 of file app_directory.c.

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 Wed Oct 28 15:48:03 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6