Thu Oct 11 06:47:33 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"

Include dependency graph for app_directory.c:

Go to the source code of this file.

Data Structures

struct  directory_item
struct  itemlist

Defines

#define VOICEMAIL_CONFIG   "voicemail.conf"

Enumerations

enum  {
  OPT_LISTBYFIRSTNAME = (1 << 0), OPT_SAYEXTENSION = (1 << 1), OPT_FROMVOICEMAIL = (1 << 2), OPT_SELECTFROMMENU = (1 << 3),
  OPT_LISTBYLASTNAME = (1 << 4), OPT_LISTBYEITHER = OPT_LISTBYFIRSTNAME | OPT_LISTBYLASTNAME, OPT_PAUSE = (1 << 5)
}
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, void *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_DEFAULT , .description = "Extension Directory" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, }
static 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 },}
enum { ... }  directory_option_flags


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

Definition at line 124 of file app_directory.c.

00124      {
00125    OPT_LISTBYFIRSTNAME = (1 << 0),
00126    OPT_SAYEXTENSION =    (1 << 1),
00127    OPT_FROMVOICEMAIL =   (1 << 2),
00128    OPT_SELECTFROMMENU =  (1 << 3),
00129    OPT_LISTBYLASTNAME =  (1 << 4),
00130    OPT_LISTBYEITHER =    OPT_LISTBYFIRSTNAME | OPT_LISTBYLASTNAME,
00131    OPT_PAUSE =           (1 << 5),
00132 } directory_option_flags;

anonymous enum

Enumerator:
OPT_ARG_FIRSTNAME 
OPT_ARG_LASTNAME 
OPT_ARG_EITHER 
OPT_ARG_PAUSE 
OPT_ARG_ARRAY_SIZE 

Definition at line 134 of file app_directory.c.

00134      {
00135    OPT_ARG_FIRSTNAME =   0,
00136    OPT_ARG_LASTNAME =    1,
00137    OPT_ARG_EITHER =      2,
00138    OPT_ARG_PAUSE =       3,
00139    /* This *must* be the last value in this enum! */
00140    OPT_ARG_ARRAY_SIZE =  4,
00141 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 882 of file app_directory.c.

static void __unreg_module ( void   )  [static]

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

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

Referenced by search_directory_sub().

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

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

Definition at line 162 of file app_directory.c.

References ast_strlen_zero().

Referenced by ast_hashtab_create(), and check_match().

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

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

Definition at line 751 of file app_directory.c.

References ast_channel::_state, ast_answer(), AST_APP_ARG, ast_app_parse_options(), ast_config_destroy(), ast_config_load, AST_DECLARE_APP_ARGS, AST_DIGIT_ANY, ast_log(), ast_set_flag, AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_stopstream(), ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_test_flag, ast_variable_retrieve(), ast_waitfordigit(), ast_waitstream(), CONFIG_STATUS_FILEINVALID, dialcontext, directory_app_options, do_directory(), LOG_ERROR, OPT_ARG_ARRAY_SIZE, OPT_ARG_EITHER, OPT_ARG_FIRSTNAME, OPT_ARG_LASTNAME, OPT_LISTBYFIRSTNAME, OPT_LISTBYLASTNAME, parse(), and realtime_directory().

Referenced by load_module().

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

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

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

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

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

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

static int load_module ( void   )  [static]

Definition at line 877 of file app_directory.c.

References ast_register_application_xml, and directory_exec().

00878 {
00879    return ast_register_application_xml(app, directory_exec);
00880 }

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

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

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

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

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

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

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

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 548 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(), buf, 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().

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

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

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

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

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

References AST_DIGIT_ANY, ast_streamfile(), ast_waitfordigit(), ast_waitstream(), buf, 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().

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

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

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

00301 {
00302    int res = 0, opt_pause = 0;
00303 
00304    if (ast_test_flag(flags, OPT_PAUSE) && !ast_strlen_zero(opts[OPT_ARG_PAUSE])) {
00305       opt_pause = atoi(opts[OPT_ARG_PAUSE]);
00306       if (opt_pause > 3000) {
00307          opt_pause = 3000;
00308       }
00309       res = ast_waitfordigit(chan, opt_pause);
00310    }
00311    return res;
00312 }

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

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

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

Definition at line 652 of file app_directory.c.

References directory_item::key.

Referenced by do_directory().

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

static int unload_module ( void   )  [static]

Definition at line 870 of file app_directory.c.

References ast_unregister_application().

00871 {
00872    int res;
00873    res = ast_unregister_application(app);
00874    return res;
00875 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Extension Directory" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, } [static]

Definition at line 882 of file app_directory.c.

char* app = "Directory" [static]

Definition at line 117 of file app_directory.c.

Definition at line 882 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 },} [static]

Definition at line 160 of file app_directory.c.

Referenced by directory_exec().

enum { ... } directory_option_flags


Generated on Thu Oct 11 06:47:34 2012 for Asterisk - the Open Source PBX by  doxygen 1.5.6