Fri Nov 12 11:49:05 2010

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)
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)
static int select_item_seq (struct ast_channel *chan, struct directory_item **items, int count, const char *dialcontext, struct ast_flags *flags)
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 = "0901e4e500243c855563a2d78b0c03e4" , .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 852 of file app_directory.c.

static void __unreg_module ( void   )  [static]

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

00461 {
00462    struct directory_item *item;
00463    const char *key = NULL;
00464    int namelen;
00465 
00466    if (ast_strlen_zero(item_fullname)) {
00467       return 0;
00468    }
00469 
00470    /* Set key to last name or first name depending on search mode */
00471    if (!use_first_name)
00472       key = strchr(item_fullname, ' ');
00473 
00474    if (key)
00475       key++;
00476    else
00477       key = item_fullname;
00478 
00479    if (compare(key, pattern_ext))
00480       return 0;
00481 
00482    ast_debug(1, "Found match %s@%s\n", item_ext, item_context);
00483 
00484    /* Match */
00485    item = ast_calloc(1, sizeof(*item));
00486    if (!item)
00487       return -1;
00488    ast_copy_string(item->context, item_context, sizeof(item->context));
00489    ast_copy_string(item->name, item_fullname, sizeof(item->name));
00490    ast_copy_string(item->exten, item_ext, sizeof(item->exten));
00491 
00492    ast_copy_string(item->key, key, sizeof(item->key));
00493    if (key != item_fullname) {
00494       /* Key is the last name. Append first name to key in order to sort Last,First */
00495       namelen = key - item_fullname - 1;
00496       if (namelen > sizeof(item->key) - strlen(item->key) - 1)
00497          namelen = sizeof(item->key) - strlen(item->key) - 1;
00498       strncat(item->key, item_fullname, namelen);
00499    }
00500 
00501    *result = item;
00502    return 1;
00503 }

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

00724 {
00725    int res = 0, digit = 3;
00726    struct ast_config *cfg, *ucfg;
00727    const char *dirintro;
00728    char *parse, *opts[OPT_ARG_ARRAY_SIZE] = { 0, };
00729    struct ast_flags flags = { 0 };
00730    struct ast_flags config_flags = { 0 };
00731    enum { FIRST, LAST, BOTH } which = LAST;
00732    char digits[9] = "digits/3";
00733    AST_DECLARE_APP_ARGS(args,
00734       AST_APP_ARG(vmcontext);
00735       AST_APP_ARG(dialcontext);
00736       AST_APP_ARG(options);
00737    );
00738 
00739    parse = ast_strdupa(data);
00740 
00741    AST_STANDARD_APP_ARGS(args, parse);
00742 
00743    if (args.options && ast_app_parse_options(directory_app_options, &flags, opts, args.options))
00744       return -1;
00745 
00746    if (!(cfg = realtime_directory(args.vmcontext))) {
00747       ast_log(LOG_ERROR, "Unable to read the configuration data!\n");
00748       return -1;
00749    }
00750 
00751    if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) {
00752       ast_log(LOG_ERROR, "Config file users.conf is in an invalid format.  Aborting.\n");
00753       ucfg = NULL;
00754    }
00755 
00756    dirintro = ast_variable_retrieve(cfg, args.vmcontext, "directoryintro");
00757    if (ast_strlen_zero(dirintro))
00758       dirintro = ast_variable_retrieve(cfg, "general", "directoryintro");
00759 
00760    if (ast_test_flag(&flags, OPT_LISTBYFIRSTNAME) && ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
00761       if (!ast_strlen_zero(opts[OPT_ARG_EITHER])) {
00762          digit = atoi(opts[OPT_ARG_EITHER]);
00763       }
00764       which = BOTH;
00765    } else if (ast_test_flag(&flags, OPT_LISTBYFIRSTNAME)) {
00766       if (!ast_strlen_zero(opts[OPT_ARG_FIRSTNAME])) {
00767          digit = atoi(opts[OPT_ARG_FIRSTNAME]);
00768       }
00769       which = FIRST;
00770    } else {
00771       if (!ast_strlen_zero(opts[OPT_ARG_LASTNAME])) {
00772          digit = atoi(opts[OPT_ARG_LASTNAME]);
00773       }
00774       which = LAST;
00775    }
00776 
00777    /* If no options specified, search by last name */
00778    if (!ast_test_flag(&flags, OPT_LISTBYFIRSTNAME) && !ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
00779       ast_set_flag(&flags, OPT_LISTBYLASTNAME);
00780       which = LAST;
00781    }
00782 
00783    if (digit > 9) {
00784       digit = 9;
00785    } else if (digit < 1) {
00786       digit = 3;
00787    }
00788    digits[7] = digit + '0';
00789 
00790    if (chan->_state != AST_STATE_UP)
00791       res = ast_answer(chan);
00792 
00793    for (;;) {
00794       if (!ast_strlen_zero(dirintro) && !res) {
00795          res = ast_stream_and_wait(chan, dirintro, AST_DIGIT_ANY);
00796       } else if (!res) {
00797          /* Stop playing sounds as soon as we have a digit. */
00798          res = ast_stream_and_wait(chan, "dir-welcome", AST_DIGIT_ANY);
00799          if (!res) {
00800             res = ast_stream_and_wait(chan, "dir-pls-enter", AST_DIGIT_ANY);
00801          }
00802          if (!res) {
00803             res = ast_stream_and_wait(chan, digits, AST_DIGIT_ANY);
00804          }
00805          if (!res) {
00806             res = ast_stream_and_wait(chan, 
00807                which == FIRST ? "dir-first" :
00808                which == LAST ? "dir-last" :
00809                "dir-firstlast", AST_DIGIT_ANY);
00810          }
00811          if (!res) {
00812             res = ast_stream_and_wait(chan, "dir-usingkeypad", AST_DIGIT_ANY);
00813          }
00814       }
00815       ast_stopstream(chan);
00816       if (!res)
00817          res = ast_waitfordigit(chan, 5000);
00818 
00819       if (res <= 0)
00820          break;
00821 
00822       res = do_directory(chan, cfg, ucfg, args.vmcontext, args.dialcontext, res, digit, &flags);
00823       if (res)
00824          break;
00825 
00826       res = ast_waitstream(chan, AST_DIGIT_ANY);
00827       ast_stopstream(chan);
00828 
00829       if (res)
00830          break;
00831    }
00832 
00833    if (ucfg)
00834       ast_config_destroy(ucfg);
00835    ast_config_destroy(cfg);
00836 
00837    return res < 0 ? -1 : 0;
00838 }

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 
) [static]

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

00647 {
00648    /* Read in the first three digits..  "digit" is the first digit, already read */
00649    int res = 0;
00650    itemlist alist = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
00651    struct directory_item *item, **ptr, **sorted = NULL;
00652    int count, i;
00653    char ext[10] = "";
00654 
00655    if (digit == '0' && !goto_exten(chan, S_OR(dialcontext, "default"), "o")) {
00656       return digit;
00657    }
00658 
00659    if (digit == '*' && !goto_exten(chan, S_OR(dialcontext, "default"), "a")) {
00660       return digit;
00661    }
00662 
00663    ext[0] = digit;
00664    if (ast_readstring(chan, ext + 1, digits - 1, 3000, 3000, "#") < 0)
00665       return -1;
00666 
00667    res = search_directory(context, vmcfg, ucfg, ext, *flags, &alist);
00668    if (res)
00669       goto exit;
00670 
00671    /* Count items in the list */
00672    count = 0;
00673    AST_LIST_TRAVERSE(&alist, item, entry) {
00674       count++;
00675    }
00676 
00677    if (count < 1) {
00678       res = ast_streamfile(chan, "dir-nomatch", chan->language);
00679       goto exit;
00680    }
00681 
00682 
00683    /* Create plain array of pointers to items (for sorting) */
00684    sorted = ast_calloc(count, sizeof(*sorted));
00685 
00686    ptr = sorted;
00687    AST_LIST_TRAVERSE(&alist, item, entry) {
00688       *ptr++ = item;
00689    }
00690 
00691    /* Sort items */
00692    sort_items(sorted, count);
00693 
00694    if (option_debug) {
00695       ast_debug(2, "Listing matching entries:\n");
00696       for (ptr = sorted, i = 0; i < count; i++, ptr++) {
00697          ast_debug(2, "%s: %s\n", ptr[0]->exten, ptr[0]->name);
00698       }
00699    }
00700 
00701    if (ast_test_flag(flags, OPT_SELECTFROMMENU)) {
00702       /* Offer multiple entries at the same time */
00703       res = select_item_menu(chan, sorted, count, dialcontext, flags);
00704    } else {
00705       /* Offer entries one by one */
00706       res = select_item_seq(chan, sorted, count, dialcontext, flags);
00707    }
00708 
00709    if (!res) {
00710       res = ast_streamfile(chan, "dir-nomore", chan->language);
00711    }
00712 
00713 exit:
00714    if (sorted)
00715       ast_free(sorted);
00716 
00717    while ((item = AST_LIST_REMOVE_HEAD(&alist, entry)))
00718       ast_free(item);
00719 
00720    return res;
00721 }

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

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

00634 {
00635    if (!ast_goto_if_exists(chan, dialcontext, ext, 1) ||
00636       (!ast_strlen_zero(chan->macrocontext) &&
00637       !ast_goto_if_exists(chan, chan->macrocontext, ext, 1))) {
00638       return 0;
00639    } else {
00640       ast_log(LOG_WARNING, "Can't find extension '%s' in current context.  "
00641          "Not Exiting the Directory!\n", ext);
00642       return -1;
00643    }
00644 }

static int load_module ( void   )  [static]

Definition at line 847 of file app_directory.c.

References ast_register_application_xml, and directory_exec().

00848 {
00849    return ast_register_application_xml(app, directory_exec);
00850 }

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

00249 {
00250    int res = 0;
00251    if ((res = ast_app_sayname(chan, ext, context)) >= 0) {
00252       ast_stopstream(chan);
00253       /* If Option 'e' was specified, also read the extension number with the name */
00254       if (ast_test_flag(flags, OPT_SAYEXTENSION)) {
00255          ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
00256          res = ast_say_character_str(chan, ext, AST_DIGIT_ANY, chan->language);
00257       }
00258    } else {
00259       res = ast_say_character_str(chan, S_OR(name, ext), AST_DIGIT_ANY, chan->language);
00260       if (!ast_strlen_zero(name) && ast_test_flag(flags, OPT_SAYEXTENSION)) {
00261          ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
00262          res = ast_say_character_str(chan, ext, AST_DIGIT_ANY, chan->language);
00263       }
00264    }
00265 
00266    return res;
00267 }

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

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

00383 {
00384    struct ast_config *cfg;
00385    struct ast_config *rtdata;
00386    struct ast_category *cat;
00387    struct ast_variable *var;
00388    char *mailbox;
00389    const char *fullname;
00390    const char *hidefromdir, *searchcontexts = NULL;
00391    char tmp[100];
00392    struct ast_flags config_flags = { 0 };
00393 
00394    /* Load flat file config. */
00395    cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags);
00396 
00397    if (!cfg) {
00398       /* Loading config failed. */
00399       ast_log(LOG_WARNING, "Loading config failed.\n");
00400       return NULL;
00401    } else if (cfg == CONFIG_STATUS_FILEINVALID) {
00402       ast_log(LOG_ERROR, "Config file %s is in an invalid format.  Aborting.\n", VOICEMAIL_CONFIG);
00403       return NULL;
00404    }
00405 
00406    /* Get realtime entries, categorized by their mailbox number
00407       and present in the requested context */
00408    if (ast_strlen_zero(context) && (searchcontexts = ast_variable_retrieve(cfg, "general", "searchcontexts"))) {
00409       if (ast_true(searchcontexts)) {
00410          rtdata = ast_load_realtime_multientry("voicemail", "mailbox LIKE", "%", SENTINEL);
00411          context = NULL;
00412       } else {
00413          rtdata = ast_load_realtime_multientry("voicemail", "mailbox LIKE", "%", "context", "default", SENTINEL);
00414          context = "default";
00415       }
00416    } else {
00417       rtdata = ast_load_realtime_multientry("voicemail", "mailbox LIKE", "%", "context", context, SENTINEL);
00418    }
00419 
00420    /* if there are no results, just return the entries from the config file */
00421    if (!rtdata) {
00422       return cfg;
00423    }
00424 
00425    mailbox = NULL;
00426    while ( (mailbox = ast_category_browse(rtdata, mailbox)) ) {
00427       const char *context = ast_variable_retrieve(rtdata, mailbox, "context");
00428 
00429       fullname = ast_variable_retrieve(rtdata, mailbox, "fullname");
00430       if (ast_true((hidefromdir = ast_variable_retrieve(rtdata, mailbox, "hidefromdir")))) {
00431          /* Skip hidden */
00432          continue;
00433       }
00434       snprintf(tmp, sizeof(tmp), "no-password,%s", S_OR(fullname, ""));
00435 
00436       /* Does the context exist within the config file? If not, make one */
00437       if (!(cat = ast_category_get(cfg, context))) {
00438          if (!(cat = ast_category_new(context, "", 99999))) {
00439             ast_log(LOG_WARNING, "Out of memory\n");
00440             ast_config_destroy(cfg);
00441             if (rtdata) {
00442                ast_config_destroy(rtdata);
00443             }
00444             return NULL;
00445          }
00446          ast_category_append(cfg, cat);
00447       }
00448 
00449       if ((var = ast_variable_new(mailbox, tmp, ""))) {
00450          ast_variable_append(cat, var);
00451       } else {
00452          ast_log(LOG_WARNING, "Out of memory adding mailbox '%s'\n", mailbox);
00453       }
00454    }
00455    ast_config_destroy(rtdata);
00456 
00457    return cfg;
00458 }

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

00583 {
00584    const char *searchcontexts = ast_variable_retrieve(vmcfg, "general", "searchcontexts");
00585    if (ast_strlen_zero(context)) {
00586       if (!ast_strlen_zero(searchcontexts) && ast_true(searchcontexts)) {
00587          /* Browse each context for a match */
00588          int res;
00589          const char *catg;
00590          for (catg = ast_category_browse(vmcfg, NULL); catg; catg = ast_category_browse(vmcfg, catg)) {
00591             if (!strcmp(catg, "general") || !strcmp(catg, "zonemessages")) {
00592                continue;
00593             }
00594 
00595             if ((res = search_directory_sub(catg, vmcfg, ucfg, ext, flags, alist))) {
00596                return res;
00597             }
00598          }
00599          return 0;
00600       } else {
00601          ast_debug(1, "Searching by category default\n");
00602          return search_directory_sub("default", vmcfg, ucfg, ext, flags, alist);
00603       }
00604    } else {
00605       /* Browse only the listed context for a match */
00606       ast_debug(1, "Searching by category %s\n", context);
00607       return search_directory_sub(context, vmcfg, ucfg, ext, flags, alist);
00608    }
00609 }

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 507 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, and ast_variable::value.

Referenced by search_directory().

00508 {
00509    struct ast_variable *v;
00510    char buf[AST_MAX_EXTENSION + 1], *pos, *bufptr, *cat;
00511    struct directory_item *item;
00512    int res;
00513 
00514    ast_debug(2, "Pattern: %s\n", ext);
00515 
00516    for (v = ast_variable_browse(vmcfg, context); v; v = v->next) {
00517 
00518       /* Ignore hidden */
00519       if (strcasestr(v->value, "hidefromdir=yes"))
00520          continue;
00521 
00522       ast_copy_string(buf, v->value, sizeof(buf));
00523       bufptr = buf;
00524 
00525       /* password,Full Name,email,pager,options */
00526       strsep(&bufptr, ",");
00527       pos = strsep(&bufptr, ",");
00528 
00529       /* No name to compare against */
00530       if (ast_strlen_zero(pos)) {
00531          continue;
00532       }
00533 
00534       res = 0;
00535       if (ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
00536          res = check_match(&item, context, pos, v->name, ext, 0 /* use_first_name */);
00537       }
00538       if (!res && ast_test_flag(&flags, OPT_LISTBYFIRSTNAME)) {
00539          res = check_match(&item, context, pos, v->name, ext, 1 /* use_first_name */);
00540       }
00541 
00542       if (!res)
00543          continue;
00544       else if (res < 0)
00545          return -1;
00546 
00547       AST_LIST_INSERT_TAIL(alist, item, entry);
00548    }
00549 
00550    if (ucfg) {
00551       for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
00552          const char *position;
00553          if (!strcasecmp(cat, "general"))
00554             continue;
00555          if (!ast_true(ast_config_option(ucfg, cat, "hasdirectory")))
00556             continue;
00557 
00558          /* Find all candidate extensions */
00559          position = ast_variable_retrieve(ucfg, cat, "fullname");
00560          if (!position)
00561             continue;
00562 
00563          res = 0;
00564          if (ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
00565             res = check_match(&item, context, position, cat, ext, 0 /* use_first_name */);
00566          }
00567          if (!res && ast_test_flag(&flags, OPT_LISTBYFIRSTNAME)) {
00568             res = check_match(&item, context, position, cat, ext, 1 /* use_first_name */);
00569          }
00570 
00571          if (!res)
00572             continue;
00573          else if (res < 0)
00574             return -1;
00575 
00576          AST_LIST_INSERT_TAIL(alist, item, entry);
00577       }
00578    }
00579    return 0;
00580 }

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

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

00270 {
00271    ast_debug(1, "Selecting '%s' - %s@%s\n", item->name, item->exten, S_OR(dialcontext, item->context));
00272 
00273    if (ast_test_flag(flags, OPT_FROMVOICEMAIL)) {
00274       /* We still want to set the exten though */
00275       ast_copy_string(chan->exten, item->exten, sizeof(chan->exten));
00276    } else if (ast_goto_if_exists(chan, S_OR(dialcontext, item->context), item->exten, 1)) {
00277       ast_log(LOG_WARNING,
00278          "Can't find extension '%s' in context '%s'.  "
00279          "Did you pass the wrong context to Directory?\n",
00280          item->exten, S_OR(dialcontext, item->context));
00281       return -1;
00282    }
00283 
00284    return 0;
00285 }

static int select_item_menu ( struct ast_channel chan,
struct directory_item **  items,
int  count,
const char *  dialcontext,
struct ast_flags flags 
) [static]

Definition at line 322 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(), and select_entry().

Referenced by do_directory().

00323 {
00324    struct directory_item **block, *item;
00325    int i, limit, res = 0;
00326    char buf[9];
00327 
00328    for (block = items; count; block += limit, count -= limit) {
00329       limit = count;
00330       if (limit > 8)
00331          limit = 8;
00332 
00333       for (i = 0; i < limit && !res; i++) {
00334          item = block[i];
00335 
00336          snprintf(buf, sizeof(buf), "digits/%d", i + 1);
00337          /* Press <num> for <name>, [ extension <ext> ] */
00338          res = ast_streamfile(chan, "dir-multi1", chan->language);
00339          if (!res)
00340             res = ast_waitstream(chan, AST_DIGIT_ANY);
00341          if (!res)
00342             res = ast_streamfile(chan, buf, chan->language);
00343          if (!res)
00344             res = ast_waitstream(chan, AST_DIGIT_ANY);
00345          if (!res)
00346             res = ast_streamfile(chan, "dir-multi2", chan->language);
00347          if (!res)
00348             res = ast_waitstream(chan, AST_DIGIT_ANY);
00349          if (!res)
00350             res = play_mailbox_owner(chan, item->context, item->exten, item->name, flags);
00351          if (!res)
00352             res = ast_waitstream(chan, AST_DIGIT_ANY);
00353          if (!res)
00354             res = ast_waitfordigit(chan, 800);
00355       }
00356 
00357       /* Press "9" for more names. */
00358       if (!res && count > limit) {
00359          res = ast_streamfile(chan, "dir-multi9", chan->language);
00360          if (!res)
00361             res = ast_waitstream(chan, AST_DIGIT_ANY);
00362       }
00363 
00364       if (!res) {
00365          res = ast_waitfordigit(chan, 3000);
00366       }
00367 
00368       if (res && res > '0' && res < '1' + limit) {
00369          return select_entry(chan, dialcontext, block[res - '1'], flags) ? -1 : 1;
00370       }
00371 
00372       if (res < 0)
00373          return -1;
00374 
00375       res = 0;
00376    }
00377 
00378    /* Nothing was selected */
00379    return 0;
00380 }

static int select_item_seq ( struct ast_channel chan,
struct directory_item **  items,
int  count,
const char *  dialcontext,
struct ast_flags flags 
) [static]

Definition at line 287 of file app_directory.c.

References AST_DIGIT_ANY, ast_stopstream(), ast_stream_and_wait(), ast_waitfordigit(), directory_item::context, directory_item::exten, directory_item::name, play_mailbox_owner(), and select_entry().

Referenced by do_directory().

00288 {
00289    struct directory_item *item, **ptr;
00290    int i, res, loop;
00291 
00292    for (ptr = items, i = 0; i < count; i++, ptr++) {
00293       item = *ptr;
00294 
00295       for (loop = 3 ; loop > 0; loop--) {
00296          res = play_mailbox_owner(chan, item->context, item->exten, item->name, flags);
00297 
00298          if (!res)
00299             res = ast_stream_and_wait(chan, "dir-instr", AST_DIGIT_ANY);
00300          if (!res)
00301             res = ast_waitfordigit(chan, 3000);
00302          ast_stopstream(chan);
00303    
00304          if (res == '1') { /* Name selected */
00305             return select_entry(chan, dialcontext, item, flags) ? -1 : 1;
00306          } else if (res == '*') {
00307             /* Skip to next match in list */
00308             break;
00309          }
00310 
00311          if (res < 0)
00312             return -1;
00313 
00314          res = 0;
00315       }
00316    }
00317 
00318    /* Nothing was selected */
00319    return 0;
00320 }

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

Definition at line 611 of file app_directory.c.

References directory_item::key.

Referenced by do_directory().

00612 {
00613    int reordered, i;
00614    struct directory_item **ptr, *tmp;
00615 
00616    if (count < 2)
00617       return;
00618 
00619    /* Bubble-sort items by the key */
00620    do {
00621       reordered = 0;
00622       for (ptr = sorted, i = 0; i < count - 1; i++, ptr++) {
00623          if (strcasecmp(ptr[0]->key, ptr[1]->key) > 0) {
00624             tmp = ptr[0];
00625             ptr[0] = ptr[1];
00626             ptr[1] = tmp;
00627             reordered++;
00628          }
00629       }
00630    } while (reordered);
00631 }

static int unload_module ( void   )  [static]

Definition at line 840 of file app_directory.c.

References ast_unregister_application().

00841 {
00842    int res;
00843    res = ast_unregister_application(app);
00844    return res;
00845 }


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

Definition at line 852 of file app_directory.c.

char* app = "Directory" [static]

Definition at line 117 of file app_directory.c.

Definition at line 852 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 by  doxygen 1.6.2