Mon Mar 19 11:30:32 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 = "88eaa8f5c1bd988bedd71113385e0886" , .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 892 of file app_directory.c.

static void __unreg_module ( void   )  [static]

Definition at line 892 of file app_directory.c.

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

Definition at line 508 of file app_directory.c.

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

Referenced by search_directory_sub().

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

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

References ast_channel::_state, args, ast_answer(), AST_APP_ARG, ast_app_parse_options(), ast_config_destroy(), ast_config_load, AST_DECLARE_APP_ARGS, AST_DIGIT_ANY, ast_log(), ast_set_flag, AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_stopstream(), ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_test_flag, ast_variable_retrieve(), ast_waitfordigit(), ast_waitstream(), config_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().

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

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

Definition at line 681 of file app_directory.c.

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

Referenced by directory_exec().

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

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

References ast_register_application_xml, and directory_exec().

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

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_flags, 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       if (ast_true((hidefromdir = ast_variable_retrieve(rtdata, mailbox, "hidefromdir")))) {
00479          /* Skip hidden */
00480          continue;
00481       }
00482       snprintf(tmp, sizeof(tmp), "no-password,%s", S_OR(fullname, ""));
00483 
00484       /* Does the context exist within the config file? If not, make one */
00485       if (!(cat = ast_category_get(cfg, context))) {
00486          if (!(cat = ast_category_new(context, "", 99999))) {
00487             ast_log(LOG_WARNING, "Out of memory\n");
00488             ast_config_destroy(cfg);
00489             if (rtdata) {
00490                ast_config_destroy(rtdata);
00491             }
00492             return NULL;
00493          }
00494          ast_category_append(cfg, cat);
00495       }
00496 
00497       if ((var = ast_variable_new(mailbox, tmp, ""))) {
00498          ast_variable_append(cat, var);
00499       } else {
00500          ast_log(LOG_WARNING, "Out of memory adding mailbox '%s'\n", mailbox);
00501       }
00502    }
00503    ast_config_destroy(rtdata);
00504 
00505    return cfg;
00506 }

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

Definition at line 630 of file app_directory.c.

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

Referenced by do_directory().

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

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

Definition at line 555 of file app_directory.c.

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

Referenced by search_directory().

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

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

References directory_item::key.

Referenced by do_directory().

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

static int unload_module ( void   )  [static]

Definition at line 880 of file app_directory.c.

References ast_unregister_application().

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


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

Definition at line 892 of file app_directory.c.

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

Definition at line 122 of file app_directory.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 892 of file app_directory.c.

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

Definition at line 167 of file app_directory.c.

Referenced by directory_exec().


Generated on Mon Mar 19 11:30:32 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7