Thu Apr 28 2011 17:13:37

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
__MODULE_INFO_SECTION 
__mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Extension Directory" , .key = ASTERISK_GPL_KEY , .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 realtime_directory().


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.

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.

     {
   OPT_ARG_FIRSTNAME =   0,
   OPT_ARG_LASTNAME =    1,
   OPT_ARG_EITHER =      2,
   OPT_ARG_PAUSE =       3,
   /* This *must* be the last value in this enum! */
   OPT_ARG_ARRAY_SIZE =  4,
};

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

{
   struct directory_item *item;
   const char *key = NULL;
   int namelen;

   if (ast_strlen_zero(item_fullname)) {
      return 0;
   }

   /* Set key to last name or first name depending on search mode */
   if (!use_first_name)
      key = strchr(item_fullname, ' ');

   if (key)
      key++;
   else
      key = item_fullname;

   if (compare(key, pattern_ext))
      return 0;

   ast_debug(1, "Found match %s@%s\n", item_ext, item_context);

   /* Match */
   item = ast_calloc(1, sizeof(*item));
   if (!item)
      return -1;
   ast_copy_string(item->context, item_context, sizeof(item->context));
   ast_copy_string(item->name, item_fullname, sizeof(item->name));
   ast_copy_string(item->exten, item_ext, sizeof(item->exten));

   ast_copy_string(item->key, key, sizeof(item->key));
   if (key != item_fullname) {
      /* Key is the last name. Append first name to key in order to sort Last,First */
      namelen = key - item_fullname - 1;
      if (namelen > sizeof(item->key) - strlen(item->key) - 1)
         namelen = sizeof(item->key) - strlen(item->key) - 1;
      strncat(item->key, item_fullname, namelen);
   }

   *result = item;
   return 1;
}
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().

{
   char digit;

   if (ast_strlen_zero(text)) {
      return -1;
   }

   while (*template) {
      digit = toupper(*text++);
      switch (digit) {
      case 0:
         return -1;
      case '1':
         digit = '1';
         break;
      case '2':
      case 'A':
      case 'B':
      case 'C':
         digit = '2';
         break;
      case '3':
      case 'D':
      case 'E':
      case 'F':
         digit = '3';
         break;
      case '4':
      case 'G':
      case 'H':
      case 'I':
         digit = '4';
         break;
      case '5':
      case 'J':
      case 'K':
      case 'L':
         digit = '5';
         break;
      case '6':
      case 'M':
      case 'N':
      case 'O':
         digit = '6';
         break;
      case '7':
      case 'P':
      case 'Q':
      case 'R':
      case 'S':
         digit = '7';
         break;
      case '8':
      case 'T':
      case 'U':
      case 'V':
         digit = '8';
         break;
      case '9':
      case 'W':
      case 'X':
      case 'Y':
      case 'Z':
         digit = '9';
         break;

      default:
         if (digit > ' ')
            return -1;
         continue;
      }

      if (*template++ != digit)
         return -1;
   }

   return 0;
}
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().

{
   int res = 0, digit = 3;
   struct ast_config *cfg, *ucfg;
   const char *dirintro;
   char *parse, *opts[OPT_ARG_ARRAY_SIZE] = { 0, };
   struct ast_flags flags = { 0 };
   struct ast_flags config_flags = { 0 };
   enum { FIRST, LAST, BOTH } which = LAST;
   char digits[9] = "digits/3";
   AST_DECLARE_APP_ARGS(args,
      AST_APP_ARG(vmcontext);
      AST_APP_ARG(dialcontext);
      AST_APP_ARG(options);
   );

   parse = ast_strdupa(data);

   AST_STANDARD_APP_ARGS(args, parse);

   if (args.options && ast_app_parse_options(directory_app_options, &flags, opts, args.options))
      return -1;

   if (!(cfg = realtime_directory(args.vmcontext))) {
      ast_log(LOG_ERROR, "Unable to read the configuration data!\n");
      return -1;
   }

   if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) {
      ast_log(LOG_ERROR, "Config file users.conf is in an invalid format.  Aborting.\n");
      ucfg = NULL;
   }

   dirintro = ast_variable_retrieve(cfg, args.vmcontext, "directoryintro");
   if (ast_strlen_zero(dirintro))
      dirintro = ast_variable_retrieve(cfg, "general", "directoryintro");
   /* the above prompts probably should be modified to include 0 for dialing operator
      and # for exiting (continues in dialplan) */

   if (ast_test_flag(&flags, OPT_LISTBYFIRSTNAME) && ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
      if (!ast_strlen_zero(opts[OPT_ARG_EITHER])) {
         digit = atoi(opts[OPT_ARG_EITHER]);
      }
      which = BOTH;
   } else if (ast_test_flag(&flags, OPT_LISTBYFIRSTNAME)) {
      if (!ast_strlen_zero(opts[OPT_ARG_FIRSTNAME])) {
         digit = atoi(opts[OPT_ARG_FIRSTNAME]);
      }
      which = FIRST;
   } else {
      if (!ast_strlen_zero(opts[OPT_ARG_LASTNAME])) {
         digit = atoi(opts[OPT_ARG_LASTNAME]);
      }
      which = LAST;
   }

   /* If no options specified, search by last name */
   if (!ast_test_flag(&flags, OPT_LISTBYFIRSTNAME) && !ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
      ast_set_flag(&flags, OPT_LISTBYLASTNAME);
      which = LAST;
   }

   if (digit > 9) {
      digit = 9;
   } else if (digit < 1) {
      digit = 3;
   }
   digits[7] = digit + '0';

   if (chan->_state != AST_STATE_UP)
      res = ast_answer(chan);

   for (;;) {
      if (!ast_strlen_zero(dirintro) && !res) {
         res = ast_stream_and_wait(chan, dirintro, AST_DIGIT_ANY);
      } else if (!res) {
         /* Stop playing sounds as soon as we have a digit. */
         res = ast_stream_and_wait(chan, "dir-welcome", AST_DIGIT_ANY);
         if (!res) {
            res = ast_stream_and_wait(chan, "dir-pls-enter", AST_DIGIT_ANY);
         }
         if (!res) {
            res = ast_stream_and_wait(chan, digits, AST_DIGIT_ANY);
         }
         if (!res) {
            res = ast_stream_and_wait(chan, 
               which == FIRST ? "dir-first" :
               which == LAST ? "dir-last" :
               "dir-firstlast", AST_DIGIT_ANY);
         }
         if (!res) {
            res = ast_stream_and_wait(chan, "dir-usingkeypad", AST_DIGIT_ANY);
         }
      }
      ast_stopstream(chan);
      if (!res)
         res = ast_waitfordigit(chan, 5000);

      if (res <= 0)
         break;

      res = do_directory(chan, cfg, ucfg, args.vmcontext, args.dialcontext, res, digit, &flags, opts);
      if (res)
         break;

      res = ast_waitstream(chan, AST_DIGIT_ANY);
      ast_stopstream(chan);

      if (res)
         break;
   }

   if (ucfg)
      ast_config_destroy(ucfg);
   ast_config_destroy(cfg);

   return res < 0 ? -1 : 0;
}
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().

{
   /* Read in the first three digits..  "digit" is the first digit, already read */
   int res = 0;
   itemlist alist = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
   struct directory_item *item, **ptr, **sorted = NULL;
   int count, i;
   char ext[10] = "";

   if (digit == '0' && !goto_exten(chan, S_OR(dialcontext, "default"), "o")) {
      return digit;
   }

   if (digit == '*' && !goto_exten(chan, S_OR(dialcontext, "default"), "a")) {
      return digit;
   }

   ext[0] = digit;
   if (ast_readstring(chan, ext + 1, digits - 1, 3000, 3000, "#") < 0)
      return -1;

   res = search_directory(context, vmcfg, ucfg, ext, *flags, &alist);
   if (res)
      goto exit;

   /* Count items in the list */
   count = 0;
   AST_LIST_TRAVERSE(&alist, item, entry) {
      count++;
   }

   if (count < 1) {
      res = ast_streamfile(chan, "dir-nomatch", chan->language);
      goto exit;
   }


   /* Create plain array of pointers to items (for sorting) */
   sorted = ast_calloc(count, sizeof(*sorted));

   ptr = sorted;
   AST_LIST_TRAVERSE(&alist, item, entry) {
      *ptr++ = item;
   }

   /* Sort items */
   sort_items(sorted, count);

   if (option_debug) {
      ast_debug(2, "Listing matching entries:\n");
      for (ptr = sorted, i = 0; i < count; i++, ptr++) {
         ast_debug(2, "%s: %s\n", ptr[0]->exten, ptr[0]->name);
      }
   }

   if (ast_test_flag(flags, OPT_SELECTFROMMENU)) {
      /* Offer multiple entries at the same time */
      res = select_item_menu(chan, sorted, count, dialcontext, flags, opts);
   } else {
      /* Offer entries one by one */
      res = select_item_seq(chan, sorted, count, dialcontext, flags, opts);
   }

   if (!res) {
      res = ast_streamfile(chan, "dir-nomore", chan->language);
   }

exit:
   if (sorted)
      ast_free(sorted);

   while ((item = AST_LIST_REMOVE_HEAD(&alist, entry)))
      ast_free(item);

   return res;
}
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().

{
   if (!ast_goto_if_exists(chan, dialcontext, ext, 1) ||
      (!ast_strlen_zero(chan->macrocontext) &&
      !ast_goto_if_exists(chan, chan->macrocontext, ext, 1))) {
      return 0;
   } else {
      ast_log(LOG_WARNING, "Can't find extension '%s' in current context.  "
         "Not Exiting the Directory!\n", ext);
      return -1;
   }
}
static int load_module ( void  ) [static]
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().

{
   int res = 0;
   if ((res = ast_app_sayname(chan, ext, context)) >= 0) {
      ast_stopstream(chan);
      /* If Option 'e' was specified, also read the extension number with the name */
      if (ast_test_flag(flags, OPT_SAYEXTENSION)) {
         ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
         res = ast_say_character_str(chan, ext, AST_DIGIT_ANY, chan->language);
      }
   } else {
      res = ast_say_character_str(chan, S_OR(name, ext), AST_DIGIT_ANY, chan->language);
      if (!ast_strlen_zero(name) && ast_test_flag(flags, OPT_SAYEXTENSION)) {
         ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
         res = ast_say_character_str(chan, ext, AST_DIGIT_ANY, chan->language);
      }
   }

   return res;
}
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().

{
   struct ast_config *cfg;
   struct ast_config *rtdata;
   struct ast_category *cat;
   struct ast_variable *var;
   char *mailbox;
   const char *fullname;
   const char *hidefromdir, *searchcontexts = NULL;
   char tmp[100];
   struct ast_flags config_flags = { 0 };

   /* Load flat file config. */
   cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags);

   if (!cfg) {
      /* Loading config failed. */
      ast_log(LOG_WARNING, "Loading config failed.\n");
      return NULL;
   } else if (cfg == CONFIG_STATUS_FILEINVALID) {
      ast_log(LOG_ERROR, "Config file %s is in an invalid format.  Aborting.\n", VOICEMAIL_CONFIG);
      return NULL;
   }

   /* Get realtime entries, categorized by their mailbox number
      and present in the requested context */
   if (ast_strlen_zero(context) && (searchcontexts = ast_variable_retrieve(cfg, "general", "searchcontexts"))) {
      if (ast_true(searchcontexts)) {
         rtdata = ast_load_realtime_multientry("voicemail", "mailbox LIKE", "%", SENTINEL);
         context = NULL;
      } else {
         rtdata = ast_load_realtime_multientry("voicemail", "mailbox LIKE", "%", "context", "default", SENTINEL);
         context = "default";
      }
   } else {
      rtdata = ast_load_realtime_multientry("voicemail", "mailbox LIKE", "%", "context", context, SENTINEL);
   }

   /* if there are no results, just return the entries from the config file */
   if (!rtdata) {
      return cfg;
   }

   mailbox = NULL;
   while ( (mailbox = ast_category_browse(rtdata, mailbox)) ) {
      const char *context = ast_variable_retrieve(rtdata, mailbox, "context");

      fullname = ast_variable_retrieve(rtdata, mailbox, "fullname");
      if (ast_true((hidefromdir = ast_variable_retrieve(rtdata, mailbox, "hidefromdir")))) {
         /* Skip hidden */
         continue;
      }
      snprintf(tmp, sizeof(tmp), "no-password,%s", S_OR(fullname, ""));

      /* Does the context exist within the config file? If not, make one */
      if (!(cat = ast_category_get(cfg, context))) {
         if (!(cat = ast_category_new(context, "", 99999))) {
            ast_log(LOG_WARNING, "Out of memory\n");
            ast_config_destroy(cfg);
            if (rtdata) {
               ast_config_destroy(rtdata);
            }
            return NULL;
         }
         ast_category_append(cfg, cat);
      }

      if ((var = ast_variable_new(mailbox, tmp, ""))) {
         ast_variable_append(cat, var);
      } else {
         ast_log(LOG_WARNING, "Out of memory adding mailbox '%s'\n", mailbox);
      }
   }
   ast_config_destroy(rtdata);

   return cfg;
}
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().

{
   const char *searchcontexts = ast_variable_retrieve(vmcfg, "general", "searchcontexts");
   if (ast_strlen_zero(context)) {
      if (!ast_strlen_zero(searchcontexts) && ast_true(searchcontexts)) {
         /* Browse each context for a match */
         int res;
         const char *catg;
         for (catg = ast_category_browse(vmcfg, NULL); catg; catg = ast_category_browse(vmcfg, catg)) {
            if (!strcmp(catg, "general") || !strcmp(catg, "zonemessages")) {
               continue;
            }

            if ((res = search_directory_sub(catg, vmcfg, ucfg, ext, flags, alist))) {
               return res;
            }
         }
         return 0;
      } else {
         ast_debug(1, "Searching by category default\n");
         return search_directory_sub("default", vmcfg, ucfg, ext, flags, alist);
      }
   } else {
      /* Browse only the listed context for a match */
      ast_debug(1, "Searching by category %s\n", context);
      return search_directory_sub(context, vmcfg, ucfg, ext, flags, 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]

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

{
   struct ast_variable *v;
   char buf[AST_MAX_EXTENSION + 1], *pos, *bufptr, *cat;
   struct directory_item *item;
   int res;

   ast_debug(2, "Pattern: %s\n", ext);

   for (v = ast_variable_browse(vmcfg, context); v; v = v->next) {

      /* Ignore hidden */
      if (strcasestr(v->value, "hidefromdir=yes"))
         continue;

      ast_copy_string(buf, v->value, sizeof(buf));
      bufptr = buf;

      /* password,Full Name,email,pager,options */
      strsep(&bufptr, ",");
      pos = strsep(&bufptr, ",");

      /* No name to compare against */
      if (ast_strlen_zero(pos)) {
         continue;
      }

      res = 0;
      if (ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
         res = check_match(&item, context, pos, v->name, ext, 0 /* use_first_name */);
      }
      if (!res && ast_test_flag(&flags, OPT_LISTBYFIRSTNAME)) {
         res = check_match(&item, context, pos, v->name, ext, 1 /* use_first_name */);
      }

      if (!res)
         continue;
      else if (res < 0)
         return -1;

      AST_LIST_INSERT_TAIL(alist, item, entry);
   }

   if (ucfg) {
      for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
         const char *position;
         if (!strcasecmp(cat, "general"))
            continue;
         if (!ast_true(ast_config_option(ucfg, cat, "hasdirectory")))
            continue;

         /* Find all candidate extensions */
         position = ast_variable_retrieve(ucfg, cat, "fullname");
         if (!position)
            continue;

         res = 0;
         if (ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
            res = check_match(&item, context, position, cat, ext, 0 /* use_first_name */);
         }
         if (!res && ast_test_flag(&flags, OPT_LISTBYFIRSTNAME)) {
            res = check_match(&item, context, position, cat, ext, 1 /* use_first_name */);
         }

         if (!res)
            continue;
         else if (res < 0)
            return -1;

         AST_LIST_INSERT_TAIL(alist, item, entry);
      }
   }
   return 0;
}
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().

{
   ast_debug(1, "Selecting '%s' - %s@%s\n", item->name, item->exten, S_OR(dialcontext, item->context));

   if (ast_test_flag(flags, OPT_FROMVOICEMAIL)) {
      /* We still want to set the exten though */
      ast_copy_string(chan->exten, item->exten, sizeof(chan->exten));
   } else if (ast_goto_if_exists(chan, S_OR(dialcontext, item->context), item->exten, 1)) {
      ast_log(LOG_WARNING,
         "Can't find extension '%s' in context '%s'.  "
         "Did you pass the wrong context to Directory?\n",
         item->exten, S_OR(dialcontext, item->context));
      return -1;
   }

   return 0;
}
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().

{
   struct directory_item **block, *item;
   int i, limit, res = 0;
   char buf[9];

   /* option p(n): cellphone pause option */
   select_item_pause(chan, flags, opts);

   for (block = items; count; block += limit, count -= limit) {
      limit = count;
      if (limit > 8)
         limit = 8;

      for (i = 0; i < limit && !res; i++) {
         item = block[i];

         snprintf(buf, sizeof(buf), "digits/%d", i + 1);
         /* Press <num> for <name>, [ extension <ext> ] */
         res = ast_streamfile(chan, "dir-multi1", chan->language);
         if (!res)
            res = ast_waitstream(chan, AST_DIGIT_ANY);
         if (!res)
            res = ast_streamfile(chan, buf, chan->language);
         if (!res)
            res = ast_waitstream(chan, AST_DIGIT_ANY);
         if (!res)
            res = ast_streamfile(chan, "dir-multi2", chan->language);
         if (!res)
            res = ast_waitstream(chan, AST_DIGIT_ANY);
         if (!res)
            res = play_mailbox_owner(chan, item->context, item->exten, item->name, flags);
         if (!res)
            res = ast_waitstream(chan, AST_DIGIT_ANY);
         if (!res)
            res = ast_waitfordigit(chan, 800);
      }

      /* Press "9" for more names. */
      if (!res && count > limit) {
         res = ast_streamfile(chan, "dir-multi9", chan->language);
         if (!res)
            res = ast_waitstream(chan, AST_DIGIT_ANY);
      }

      if (!res) {
         res = ast_waitfordigit(chan, 3000);
      }

      if (res && res > '0' && res < '1' + limit) {
         return select_entry(chan, dialcontext, block[res - '1'], flags) ? -1 : 1;
      }

      if (res < 0)
         return -1;

      res = 0;
   }

   /* Nothing was selected */
   return 0;
}
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().

{
   int res = 0, opt_pause = 0;

   if (ast_test_flag(flags, OPT_PAUSE) && !ast_strlen_zero(opts[OPT_ARG_PAUSE])) {
      opt_pause = atoi(opts[OPT_ARG_PAUSE]);
      if (opt_pause > 3000) {
         opt_pause = 3000;
      }
      res = ast_waitfordigit(chan, opt_pause);
   }
   return res;
}
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().

{
   struct directory_item *item, **ptr;
   int i, res, loop;

   /* option p(n): cellphone pause option */
   /* allow early press of selection key */
   res = select_item_pause(chan, flags, opts);

   for (ptr = items, i = 0; i < count; i++, ptr++) {
      item = *ptr;

      for (loop = 3 ; loop > 0; loop--) {
         if (!res)
            res = play_mailbox_owner(chan, item->context, item->exten, item->name, flags);
         if (!res)
            res = ast_stream_and_wait(chan, "dir-instr", AST_DIGIT_ANY);
         if (!res)
            res = ast_waitfordigit(chan, 3000);
         ast_stopstream(chan);
   
         if (res == '0') { /* operator selected */
            goto_exten(chan, dialcontext, "o");
            return '0';
         } else if (res == '1') { /* Name selected */
            return select_entry(chan, dialcontext, item, flags) ? -1 : 1;
         } else if (res == '*') {
            /* Skip to next match in list */
            break;
         } else if (res == '#') {
            /* Exit reading, continue in dialplan */
            return res;
         }

         if (res < 0)
            return -1;

         res = 0;
      }
      res = 0;
   }

   /* Nothing was selected */
   return 0;
}
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().

{
   int reordered, i;
   struct directory_item **ptr, *tmp;

   if (count < 2)
      return;

   /* Bubble-sort items by the key */
   do {
      reordered = 0;
      for (ptr = sorted, i = 0; i < count - 1; i++, ptr++) {
         if (strcasecmp(ptr[0]->key, ptr[1]->key) > 0) {
            tmp = ptr[0];
            ptr[0] = ptr[1];
            ptr[1] = tmp;
            reordered++;
         }
      }
   } while (reordered);
}
static int unload_module ( void  ) [static]

Definition at line 870 of file app_directory.c.

References ast_unregister_application().

{
   int res;
   res = ast_unregister_application(app);
   return res;
}

Variable Documentation

struct ast_module_info __MODULE_INFO_SECTION __mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Extension Directory" , .key = ASTERISK_GPL_KEY , .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