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), OPT_NOANSWER = (1 << 6) } |
| 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_context, 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, const char *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_config * | realtime_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 | search_directory_sub (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 *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 *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 *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_LOAD_ORDER , .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 = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, } |
| static const char | app [] = "Directory" |
| static struct ast_module_info * | ast_module_info = &__mod_info |
| 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 }, [ 'n' ] = { .flag = OPT_NOANSWER },} |
Provide a directory of extensions.
Definition in file app_directory.c.
| #define VOICEMAIL_CONFIG "voicemail.conf" |
Definition at line 127 of file app_directory.c.
Referenced by realtime_directory().
| anonymous enum |
| OPT_LISTBYFIRSTNAME | |
| OPT_SAYEXTENSION | |
| OPT_FROMVOICEMAIL | |
| OPT_SELECTFROMMENU | |
| OPT_LISTBYLASTNAME | |
| OPT_LISTBYEITHER | |
| OPT_PAUSE | |
| OPT_NOANSWER |
Definition at line 129 of file app_directory.c.
{
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),
OPT_NOANSWER = (1 << 6),
};
| anonymous enum |
Definition at line 140 of file app_directory.c.
{
OPT_ARG_FIRSTNAME = 0,
OPT_ARG_LASTNAME = 1,
OPT_ARG_EITHER = 2,
OPT_ARG_PAUSE = 3,
/* This *must* be the last value in this enum! */
OPT_ARG_ARRAY_SIZE = 4,
};
| static void __reg_module | ( | void | ) | [static] |
Definition at line 892 of file app_directory.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 892 of file app_directory.c.
| static int check_match | ( | struct directory_item ** | result, |
| const char * | item_context, | ||
| const char * | item_fullname, | ||
| const char * | item_ext, | ||
| const char * | pattern_ext, | ||
| int | use_first_name | ||
| ) | [static] |
Definition at line 508 of file app_directory.c.
References ast_calloc, ast_copy_string(), ast_debug, ast_strlen_zero(), compare(), directory_item::context, directory_item::exten, directory_item::key, and directory_item::name.
Referenced by search_directory_sub().
{
struct directory_item *item;
const char *key = NULL;
int namelen;
if (ast_strlen_zero(item_fullname)) {
return 0;
}
/* Set key to last name or first name depending on search mode */
if (!use_first_name)
key = strchr(item_fullname, ' ');
if (key)
key++;
else
key = item_fullname;
if (compare(key, pattern_ext))
return 0;
ast_debug(1, "Found match %s@%s\n", item_ext, item_context);
/* Match */
item = ast_calloc(1, sizeof(*item));
if (!item)
return -1;
ast_copy_string(item->context, item_context, sizeof(item->context));
ast_copy_string(item->name, item_fullname, sizeof(item->name));
ast_copy_string(item->exten, item_ext, sizeof(item->exten));
ast_copy_string(item->key, key, sizeof(item->key));
if (key != item_fullname) {
/* Key is the last name. Append first name to key in order to sort Last,First */
namelen = key - item_fullname - 1;
if (namelen > sizeof(item->key) - strlen(item->key) - 1)
namelen = sizeof(item->key) - strlen(item->key) - 1;
strncat(item->key, item_fullname, namelen);
}
*result = item;
return 1;
}
| static int compare | ( | const char * | text, |
| const char * | template | ||
| ) | [static] |
Definition at line 169 of file app_directory.c.
References ast_strlen_zero().
Referenced by ast_hashtab_create(), and check_match().
{
char digit;
if (ast_strlen_zero(text)) {
return -1;
}
while (*template) {
digit = toupper(*text++);
switch (digit) {
case 0:
return -1;
case '1':
digit = '1';
break;
case '2':
case 'A':
case 'B':
case 'C':
digit = '2';
break;
case '3':
case 'D':
case 'E':
case 'F':
digit = '3';
break;
case '4':
case 'G':
case 'H':
case 'I':
digit = '4';
break;
case '5':
case 'J':
case 'K':
case 'L':
digit = '5';
break;
case '6':
case 'M':
case 'N':
case 'O':
digit = '6';
break;
case '7':
case 'P':
case 'Q':
case 'R':
case 'S':
digit = '7';
break;
case '8':
case 'T':
case 'U':
case 'V':
digit = '8';
break;
case '9':
case 'W':
case 'X':
case 'Y':
case 'Z':
digit = '9';
break;
default:
if (digit > ' ')
return -1;
continue;
}
if (*template++ != digit)
return -1;
}
return 0;
}
| static int directory_exec | ( | struct ast_channel * | chan, |
| const char * | data | ||
| ) | [static] |
Definition at line 758 of file app_directory.c.
References ast_channel::_state, args, 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(), CONFIG_STATUS_FILEINVALID, dialcontext, directory_app_options, do_directory(), LOG_ERROR, OPT_ARG_ARRAY_SIZE, OPT_ARG_EITHER, OPT_ARG_FIRSTNAME, OPT_ARG_LASTNAME, OPT_LISTBYFIRSTNAME, OPT_LISTBYLASTNAME, OPT_NOANSWER, parse(), and realtime_directory().
Referenced by load_module().
{
int res = 0, digit = 3;
struct ast_config *cfg, *ucfg;
const char *dirintro;
char *parse, *opts[OPT_ARG_ARRAY_SIZE] = { 0, };
struct ast_flags flags = { 0 };
struct ast_flags config_flags = { 0 };
enum { FIRST, LAST, BOTH } which = LAST;
char digits[9] = "digits/3";
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(vmcontext);
AST_APP_ARG(dialcontext);
AST_APP_ARG(options);
);
parse = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, parse);
if (args.options && ast_app_parse_options(directory_app_options, &flags, opts, args.options))
return -1;
if (!(cfg = realtime_directory(args.vmcontext))) {
ast_log(LOG_ERROR, "Unable to read the configuration data!\n");
return -1;
}
if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) {
ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Aborting.\n");
ucfg = NULL;
}
dirintro = ast_variable_retrieve(cfg, args.vmcontext, "directoryintro");
if (ast_strlen_zero(dirintro))
dirintro = ast_variable_retrieve(cfg, "general", "directoryintro");
/* the above prompts probably should be modified to include 0 for dialing operator
and # for exiting (continues in dialplan) */
if (ast_test_flag(&flags, OPT_LISTBYFIRSTNAME) && ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
if (!ast_strlen_zero(opts[OPT_ARG_EITHER])) {
digit = atoi(opts[OPT_ARG_EITHER]);
}
which = BOTH;
} else if (ast_test_flag(&flags, OPT_LISTBYFIRSTNAME)) {
if (!ast_strlen_zero(opts[OPT_ARG_FIRSTNAME])) {
digit = atoi(opts[OPT_ARG_FIRSTNAME]);
}
which = FIRST;
} else {
if (!ast_strlen_zero(opts[OPT_ARG_LASTNAME])) {
digit = atoi(opts[OPT_ARG_LASTNAME]);
}
which = LAST;
}
/* If no options specified, search by last name */
if (!ast_test_flag(&flags, OPT_LISTBYFIRSTNAME) && !ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
ast_set_flag(&flags, OPT_LISTBYLASTNAME);
which = LAST;
}
if (digit > 9) {
digit = 9;
} else if (digit < 1) {
digit = 3;
}
digits[7] = digit + '0';
if (chan->_state != AST_STATE_UP) {
if (!ast_test_flag(&flags, OPT_NOANSWER)) {
/* Otherwise answer unless we're supposed to read while on-hook */
res = ast_answer(chan);
}
}
for (;;) {
if (!ast_strlen_zero(dirintro) && !res) {
res = ast_stream_and_wait(chan, dirintro, AST_DIGIT_ANY);
} else if (!res) {
/* Stop playing sounds as soon as we have a digit. */
res = ast_stream_and_wait(chan, "dir-welcome", AST_DIGIT_ANY);
if (!res) {
res = ast_stream_and_wait(chan, "dir-pls-enter", AST_DIGIT_ANY);
}
if (!res) {
res = ast_stream_and_wait(chan, digits, AST_DIGIT_ANY);
}
if (!res) {
res = ast_stream_and_wait(chan,
which == FIRST ? "dir-first" :
which == LAST ? "dir-last" :
"dir-firstlast", AST_DIGIT_ANY);
}
if (!res) {
res = ast_stream_and_wait(chan, "dir-usingkeypad", AST_DIGIT_ANY);
}
}
ast_stopstream(chan);
if (!res)
res = ast_waitfordigit(chan, 5000);
if (res <= 0)
break;
res = do_directory(chan, cfg, ucfg, args.vmcontext, args.dialcontext, res, digit, &flags, opts);
if (res)
break;
res = ast_waitstream(chan, AST_DIGIT_ANY);
ast_stopstream(chan);
if (res)
break;
}
if (ucfg)
ast_config_destroy(ucfg);
ast_config_destroy(cfg);
return res < 0 ? -1 : 0;
}
| 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 681 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_readstring(), ast_streamfile(), ast_test_flag, directory_item::entry, ext, directory_item::exten, goto_exten(), ast_channel::language, directory_item::name, OPT_SELECTFROMMENU, option_debug, search_directory(), select_item_menu(), select_item_seq(), and sort_items().
Referenced by directory_exec().
{
/* Read in the first three digits.. "digit" is the first digit, already read */
int res = 0;
itemlist alist = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
struct directory_item *item, **ptr, **sorted = NULL;
int count, i;
char ext[10] = "";
if (digit == '0' && !goto_exten(chan, dialcontext, "o")) {
return digit;
}
if (digit == '*' && !goto_exten(chan, dialcontext, "a")) {
return digit;
}
ext[0] = digit;
if (ast_readstring(chan, ext + 1, digits - 1, 3000, 3000, "#") < 0)
return -1;
res = search_directory(context, vmcfg, ucfg, ext, *flags, &alist);
if (res)
goto exit;
/* Count items in the list */
count = 0;
AST_LIST_TRAVERSE(&alist, item, entry) {
count++;
}
if (count < 1) {
res = ast_streamfile(chan, "dir-nomatch", chan->language);
goto exit;
}
/* Create plain array of pointers to items (for sorting) */
sorted = ast_calloc(count, sizeof(*sorted));
ptr = sorted;
AST_LIST_TRAVERSE(&alist, item, entry) {
*ptr++ = item;
}
/* Sort items */
sort_items(sorted, count);
if (option_debug) {
ast_debug(2, "Listing matching entries:\n");
for (ptr = sorted, i = 0; i < count; i++, ptr++) {
ast_debug(2, "%s: %s\n", ptr[0]->exten, ptr[0]->name);
}
}
if (ast_test_flag(flags, OPT_SELECTFROMMENU)) {
/* Offer multiple entries at the same time */
res = select_item_menu(chan, sorted, count, dialcontext, flags, opts);
} else {
/* Offer entries one by one */
res = select_item_seq(chan, sorted, count, dialcontext, flags, opts);
}
if (!res) {
res = ast_streamfile(chan, "dir-nomore", chan->language);
}
exit:
if (sorted)
ast_free(sorted);
while ((item = AST_LIST_REMOVE_HEAD(&alist, entry)))
ast_free(item);
return res;
}
| static int goto_exten | ( | struct ast_channel * | chan, |
| const char * | dialcontext, | ||
| char * | ext | ||
| ) | [static] |
Definition at line 249 of file app_directory.c.
References ast_goto_if_exists(), ast_log(), ast_strlen_zero(), ast_channel::context, LOG_WARNING, ast_channel::macrocontext, and S_OR.
Referenced by do_directory(), and select_item_seq().
{
if (!ast_goto_if_exists(chan, S_OR(dialcontext, chan->context), ext, 1) ||
(!ast_strlen_zero(chan->macrocontext) &&
!ast_goto_if_exists(chan, chan->macrocontext, ext, 1))) {
return 0;
} else {
ast_log(LOG_WARNING, "Can't find extension '%s' in current context. "
"Not Exiting the Directory!\n", ext);
return -1;
}
}
| static int load_module | ( | void | ) | [static] |
Definition at line 887 of file app_directory.c.
References ast_register_application_xml, and directory_exec().
{
return ast_register_application_xml(app, directory_exec);
}
| 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 267 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, ast_channel::language, OPT_SAYEXTENSION, and S_OR.
Referenced by select_item_menu(), and select_item_seq().
{
int res = 0;
if ((res = ast_app_sayname(chan, ext, context)) >= 0) {
ast_stopstream(chan);
/* If Option 'e' was specified, also read the extension number with the name */
if (ast_test_flag(flags, OPT_SAYEXTENSION)) {
ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
res = ast_say_character_str(chan, ext, AST_DIGIT_ANY, chan->language);
}
} else {
res = ast_say_character_str(chan, S_OR(name, ext), AST_DIGIT_ANY, chan->language);
if (!ast_strlen_zero(name) && ast_test_flag(flags, OPT_SAYEXTENSION)) {
ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
res = ast_say_character_str(chan, ext, AST_DIGIT_ANY, chan->language);
}
}
return res;
}
| static struct ast_config* realtime_directory | ( | char * | context | ) | [static, read] |
Definition at line 430 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_strlen_zero(), ast_true(), ast_variable_append(), ast_variable_new(), ast_variable_retrieve(), CONFIG_STATUS_FILEINVALID, LOG_ERROR, LOG_WARNING, mailbox, S_OR, SENTINEL, var, and VOICEMAIL_CONFIG.
Referenced by directory_exec().
{
struct ast_config *cfg;
struct ast_config *rtdata;
struct ast_category *cat;
struct ast_variable *var;
char *mailbox;
const char *fullname;
const char *hidefromdir, *searchcontexts = NULL;
char tmp[100];
struct ast_flags config_flags = { 0 };
/* Load flat file config. */
cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags);
if (!cfg) {
/* Loading config failed. */
ast_log(LOG_WARNING, "Loading config failed.\n");
return NULL;
} else if (cfg == CONFIG_STATUS_FILEINVALID) {
ast_log(LOG_ERROR, "Config file %s is in an invalid format. Aborting.\n", VOICEMAIL_CONFIG);
return NULL;
}
/* Get realtime entries, categorized by their mailbox number
and present in the requested context */
if (ast_strlen_zero(context) && (searchcontexts = ast_variable_retrieve(cfg, "general", "searchcontexts"))) {
if (ast_true(searchcontexts)) {
rtdata = ast_load_realtime_multientry("voicemail", "mailbox LIKE", "%", SENTINEL);
context = NULL;
} else {
rtdata = ast_load_realtime_multientry("voicemail", "mailbox LIKE", "%", "context", "default", SENTINEL);
context = "default";
}
} else {
rtdata = ast_load_realtime_multientry("voicemail", "mailbox LIKE", "%", "context", context, SENTINEL);
}
/* if there are no results, just return the entries from the config file */
if (!rtdata) {
return cfg;
}
mailbox = NULL;
while ( (mailbox = ast_category_browse(rtdata, mailbox)) ) {
const char *context = ast_variable_retrieve(rtdata, mailbox, "context");
fullname = ast_variable_retrieve(rtdata, mailbox, "fullname");
if (ast_true((hidefromdir = ast_variable_retrieve(rtdata, mailbox, "hidefromdir")))) {
/* Skip hidden */
continue;
}
snprintf(tmp, sizeof(tmp), "no-password,%s", S_OR(fullname, ""));
/* Does the context exist within the config file? If not, make one */
if (!(cat = ast_category_get(cfg, context))) {
if (!(cat = ast_category_new(context, "", 99999))) {
ast_log(LOG_WARNING, "Out of memory\n");
ast_config_destroy(cfg);
if (rtdata) {
ast_config_destroy(rtdata);
}
return NULL;
}
ast_category_append(cfg, cat);
}
if ((var = ast_variable_new(mailbox, tmp, ""))) {
ast_variable_append(cat, var);
} else {
ast_log(LOG_WARNING, "Out of memory adding mailbox '%s'\n", mailbox);
}
}
ast_config_destroy(rtdata);
return cfg;
}
| 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 630 of file app_directory.c.
References ast_category_browse(), ast_debug, ast_strlen_zero(), ast_true(), ast_variable_retrieve(), and search_directory_sub().
Referenced by do_directory().
{
const char *searchcontexts = ast_variable_retrieve(vmcfg, "general", "searchcontexts");
if (ast_strlen_zero(context)) {
if (!ast_strlen_zero(searchcontexts) && ast_true(searchcontexts)) {
/* Browse each context for a match */
int res;
const char *catg;
for (catg = ast_category_browse(vmcfg, NULL); catg; catg = ast_category_browse(vmcfg, catg)) {
if (!strcmp(catg, "general") || !strcmp(catg, "zonemessages")) {
continue;
}
if ((res = search_directory_sub(catg, vmcfg, ucfg, ext, flags, alist))) {
return res;
}
}
return 0;
} else {
ast_debug(1, "Searching by category default\n");
return search_directory_sub("default", vmcfg, ucfg, ext, flags, alist);
}
} else {
/* Browse only the listed context for a match */
ast_debug(1, "Searching by category %s\n", context);
return search_directory_sub(context, vmcfg, ucfg, ext, flags, alist);
}
}
| static int search_directory_sub | ( | const char * | context, |
| struct ast_config * | vmcfg, | ||
| struct ast_config * | ucfg, | ||
| const char * | ext, | ||
| struct ast_flags | flags, | ||
| itemlist * | alist | ||
| ) | [static] |
Definition at line 555 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(), check_match(), directory_item::entry, ast_variable::name, ast_variable::next, OPT_LISTBYFIRSTNAME, OPT_LISTBYLASTNAME, strcasestr(), strsep(), and ast_variable::value.
Referenced by search_directory().
{
struct ast_variable *v;
char buf[AST_MAX_EXTENSION + 1], *pos, *bufptr, *cat;
struct directory_item *item;
int res;
ast_debug(2, "Pattern: %s\n", ext);
for (v = ast_variable_browse(vmcfg, context); v; v = v->next) {
/* Ignore hidden */
if (strcasestr(v->value, "hidefromdir=yes"))
continue;
ast_copy_string(buf, v->value, sizeof(buf));
bufptr = buf;
/* password,Full Name,email,pager,options */
strsep(&bufptr, ",");
pos = strsep(&bufptr, ",");
/* No name to compare against */
if (ast_strlen_zero(pos)) {
continue;
}
res = 0;
if (ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
res = check_match(&item, context, pos, v->name, ext, 0 /* use_first_name */);
}
if (!res && ast_test_flag(&flags, OPT_LISTBYFIRSTNAME)) {
res = check_match(&item, context, pos, v->name, ext, 1 /* use_first_name */);
}
if (!res)
continue;
else if (res < 0)
return -1;
AST_LIST_INSERT_TAIL(alist, item, entry);
}
if (ucfg) {
for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
const char *position;
if (!strcasecmp(cat, "general"))
continue;
if (!ast_true(ast_config_option(ucfg, cat, "hasdirectory")))
continue;
/* Find all candidate extensions */
position = ast_variable_retrieve(ucfg, cat, "fullname");
if (!position)
continue;
res = 0;
if (ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
res = check_match(&item, context, position, cat, ext, 0 /* use_first_name */);
}
if (!res && ast_test_flag(&flags, OPT_LISTBYFIRSTNAME)) {
res = check_match(&item, context, position, cat, ext, 1 /* use_first_name */);
}
if (!res)
continue;
else if (res < 0)
return -1;
AST_LIST_INSERT_TAIL(alist, item, entry);
}
}
return 0;
}
| static int select_entry | ( | struct ast_channel * | chan, |
| const char * | dialcontext, | ||
| const struct directory_item * | item, | ||
| struct ast_flags * | flags | ||
| ) | [static] |
Definition at line 289 of file app_directory.c.
References ast_copy_string(), ast_debug, ast_goto_if_exists(), ast_log(), ast_test_flag, directory_item::context, directory_item::exten, ast_channel::exten, LOG_WARNING, directory_item::name, OPT_FROMVOICEMAIL, and S_OR.
Referenced by select_item_menu(), and select_item_seq().
{
ast_debug(1, "Selecting '%s' - %s@%s\n", item->name, item->exten, S_OR(dialcontext, item->context));
if (ast_test_flag(flags, OPT_FROMVOICEMAIL)) {
/* We still want to set the exten though */
ast_copy_string(chan->exten, item->exten, sizeof(chan->exten));
} else if (ast_goto_if_exists(chan, S_OR(dialcontext, item->context), item->exten, 1)) {
ast_log(LOG_WARNING,
"Can't find extension '%s' in context '%s'. "
"Did you pass the wrong context to Directory?\n",
item->exten, S_OR(dialcontext, item->context));
return -1;
}
return 0;
}
| static int select_item_menu | ( | struct ast_channel * | chan, |
| struct directory_item ** | items, | ||
| int | count, | ||
| const char * | dialcontext, | ||
| struct ast_flags * | flags, | ||
| char * | opts[] | ||
| ) | [static] |
Definition at line 367 of file app_directory.c.
References AST_DIGIT_ANY, ast_streamfile(), ast_waitfordigit(), ast_waitstream(), directory_item::context, directory_item::exten, ast_channel::language, directory_item::name, play_mailbox_owner(), select_entry(), and select_item_pause().
Referenced by do_directory().
{
struct directory_item **block, *item;
int i, limit, res = 0;
char buf[9];
/* option p(n): cellphone pause option */
select_item_pause(chan, flags, opts);
for (block = items; count; block += limit, count -= limit) {
limit = count;
if (limit > 8)
limit = 8;
for (i = 0; i < limit && !res; i++) {
item = block[i];
snprintf(buf, sizeof(buf), "digits/%d", i + 1);
/* Press <num> for <name>, [ extension <ext> ] */
res = ast_streamfile(chan, "dir-multi1", chan->language);
if (!res)
res = ast_waitstream(chan, AST_DIGIT_ANY);
if (!res)
res = ast_streamfile(chan, buf, chan->language);
if (!res)
res = ast_waitstream(chan, AST_DIGIT_ANY);
if (!res)
res = ast_streamfile(chan, "dir-multi2", chan->language);
if (!res)
res = ast_waitstream(chan, AST_DIGIT_ANY);
if (!res)
res = play_mailbox_owner(chan, item->context, item->exten, item->name, flags);
if (!res)
res = ast_waitstream(chan, AST_DIGIT_ANY);
if (!res)
res = ast_waitfordigit(chan, 800);
}
/* Press "9" for more names. */
if (!res && count > limit) {
res = ast_streamfile(chan, "dir-multi9", chan->language);
if (!res)
res = ast_waitstream(chan, AST_DIGIT_ANY);
}
if (!res) {
res = ast_waitfordigit(chan, 3000);
}
if (res && res > '0' && res < '1' + limit) {
return select_entry(chan, dialcontext, block[res - '1'], flags) ? -1 : 1;
}
if (res < 0)
return -1;
res = 0;
}
/* Nothing was selected */
return 0;
}
| static int select_item_pause | ( | struct ast_channel * | chan, |
| struct ast_flags * | flags, | ||
| char * | opts[] | ||
| ) | [static] |
Definition at line 307 of file app_directory.c.
References ast_strlen_zero(), ast_test_flag, ast_waitfordigit(), OPT_ARG_PAUSE, and OPT_PAUSE.
Referenced by select_item_menu(), and select_item_seq().
{
int res = 0, opt_pause = 0;
if (ast_test_flag(flags, OPT_PAUSE) && !ast_strlen_zero(opts[OPT_ARG_PAUSE])) {
opt_pause = atoi(opts[OPT_ARG_PAUSE]);
if (opt_pause > 3000) {
opt_pause = 3000;
}
res = ast_waitfordigit(chan, opt_pause);
}
return res;
}
| static int select_item_seq | ( | struct ast_channel * | chan, |
| struct directory_item ** | items, | ||
| int | count, | ||
| const char * | dialcontext, | ||
| struct ast_flags * | flags, | ||
| char * | opts[] | ||
| ) | [static] |
Definition at line 321 of file app_directory.c.
References AST_DIGIT_ANY, ast_stopstream(), ast_stream_and_wait(), ast_waitfordigit(), directory_item::context, directory_item::exten, goto_exten(), directory_item::name, play_mailbox_owner(), select_entry(), and select_item_pause().
Referenced by do_directory().
{
struct directory_item *item, **ptr;
int i, res, loop;
/* option p(n): cellphone pause option */
/* allow early press of selection key */
res = select_item_pause(chan, flags, opts);
for (ptr = items, i = 0; i < count; i++, ptr++) {
item = *ptr;
for (loop = 3 ; loop > 0; loop--) {
if (!res)
res = play_mailbox_owner(chan, item->context, item->exten, item->name, flags);
if (!res)
res = ast_stream_and_wait(chan, "dir-instr", AST_DIGIT_ANY);
if (!res)
res = ast_waitfordigit(chan, 3000);
ast_stopstream(chan);
if (res == '0') { /* operator selected */
goto_exten(chan, dialcontext, "o");
return '0';
} else if (res == '1') { /* Name selected */
return select_entry(chan, dialcontext, item, flags) ? -1 : 1;
} else if (res == '*') {
/* Skip to next match in list */
break;
} else if (res == '#') {
/* Exit reading, continue in dialplan */
return res;
}
if (res < 0)
return -1;
res = 0;
}
res = 0;
}
/* Nothing was selected */
return 0;
}
| static void sort_items | ( | struct directory_item ** | sorted, |
| int | count | ||
| ) | [static] |
Definition at line 659 of file app_directory.c.
References directory_item::key.
Referenced by do_directory().
{
int reordered, i;
struct directory_item **ptr, *tmp;
if (count < 2)
return;
/* Bubble-sort items by the key */
do {
reordered = 0;
for (ptr = sorted, i = 0; i < count - 1; i++, ptr++) {
if (strcasecmp(ptr[0]->key, ptr[1]->key) > 0) {
tmp = ptr[0];
ptr[0] = ptr[1];
ptr[1] = tmp;
reordered++;
}
}
} while (reordered);
}
| static int unload_module | ( | void | ) | [static] |
Definition at line 880 of file app_directory.c.
References ast_unregister_application().
{
int res;
res = ast_unregister_application(app);
return res;
}
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .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 = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, } [static] |
Definition at line 892 of file app_directory.c.
const char app[] = "Directory" [static] |
Definition at line 122 of file app_directory.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 892 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 }, [ 'n' ] = { .flag = OPT_NOANSWER },} [static] |
Definition at line 167 of file app_directory.c.
Referenced by directory_exec().