Mon Jun 27 16:50:58 2011

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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .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 125 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 127 of file app_directory.c.

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

anonymous enum

Enumerator:
OPT_ARG_FIRSTNAME 
OPT_ARG_LASTNAME 
OPT_ARG_EITHER 
OPT_ARG_PAUSE 
OPT_ARG_ARRAY_SIZE 

Definition at line 138 of file app_directory.c.

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


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 890 of file app_directory.c.

static void __unreg_module ( void   )  [static]

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

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

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

Definition at line 167 of file app_directory.c.

References ast_strlen_zero().

Referenced by ast_hashtab_create(), and check_match().

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

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

Definition at line 756 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_flags, 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().

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

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 679 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, S_OR, search_directory(), select_item_menu(), select_item_seq(), and sort_items().

Referenced by directory_exec().

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

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

Definition at line 247 of file app_directory.c.

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

Referenced by do_directory(), and select_item_seq().

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

static int load_module ( void   )  [static]

Definition at line 885 of file app_directory.c.

References ast_register_application_xml, and directory_exec().

00886 {
00887    return ast_register_application_xml(app, directory_exec);
00888 }

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

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

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

Definition at line 428 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_flags, CONFIG_STATUS_FILEINVALID, LOG_ERROR, LOG_WARNING, mailbox, S_OR, SENTINEL, var, and VOICEMAIL_CONFIG.

Referenced by directory_exec().

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Definition at line 657 of file app_directory.c.

References directory_item::key.

Referenced by do_directory().

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

static int unload_module ( void   )  [static]

Definition at line 878 of file app_directory.c.

References ast_unregister_application().

00879 {
00880    int res;
00881    res = ast_unregister_application(app);
00882    return res;
00883 }


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

Definition at line 890 of file app_directory.c.

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

Definition at line 120 of file app_directory.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

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

Referenced by directory_exec().


Generated on Mon Jun 27 16:50:58 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7