Wed Aug 18 22:33:58 2010

Asterisk developer's documentation


app_directory.c File Reference

Provide a directory of extensions. More...

#include "asterisk.h"
#include <ctype.h>
#include "asterisk/paths.h"
#include "asterisk/file.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/say.h"
#include "asterisk/app.h"
#include "asterisk/utils.h"

Go to the source code of this file.

Data Structures

struct  directory_item
struct  itemlist

Defines

#define VOICEMAIL_CONFIG   "voicemail.conf"

Enumerations

enum  {
  OPT_LISTBYFIRSTNAME = (1 << 0), OPT_SAYEXTENSION = (1 << 1), OPT_FROMVOICEMAIL = (1 << 2), OPT_SELECTFROMMENU = (1 << 3),
  OPT_LISTBYLASTNAME = (1 << 4), OPT_LISTBYEITHER = OPT_LISTBYFIRSTNAME | OPT_LISTBYLASTNAME, OPT_PAUSE = (1 << 5)
}
enum  {
  OPT_ARG_FIRSTNAME = 0, OPT_ARG_LASTNAME = 1, OPT_ARG_EITHER = 2, OPT_ARG_PAUSE = 3,
  OPT_ARG_ARRAY_SIZE = 4
}

Functions

static void __reg_module (void)
static void __unreg_module (void)
static int check_match (struct directory_item **result, const char *item_fullname, const char *item_ext, const char *pattern_ext, int use_first_name)
static int compare (const char *text, const char *template)
static int directory_exec (struct ast_channel *chan, void *data)
static int do_directory (struct ast_channel *chan, struct ast_config *vmcfg, struct ast_config *ucfg, char *context, char *dialcontext, char digit, int digits, struct ast_flags *flags, char *opts[])
static int goto_exten (struct ast_channel *chan, const char *dialcontext, char *ext)
static int load_module (void)
static int play_mailbox_owner (struct ast_channel *chan, const char *context, const char *ext, const char *name, struct ast_flags *flags)
static struct ast_configrealtime_directory (char *context)
static int search_directory (const char *context, struct ast_config *vmcfg, struct ast_config *ucfg, const char *ext, struct ast_flags flags, itemlist *alist)
static int select_entry (struct ast_channel *chan, const char *context, const char *dialcontext, const struct directory_item *item, struct ast_flags *flags)
static int select_item_menu (struct ast_channel *chan, struct directory_item **items, int count, const char *context, const char *dialcontext, struct ast_flags *flags, char *opts[])
static int select_item_pause (struct ast_channel *chan, struct ast_flags *flags, char *opts[])
static int select_item_seq (struct ast_channel *chan, struct directory_item **items, int count, const char *context, const char *dialcontext, struct ast_flags *flags, char *opts[])
static void sort_items (struct directory_item **sorted, int count)
static int unload_module (void)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Extension Directory" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, }
static char * app = "Directory"
static struct ast_module_infoast_module_info = &__mod_info
static char * descrip
static struct ast_app_option directory_app_options [128] = { [ 'f' ] = { .flag = OPT_LISTBYFIRSTNAME , .arg_index = OPT_ARG_FIRSTNAME + 1 }, [ 'l' ] = { .flag = OPT_LISTBYLASTNAME , .arg_index = OPT_ARG_LASTNAME + 1 }, [ 'b' ] = { .flag = OPT_LISTBYEITHER , .arg_index = OPT_ARG_EITHER + 1 }, [ 'p' ] = { .flag = OPT_PAUSE , .arg_index = OPT_ARG_PAUSE + 1 }, [ 'e' ] = { .flag = OPT_SAYEXTENSION }, [ 'v' ] = { .flag = OPT_FROMVOICEMAIL }, [ 'm' ] = { .flag = OPT_SELECTFROMMENU },}
enum { ... }  directory_option_flags
static char * synopsis = "Provide directory of voicemail extensions"


Detailed Description

Provide a directory of extensions.

Author:
Mark Spencer <markster@digium.com>

Definition in file app_directory.c.


Define Documentation

#define VOICEMAIL_CONFIG   "voicemail.conf"

Definition at line 91 of file app_directory.c.

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


Enumeration Type Documentation

anonymous enum

Enumerator:
OPT_LISTBYFIRSTNAME 
OPT_SAYEXTENSION 
OPT_FROMVOICEMAIL 
OPT_SELECTFROMMENU 
OPT_LISTBYLASTNAME 
OPT_LISTBYEITHER 
OPT_PAUSE 

Definition at line 93 of file app_directory.c.

00093      {
00094    OPT_LISTBYFIRSTNAME = (1 << 0),
00095    OPT_SAYEXTENSION =    (1 << 1),
00096    OPT_FROMVOICEMAIL =   (1 << 2),
00097    OPT_SELECTFROMMENU =  (1 << 3),
00098    OPT_LISTBYLASTNAME =  (1 << 4),
00099    OPT_LISTBYEITHER =    OPT_LISTBYFIRSTNAME | OPT_LISTBYLASTNAME,
00100    OPT_PAUSE =           (1 << 5),
00101 } directory_option_flags;

anonymous enum

Enumerator:
OPT_ARG_FIRSTNAME 
OPT_ARG_LASTNAME 
OPT_ARG_EITHER 
OPT_ARG_PAUSE 
OPT_ARG_ARRAY_SIZE 

Definition at line 103 of file app_directory.c.

00103      {
00104    OPT_ARG_FIRSTNAME =   0,
00105    OPT_ARG_LASTNAME =    1,
00106    OPT_ARG_EITHER =      2,
00107    OPT_ARG_PAUSE =       3,
00108    /* This *must* be the last value in this enum! */
00109    OPT_ARG_ARRAY_SIZE =  4,
00110 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 807 of file app_directory.c.

static void __unreg_module ( void   )  [static]

Definition at line 807 of file app_directory.c.

static int check_match ( struct directory_item **  result,
const char *  item_fullname,
const char *  item_ext,
const char *  pattern_ext,
int  use_first_name 
) [static]

Definition at line 437 of file app_directory.c.

References ast_calloc, ast_copy_string(), compare(), and directory_item::key.

Referenced by search_directory().

00438 {
00439    struct directory_item *item;
00440    const char *key = NULL;
00441    int namelen;
00442 
00443 
00444    /* Set key to last name or first name depending on search mode */
00445    if (!use_first_name)
00446       key = strchr(item_fullname, ' ');
00447 
00448    if (key)
00449       key++;
00450    else
00451       key = item_fullname;
00452 
00453    if (compare(key, pattern_ext))
00454       return 0;
00455 
00456    /* Match */
00457    item = ast_calloc(1, sizeof(*item));
00458    if (!item)
00459       return -1;
00460    ast_copy_string(item->name, item_fullname, sizeof(item->name));
00461    ast_copy_string(item->exten, item_ext, sizeof(item->exten));
00462 
00463    ast_copy_string(item->key, key, sizeof(item->key));
00464    if (key != item_fullname) {
00465       /* Key is the last name. Append first name to key in order to sort Last,First */
00466       namelen = key - item_fullname - 1;
00467       if (namelen > sizeof(item->key) - strlen(item->key) - 1)
00468          namelen = sizeof(item->key) - strlen(item->key) - 1;
00469       strncat(item->key, item_fullname, namelen);
00470    }
00471 
00472    *result = item;
00473    return 1;
00474 }

static int compare ( const char *  text,
const char *  template 
) [static]

Definition at line 130 of file app_directory.c.

References ast_strlen_zero().

Referenced by ast_hashtab_create(), and check_match().

00131 {
00132    char digit;
00133 
00134    if (ast_strlen_zero(text)) {
00135       return -1;
00136    }
00137 
00138    while (*template) {
00139       digit = toupper(*text++);
00140       switch (digit) {
00141       case 0:
00142          return -1;
00143       case '1':
00144          digit = '1';
00145          break;
00146       case '2':
00147       case 'A':
00148       case 'B':
00149       case 'C':
00150          digit = '2';
00151          break;
00152       case '3':
00153       case 'D':
00154       case 'E':
00155       case 'F':
00156          digit = '3';
00157          break;
00158       case '4':
00159       case 'G':
00160       case 'H':
00161       case 'I':
00162          digit = '4';
00163          break;
00164       case '5':
00165       case 'J':
00166       case 'K':
00167       case 'L':
00168          digit = '5';
00169          break;
00170       case '6':
00171       case 'M':
00172       case 'N':
00173       case 'O':
00174          digit = '6';
00175          break;
00176       case '7':
00177       case 'P':
00178       case 'Q':
00179       case 'R':
00180       case 'S':
00181          digit = '7';
00182          break;
00183       case '8':
00184       case 'T':
00185       case 'U':
00186       case 'V':
00187          digit = '8';
00188          break;
00189       case '9':
00190       case 'W':
00191       case 'X':
00192       case 'Y':
00193       case 'Z':
00194          digit = '9';
00195          break;
00196 
00197       default:
00198          if (digit > ' ')
00199             return -1;
00200          continue;
00201       }
00202 
00203       if (*template++ != digit)
00204          return -1;
00205    }
00206 
00207    return 0;
00208 }

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

Definition at line 672 of file app_directory.c.

References ast_channel::_state, ast_answer(), AST_APP_ARG, ast_app_parse_options(), ast_config_destroy(), ast_config_load, AST_DECLARE_APP_ARGS, AST_DIGIT_ANY, ast_log(), ast_set_flag, AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_stopstream(), ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_test_flag, ast_variable_retrieve(), ast_waitfordigit(), ast_waitstream(), chan, config_flags, dialcontext, directory_app_options, do_directory(), ast_flags::flags, LOG_ERROR, LOG_WARNING, OPT_ARG_ARRAY_SIZE, OPT_ARG_EITHER, OPT_ARG_FIRSTNAME, OPT_ARG_LASTNAME, OPT_LISTBYFIRSTNAME, OPT_LISTBYLASTNAME, parse(), and realtime_directory().

Referenced by load_module().

00673 {
00674    int res = 0, digit = 3;
00675    struct ast_config *cfg, *ucfg;
00676    const char *dirintro;
00677    char *parse, *opts[OPT_ARG_ARRAY_SIZE] = { "", };
00678    struct ast_flags flags = { 0 };
00679    struct ast_flags config_flags = { 0 };
00680    enum { FIRST, LAST, BOTH } which = LAST;
00681    char digits[9] = "digits/3";
00682    AST_DECLARE_APP_ARGS(args,
00683       AST_APP_ARG(vmcontext);
00684       AST_APP_ARG(dialcontext);
00685       AST_APP_ARG(options);
00686    );
00687 
00688    if (ast_strlen_zero(data)) {
00689       ast_log(LOG_WARNING, "Directory requires an argument (context[,dialcontext])\n");
00690       return -1;
00691    }
00692 
00693    parse = ast_strdupa(data);
00694 
00695    AST_STANDARD_APP_ARGS(args, parse);
00696 
00697    if (args.options && ast_app_parse_options(directory_app_options, &flags, opts, args.options))
00698       return -1;
00699 
00700    if (ast_strlen_zero(args.dialcontext))
00701       args.dialcontext = args.vmcontext;
00702 
00703    cfg = realtime_directory(args.vmcontext);
00704    if (!cfg) {
00705       ast_log(LOG_ERROR, "Unable to read the configuration data!\n");
00706       return -1;
00707    }
00708 
00709    ucfg = ast_config_load("users.conf", config_flags);
00710 
00711    dirintro = ast_variable_retrieve(cfg, args.vmcontext, "directoryintro");
00712    if (ast_strlen_zero(dirintro))
00713       dirintro = ast_variable_retrieve(cfg, "general", "directoryintro");
00714 
00715    if (ast_test_flag(&flags, OPT_LISTBYFIRSTNAME) && ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
00716       if (!ast_strlen_zero(opts[OPT_ARG_EITHER])) {
00717          digit = atoi(opts[OPT_ARG_EITHER]);
00718       }
00719       which = BOTH;
00720    } else if (ast_test_flag(&flags, OPT_LISTBYFIRSTNAME)) {
00721       if (!ast_strlen_zero(opts[OPT_ARG_FIRSTNAME])) {
00722          digit = atoi(opts[OPT_ARG_FIRSTNAME]);
00723       }
00724       which = FIRST;
00725    } else {
00726       if (!ast_strlen_zero(opts[OPT_ARG_LASTNAME])) {
00727          digit = atoi(opts[OPT_ARG_LASTNAME]);
00728       }
00729       which = LAST;
00730    }
00731 
00732    /* If no options specified, search by last name */
00733    if (!ast_test_flag(&flags, OPT_LISTBYFIRSTNAME) && !ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
00734       ast_set_flag(&flags, OPT_LISTBYLASTNAME);
00735       which = LAST;
00736    }
00737 
00738    if (digit > 9) {
00739       digit = 9;
00740    } else if (digit < 1) {
00741       digit = 3;
00742    }
00743    digits[7] = digit + '0';
00744 
00745    if (chan->_state != AST_STATE_UP)
00746       res = ast_answer(chan);
00747 
00748    for (;;) {
00749       if (!ast_strlen_zero(dirintro) && !res) {
00750          res = ast_stream_and_wait(chan, dirintro, AST_DIGIT_ANY);
00751       } else if (!res) {
00752          /* Stop playing sounds as soon as we have a digit. */
00753          res = ast_stream_and_wait(chan, "dir-welcome", AST_DIGIT_ANY);
00754          if (!res) {
00755             res = ast_stream_and_wait(chan, "dir-pls-enter", AST_DIGIT_ANY);
00756          }
00757          if (!res) {
00758             res = ast_stream_and_wait(chan, digits, AST_DIGIT_ANY);
00759          }
00760          if (!res) {
00761             res = ast_stream_and_wait(chan, 
00762                which == FIRST ? "dir-first" :
00763                which == LAST ? "dir-last" :
00764                "dir-firstlast", AST_DIGIT_ANY);
00765          }
00766          if (!res) {
00767             res = ast_stream_and_wait(chan, "dir-usingkeypad", AST_DIGIT_ANY);
00768          }
00769       }
00770       ast_stopstream(chan);
00771       if (!res)
00772          res = ast_waitfordigit(chan, 5000);
00773 
00774       if (res <= 0)
00775          break;
00776 
00777       res = do_directory(chan, cfg, ucfg, args.vmcontext, args.dialcontext, res, digit, &flags, opts);
00778       if (res)
00779          break;
00780 
00781       res = ast_waitstream(chan, AST_DIGIT_ANY);
00782       ast_stopstream(chan);
00783 
00784       if (res)
00785          break;
00786    }
00787 
00788    if (ucfg)
00789       ast_config_destroy(ucfg);
00790    ast_config_destroy(cfg);
00791 
00792    return res < 0 ? -1 : 0;
00793 }

static int do_directory ( struct ast_channel chan,
struct ast_config vmcfg,
struct ast_config ucfg,
char *  context,
char *  dialcontext,
char  digit,
int  digits,
struct ast_flags flags,
char *  opts[] 
) [static]

Definition at line 588 of file app_directory.c.

References ast_calloc, ast_debug, ast_free, AST_LIST_HEAD_NOLOCK_INIT_VALUE, AST_LIST_REMOVE_HEAD, AST_LIST_TRAVERSE, ast_log(), ast_readstring(), ast_streamfile(), ast_strlen_zero(), ast_test_flag, chan, directory_item::entry, ext, directory_item::exten, goto_exten(), ast_channel::language, LOG_DEBUG, LOG_WARNING, directory_item::name, OPT_SELECTFROMMENU, option_debug, search_directory(), select_item_menu(), select_item_seq(), and sort_items().

Referenced by directory_exec().

00589 {
00590    /* Read in the first three digits..  "digit" is the first digit, already read */
00591    int res = 0;
00592    itemlist alist = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
00593    struct directory_item *item, **ptr, **sorted = NULL;
00594    int count, i;
00595    char ext[10] = "";
00596 
00597    if (ast_strlen_zero(context)) {
00598       ast_log(LOG_WARNING,
00599          "Directory must be called with an argument "
00600          "(context in which to interpret extensions)\n");
00601       return -1;
00602    }
00603 
00604    if (digit == '0' && !goto_exten(chan, dialcontext, "o")) {
00605       return digit;
00606    }
00607 
00608    if (digit == '*' && !goto_exten(chan, dialcontext, "a")) {
00609       return digit;
00610    }
00611 
00612    ext[0] = digit;
00613    if (ast_readstring(chan, ext + 1, digits - 1, 3000, 3000, "#") < 0)
00614       return -1;
00615 
00616    res = search_directory(context, vmcfg, ucfg, ext, *flags, &alist);
00617    if (res)
00618       goto exit;
00619 
00620    /* Count items in the list */
00621    count = 0;
00622    AST_LIST_TRAVERSE(&alist, item, entry) {
00623       count++;
00624    }
00625 
00626    if (count < 1) {
00627       res = ast_streamfile(chan, "dir-nomatch", chan->language);
00628       goto exit;
00629    }
00630 
00631 
00632    /* Create plain array of pointers to items (for sorting) */
00633    sorted = ast_calloc(count, sizeof(*sorted));
00634 
00635    ptr = sorted;
00636    AST_LIST_TRAVERSE(&alist, item, entry) {
00637       *ptr++ = item;
00638    }
00639 
00640    /* Sort items */
00641    sort_items(sorted, count);
00642 
00643    if (option_debug) {
00644       ast_debug(2, "Listing matching entries:\n");
00645       for (ptr = sorted, i = 0; i < count; i++, ptr++) {
00646          ast_log(LOG_DEBUG, "%s: %s\n", ptr[0]->exten, ptr[0]->name);
00647       }
00648    }
00649 
00650    if (ast_test_flag(flags, OPT_SELECTFROMMENU)) {
00651       /* Offer multiple entries at the same time */
00652       res = select_item_menu(chan, sorted, count, context, dialcontext, flags, opts);
00653    } else {
00654       /* Offer entries one by one */
00655       res = select_item_seq(chan, sorted, count, context, dialcontext, flags, opts);
00656    }
00657 
00658    if (!res) {
00659       res = ast_streamfile(chan, "dir-nomore", chan->language);
00660    }
00661 
00662 exit:
00663    if (sorted)
00664       ast_free(sorted);
00665 
00666    while ((item = AST_LIST_REMOVE_HEAD(&alist, entry)))
00667       ast_free(item);
00668 
00669    return res;
00670 }

static int goto_exten ( struct ast_channel chan,
const char *  dialcontext,
char *  ext 
) [static]

Definition at line 575 of file app_directory.c.

References ast_goto_if_exists(), ast_log(), ast_strlen_zero(), chan, LOG_WARNING, and ast_channel::macrocontext.

Referenced by do_directory().

00576 {
00577    if (!ast_goto_if_exists(chan, dialcontext, ext, 1) ||
00578       (!ast_strlen_zero(chan->macrocontext) &&
00579       !ast_goto_if_exists(chan, chan->macrocontext, ext, 1))) {
00580       return 0;
00581    } else {
00582       ast_log(LOG_WARNING, "Can't find extension '%s' in current context.  "
00583          "Not Exiting the Directory!\n", ext);
00584       return -1;
00585    }
00586 }

static int load_module ( void   )  [static]

Definition at line 802 of file app_directory.c.

References ast_register_application, and directory_exec().

00803 {
00804    return ast_register_application(app, directory_exec, synopsis, descrip);
00805 }

static int play_mailbox_owner ( struct ast_channel chan,
const char *  context,
const char *  ext,
const char *  name,
struct ast_flags flags 
) [static]

Definition at line 215 of file app_directory.c.

References ast_app_sayname(), AST_DIGIT_ANY, ast_say_character_str(), ast_stopstream(), ast_stream_and_wait(), ast_strlen_zero(), ast_test_flag, chan, ast_channel::language, OPT_SAYEXTENSION, and S_OR.

Referenced by select_item_menu(), and select_item_seq().

00217 {
00218    int res = 0;
00219    if ((res = ast_app_sayname(chan, ext, context)) >= 0) {
00220       ast_stopstream(chan);
00221       /* If Option 'e' was specified, also read the extension number with the name */
00222       if (ast_test_flag(flags, OPT_SAYEXTENSION)) {
00223          ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
00224          res = ast_say_character_str(chan, ext, AST_DIGIT_ANY, chan->language);
00225       }
00226    } else {
00227       res = ast_say_character_str(chan, S_OR(name, ext), AST_DIGIT_ANY, chan->language);
00228       if (!ast_strlen_zero(name) && ast_test_flag(flags, OPT_SAYEXTENSION)) {
00229          ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
00230          res = ast_say_character_str(chan, ext, AST_DIGIT_ANY, chan->language);
00231       }
00232    }
00233 
00234    return res;
00235 }

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

Definition at line 374 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_true(), ast_variable_append(), ast_variable_new(), ast_variable_retrieve(), config_flags, LOG_WARNING, mailbox, S_OR, SENTINEL, var, and VOICEMAIL_CONFIG.

Referenced by directory_exec().

00375 {
00376    struct ast_config *cfg;
00377    struct ast_config *rtdata;
00378    struct ast_category *cat;
00379    struct ast_variable *var;
00380    char *mailbox;
00381    const char *fullname;
00382    const char *hidefromdir;
00383    char tmp[100];
00384    struct ast_flags config_flags = { 0 };
00385 
00386    /* Load flat file config. */
00387    cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags);
00388 
00389    if (!cfg) {
00390       /* Loading config failed. */
00391       ast_log(LOG_WARNING, "Loading config failed.\n");
00392       return NULL;
00393    }
00394 
00395    /* Get realtime entries, categorized by their mailbox number
00396       and present in the requested context */
00397    rtdata = ast_load_realtime_multientry("voicemail", "mailbox LIKE", "%", "context", context, SENTINEL);
00398 
00399    /* if there are no results, just return the entries from the config file */
00400    if (!rtdata)
00401       return cfg;
00402 
00403    /* Does the context exist within the config file? If not, make one */
00404    cat = ast_category_get(cfg, context);
00405    if (!cat) {
00406       cat = ast_category_new(context, "", 99999);
00407       if (!cat) {
00408          ast_log(LOG_WARNING, "Out of memory\n");
00409          ast_config_destroy(cfg);
00410          if (rtdata) {
00411             ast_config_destroy(rtdata);
00412          }
00413          return NULL;
00414       }
00415       ast_category_append(cfg, cat);
00416    }
00417 
00418    mailbox = NULL;
00419    while ( (mailbox = ast_category_browse(rtdata, mailbox)) ) {
00420       fullname = ast_variable_retrieve(rtdata, mailbox, "fullname");
00421       if (ast_true((hidefromdir = ast_variable_retrieve(rtdata, mailbox, "hidefromdir")))) {
00422          /* Skip hidden */
00423          continue;
00424       }
00425       snprintf(tmp, sizeof(tmp), "no-password,%s", S_OR(fullname, ""));
00426       var = ast_variable_new(mailbox, tmp, "");
00427       if (var)
00428          ast_variable_append(cat, var);
00429       else
00430          ast_log(LOG_WARNING, "Out of memory adding mailbox '%s'\n", mailbox);
00431    }
00432    ast_config_destroy(rtdata);
00433 
00434    return cfg;
00435 }

static int search_directory ( const char *  context,
struct ast_config vmcfg,
struct ast_config ucfg,
const char *  ext,
struct ast_flags  flags,
itemlist alist 
) [static]

Definition at line 478 of file app_directory.c.

References ast_category_browse(), ast_config_option(), ast_copy_string(), ast_debug, AST_LIST_INSERT_TAIL, AST_MAX_EXTENSION, ast_strlen_zero(), ast_test_flag, ast_true(), ast_variable_browse(), ast_variable_retrieve(), buf, check_match(), directory_item::entry, ast_variable::name, ast_variable::next, OPT_LISTBYFIRSTNAME, OPT_LISTBYLASTNAME, strcasestr(), strsep(), and ast_variable::value.

Referenced by do_directory().

00479 {
00480    struct ast_variable *v;
00481    char buf[AST_MAX_EXTENSION + 1], *pos, *bufptr, *cat;
00482    struct directory_item *item;
00483    int res;
00484 
00485    ast_debug(2, "Pattern: %s\n", ext);
00486 
00487    for (v = ast_variable_browse(vmcfg, context); v; v = v->next) {
00488 
00489       /* Ignore hidden */
00490       if (strcasestr(v->value, "hidefromdir=yes"))
00491          continue;
00492 
00493       ast_copy_string(buf, v->value, sizeof(buf));
00494       bufptr = buf;
00495 
00496       /* password,Full Name,email,pager,options */
00497       strsep(&bufptr, ",");
00498       pos = strsep(&bufptr, ",");
00499 
00500       /* No name to compare against */
00501       if (ast_strlen_zero(pos)) {
00502          continue;
00503       }
00504 
00505       res = 0;
00506       if (ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
00507          res = check_match(&item, pos, v->name, ext, 0 /* use_first_name */);
00508       }
00509       if (!res && ast_test_flag(&flags, OPT_LISTBYFIRSTNAME)) {
00510          res = check_match(&item, pos, v->name, ext, 1 /* use_first_name */);
00511       }
00512 
00513       if (!res)
00514          continue;
00515       else if (res < 0)
00516          return -1;
00517 
00518       AST_LIST_INSERT_TAIL(alist, item, entry);
00519    }
00520 
00521    if (ucfg) {
00522       for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
00523          const char *position;
00524          if (!strcasecmp(cat, "general"))
00525             continue;
00526          if (!ast_true(ast_config_option(ucfg, cat, "hasdirectory")))
00527             continue;
00528 
00529          /* Find all candidate extensions */
00530          position = ast_variable_retrieve(ucfg, cat, "fullname");
00531          if (!position)
00532             continue;
00533 
00534          res = 0;
00535          if (ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
00536             res = check_match(&item, position, cat, ext, 0 /* use_first_name */);
00537          }
00538          if (!res && ast_test_flag(&flags, OPT_LISTBYFIRSTNAME)) {
00539             res = check_match(&item, position, cat, ext, 1 /* use_first_name */);
00540          }
00541 
00542          if (!res)
00543             continue;
00544          else if (res < 0)
00545             return -1;
00546 
00547          AST_LIST_INSERT_TAIL(alist, item, entry);
00548       }
00549    }
00550    return 0;
00551 }

static int select_entry ( struct ast_channel chan,
const char *  context,
const char *  dialcontext,
const struct directory_item item,
struct ast_flags flags 
) [static]

Definition at line 237 of file app_directory.c.

References ast_copy_string(), ast_debug, ast_goto_if_exists(), ast_log(), ast_test_flag, chan, ast_channel::exten, directory_item::exten, LOG_WARNING, directory_item::name, and OPT_FROMVOICEMAIL.

Referenced by select_item_menu(), and select_item_seq().

00238 {
00239    ast_debug(1, "Selecting '%s' - %s@%s\n", item->name, item->exten, dialcontext);
00240 
00241    if (ast_test_flag(flags, OPT_FROMVOICEMAIL)) {
00242       /* We still want to set the exten though */
00243       ast_copy_string(chan->exten, item->exten, sizeof(chan->exten));
00244    } else if (ast_goto_if_exists(chan, dialcontext, item->exten, 1)) {
00245       ast_log(LOG_WARNING,
00246          "Can't find extension '%s' in context '%s'.  "
00247          "Did you pass the wrong context to Directory?\n",
00248          item->exten, dialcontext);
00249       return -1;
00250    }
00251 
00252    return 0;
00253 }

static int select_item_menu ( struct ast_channel chan,
struct directory_item **  items,
int  count,
const char *  context,
const char *  dialcontext,
struct ast_flags flags,
char *  opts[] 
) [static]

Definition at line 311 of file app_directory.c.

References AST_DIGIT_ANY, ast_streamfile(), ast_waitfordigit(), ast_waitstream(), buf, chan, directory_item::exten, ast_channel::language, directory_item::name, play_mailbox_owner(), select_entry(), and select_item_pause().

Referenced by do_directory().

00312 {
00313    struct directory_item **block, *item;
00314    int i, limit, res = 0;
00315    char buf[9];
00316 
00317    /* option p(n): cellphone pause option */
00318    select_item_pause(chan, flags, opts);
00319 
00320    for (block = items; count; block += limit, count -= limit) {
00321       limit = count;
00322       if (limit > 8)
00323          limit = 8;
00324 
00325       for (i = 0; i < limit && !res; i++) {
00326          item = block[i];
00327 
00328          snprintf(buf, sizeof(buf), "digits/%d", i + 1);
00329          /* Press <num> for <name>, [ extension <ext> ] */
00330          res = ast_streamfile(chan, "dir-multi1", chan->language);
00331          if (!res)
00332             res = ast_waitstream(chan, AST_DIGIT_ANY);
00333          if (!res)
00334             res = ast_streamfile(chan, buf, chan->language);
00335          if (!res)
00336             res = ast_waitstream(chan, AST_DIGIT_ANY);
00337          if (!res)
00338             res = ast_streamfile(chan, "dir-multi2", chan->language);
00339          if (!res)
00340             res = ast_waitstream(chan, AST_DIGIT_ANY);
00341          if (!res)
00342             res = play_mailbox_owner(chan, context, item->exten, item->name, flags);
00343          if (!res)
00344             res = ast_waitstream(chan, AST_DIGIT_ANY);
00345          if (!res)
00346             res = ast_waitfordigit(chan, 800);
00347       }
00348 
00349       /* Press "9" for more names. */
00350       if (!res && count > limit) {
00351          res = ast_streamfile(chan, "dir-multi9", chan->language);
00352          if (!res)
00353             res = ast_waitstream(chan, AST_DIGIT_ANY);
00354       }
00355 
00356       if (!res) {
00357          res = ast_waitfordigit(chan, 3000);
00358       }
00359 
00360       if (res && res > '0' && res < '1' + limit) {
00361          return select_entry(chan, context, dialcontext, block[res - '1'], flags) ? -1 : 1;
00362       }
00363 
00364       if (res < 0)
00365          return -1;
00366 
00367       res = 0;
00368    }
00369 
00370    /* Nothing was selected */
00371    return 0;
00372 }

static int select_item_pause ( struct ast_channel chan,
struct ast_flags flags,
char *  opts[] 
) [static]

Definition at line 255 of file app_directory.c.

References ast_strlen_zero(), ast_test_flag, ast_waitfordigit(), chan, OPT_ARG_PAUSE, and OPT_PAUSE.

Referenced by select_item_menu(), and select_item_seq().

00256 {
00257    int res = 0, opt_pause = 0;
00258 
00259    if (ast_test_flag(flags, OPT_PAUSE) && !ast_strlen_zero(opts[OPT_ARG_PAUSE])) {
00260       opt_pause = atoi(opts[OPT_ARG_PAUSE]);
00261       if (opt_pause > 3000) {
00262          opt_pause = 3000;
00263       }
00264       res = ast_waitfordigit(chan, opt_pause);
00265    }
00266    return res;
00267 }

static int select_item_seq ( struct ast_channel chan,
struct directory_item **  items,
int  count,
const char *  context,
const char *  dialcontext,
struct ast_flags flags,
char *  opts[] 
) [static]

Definition at line 269 of file app_directory.c.

References AST_DIGIT_ANY, ast_stopstream(), ast_stream_and_wait(), ast_waitfordigit(), chan, directory_item::exten, directory_item::name, play_mailbox_owner(), select_entry(), and select_item_pause().

Referenced by do_directory().

00271 {
00272    struct directory_item *item, **ptr;
00273    int i, res, loop;
00274 
00275    /* option p(n): cellphone pause option */
00276    /* allow early press of selection key */
00277    res = select_item_pause(chan, flags, opts);
00278 
00279    for (ptr = items, i = 0; i < count; i++, ptr++) {
00280       item = *ptr;
00281 
00282       for (loop = 3 ; loop > 0; loop--) {
00283 
00284          if (!res)
00285             res = play_mailbox_owner(chan, context, item->exten, item->name, flags);
00286          if (!res)
00287             res = ast_stream_and_wait(chan, "dir-instr", AST_DIGIT_ANY);
00288          if (!res)
00289             res = ast_waitfordigit(chan, 3000);
00290          ast_stopstream(chan);
00291    
00292          if (res == '1') { /* Name selected */
00293             return select_entry(chan, context, dialcontext, item, flags) ? -1 : 1;
00294          } else if (res == '*') {
00295             /* Skip to next match in list */
00296             break;
00297          }
00298 
00299          if (res < 0)
00300             return -1;
00301 
00302          res = 0;
00303       }
00304       res = 0;
00305    }
00306 
00307    /* Nothing was selected */
00308    return 0;
00309 }

static void sort_items ( struct directory_item **  sorted,
int  count 
) [static]

Definition at line 553 of file app_directory.c.

References directory_item::key.

Referenced by do_directory().

00554 {
00555    int reordered, i;
00556    struct directory_item **ptr, *tmp;
00557 
00558    if (count < 2)
00559       return;
00560 
00561    /* Bubble-sort items by the key */
00562    do {
00563       reordered = 0;
00564       for (ptr = sorted, i = 0; i < count - 1; i++, ptr++) {
00565          if (strcasecmp(ptr[0]->key, ptr[1]->key) > 0) {
00566             tmp = ptr[0];
00567             ptr[0] = ptr[1];
00568             ptr[1] = tmp;
00569             reordered++;
00570          }
00571       }
00572    } while (reordered);
00573 }

static int unload_module ( void   )  [static]

Definition at line 795 of file app_directory.c.

References ast_unregister_application().

00796 {
00797    int res;
00798    res = ast_unregister_application(app);
00799    return res;
00800 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Extension Directory" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, } [static]

Definition at line 807 of file app_directory.c.

char* app = "Directory" [static]

Definition at line 45 of file app_directory.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 807 of file app_directory.c.

char* descrip [static]

Definition at line 48 of file app_directory.c.

struct ast_app_option directory_app_options[128] = { [ 'f' ] = { .flag = OPT_LISTBYFIRSTNAME , .arg_index = OPT_ARG_FIRSTNAME + 1 }, [ 'l' ] = { .flag = OPT_LISTBYLASTNAME , .arg_index = OPT_ARG_LASTNAME + 1 }, [ 'b' ] = { .flag = OPT_LISTBYEITHER , .arg_index = OPT_ARG_EITHER + 1 }, [ 'p' ] = { .flag = OPT_PAUSE , .arg_index = OPT_ARG_PAUSE + 1 }, [ 'e' ] = { .flag = OPT_SAYEXTENSION }, [ 'v' ] = { .flag = OPT_FROMVOICEMAIL }, [ 'm' ] = { .flag = OPT_SELECTFROMMENU },} [static]

Definition at line 128 of file app_directory.c.

Referenced by directory_exec().

enum { ... } directory_option_flags

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

Definition at line 47 of file app_directory.c.


Generated on Wed Aug 18 22:33:58 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7