Mon Oct 8 12:39:07 2012

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), 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_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 = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, }
static const char app [] = "Directory"
static struct ast_module_infoast_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 },}


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 127 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 

Definition at line 129 of file app_directory.c.

00129      {
00130    OPT_LISTBYFIRSTNAME = (1 << 0),
00131    OPT_SAYEXTENSION =    (1 << 1),
00132    OPT_FROMVOICEMAIL =   (1 << 2),
00133    OPT_SELECTFROMMENU =  (1 << 3),
00134    OPT_LISTBYLASTNAME =  (1 << 4),
00135    OPT_LISTBYEITHER =    OPT_LISTBYFIRSTNAME | OPT_LISTBYLASTNAME,
00136    OPT_PAUSE =           (1 << 5),
00137    OPT_NOANSWER =        (1 << 6),
00138 };

anonymous enum

Enumerator:
OPT_ARG_FIRSTNAME 
OPT_ARG_LASTNAME 
OPT_ARG_EITHER 
OPT_ARG_PAUSE 
OPT_ARG_ARRAY_SIZE 

Definition at line 140 of file app_directory.c.

00140      {
00141    OPT_ARG_FIRSTNAME =   0,
00142    OPT_ARG_LASTNAME =    1,
00143    OPT_ARG_EITHER =      2,
00144    OPT_ARG_PAUSE =       3,
00145    /* This *must* be the last value in this enum! */
00146    OPT_ARG_ARRAY_SIZE =  4,
00147 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 893 of file app_directory.c.

static void __unreg_module ( void   )  [static]

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

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

Referenced by search_directory_sub().

00510 {
00511    struct directory_item *item;
00512    const char *key = NULL;
00513    int namelen;
00514 
00515    if (ast_strlen_zero(item_fullname)) {
00516       return 0;
00517    }
00518 
00519    /* Set key to last name or first name depending on search mode */
00520    if (!use_first_name)
00521       key = strchr(item_fullname, ' ');
00522 
00523    if (key)
00524       key++;
00525    else
00526       key = item_fullname;
00527 
00528    if (compare(key, pattern_ext))
00529       return 0;
00530 
00531    ast_debug(1, "Found match %s@%s\n", item_ext, item_context);
00532 
00533    /* Match */
00534    item = ast_calloc(1, sizeof(*item));
00535    if (!item)
00536       return -1;
00537    ast_copy_string(item->context, item_context, sizeof(item->context));
00538    ast_copy_string(item->name, item_fullname, sizeof(item->name));
00539    ast_copy_string(item->exten, item_ext, sizeof(item->exten));
00540 
00541    ast_copy_string(item->key, key, sizeof(item->key));
00542    if (key != item_fullname) {
00543       /* Key is the last name. Append first name to key in order to sort Last,First */
00544       namelen = key - item_fullname - 1;
00545       if (namelen > sizeof(item->key) - strlen(item->key) - 1)
00546          namelen = sizeof(item->key) - strlen(item->key) - 1;
00547       strncat(item->key, item_fullname, namelen);
00548    }
00549 
00550    *result = item;
00551    return 1;
00552 }

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().

00170 {
00171    char digit;
00172 
00173    if (ast_strlen_zero(text)) {
00174       return -1;
00175    }
00176 
00177    while (*template) {
00178       digit = toupper(*text++);
00179       switch (digit) {
00180       case 0:
00181          return -1;
00182       case '1':
00183          digit = '1';
00184          break;
00185       case '2':
00186       case 'A':
00187       case 'B':
00188       case 'C':
00189          digit = '2';
00190          break;
00191       case '3':
00192       case 'D':
00193       case 'E':
00194       case 'F':
00195          digit = '3';
00196          break;
00197       case '4':
00198       case 'G':
00199       case 'H':
00200       case 'I':
00201          digit = '4';
00202          break;
00203       case '5':
00204       case 'J':
00205       case 'K':
00206       case 'L':
00207          digit = '5';
00208          break;
00209       case '6':
00210       case 'M':
00211       case 'N':
00212       case 'O':
00213          digit = '6';
00214          break;
00215       case '7':
00216       case 'P':
00217       case 'Q':
00218       case 'R':
00219       case 'S':
00220          digit = '7';
00221          break;
00222       case '8':
00223       case 'T':
00224       case 'U':
00225       case 'V':
00226          digit = '8';
00227          break;
00228       case '9':
00229       case 'W':
00230       case 'X':
00231       case 'Y':
00232       case 'Z':
00233          digit = '9';
00234          break;
00235 
00236       default:
00237          if (digit > ' ')
00238             return -1;
00239          continue;
00240       }
00241 
00242       if (*template++ != digit)
00243          return -1;
00244    }
00245 
00246    return 0;
00247 }

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

Definition at line 759 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(), ast_flags::flags, 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().

00760 {
00761    int res = 0, digit = 3;
00762    struct ast_config *cfg, *ucfg;
00763    const char *dirintro;
00764    char *parse, *opts[OPT_ARG_ARRAY_SIZE] = { 0, };
00765    struct ast_flags flags = { 0 };
00766    struct ast_flags config_flags = { 0 };
00767    enum { FIRST, LAST, BOTH } which = LAST;
00768    char digits[9] = "digits/3";
00769    AST_DECLARE_APP_ARGS(args,
00770       AST_APP_ARG(vmcontext);
00771       AST_APP_ARG(dialcontext);
00772       AST_APP_ARG(options);
00773    );
00774 
00775    parse = ast_strdupa(data);
00776 
00777    AST_STANDARD_APP_ARGS(args, parse);
00778 
00779    if (args.options && ast_app_parse_options(directory_app_options, &flags, opts, args.options))
00780       return -1;
00781 
00782    if (!(cfg = realtime_directory(args.vmcontext))) {
00783       ast_log(LOG_ERROR, "Unable to read the configuration data!\n");
00784       return -1;
00785    }
00786 
00787    if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) {
00788       ast_log(LOG_ERROR, "Config file users.conf is in an invalid format.  Aborting.\n");
00789       ucfg = NULL;
00790    }
00791 
00792    dirintro = ast_variable_retrieve(cfg, args.vmcontext, "directoryintro");
00793    if (ast_strlen_zero(dirintro))
00794       dirintro = ast_variable_retrieve(cfg, "general", "directoryintro");
00795    /* the above prompts probably should be modified to include 0 for dialing operator
00796       and # for exiting (continues in dialplan) */
00797 
00798    if (ast_test_flag(&flags, OPT_LISTBYFIRSTNAME) && ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
00799       if (!ast_strlen_zero(opts[OPT_ARG_EITHER])) {
00800          digit = atoi(opts[OPT_ARG_EITHER]);
00801       }
00802       which = BOTH;
00803    } else if (ast_test_flag(&flags, OPT_LISTBYFIRSTNAME)) {
00804       if (!ast_strlen_zero(opts[OPT_ARG_FIRSTNAME])) {
00805          digit = atoi(opts[OPT_ARG_FIRSTNAME]);
00806       }
00807       which = FIRST;
00808    } else {
00809       if (!ast_strlen_zero(opts[OPT_ARG_LASTNAME])) {
00810          digit = atoi(opts[OPT_ARG_LASTNAME]);
00811       }
00812       which = LAST;
00813    }
00814 
00815    /* If no options specified, search by last name */
00816    if (!ast_test_flag(&flags, OPT_LISTBYFIRSTNAME) && !ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
00817       ast_set_flag(&flags, OPT_LISTBYLASTNAME);
00818       which = LAST;
00819    }
00820 
00821    if (digit > 9) {
00822       digit = 9;
00823    } else if (digit < 1) {
00824       digit = 3;
00825    }
00826    digits[7] = digit + '0';
00827 
00828    if (chan->_state != AST_STATE_UP) {
00829       if (!ast_test_flag(&flags, OPT_NOANSWER)) {
00830          /* Otherwise answer unless we're supposed to read while on-hook */
00831          res = ast_answer(chan);
00832       }
00833    }
00834    for (;;) {
00835       if (!ast_strlen_zero(dirintro) && !res) {
00836          res = ast_stream_and_wait(chan, dirintro, AST_DIGIT_ANY);
00837       } else if (!res) {
00838          /* Stop playing sounds as soon as we have a digit. */
00839          res = ast_stream_and_wait(chan, "dir-welcome", AST_DIGIT_ANY);
00840          if (!res) {
00841             res = ast_stream_and_wait(chan, "dir-pls-enter", AST_DIGIT_ANY);
00842          }
00843          if (!res) {
00844             res = ast_stream_and_wait(chan, digits, AST_DIGIT_ANY);
00845          }
00846          if (!res) {
00847             res = ast_stream_and_wait(chan, 
00848                which == FIRST ? "dir-first" :
00849                which == LAST ? "dir-last" :
00850                "dir-firstlast", AST_DIGIT_ANY);
00851          }
00852          if (!res) {
00853             res = ast_stream_and_wait(chan, "dir-usingkeypad", AST_DIGIT_ANY);
00854          }
00855       }
00856       ast_stopstream(chan);
00857       if (!res)
00858          res = ast_waitfordigit(chan, 5000);
00859 
00860       if (res <= 0)
00861          break;
00862 
00863       res = do_directory(chan, cfg, ucfg, args.vmcontext, args.dialcontext, res, digit, &flags, opts);
00864       if (res)
00865          break;
00866 
00867       res = ast_waitstream(chan, AST_DIGIT_ANY);
00868       ast_stopstream(chan);
00869 
00870       if (res)
00871          break;
00872    }
00873 
00874    if (ucfg)
00875       ast_config_destroy(ucfg);
00876    ast_config_destroy(cfg);
00877 
00878    return res < 0 ? -1 : 0;
00879 }

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 682 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().

00683 {
00684    /* Read in the first three digits..  "digit" is the first digit, already read */
00685    int res = 0;
00686    itemlist alist = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
00687    struct directory_item *item, **ptr, **sorted = NULL;
00688    int count, i;
00689    char ext[10] = "";
00690 
00691    if (digit == '0' && !goto_exten(chan, dialcontext, "o")) {
00692       return digit;
00693    }
00694 
00695    if (digit == '*' && !goto_exten(chan, dialcontext, "a")) {
00696       return digit;
00697    }
00698 
00699    ext[0] = digit;
00700    if (ast_readstring(chan, ext + 1, digits - 1, 3000, 3000, "#") < 0)
00701       return -1;
00702 
00703    res = search_directory(context, vmcfg, ucfg, ext, *flags, &alist);
00704    if (res)
00705       goto exit;
00706 
00707    /* Count items in the list */
00708    count = 0;
00709    AST_LIST_TRAVERSE(&alist, item, entry) {
00710       count++;
00711    }
00712 
00713    if (count < 1) {
00714       res = ast_streamfile(chan, "dir-nomatch", chan->language);
00715       goto exit;
00716    }
00717 
00718 
00719    /* Create plain array of pointers to items (for sorting) */
00720    sorted = ast_calloc(count, sizeof(*sorted));
00721 
00722    ptr = sorted;
00723    AST_LIST_TRAVERSE(&alist, item, entry) {
00724       *ptr++ = item;
00725    }
00726 
00727    /* Sort items */
00728    sort_items(sorted, count);
00729 
00730    if (option_debug) {
00731       ast_debug(2, "Listing matching entries:\n");
00732       for (ptr = sorted, i = 0; i < count; i++, ptr++) {
00733          ast_debug(2, "%s: %s\n", ptr[0]->exten, ptr[0]->name);
00734       }
00735    }
00736 
00737    if (ast_test_flag(flags, OPT_SELECTFROMMENU)) {
00738       /* Offer multiple entries at the same time */
00739       res = select_item_menu(chan, sorted, count, dialcontext, flags, opts);
00740    } else {
00741       /* Offer entries one by one */
00742       res = select_item_seq(chan, sorted, count, dialcontext, flags, opts);
00743    }
00744 
00745    if (!res) {
00746       res = ast_streamfile(chan, "dir-nomore", chan->language);
00747    }
00748 
00749 exit:
00750    if (sorted)
00751       ast_free(sorted);
00752 
00753    while ((item = AST_LIST_REMOVE_HEAD(&alist, entry)))
00754       ast_free(item);
00755 
00756    return res;
00757 }

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().

00250 {
00251    if (!ast_goto_if_exists(chan, S_OR(dialcontext, chan->context), ext, 1) ||
00252       (!ast_strlen_zero(chan->macrocontext) &&
00253       !ast_goto_if_exists(chan, chan->macrocontext, ext, 1))) {
00254       return 0;
00255    } else {
00256       ast_log(LOG_WARNING, "Can't find extension '%s' in current context.  "
00257          "Not Exiting the Directory!\n", ext);
00258       return -1;
00259    }
00260 }

static int load_module ( void   )  [static]

Definition at line 888 of file app_directory.c.

References ast_register_application_xml, and directory_exec().

00889 {
00890    return ast_register_application_xml(app, directory_exec);
00891 }

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().

00269 {
00270    int res = 0;
00271    if ((res = ast_app_sayname(chan, ext, context)) >= 0) {
00272       ast_stopstream(chan);
00273       /* If Option 'e' was specified, also read the extension number with the name */
00274       if (ast_test_flag(flags, OPT_SAYEXTENSION)) {
00275          ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
00276          res = ast_say_character_str(chan, ext, AST_DIGIT_ANY, chan->language);
00277       }
00278    } else {
00279       res = ast_say_character_str(chan, S_OR(name, ext), AST_DIGIT_ANY, chan->language);
00280       if (!ast_strlen_zero(name) && ast_test_flag(flags, OPT_SAYEXTENSION)) {
00281          ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
00282          res = ast_say_character_str(chan, ext, AST_DIGIT_ANY, chan->language);
00283       }
00284    }
00285 
00286    return res;
00287 }

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

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().

00431 {
00432    struct ast_config *cfg;
00433    struct ast_config *rtdata;
00434    struct ast_category *cat;
00435    struct ast_variable *var;
00436    char *mailbox;
00437    const char *fullname;
00438    const char *hidefromdir, *searchcontexts = NULL;
00439    char tmp[100];
00440    struct ast_flags config_flags = { 0 };
00441 
00442    /* Load flat file config. */
00443    cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags);
00444 
00445    if (!cfg) {
00446       /* Loading config failed. */
00447       ast_log(LOG_WARNING, "Loading config failed.\n");
00448       return NULL;
00449    } else if (cfg == CONFIG_STATUS_FILEINVALID) {
00450       ast_log(LOG_ERROR, "Config file %s is in an invalid format.  Aborting.\n", VOICEMAIL_CONFIG);
00451       return NULL;
00452    }
00453 
00454    /* Get realtime entries, categorized by their mailbox number
00455       and present in the requested context */
00456    if (ast_strlen_zero(context) && (searchcontexts = ast_variable_retrieve(cfg, "general", "searchcontexts"))) {
00457       if (ast_true(searchcontexts)) {
00458          rtdata = ast_load_realtime_multientry("voicemail", "mailbox LIKE", "%", SENTINEL);
00459          context = NULL;
00460       } else {
00461          rtdata = ast_load_realtime_multientry("voicemail", "mailbox LIKE", "%", "context", "default", SENTINEL);
00462          context = "default";
00463       }
00464    } else {
00465       rtdata = ast_load_realtime_multientry("voicemail", "mailbox LIKE", "%", "context", context, SENTINEL);
00466    }
00467 
00468    /* if there are no results, just return the entries from the config file */
00469    if (!rtdata) {
00470       return cfg;
00471    }
00472 
00473    mailbox = NULL;
00474    while ( (mailbox = ast_category_browse(rtdata, mailbox)) ) {
00475       const char *context = ast_variable_retrieve(rtdata, mailbox, "context");
00476 
00477       fullname = ast_variable_retrieve(rtdata, mailbox, "fullname");
00478       hidefromdir = ast_variable_retrieve(rtdata, mailbox, "hidefromdir");
00479       if (ast_true(hidefromdir)) {
00480          /* Skip hidden */
00481          continue;
00482       }
00483       snprintf(tmp, sizeof(tmp), "no-password,%s", S_OR(fullname, ""));
00484 
00485       /* Does the context exist within the config file? If not, make one */
00486       if (!(cat = ast_category_get(cfg, context))) {
00487          if (!(cat = ast_category_new(context, "", 99999))) {
00488             ast_log(LOG_WARNING, "Out of memory\n");
00489             ast_config_destroy(cfg);
00490             if (rtdata) {
00491                ast_config_destroy(rtdata);
00492             }
00493             return NULL;
00494          }
00495          ast_category_append(cfg, cat);
00496       }
00497 
00498       if ((var = ast_variable_new(mailbox, tmp, ""))) {
00499          ast_variable_append(cat, var);
00500       } else {
00501          ast_log(LOG_WARNING, "Out of memory adding mailbox '%s'\n", mailbox);
00502       }
00503    }
00504    ast_config_destroy(rtdata);
00505 
00506    return cfg;
00507 }

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 631 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().

00632 {
00633    const char *searchcontexts = ast_variable_retrieve(vmcfg, "general", "searchcontexts");
00634    if (ast_strlen_zero(context)) {
00635       if (!ast_strlen_zero(searchcontexts) && ast_true(searchcontexts)) {
00636          /* Browse each context for a match */
00637          int res;
00638          const char *catg;
00639          for (catg = ast_category_browse(vmcfg, NULL); catg; catg = ast_category_browse(vmcfg, catg)) {
00640             if (!strcmp(catg, "general") || !strcmp(catg, "zonemessages")) {
00641                continue;
00642             }
00643 
00644             if ((res = search_directory_sub(catg, vmcfg, ucfg, ext, flags, alist))) {
00645                return res;
00646             }
00647          }
00648          return 0;
00649       } else {
00650          ast_debug(1, "Searching by category default\n");
00651          return search_directory_sub("default", vmcfg, ucfg, ext, flags, alist);
00652       }
00653    } else {
00654       /* Browse only the listed context for a match */
00655       ast_debug(1, "Searching by category %s\n", context);
00656       return search_directory_sub(context, vmcfg, ucfg, ext, flags, alist);
00657    }
00658 }

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 556 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().

00557 {
00558    struct ast_variable *v;
00559    char buf[AST_MAX_EXTENSION + 1], *pos, *bufptr, *cat;
00560    struct directory_item *item;
00561    int res;
00562 
00563    ast_debug(2, "Pattern: %s\n", ext);
00564 
00565    for (v = ast_variable_browse(vmcfg, context); v; v = v->next) {
00566 
00567       /* Ignore hidden */
00568       if (strcasestr(v->value, "hidefromdir=yes"))
00569          continue;
00570 
00571       ast_copy_string(buf, v->value, sizeof(buf));
00572       bufptr = buf;
00573 
00574       /* password,Full Name,email,pager,options */
00575       strsep(&bufptr, ",");
00576       pos = strsep(&bufptr, ",");
00577 
00578       /* No name to compare against */
00579       if (ast_strlen_zero(pos)) {
00580          continue;
00581       }
00582 
00583       res = 0;
00584       if (ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
00585          res = check_match(&item, context, pos, v->name, ext, 0 /* use_first_name */);
00586       }
00587       if (!res && ast_test_flag(&flags, OPT_LISTBYFIRSTNAME)) {
00588          res = check_match(&item, context, pos, v->name, ext, 1 /* use_first_name */);
00589       }
00590 
00591       if (!res)
00592          continue;
00593       else if (res < 0)
00594          return -1;
00595 
00596       AST_LIST_INSERT_TAIL(alist, item, entry);
00597    }
00598 
00599    if (ucfg) {
00600       for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
00601          const char *position;
00602          if (!strcasecmp(cat, "general"))
00603             continue;
00604          if (!ast_true(ast_config_option(ucfg, cat, "hasdirectory")))
00605             continue;
00606 
00607          /* Find all candidate extensions */
00608          position = ast_variable_retrieve(ucfg, cat, "fullname");
00609          if (!position)
00610             continue;
00611 
00612          res = 0;
00613          if (ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
00614             res = check_match(&item, context, position, cat, ext, 0 /* use_first_name */);
00615          }
00616          if (!res && ast_test_flag(&flags, OPT_LISTBYFIRSTNAME)) {
00617             res = check_match(&item, context, position, cat, ext, 1 /* use_first_name */);
00618          }
00619 
00620          if (!res)
00621             continue;
00622          else if (res < 0)
00623             return -1;
00624 
00625          AST_LIST_INSERT_TAIL(alist, item, entry);
00626       }
00627    }
00628    return 0;
00629 }

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, ast_channel::exten, directory_item::exten, LOG_WARNING, directory_item::name, OPT_FROMVOICEMAIL, and S_OR.

Referenced by select_item_menu(), and select_item_seq().

00290 {
00291    ast_debug(1, "Selecting '%s' - %s@%s\n", item->name, item->exten, S_OR(dialcontext, item->context));
00292 
00293    if (ast_test_flag(flags, OPT_FROMVOICEMAIL)) {
00294       /* We still want to set the exten though */
00295       ast_copy_string(chan->exten, item->exten, sizeof(chan->exten));
00296    } else if (ast_goto_if_exists(chan, S_OR(dialcontext, item->context), item->exten, 1)) {
00297       ast_log(LOG_WARNING,
00298          "Can't find extension '%s' in context '%s'.  "
00299          "Did you pass the wrong context to Directory?\n",
00300          item->exten, S_OR(dialcontext, item->context));
00301       return -1;
00302    }
00303 
00304    return 0;
00305 }

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().

00368 {
00369    struct directory_item **block, *item;
00370    int i, limit, res = 0;
00371    char buf[9];
00372 
00373    /* option p(n): cellphone pause option */
00374    select_item_pause(chan, flags, opts);
00375 
00376    for (block = items; count; block += limit, count -= limit) {
00377       limit = count;
00378       if (limit > 8)
00379          limit = 8;
00380 
00381       for (i = 0; i < limit && !res; i++) {
00382          item = block[i];
00383 
00384          snprintf(buf, sizeof(buf), "digits/%d", i + 1);
00385          /* Press <num> for <name>, [ extension <ext> ] */
00386          res = ast_streamfile(chan, "dir-multi1", chan->language);
00387          if (!res)
00388             res = ast_waitstream(chan, AST_DIGIT_ANY);
00389          if (!res)
00390             res = ast_streamfile(chan, buf, chan->language);
00391          if (!res)
00392             res = ast_waitstream(chan, AST_DIGIT_ANY);
00393          if (!res)
00394             res = ast_streamfile(chan, "dir-multi2", chan->language);
00395          if (!res)
00396             res = ast_waitstream(chan, AST_DIGIT_ANY);
00397          if (!res)
00398             res = play_mailbox_owner(chan, item->context, item->exten, item->name, flags);
00399          if (!res)
00400             res = ast_waitstream(chan, AST_DIGIT_ANY);
00401          if (!res)
00402             res = ast_waitfordigit(chan, 800);
00403       }
00404 
00405       /* Press "9" for more names. */
00406       if (!res && count > limit) {
00407          res = ast_streamfile(chan, "dir-multi9", chan->language);
00408          if (!res)
00409             res = ast_waitstream(chan, AST_DIGIT_ANY);
00410       }
00411 
00412       if (!res) {
00413          res = ast_waitfordigit(chan, 3000);
00414       }
00415 
00416       if (res && res > '0' && res < '1' + limit) {
00417          return select_entry(chan, dialcontext, block[res - '1'], flags) ? -1 : 1;
00418       }
00419 
00420       if (res < 0)
00421          return -1;
00422 
00423       res = 0;
00424    }
00425 
00426    /* Nothing was selected */
00427    return 0;
00428 }

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().

00308 {
00309    int res = 0, opt_pause = 0;
00310 
00311    if (ast_test_flag(flags, OPT_PAUSE) && !ast_strlen_zero(opts[OPT_ARG_PAUSE])) {
00312       opt_pause = atoi(opts[OPT_ARG_PAUSE]);
00313       if (opt_pause > 3000) {
00314          opt_pause = 3000;
00315       }
00316       res = ast_waitfordigit(chan, opt_pause);
00317    }
00318    return res;
00319 }

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().

00322 {
00323    struct directory_item *item, **ptr;
00324    int i, res, loop;
00325 
00326    /* option p(n): cellphone pause option */
00327    /* allow early press of selection key */
00328    res = select_item_pause(chan, flags, opts);
00329 
00330    for (ptr = items, i = 0; i < count; i++, ptr++) {
00331       item = *ptr;
00332 
00333       for (loop = 3 ; loop > 0; loop--) {
00334          if (!res)
00335             res = play_mailbox_owner(chan, item->context, item->exten, item->name, flags);
00336          if (!res)
00337             res = ast_stream_and_wait(chan, "dir-instr", AST_DIGIT_ANY);
00338          if (!res)
00339             res = ast_waitfordigit(chan, 3000);
00340          ast_stopstream(chan);
00341    
00342          if (res == '0') { /* operator selected */
00343             goto_exten(chan, dialcontext, "o");
00344             return '0';
00345          } else if (res == '1') { /* Name selected */
00346             return select_entry(chan, dialcontext, item, flags) ? -1 : 1;
00347          } else if (res == '*') {
00348             /* Skip to next match in list */
00349             break;
00350          } else if (res == '#') {
00351             /* Exit reading, continue in dialplan */
00352             return res;
00353          }
00354 
00355          if (res < 0)
00356             return -1;
00357 
00358          res = 0;
00359       }
00360       res = 0;
00361    }
00362 
00363    /* Nothing was selected */
00364    return 0;
00365 }

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

Definition at line 660 of file app_directory.c.

References directory_item::key.

Referenced by do_directory().

00661 {
00662    int reordered, i;
00663    struct directory_item **ptr, *tmp;
00664 
00665    if (count < 2)
00666       return;
00667 
00668    /* Bubble-sort items by the key */
00669    do {
00670       reordered = 0;
00671       for (ptr = sorted, i = 0; i < count - 1; i++, ptr++) {
00672          if (strcasecmp(ptr[0]->key, ptr[1]->key) > 0) {
00673             tmp = ptr[0];
00674             ptr[0] = ptr[1];
00675             ptr[1] = tmp;
00676             reordered++;
00677          }
00678       }
00679    } while (reordered);
00680 }

static int unload_module ( void   )  [static]

Definition at line 881 of file app_directory.c.

References ast_unregister_application().

00882 {
00883    int res;
00884    res = ast_unregister_application(app);
00885    return res;
00886 }


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 = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, } [static]

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


Generated on Mon Oct 8 12:39:07 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7