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"

Include dependency graph for app_directory.c:

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),
  OPT_ALIAS = (1 << 7)
}
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 __init_commonbuf (void)
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_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 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, .support_level = AST_MODULE_SUPPORT_CORE, }
static const char app [] = "Directory"
static struct ast_module_infoast_module_info = &__mod_info
static struct ast_threadstorage commonbuf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_commonbuf , .custom_init = NULL , }
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 }, [ 'a' ] = { .flag = OPT_ALIAS },}


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 146 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 
OPT_NOANSWER 
OPT_ALIAS 

Definition at line 148 of file app_directory.c.

00148      {
00149    OPT_LISTBYFIRSTNAME = (1 << 0),
00150    OPT_SAYEXTENSION =    (1 << 1),
00151    OPT_FROMVOICEMAIL =   (1 << 2),
00152    OPT_SELECTFROMMENU =  (1 << 3),
00153    OPT_LISTBYLASTNAME =  (1 << 4),
00154    OPT_LISTBYEITHER =    OPT_LISTBYFIRSTNAME | OPT_LISTBYLASTNAME,
00155    OPT_PAUSE =           (1 << 5),
00156    OPT_NOANSWER =        (1 << 6),
00157    OPT_ALIAS =           (1 << 7),
00158 };

anonymous enum

Enumerator:
OPT_ARG_FIRSTNAME 
OPT_ARG_LASTNAME 
OPT_ARG_EITHER 
OPT_ARG_PAUSE 
OPT_ARG_ARRAY_SIZE 

Definition at line 160 of file app_directory.c.

00160      {
00161    OPT_ARG_FIRSTNAME =   0,
00162    OPT_ARG_LASTNAME =    1,
00163    OPT_ARG_EITHER =      2,
00164    OPT_ARG_PAUSE =       3,
00165    /* This *must* be the last value in this enum! */
00166    OPT_ARG_ARRAY_SIZE =  4,
00167 };


Function Documentation

static void __init_commonbuf ( void   )  [static]

Definition at line 461 of file app_directory.c.

00464 {

static void __reg_module ( void   )  [static]

Definition at line 981 of file app_directory.c.

static void __unreg_module ( void   )  [static]

Definition at line 981 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 554 of file app_directory.c.

References ast_calloc, ast_copy_string(), ast_debug, ast_strlen_zero, compare(), directory_item::context, directory_item::exten, item, directory_item::key, directory_item::name, and NULL.

Referenced by search_directory_sub().

00555 {
00556    struct directory_item *item;
00557    const char *key = NULL;
00558    int namelen;
00559 
00560    if (ast_strlen_zero(item_fullname)) {
00561       return 0;
00562    }
00563 
00564    /* Set key to last name or first name depending on search mode */
00565    if (!use_first_name)
00566       key = strchr(item_fullname, ' ');
00567 
00568    if (key)
00569       key++;
00570    else
00571       key = item_fullname;
00572 
00573    if (compare(key, pattern_ext))
00574       return 0;
00575 
00576    ast_debug(1, "Found match %s@%s\n", item_ext, item_context);
00577 
00578    /* Match */
00579    item = ast_calloc(1, sizeof(*item));
00580    if (!item)
00581       return -1;
00582    ast_copy_string(item->context, item_context, sizeof(item->context));
00583    ast_copy_string(item->name, item_fullname, sizeof(item->name));
00584    ast_copy_string(item->exten, item_ext, sizeof(item->exten));
00585 
00586    ast_copy_string(item->key, key, sizeof(item->key));
00587    if (key != item_fullname) {
00588       /* Key is the last name. Append first name to key in order to sort Last,First */
00589       namelen = key - item_fullname - 1;
00590       if (namelen > sizeof(item->key) - strlen(item->key) - 1)
00591          namelen = sizeof(item->key) - strlen(item->key) - 1;
00592       strncat(item->key, item_fullname, namelen);
00593    }
00594 
00595    *result = item;
00596    return 1;
00597 }

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

Definition at line 190 of file app_directory.c.

References ast_strlen_zero, and digit.

Referenced by ast_hashtab_create(), ast_sip_is_content_type(), and check_match().

00191 {
00192    char digit;
00193 
00194    if (ast_strlen_zero(text)) {
00195       return -1;
00196    }
00197 
00198    while (*template) {
00199       digit = toupper(*text++);
00200       switch (digit) {
00201       case 0:
00202          return -1;
00203       case '1':
00204          digit = '1';
00205          break;
00206       case '2':
00207       case 'A':
00208       case 'B':
00209       case 'C':
00210          digit = '2';
00211          break;
00212       case '3':
00213       case 'D':
00214       case 'E':
00215       case 'F':
00216          digit = '3';
00217          break;
00218       case '4':
00219       case 'G':
00220       case 'H':
00221       case 'I':
00222          digit = '4';
00223          break;
00224       case '5':
00225       case 'J':
00226       case 'K':
00227       case 'L':
00228          digit = '5';
00229          break;
00230       case '6':
00231       case 'M':
00232       case 'N':
00233       case 'O':
00234          digit = '6';
00235          break;
00236       case '7':
00237       case 'P':
00238       case 'Q':
00239       case 'R':
00240       case 'S':
00241          digit = '7';
00242          break;
00243       case '8':
00244       case 'T':
00245       case 'U':
00246       case 'V':
00247          digit = '8';
00248          break;
00249       case '9':
00250       case 'W':
00251       case 'X':
00252       case 'Y':
00253       case 'Z':
00254          digit = '9';
00255          break;
00256 
00257       default:
00258          if (digit > ' ')
00259             return -1;
00260          continue;
00261       }
00262 
00263       if (*template++ != digit)
00264          return -1;
00265    }
00266 
00267    return 0;
00268 }

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

Definition at line 836 of file app_directory.c.

References args, ast_answer(), AST_APP_ARG, ast_app_parse_options(), ast_check_hangup(), 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, digit, directory_app_options, do_directory(), LOG_ERROR, NULL, OPT_ARG_ARRAY_SIZE, OPT_ARG_EITHER, OPT_ARG_FIRSTNAME, OPT_ARG_LASTNAME, OPT_LISTBYFIRSTNAME, OPT_LISTBYLASTNAME, OPT_NOANSWER, parse(), pbx_builtin_setvar_helper(), and realtime_directory().

Referenced by load_module().

00837 {
00838    int res = 0, digit = 3;
00839    struct ast_config *cfg, *ucfg;
00840    const char *dirintro;
00841    char *parse, *opts[OPT_ARG_ARRAY_SIZE] = { 0, };
00842    struct ast_flags flags = { 0 };
00843    struct ast_flags config_flags = { 0 };
00844    enum { FIRST, LAST, BOTH } which = LAST;
00845    char digits[9] = "digits/3";
00846    AST_DECLARE_APP_ARGS(args,
00847       AST_APP_ARG(vmcontext);
00848       AST_APP_ARG(dialcontext);
00849       AST_APP_ARG(options);
00850    );
00851 
00852    parse = ast_strdupa(data);
00853 
00854    AST_STANDARD_APP_ARGS(args, parse);
00855 
00856    if (args.options && ast_app_parse_options(directory_app_options, &flags, opts, args.options))
00857       return -1;
00858 
00859    if (!(cfg = realtime_directory(args.vmcontext))) {
00860       ast_log(LOG_ERROR, "Unable to read the configuration data!\n");
00861       return -1;
00862    }
00863 
00864    if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) {
00865       ast_log(LOG_ERROR, "Config file users.conf is in an invalid format.  Aborting.\n");
00866       ucfg = NULL;
00867    }
00868 
00869    dirintro = ast_variable_retrieve(cfg, args.vmcontext, "directoryintro");
00870    if (ast_strlen_zero(dirintro))
00871       dirintro = ast_variable_retrieve(cfg, "general", "directoryintro");
00872    /* the above prompts probably should be modified to include 0 for dialing operator
00873       and # for exiting (continues in dialplan) */
00874 
00875    if (ast_test_flag(&flags, OPT_LISTBYFIRSTNAME) && ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
00876       if (!ast_strlen_zero(opts[OPT_ARG_EITHER])) {
00877          digit = atoi(opts[OPT_ARG_EITHER]);
00878       }
00879       which = BOTH;
00880    } else if (ast_test_flag(&flags, OPT_LISTBYFIRSTNAME)) {
00881       if (!ast_strlen_zero(opts[OPT_ARG_FIRSTNAME])) {
00882          digit = atoi(opts[OPT_ARG_FIRSTNAME]);
00883       }
00884       which = FIRST;
00885    } else {
00886       if (!ast_strlen_zero(opts[OPT_ARG_LASTNAME])) {
00887          digit = atoi(opts[OPT_ARG_LASTNAME]);
00888       }
00889       which = LAST;
00890    }
00891 
00892    /* If no options specified, search by last name */
00893    if (!ast_test_flag(&flags, OPT_LISTBYFIRSTNAME) && !ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
00894       ast_set_flag(&flags, OPT_LISTBYLASTNAME);
00895       which = LAST;
00896    }
00897 
00898    if (digit > 9) {
00899       digit = 9;
00900    } else if (digit < 1) {
00901       digit = 3;
00902    }
00903    digits[7] = digit + '0';
00904 
00905    if (ast_channel_state(chan) != AST_STATE_UP) {
00906       if (!ast_test_flag(&flags, OPT_NOANSWER)) {
00907          /* Otherwise answer unless we're supposed to read while on-hook */
00908          res = ast_answer(chan);
00909       }
00910    }
00911    for (;;) {
00912       if (!ast_strlen_zero(dirintro) && !res) {
00913          res = ast_stream_and_wait(chan, dirintro, AST_DIGIT_ANY);
00914       } else if (!res) {
00915          /* Stop playing sounds as soon as we have a digit. */
00916          res = ast_stream_and_wait(chan, "dir-welcome", AST_DIGIT_ANY);
00917          if (!res) {
00918             res = ast_stream_and_wait(chan, "dir-pls-enter", AST_DIGIT_ANY);
00919          }
00920          if (!res) {
00921             res = ast_stream_and_wait(chan, digits, AST_DIGIT_ANY);
00922          }
00923          if (!res) {
00924             res = ast_stream_and_wait(chan, 
00925                which == FIRST ? "dir-first" :
00926                which == LAST ? "dir-last" :
00927                "dir-firstlast", AST_DIGIT_ANY);
00928          }
00929          if (!res) {
00930             res = ast_stream_and_wait(chan, "dir-usingkeypad", AST_DIGIT_ANY);
00931          }
00932       }
00933       ast_stopstream(chan);
00934       if (!res)
00935          res = ast_waitfordigit(chan, 5000);
00936 
00937       if (res <= 0) {
00938          if (res == 0) {
00939             pbx_builtin_setvar_helper(chan, "DIRECTORY_RESULT", "TIMEOUT");
00940          }
00941          break;
00942       }
00943 
00944       res = do_directory(chan, cfg, ucfg, args.vmcontext, args.dialcontext, res, digit, &flags, opts);
00945       if (res)
00946          break;
00947 
00948       res = ast_waitstream(chan, AST_DIGIT_ANY);
00949       ast_stopstream(chan);
00950       if (res < 0) {
00951          break;
00952       }
00953    }
00954 
00955    if (ucfg)
00956       ast_config_destroy(ucfg);
00957    ast_config_destroy(cfg);
00958 
00959    if (ast_check_hangup(chan)) {
00960       pbx_builtin_setvar_helper(chan, "DIRECTORY_RESULT", "HANGUP");
00961    } else if (res < 0) {
00962       /* If the res < 0 and we didn't hangup, an unaccounted for error must have happened. */
00963       pbx_builtin_setvar_helper(chan, "DIRECTORY_RESULT", "FAILED");
00964    }
00965 
00966    return res < 0 ? -1 : 0;
00967 }

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

References ast_calloc, ast_channel_language(), ast_debug, ast_free, AST_LIST_HEAD_NOLOCK_INIT_VALUE, AST_LIST_REMOVE_HEAD, AST_LIST_TRAVERSE, ast_readstring(), ast_streamfile(), ast_test_flag, ext, directory_item::exten, goto_exten(), item, directory_item::name, NULL, OPT_SELECTFROMMENU, option_debug, pbx_builtin_setvar_helper(), search_directory(), select_item_menu(), select_item_seq(), and sort_items().

Referenced by directory_exec().

00758 {
00759    /* Read in the first three digits..  "digit" is the first digit, already read */
00760    int res = 0;
00761    itemlist alist = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
00762    struct directory_item *item, **ptr, **sorted = NULL;
00763    int count, i;
00764    char ext[10] = "";
00765 
00766    if (digit == '0' && !goto_exten(chan, dialcontext, "o")) {
00767       pbx_builtin_setvar_helper(chan, "DIRECTORY_RESULT", "OPERATOR");
00768       return digit;
00769    }
00770 
00771    if (digit == '*' && !goto_exten(chan, dialcontext, "a")) {
00772       pbx_builtin_setvar_helper(chan, "DIRECTORY_RESULT", "ASSISTANT");
00773       return digit;
00774    }
00775 
00776    ext[0] = digit;
00777    if (ast_readstring(chan, ext + 1, digits - 1, 3000, 3000, "#") < 0)
00778       return -1;
00779 
00780    res = search_directory(context, vmcfg, ucfg, ext, *flags, &alist);
00781    if (res)
00782       goto exit;
00783 
00784    /* Count items in the list */
00785    count = 0;
00786    AST_LIST_TRAVERSE(&alist, item, entry) {
00787       count++;
00788    }
00789 
00790    if (count < 1) {
00791       res = ast_streamfile(chan, "dir-nomatch", ast_channel_language(chan));
00792       goto exit;
00793    }
00794 
00795 
00796    /* Create plain array of pointers to items (for sorting) */
00797    sorted = ast_calloc(count, sizeof(*sorted));
00798 
00799    ptr = sorted;
00800    AST_LIST_TRAVERSE(&alist, item, entry) {
00801       *ptr++ = item;
00802    }
00803 
00804    /* Sort items */
00805    sort_items(sorted, count);
00806 
00807    if (option_debug) {
00808       ast_debug(2, "Listing matching entries:\n");
00809       for (ptr = sorted, i = 0; i < count; i++, ptr++) {
00810          ast_debug(2, "%s: %s\n", ptr[0]->exten, ptr[0]->name);
00811       }
00812    }
00813 
00814    if (ast_test_flag(flags, OPT_SELECTFROMMENU)) {
00815       /* Offer multiple entries at the same time */
00816       res = select_item_menu(chan, sorted, count, dialcontext, flags, opts);
00817    } else {
00818       /* Offer entries one by one */
00819       res = select_item_seq(chan, sorted, count, dialcontext, flags, opts);
00820    }
00821 
00822    if (!res) {
00823       res = ast_streamfile(chan, "dir-nomore", ast_channel_language(chan));
00824    }
00825 
00826 exit:
00827    if (sorted)
00828       ast_free(sorted);
00829 
00830    while ((item = AST_LIST_REMOVE_HEAD(&alist, entry)))
00831       ast_free(item);
00832 
00833    return res;
00834 }

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

Definition at line 270 of file app_directory.c.

References ast_channel_context(), ast_channel_macrocontext(), ast_goto_if_exists(), ast_log, ast_strlen_zero, LOG_WARNING, and S_OR.

Referenced by do_directory(), and select_item_seq().

00271 {
00272    if (!ast_goto_if_exists(chan, S_OR(dialcontext, ast_channel_context(chan)), ext, 1) ||
00273       (!ast_strlen_zero(ast_channel_macrocontext(chan)) &&
00274       !ast_goto_if_exists(chan, ast_channel_macrocontext(chan), ext, 1))) {
00275       return 0;
00276    } else {
00277       ast_log(LOG_WARNING, "Can't find extension '%s' in current context.  "
00278          "Not Exiting the Directory!\n", ext);
00279       return -1;
00280    }
00281 }

static int load_module ( void   )  [static]

Definition at line 976 of file app_directory.c.

References ast_register_application_xml, and directory_exec().

00977 {
00978    return ast_register_application_xml(app, directory_exec);
00979 }

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

References ast_alloca, ast_app_sayname(), ast_channel_language(), AST_DIGIT_ANY, AST_SAY_CASE_NONE, ast_say_character_str(), ast_stopstream(), ast_stream_and_wait(), ast_strlen_zero, ast_test_flag, OPT_SAYEXTENSION, and S_OR.

Referenced by select_item_menu(), and select_item_seq().

00290 {
00291    int res = 0;
00292    char *mailbox_id;
00293 
00294    mailbox_id = ast_alloca(strlen(ext) + strlen(context) + 2);
00295    sprintf(mailbox_id, "%s@%s", ext, context); /* Safe */
00296 
00297    res = ast_app_sayname(chan, mailbox_id);
00298    if (res >= 0) {
00299       ast_stopstream(chan);
00300       /* If Option 'e' was specified, also read the extension number with the name */
00301       if (ast_test_flag(flags, OPT_SAYEXTENSION)) {
00302          ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
00303          res = ast_say_character_str(chan, ext, AST_DIGIT_ANY, ast_channel_language(chan), AST_SAY_CASE_NONE);
00304       }
00305    } else {
00306       res = ast_say_character_str(chan, S_OR(name, ext), AST_DIGIT_ANY, ast_channel_language(chan), AST_SAY_CASE_NONE);
00307       if (!ast_strlen_zero(name) && ast_test_flag(flags, OPT_SAYEXTENSION)) {
00308          ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
00309          res = ast_say_character_str(chan, ext, AST_DIGIT_ANY, ast_channel_language(chan), AST_SAY_CASE_NONE);
00310       }
00311    }
00312 
00313    return res;
00314 }

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

Definition at line 463 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_str_append(), ast_str_buffer(), ast_str_set(), ast_str_thread_get(), ast_strlen_zero, ast_true(), ast_variable_append(), ast_variable_browse(), ast_variable_new(), ast_variable_retrieve(), CONFIG_STATUS_FILEINVALID, LOG_ERROR, LOG_WARNING, mailbox, ast_variable::name, ast_variable::next, NULL, S_OR, SENTINEL, tmp(), ast_variable::value, var, and VOICEMAIL_CONFIG.

Referenced by directory_exec().

00464 {
00465    struct ast_config *cfg;
00466    struct ast_config *rtdata = NULL;
00467    struct ast_category *cat;
00468    struct ast_variable *var;
00469    char *mailbox;
00470    const char *fullname;
00471    const char *hidefromdir, *searchcontexts = NULL;
00472    struct ast_flags config_flags = { 0 };
00473    struct ast_str *tmp = ast_str_thread_get(&commonbuf, 100);
00474 
00475    if (!tmp) {
00476       return NULL;
00477    }
00478 
00479    /* Load flat file config. */
00480    cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags);
00481 
00482    if (!cfg) {
00483       /* Loading config failed. */
00484       ast_log(LOG_WARNING, "Loading config failed.\n");
00485       return NULL;
00486    } else if (cfg == CONFIG_STATUS_FILEINVALID) {
00487       ast_log(LOG_ERROR, "Config file %s is in an invalid format.  Aborting.\n", VOICEMAIL_CONFIG);
00488       return NULL;
00489    }
00490 
00491    /* Get realtime entries, categorized by their mailbox number
00492       and present in the requested context */
00493    if (ast_strlen_zero(context) && (searchcontexts = ast_variable_retrieve(cfg, "general", "searchcontexts"))) {
00494       if (ast_true(searchcontexts)) {
00495          rtdata = ast_load_realtime_multientry("voicemail", "mailbox LIKE", "%", SENTINEL);
00496          context = NULL;
00497       } else {
00498          rtdata = ast_load_realtime_multientry("voicemail", "mailbox LIKE", "%", "context", "default", SENTINEL);
00499          context = "default";
00500       }
00501    } else if (!ast_strlen_zero(context)) {
00502       rtdata = ast_load_realtime_multientry("voicemail", "mailbox LIKE", "%", "context", context, SENTINEL);
00503    }
00504 
00505    /* if there are no results, just return the entries from the config file */
00506    if (!rtdata) {
00507       return cfg;
00508    }
00509 
00510    mailbox = NULL;
00511    while ( (mailbox = ast_category_browse(rtdata, mailbox)) ) {
00512       struct ast_variable *alias;
00513       const char *ctx = ast_variable_retrieve(rtdata, mailbox, "context");
00514 
00515       fullname = ast_variable_retrieve(rtdata, mailbox, "fullname");
00516       hidefromdir = ast_variable_retrieve(rtdata, mailbox, "hidefromdir");
00517       if (ast_true(hidefromdir)) {
00518          /* Skip hidden */
00519          continue;
00520       }
00521       ast_str_set(&tmp, 0, "no-password,%s", S_OR(fullname, ""));
00522       if (ast_variable_retrieve(rtdata, mailbox, "alias")) {
00523          for (alias = ast_variable_browse(rtdata, mailbox); alias; alias = alias->next) {
00524             if (!strcasecmp(alias->name, "alias")) {
00525                ast_str_append(&tmp, 0, "|alias=%s", alias->value);
00526             }
00527          }
00528       }
00529 
00530       /* Does the context exist within the config file? If not, make one */
00531       if (!(cat = ast_category_get(cfg, ctx, NULL))) {
00532          if (!(cat = ast_category_new(ctx, "", 99999))) {
00533             ast_log(LOG_WARNING, "Out of memory\n");
00534             ast_config_destroy(cfg);
00535             if (rtdata) {
00536                ast_config_destroy(rtdata);
00537             }
00538             return NULL;
00539          }
00540          ast_category_append(cfg, cat);
00541       }
00542 
00543       if ((var = ast_variable_new(mailbox, ast_str_buffer(tmp), ""))) {
00544          ast_variable_append(cat, var);
00545       } else {
00546          ast_log(LOG_WARNING, "Out of memory adding mailbox '%s'\n", mailbox);
00547       }
00548    }
00549    ast_config_destroy(rtdata);
00550 
00551    return cfg;
00552 }

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

References ast_category_browse(), ast_debug, ast_strlen_zero, ast_true(), ast_variable_retrieve(), NULL, and search_directory_sub().

Referenced by do_directory().

00707 {
00708    const char *searchcontexts = ast_variable_retrieve(vmcfg, "general", "searchcontexts");
00709    if (ast_strlen_zero(context)) {
00710       if (!ast_strlen_zero(searchcontexts) && ast_true(searchcontexts)) {
00711          /* Browse each context for a match */
00712          int res;
00713          const char *catg;
00714          for (catg = ast_category_browse(vmcfg, NULL); catg; catg = ast_category_browse(vmcfg, catg)) {
00715             if (!strcmp(catg, "general") || !strcmp(catg, "zonemessages")) {
00716                continue;
00717             }
00718 
00719             if ((res = search_directory_sub(catg, vmcfg, ucfg, ext, flags, alist))) {
00720                return res;
00721             }
00722          }
00723          return 0;
00724       } else {
00725          ast_debug(1, "Searching by category default\n");
00726          return search_directory_sub("default", vmcfg, ucfg, ext, flags, alist);
00727       }
00728    } else {
00729       /* Browse only the listed context for a match */
00730       ast_debug(1, "Searching by category %s\n", context);
00731       return search_directory_sub(context, vmcfg, ucfg, ext, flags, alist);
00732    }
00733 }

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

References a, ast_category_browse(), ast_config_option(), ast_debug, AST_LIST_INSERT_TAIL, ast_str_buffer(), ast_str_set(), ast_str_thread_get(), ast_strlen_zero, ast_test_flag, ast_true(), ast_variable_browse(), ast_variable_retrieve(), buf, check_match(), item, ast_variable::name, ast_variable::next, NULL, OPT_ALIAS, OPT_LISTBYFIRSTNAME, OPT_LISTBYLASTNAME, strcasestr(), strsep(), and ast_variable::value.

Referenced by search_directory().

00602 {
00603    struct ast_variable *v;
00604    struct ast_str *buf = ast_str_thread_get(&commonbuf, 100);
00605    char *pos, *bufptr, *cat, *alias;
00606    struct directory_item *item;
00607    int res;
00608 
00609    if (!buf) {
00610       return -1;
00611    }
00612 
00613    ast_debug(2, "Pattern: %s\n", ext);
00614 
00615    for (v = ast_variable_browse(vmcfg, context); v; v = v->next) {
00616 
00617       /* Ignore hidden */
00618       if (strcasestr(v->value, "hidefromdir=yes")) {
00619          continue;
00620       }
00621 
00622       ast_str_set(&buf, 0, "%s", v->value);
00623       bufptr = ast_str_buffer(buf);
00624 
00625       /* password,Full Name,email,pager,options */
00626       strsep(&bufptr, ",");
00627       pos = strsep(&bufptr, ",");
00628 
00629       /* No name to compare against */
00630       if (ast_strlen_zero(pos)) {
00631          continue;
00632       }
00633 
00634       res = 0;
00635       if (ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
00636          res = check_match(&item, context, pos, v->name, ext, 0 /* use_first_name */);
00637       }
00638       if (!res && ast_test_flag(&flags, OPT_LISTBYFIRSTNAME)) {
00639          res = check_match(&item, context, pos, v->name, ext, 1 /* use_first_name */);
00640       }
00641       if (!res && ast_test_flag(&flags, OPT_ALIAS) && (alias = strcasestr(bufptr, "alias="))) {
00642          char *a;
00643          ast_debug(1, "Found alias: %s\n", alias);
00644          while ((a = strsep(&alias, "|"))) {
00645             if (!strncasecmp(a, "alias=", 6)) {
00646                if ((res = check_match(&item, context, a + 6, v->name, ext, 1))) {
00647                   break;
00648                }
00649             }
00650          }
00651       }
00652 
00653       if (!res) {
00654          continue;
00655       } else if (res < 0) {
00656          return -1;
00657       }
00658 
00659       AST_LIST_INSERT_TAIL(alist, item, entry);
00660    }
00661 
00662    if (ucfg) {
00663       for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
00664          const char *position;
00665 
00666          if (!strcasecmp(cat, "general")) {
00667             continue;
00668          }
00669          if (!ast_true(ast_config_option(ucfg, cat, "hasdirectory"))) {
00670             continue;
00671          }
00672 
00673          /* Find all candidate extensions */
00674          if (!(position = ast_variable_retrieve(ucfg, cat, "fullname"))) {
00675             continue;
00676          }
00677 
00678          res = 0;
00679          if (ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
00680             res = check_match(&item, context, position, cat, ext, 0 /* use_first_name */);
00681          }
00682          if (!res && ast_test_flag(&flags, OPT_LISTBYFIRSTNAME)) {
00683             res = check_match(&item, context, position, cat, ext, 1 /* use_first_name */);
00684          }
00685          if (!res && ast_test_flag(&flags, OPT_ALIAS)) {
00686             struct ast_variable *alias;
00687             for (alias = ast_variable_browse(ucfg, cat); alias; alias = alias->next) {
00688                if (!strcasecmp(v->name, "alias") && (res = check_match(&item, context, v->value, cat, ext, 1))) {
00689                   break;
00690                }
00691             }
00692          }
00693 
00694          if (!res) {
00695             continue;
00696          } else if (res < 0) {
00697             return -1;
00698          }
00699 
00700          AST_LIST_INSERT_TAIL(alist, item, entry);
00701       }
00702    }
00703    return 0;
00704 }

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

Definition at line 316 of file app_directory.c.

References ast_channel_exten_set(), ast_debug, ast_goto_if_exists(), ast_log, ast_test_flag, directory_item::context, directory_item::exten, LOG_WARNING, directory_item::name, OPT_FROMVOICEMAIL, pbx_builtin_setvar_helper(), and S_OR.

Referenced by select_item_menu(), and select_item_seq().

00317 {
00318    ast_debug(1, "Selecting '%s' - %s@%s\n", item->name, item->exten, S_OR(dialcontext, item->context));
00319 
00320    if (ast_test_flag(flags, OPT_FROMVOICEMAIL)) {
00321       /* We still want to set the exten though */
00322       ast_channel_exten_set(chan, item->exten);
00323    } else if (ast_goto_if_exists(chan, S_OR(dialcontext, item->context), item->exten, 1)) {
00324       ast_log(LOG_WARNING,
00325          "Can't find extension '%s' in context '%s'.  "
00326          "Did you pass the wrong context to Directory?\n",
00327          item->exten, S_OR(dialcontext, item->context));
00328       return -1;
00329    }
00330 
00331    pbx_builtin_setvar_helper(chan, "DIRECTORY_RESULT", "SELECTED");
00332    return 0;
00333 }

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

References ast_channel_language(), AST_DIGIT_ANY, ast_streamfile(), ast_waitfordigit(), ast_waitstream(), buf, directory_item::context, directory_item::exten, item, directory_item::name, pbx_builtin_setvar_helper(), play_mailbox_owner(), select_entry(), and select_item_pause().

Referenced by do_directory().

00398 {
00399    struct directory_item **block, *item;
00400    int i, limit, res = 0;
00401    char buf[9];
00402 
00403    /* option p(n): cellphone pause option */
00404    select_item_pause(chan, flags, opts);
00405 
00406    for (block = items; count; block += limit, count -= limit) {
00407       limit = count;
00408       if (limit > 8)
00409          limit = 8;
00410 
00411       for (i = 0; i < limit && !res; i++) {
00412          item = block[i];
00413 
00414          snprintf(buf, sizeof(buf), "digits/%d", i + 1);
00415          /* Press <num> for <name>, [ extension <ext> ] */
00416          res = ast_streamfile(chan, "dir-multi1", ast_channel_language(chan));
00417          if (!res)
00418             res = ast_waitstream(chan, AST_DIGIT_ANY);
00419          if (!res)
00420             res = ast_streamfile(chan, buf, ast_channel_language(chan));
00421          if (!res)
00422             res = ast_waitstream(chan, AST_DIGIT_ANY);
00423          if (!res)
00424             res = ast_streamfile(chan, "dir-multi2", ast_channel_language(chan));
00425          if (!res)
00426             res = ast_waitstream(chan, AST_DIGIT_ANY);
00427          if (!res)
00428             res = play_mailbox_owner(chan, item->context, item->exten, item->name, flags);
00429          if (!res)
00430             res = ast_waitstream(chan, AST_DIGIT_ANY);
00431          if (!res)
00432             res = ast_waitfordigit(chan, 800);
00433       }
00434 
00435       /* Press "9" for more names. */
00436       if (!res && count > limit) {
00437          res = ast_streamfile(chan, "dir-multi9", ast_channel_language(chan));
00438          if (!res)
00439             res = ast_waitstream(chan, AST_DIGIT_ANY);
00440       }
00441 
00442       if (!res) {
00443          res = ast_waitfordigit(chan, 3000);
00444       }
00445 
00446       if (res && res > '0' && res < '1' + limit) {
00447          pbx_builtin_setvar_helper(chan, "DIRECTORY_RESULT", "SELECTED");
00448          return select_entry(chan, dialcontext, block[res - '1'], flags) ? -1 : 1;
00449       }
00450 
00451       if (res < 0)
00452          return -1;
00453 
00454       res = 0;
00455    }
00456 
00457    /* Nothing was selected */
00458    return 0;
00459 }

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

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

00336 {
00337    int res = 0, opt_pause = 0;
00338 
00339    if (ast_test_flag(flags, OPT_PAUSE) && !ast_strlen_zero(opts[OPT_ARG_PAUSE])) {
00340       opt_pause = atoi(opts[OPT_ARG_PAUSE]);
00341       if (opt_pause > 3000) {
00342          opt_pause = 3000;
00343       }
00344       res = ast_waitfordigit(chan, opt_pause);
00345    }
00346    return res;
00347 }

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 349 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(), item, directory_item::name, pbx_builtin_setvar_helper(), play_mailbox_owner(), select_entry(), and select_item_pause().

Referenced by do_directory().

00350 {
00351    struct directory_item *item, **ptr;
00352    int i, res, loop;
00353 
00354    /* option p(n): cellphone pause option */
00355    /* allow early press of selection key */
00356    res = select_item_pause(chan, flags, opts);
00357 
00358    for (ptr = items, i = 0; i < count; i++, ptr++) {
00359       item = *ptr;
00360 
00361       for (loop = 3 ; loop > 0; loop--) {
00362          if (!res)
00363             res = play_mailbox_owner(chan, item->context, item->exten, item->name, flags);
00364          if (!res)
00365             res = ast_stream_and_wait(chan, "dir-instr", AST_DIGIT_ANY);
00366          if (!res)
00367             res = ast_waitfordigit(chan, 3000);
00368          ast_stopstream(chan);
00369    
00370          if (res == '0') { /* operator selected */
00371             goto_exten(chan, dialcontext, "o");
00372             pbx_builtin_setvar_helper(chan, "DIRECTORY_RESULT", "OPERATOR");
00373             return '0';
00374          } else if (res == '1') { /* Name selected */
00375             return select_entry(chan, dialcontext, item, flags) ? -1 : 1;
00376          } else if (res == '*') {
00377             /* Skip to next match in list */
00378             break;
00379          } else if (res == '#') {
00380             /* Exit reading, continue in dialplan */
00381             pbx_builtin_setvar_helper(chan, "DIRECTORY_RESULT", "USEREXIT");
00382             return res;
00383          }
00384 
00385          if (res < 0)
00386             return -1;
00387 
00388          res = 0;
00389       }
00390       res = 0;
00391    }
00392 
00393    /* Nothing was selected */
00394    return 0;
00395 }

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

Definition at line 735 of file app_directory.c.

References directory_item::key, and tmp().

Referenced by do_directory().

00736 {
00737    int reordered, i;
00738    struct directory_item **ptr, *tmp;
00739 
00740    if (count < 2)
00741       return;
00742 
00743    /* Bubble-sort items by the key */
00744    do {
00745       reordered = 0;
00746       for (ptr = sorted, i = 0; i < count - 1; i++, ptr++) {
00747          if (strcasecmp(ptr[0]->key, ptr[1]->key) > 0) {
00748             tmp = ptr[0];
00749             ptr[0] = ptr[1];
00750             ptr[1] = tmp;
00751             reordered++;
00752          }
00753       }
00754    } while (reordered);
00755 }

static int unload_module ( void   )  [static]

Definition at line 969 of file app_directory.c.

References ast_unregister_application().

00970 {
00971    int res;
00972    res = ast_unregister_application(app);
00973    return res;
00974 }


Variable Documentation

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, .support_level = AST_MODULE_SUPPORT_CORE, } [static]

Definition at line 981 of file app_directory.c.

const char app[] = "Directory" [static]

Definition at line 141 of file app_directory.c.

Definition at line 981 of file app_directory.c.

struct ast_threadstorage commonbuf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_commonbuf , .custom_init = NULL , } [static]

Definition at line 461 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 }, [ 'a' ] = { .flag = OPT_ALIAS },} [static]

Definition at line 188 of file app_directory.c.

Referenced by directory_exec().


Generated on Thu Apr 16 06:28:25 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6