Mon Mar 20 08:25:46 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"

Go to the source code of this file.

Defines

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

Functions

char * convert (char *lastname)
char * description (void)
 Provides a description of the module.
int directory_exec (struct ast_channel *chan, void *data)
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.
int play_mailbox_owner (struct ast_channel *chan, char *context, char *dialcontext, char *ext, char *name)
ast_configrealtime_directory (char *context)
int unload_module (void)
 Cleanup all module structures, sockets, etc.
int usecount (void)
 Provides a usecount.

Variables

char * app = "Directory"
char * descrip
 LOCAL_USER_DECL
 STANDARD_LOCAL_USER
char * synopsis = "Provide directory of voicemail extensions"
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 74 of file app_directory.c.

Referenced by convert(), and do_directory().

#define VOICEMAIL_CONFIG   "voicemail.conf"
 

Definition at line 71 of file app_directory.c.

Referenced by load_config(), and realtime_directory().


Function Documentation

char* convert char *  lastname  )  [static]
 

Definition at line 80 of file app_directory.c.

References malloc, and NUMDIGITS.

Referenced by do_directory().

00081 {
00082    char *tmp;
00083    int lcount = 0;
00084    tmp = malloc(NUMDIGITS + 1);
00085    if (tmp) {
00086       while((*lastname > 32) && lcount < NUMDIGITS) {
00087          switch(toupper(*lastname)) {
00088          case '1':
00089             tmp[lcount++] = '1';
00090             break;
00091          case '2':
00092          case 'A':
00093          case 'B':
00094          case 'C':
00095             tmp[lcount++] = '2';
00096             break;
00097          case '3':
00098          case 'D':
00099          case 'E':
00100          case 'F':
00101             tmp[lcount++] = '3';
00102             break;
00103          case '4':
00104          case 'G':
00105          case 'H':
00106          case 'I':
00107             tmp[lcount++] = '4';
00108             break;
00109          case '5':
00110          case 'J':
00111          case 'K':
00112          case 'L':
00113             tmp[lcount++] = '5';
00114             break;
00115          case '6':
00116          case 'M':
00117          case 'N':
00118          case 'O':
00119             tmp[lcount++] = '6';
00120             break;
00121          case '7':
00122          case 'P':
00123          case 'Q':
00124          case 'R':
00125          case 'S':
00126             tmp[lcount++] = '7';
00127             break;
00128          case '8':
00129          case 'T':
00130          case 'U':
00131          case 'V':
00132             tmp[lcount++] = '8';
00133             break;
00134          case '9':
00135          case 'W':
00136          case 'X':
00137          case 'Y':
00138          case 'Z':
00139             tmp[lcount++] = '9';
00140             break;
00141          }
00142          lastname++;
00143       }
00144       tmp[lcount] = '\0';
00145    }
00146    return tmp;
00147 }

char* description void   ) 
 

Provides a description of the module.

Returns:
a short description of your module

Definition at line 501 of file app_directory.c.

00502 {
00503    return tdesc;
00504 }

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

Definition at line 411 of file app_directory.c.

References ast_channel::_state, ast_answer(), ast_config_destroy(), AST_DIGIT_ANY, ast_log(), ast_stopstream(), ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_variable_retrieve(), ast_waitfordigit(), ast_waitstream(), cfg, do_directory(), ast_channel::language, LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_WARNING, and realtime_directory().

Referenced by load_module().

00412 {
00413    int res = 0;
00414    struct localuser *u;
00415    struct ast_config *cfg;
00416    int last = 1;
00417    char *context, *dialcontext, *dirintro, *options;
00418 
00419    if (ast_strlen_zero(data)) {
00420       ast_log(LOG_WARNING, "Directory requires an argument (context[,dialcontext])\n");
00421       return -1;
00422    }
00423 
00424    LOCAL_USER_ADD(u);
00425 
00426    context = ast_strdupa(data);
00427    dialcontext = strchr(context, '|');
00428    if (dialcontext) {
00429       *dialcontext = '\0';
00430       dialcontext++;
00431       options = strchr(dialcontext, '|');
00432       if (options) {
00433          *options = '\0';
00434          options++; 
00435          if (strchr(options, 'f'))
00436             last = 0;
00437       }
00438    } else   
00439       dialcontext = context;
00440 
00441    cfg = realtime_directory(context);
00442    if (!cfg) {
00443       LOCAL_USER_REMOVE(u);
00444       return -1;
00445    }
00446 
00447    dirintro = ast_variable_retrieve(cfg, context, "directoryintro");
00448    if (ast_strlen_zero(dirintro))
00449       dirintro = ast_variable_retrieve(cfg, "general", "directoryintro");
00450    if (ast_strlen_zero(dirintro)) {
00451       if (last)
00452          dirintro = "dir-intro"; 
00453       else
00454          dirintro = "dir-intro-fn";
00455    }
00456 
00457    if (chan->_state != AST_STATE_UP) 
00458       res = ast_answer(chan);
00459 
00460    for (;;) {
00461       if (!res)
00462          res = ast_streamfile(chan, dirintro, chan->language);
00463       if (!res)
00464          res = ast_waitstream(chan, AST_DIGIT_ANY);
00465       ast_stopstream(chan);
00466       if (!res)
00467          res = ast_waitfordigit(chan, 5000);
00468       if (res > 0) {
00469          res = do_directory(chan, cfg, context, dialcontext, res, last);
00470          if (res > 0) {
00471             res = ast_waitstream(chan, AST_DIGIT_ANY);
00472             ast_stopstream(chan);
00473             if (res >= 0) {
00474                continue;
00475             }
00476          }
00477       }
00478       break;
00479    }
00480    ast_config_destroy(cfg);
00481    LOCAL_USER_REMOVE(u);
00482    return res;
00483 }

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

Definition at line 291 of file app_directory.c.

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

00292 {
00293    /* Read in the first three digits..  "digit" is the first digit, already read */
00294    char ext[NUMDIGITS + 1];
00295    char name[80] = "";
00296    struct ast_variable *v;
00297    int res;
00298    int found=0;
00299    int lastuserchoice = 0;
00300    char *start, *pos, *conv,*stringp=NULL;
00301 
00302    if (ast_strlen_zero(context)) {
00303       ast_log(LOG_WARNING,
00304          "Directory must be called with an argument "
00305          "(context in which to interpret extensions)\n");
00306       return -1;
00307    }
00308    if (digit == '0') {
00309       if (!ast_goto_if_exists(chan, chan->context, "o", 1) ||
00310           (!ast_strlen_zero(chan->macrocontext) &&
00311            !ast_goto_if_exists(chan, chan->macrocontext, "o", 1))) {
00312          return 0;
00313       } else {
00314          ast_log(LOG_WARNING, "Can't find extension 'o' in current context.  "
00315             "Not Exiting the Directory!\n");
00316          res = 0;
00317       }
00318    }  
00319    if (digit == '*') {
00320       if (!ast_goto_if_exists(chan, chan->context, "a", 1) ||
00321           (!ast_strlen_zero(chan->macrocontext) &&
00322            !ast_goto_if_exists(chan, chan->macrocontext, "a", 1))) {
00323          return 0;
00324       } else {
00325          ast_log(LOG_WARNING, "Can't find extension 'a' in current context.  "
00326             "Not Exiting the Directory!\n");
00327          res = 0;
00328       }
00329    }  
00330    memset(ext, 0, sizeof(ext));
00331    ext[0] = digit;
00332    res = 0;
00333    if (ast_readstring(chan, ext + 1, NUMDIGITS - 1, 3000, 3000, "#") < 0) res = -1;
00334    if (!res) {
00335       /* Search for all names which start with those digits */
00336       v = ast_variable_browse(cfg, context);
00337       while(v && !res) {
00338          /* Find all candidate extensions */
00339          while(v) {
00340             /* Find a candidate extension */
00341             start = strdup(v->value);
00342             if (start && !strcasestr(start, "hidefromdir=yes")) {
00343                stringp=start;
00344                strsep(&stringp, ",");
00345                pos = strsep(&stringp, ",");
00346                if (pos) {
00347                   ast_copy_string(name, pos, sizeof(name));
00348                   /* Grab the last name */
00349                   if (last && strrchr(pos,' '))
00350                      pos = strrchr(pos, ' ') + 1;
00351                   conv = convert(pos);
00352                   if (conv) {
00353                      if (!strcmp(conv, ext)) {
00354                         /* Match! */
00355                         found++;
00356                         free(conv);
00357                         free(start);
00358                         break;
00359                      }
00360                      free(conv);
00361                   }
00362                }
00363                free(start);
00364             }
00365             v = v->next;
00366          }
00367 
00368          if (v) {
00369             /* We have a match -- play a greeting if they have it */
00370             res = play_mailbox_owner(chan, context, dialcontext, v->name, name);
00371             switch (res) {
00372                case -1:
00373                   /* user pressed '1' but extension does not exist, or
00374                    * user hungup
00375                    */
00376                   lastuserchoice = 0;
00377                   break;
00378                case '1':
00379                   /* user pressed '1' and extensions exists;
00380                      play_mailbox_owner will already have done
00381                      a goto() on the channel
00382                    */
00383                   lastuserchoice = res;
00384                   break;
00385                case '*':
00386                   /* user pressed '*' to skip something found */
00387                   lastuserchoice = res;
00388                   res = 0;
00389                   break;
00390                default:
00391                   break;
00392             }
00393             v = v->next;
00394          }
00395       }
00396 
00397       if (lastuserchoice != '1') {
00398          if (found) 
00399             res = ast_streamfile(chan, "dir-nomore", chan->language);
00400          else
00401             res = ast_streamfile(chan, "dir-nomatch", chan->language);
00402          if (!res)
00403             res = 1;
00404          return res;
00405       }
00406       return 0;
00407    }
00408    return res;
00409 }

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

00514 {
00515    return ASTERISK_GPL_KEY;
00516 }

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

References app, ast_register_application(), descrip, directory_exec(), and synopsis.

00497 {
00498    return ast_register_application(app, directory_exec, synopsis, descrip);
00499 }

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

Definition at line 154 of file app_directory.c.

References ast_config_AST_SPOOL_DIR, AST_DIGIT_ANY, 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, LOG_WARNING, and name.

Referenced by do_directory().

00154                                                                                                                  {
00155    int res = 0;
00156    int loop = 3;
00157    char fn[256];
00158    char fn2[256];
00159 
00160    /* Check for the VoiceMail2 greeting first */
00161    snprintf(fn, sizeof(fn), "%s/voicemail/%s/%s/greet",
00162       (char *)ast_config_AST_SPOOL_DIR, context, ext);
00163 
00164    /* Otherwise, check for an old-style Voicemail greeting */
00165    snprintf(fn2, sizeof(fn2), "%s/vm/%s/greet",
00166       (char *)ast_config_AST_SPOOL_DIR, ext);
00167 
00168    if (ast_fileexists(fn, NULL, chan->language) > 0) {
00169       res = ast_streamfile(chan, fn, chan->language);
00170       if (!res) {
00171          res = ast_waitstream(chan, AST_DIGIT_ANY);
00172       }
00173       ast_stopstream(chan);
00174    } else if (ast_fileexists(fn2, NULL, chan->language) > 0) {
00175       res = ast_streamfile(chan, fn2, chan->language);
00176       if (!res) {
00177          res = ast_waitstream(chan, AST_DIGIT_ANY);
00178       }
00179       ast_stopstream(chan);
00180    } else {
00181       res = ast_say_character_str(chan, !ast_strlen_zero(name) ? name : ext,
00182                AST_DIGIT_ANY, chan->language);
00183    }
00184 
00185    while (loop) {
00186       if (!res) {
00187          res = ast_streamfile(chan, "dir-instr", chan->language);
00188       }
00189       if (!res) {
00190          res = ast_waitstream(chan, AST_DIGIT_ANY);
00191       }
00192       if (!res) {
00193          res = ast_waitfordigit(chan, 3000);
00194       }
00195       ast_stopstream(chan);
00196    
00197       if (res > -1) {
00198          switch (res) {
00199             case '1':
00200                /* Name selected */
00201                loop = 0;
00202                if (ast_goto_if_exists(chan, dialcontext, ext, 1)) {
00203                   ast_log(LOG_WARNING,
00204                      "Can't find extension '%s' in context '%s'.  "
00205                      "Did you pass the wrong context to Directory?\n",
00206                      ext, dialcontext);
00207                   res = -1;
00208                }
00209                break;
00210    
00211             case '*':   
00212                /* Skip to next match in list */
00213                loop = 0;
00214                break;
00215    
00216             default:
00217                /* Not '1', or '*', so decrement number of tries */
00218                res = 0;
00219                loop--;
00220                break;
00221          } /* end switch */
00222       } /* end if */
00223       else {
00224          /* User hungup, so jump out now */
00225          loop = 0;
00226       }
00227    } /* end while */
00228 
00229    return(res);
00230 }

struct ast_config* realtime_directory char *  context  )  [static]
 

Definition at line 232 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, var, and VOICEMAIL_CONFIG.

Referenced by directory_exec().

00233 {
00234    struct ast_config *cfg;
00235    struct ast_config *rtdata;
00236    struct ast_category *cat;
00237    struct ast_variable *var;
00238    char *mailbox;
00239    char *fullname;
00240    char *hidefromdir;
00241    char tmp[100];
00242 
00243    /* Load flat file config. */
00244    cfg = ast_config_load(VOICEMAIL_CONFIG);
00245 
00246    if (!cfg) {
00247       /* Loading config failed. */
00248       ast_log(LOG_WARNING, "Loading config failed.\n");
00249       return NULL;
00250    }
00251 
00252    /* Get realtime entries, categorized by their mailbox number
00253       and present in the requested context */
00254    rtdata = ast_load_realtime_multientry("voicemail", "mailbox LIKE", "%", "context", context, NULL);
00255 
00256    /* if there are no results, just return the entries from the config file */
00257    if (!rtdata)
00258       return cfg;
00259 
00260    /* Does the context exist within the config file? If not, make one */
00261    cat = ast_category_get(cfg, context);
00262    if (!cat) {
00263       cat = ast_category_new(context);
00264       if (!cat) {
00265          ast_log(LOG_WARNING, "Out of memory\n");
00266          ast_config_destroy(cfg);
00267          return NULL;
00268       }
00269       ast_category_append(cfg, cat);
00270    }
00271 
00272    mailbox = ast_category_browse(rtdata, NULL);
00273    while (mailbox) {
00274       fullname = ast_variable_retrieve(rtdata, mailbox, "fullname");
00275       hidefromdir = ast_variable_retrieve(rtdata, mailbox, "hidefromdir");
00276       snprintf(tmp, sizeof(tmp), "no-password,%s,hidefromdir=%s",
00277           fullname ? fullname : "",
00278           hidefromdir ? hidefromdir : "no");
00279       var = ast_variable_new(mailbox, tmp);
00280       if (var)
00281          ast_variable_append(cat, var);
00282       else
00283          ast_log(LOG_WARNING, "Out of memory adding mailbox '%s'\n", mailbox);
00284       mailbox = ast_category_browse(rtdata, mailbox);
00285    }
00286    ast_config_destroy(rtdata);
00287 
00288    return cfg;
00289 }

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

References app, and ast_unregister_application().

00486 {
00487    int res;
00488 
00489    res = ast_unregister_application(app);
00490 
00491    STANDARD_HANGUP_LOCALUSERS;
00492 
00493    return res;
00494 }

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

References STANDARD_USECOUNT.

00507 {
00508    int res;
00509    STANDARD_USECOUNT(res);
00510    return res;
00511 }


Variable Documentation

char* app = "Directory" [static]
 

Definition at line 46 of file app_directory.c.

Referenced by load_module(), and unload_module().

char* descrip [static]
 

Definition at line 49 of file app_directory.c.

Referenced by load_module().

LOCAL_USER_DECL
 

Definition at line 78 of file app_directory.c.

STANDARD_LOCAL_USER
 

Definition at line 76 of file app_directory.c.

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

Definition at line 48 of file app_directory.c.

Referenced by load_module().

char* tdesc = "Extension Directory" [static]
 

Definition at line 45 of file app_directory.c.


Generated on Mon Mar 20 08:25:46 2006 for Asterisk - the Open Source PBX by  doxygen 1.3.9.1