#include "asterisk.h"
#include <ctype.h>
#include "asterisk/paths.h"
#include "asterisk/file.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/say.h"
#include "asterisk/app.h"
#include "asterisk/utils.h"
Go to the source code of this file.
Data Structures | |
struct | directory_item |
struct | itemlist |
Defines | |
#define | VOICEMAIL_CONFIG "voicemail.conf" |
Enumerations | |
enum | { OPT_LISTBYFIRSTNAME = (1 << 0), OPT_SAYEXTENSION = (1 << 1), OPT_FROMVOICEMAIL = (1 << 2), OPT_SELECTFROMMENU = (1 << 3), OPT_LISTBYLASTNAME = (1 << 4), OPT_LISTBYEITHER = OPT_LISTBYFIRSTNAME | OPT_LISTBYLASTNAME, OPT_PAUSE = (1 << 5), OPT_NOANSWER = (1 << 6) } |
enum | { OPT_ARG_FIRSTNAME = 0, OPT_ARG_LASTNAME = 1, OPT_ARG_EITHER = 2, OPT_ARG_PAUSE = 3, OPT_ARG_ARRAY_SIZE = 4 } |
Functions | |
static void | __reg_module (void) |
static void | __unreg_module (void) |
static int | check_match (struct directory_item **result, const char *item_context, const char *item_fullname, const char *item_ext, const char *pattern_ext, int use_first_name) |
static int | compare (const char *text, const char *template) |
static int | directory_exec (struct ast_channel *chan, const char *data) |
static int | do_directory (struct ast_channel *chan, struct ast_config *vmcfg, struct ast_config *ucfg, char *context, char *dialcontext, char digit, int digits, struct ast_flags *flags, char *opts[]) |
static int | goto_exten (struct ast_channel *chan, const char *dialcontext, char *ext) |
static int | load_module (void) |
static int | play_mailbox_owner (struct ast_channel *chan, const char *context, const char *ext, const char *name, struct ast_flags *flags) |
static struct ast_config * | realtime_directory (char *context) |
static int | search_directory (const char *context, struct ast_config *vmcfg, struct ast_config *ucfg, const char *ext, struct ast_flags flags, itemlist *alist) |
static int | search_directory_sub (const char *context, struct ast_config *vmcfg, struct ast_config *ucfg, const char *ext, struct ast_flags flags, itemlist *alist) |
static int | select_entry (struct ast_channel *chan, const char *dialcontext, const struct directory_item *item, struct ast_flags *flags) |
static int | select_item_menu (struct ast_channel *chan, struct directory_item **items, int count, const char *dialcontext, struct ast_flags *flags, char *opts[]) |
static int | select_item_pause (struct ast_channel *chan, struct ast_flags *flags, char *opts[]) |
static int | select_item_seq (struct ast_channel *chan, struct directory_item **items, int count, const char *dialcontext, struct ast_flags *flags, char *opts[]) |
static void | sort_items (struct directory_item **sorted, int count) |
static int | unload_module (void) |
Variables | |
static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Extension Directory" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "88eaa8f5c1bd988bedd71113385e0886" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, } |
static const char | app [] = "Directory" |
static struct ast_module_info * | ast_module_info = &__mod_info |
static struct ast_app_option | directory_app_options [128] = { [ 'f' ] = { .flag = OPT_LISTBYFIRSTNAME , .arg_index = OPT_ARG_FIRSTNAME + 1 }, [ 'l' ] = { .flag = OPT_LISTBYLASTNAME , .arg_index = OPT_ARG_LASTNAME + 1 }, [ 'b' ] = { .flag = OPT_LISTBYEITHER , .arg_index = OPT_ARG_EITHER + 1 }, [ 'p' ] = { .flag = OPT_PAUSE , .arg_index = OPT_ARG_PAUSE + 1 }, [ 'e' ] = { .flag = OPT_SAYEXTENSION }, [ 'v' ] = { .flag = OPT_FROMVOICEMAIL }, [ 'm' ] = { .flag = OPT_SELECTFROMMENU }, [ 'n' ] = { .flag = OPT_NOANSWER },} |
Definition in file app_directory.c.
#define VOICEMAIL_CONFIG "voicemail.conf" |
Definition at line 127 of file app_directory.c.
Referenced by load_config(), realtime_directory(), and vm_change_password().
anonymous enum |
OPT_LISTBYFIRSTNAME | |
OPT_SAYEXTENSION | |
OPT_FROMVOICEMAIL | |
OPT_SELECTFROMMENU | |
OPT_LISTBYLASTNAME | |
OPT_LISTBYEITHER | |
OPT_PAUSE | |
OPT_NOANSWER |
Definition at line 129 of file app_directory.c.
00129 { 00130 OPT_LISTBYFIRSTNAME = (1 << 0), 00131 OPT_SAYEXTENSION = (1 << 1), 00132 OPT_FROMVOICEMAIL = (1 << 2), 00133 OPT_SELECTFROMMENU = (1 << 3), 00134 OPT_LISTBYLASTNAME = (1 << 4), 00135 OPT_LISTBYEITHER = OPT_LISTBYFIRSTNAME | OPT_LISTBYLASTNAME, 00136 OPT_PAUSE = (1 << 5), 00137 OPT_NOANSWER = (1 << 6), 00138 };
anonymous enum |
Definition at line 140 of file app_directory.c.
00140 { 00141 OPT_ARG_FIRSTNAME = 0, 00142 OPT_ARG_LASTNAME = 1, 00143 OPT_ARG_EITHER = 2, 00144 OPT_ARG_PAUSE = 3, 00145 /* This *must* be the last value in this enum! */ 00146 OPT_ARG_ARRAY_SIZE = 4, 00147 };
static void __reg_module | ( | void | ) | [static] |
Definition at line 892 of file app_directory.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 892 of file app_directory.c.
static int check_match | ( | struct directory_item ** | result, | |
const char * | item_context, | |||
const char * | item_fullname, | |||
const char * | item_ext, | |||
const char * | pattern_ext, | |||
int | use_first_name | |||
) | [static] |
Definition at line 508 of file app_directory.c.
References ast_calloc, ast_copy_string(), ast_debug, ast_strlen_zero(), compare(), and directory_item::key.
Referenced by search_directory_sub().
00509 { 00510 struct directory_item *item; 00511 const char *key = NULL; 00512 int namelen; 00513 00514 if (ast_strlen_zero(item_fullname)) { 00515 return 0; 00516 } 00517 00518 /* Set key to last name or first name depending on search mode */ 00519 if (!use_first_name) 00520 key = strchr(item_fullname, ' '); 00521 00522 if (key) 00523 key++; 00524 else 00525 key = item_fullname; 00526 00527 if (compare(key, pattern_ext)) 00528 return 0; 00529 00530 ast_debug(1, "Found match %s@%s\n", item_ext, item_context); 00531 00532 /* Match */ 00533 item = ast_calloc(1, sizeof(*item)); 00534 if (!item) 00535 return -1; 00536 ast_copy_string(item->context, item_context, sizeof(item->context)); 00537 ast_copy_string(item->name, item_fullname, sizeof(item->name)); 00538 ast_copy_string(item->exten, item_ext, sizeof(item->exten)); 00539 00540 ast_copy_string(item->key, key, sizeof(item->key)); 00541 if (key != item_fullname) { 00542 /* Key is the last name. Append first name to key in order to sort Last,First */ 00543 namelen = key - item_fullname - 1; 00544 if (namelen > sizeof(item->key) - strlen(item->key) - 1) 00545 namelen = sizeof(item->key) - strlen(item->key) - 1; 00546 strncat(item->key, item_fullname, namelen); 00547 } 00548 00549 *result = item; 00550 return 1; 00551 }
static int compare | ( | const char * | text, | |
const char * | template | |||
) | [static] |
Definition at line 169 of file app_directory.c.
References ast_strlen_zero().
Referenced by ast_hashtab_create(), and check_match().
00170 { 00171 char digit; 00172 00173 if (ast_strlen_zero(text)) { 00174 return -1; 00175 } 00176 00177 while (*template) { 00178 digit = toupper(*text++); 00179 switch (digit) { 00180 case 0: 00181 return -1; 00182 case '1': 00183 digit = '1'; 00184 break; 00185 case '2': 00186 case 'A': 00187 case 'B': 00188 case 'C': 00189 digit = '2'; 00190 break; 00191 case '3': 00192 case 'D': 00193 case 'E': 00194 case 'F': 00195 digit = '3'; 00196 break; 00197 case '4': 00198 case 'G': 00199 case 'H': 00200 case 'I': 00201 digit = '4'; 00202 break; 00203 case '5': 00204 case 'J': 00205 case 'K': 00206 case 'L': 00207 digit = '5'; 00208 break; 00209 case '6': 00210 case 'M': 00211 case 'N': 00212 case 'O': 00213 digit = '6'; 00214 break; 00215 case '7': 00216 case 'P': 00217 case 'Q': 00218 case 'R': 00219 case 'S': 00220 digit = '7'; 00221 break; 00222 case '8': 00223 case 'T': 00224 case 'U': 00225 case 'V': 00226 digit = '8'; 00227 break; 00228 case '9': 00229 case 'W': 00230 case 'X': 00231 case 'Y': 00232 case 'Z': 00233 digit = '9'; 00234 break; 00235 00236 default: 00237 if (digit > ' ') 00238 return -1; 00239 continue; 00240 } 00241 00242 if (*template++ != digit) 00243 return -1; 00244 } 00245 00246 return 0; 00247 }
static int directory_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
Definition at line 758 of file app_directory.c.
References ast_channel::_state, args, ast_answer(), AST_APP_ARG, ast_app_parse_options(), ast_config_destroy(), ast_config_load, AST_DECLARE_APP_ARGS, AST_DIGIT_ANY, ast_log(), ast_set_flag, AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_stopstream(), ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_test_flag, ast_variable_retrieve(), ast_waitfordigit(), ast_waitstream(), config_flags, CONFIG_STATUS_FILEINVALID, dialcontext, directory_app_options, do_directory(), ast_flags::flags, LOG_ERROR, OPT_ARG_ARRAY_SIZE, OPT_ARG_EITHER, OPT_ARG_FIRSTNAME, OPT_ARG_LASTNAME, OPT_LISTBYFIRSTNAME, OPT_LISTBYLASTNAME, OPT_NOANSWER, parse(), and realtime_directory().
Referenced by load_module().
00759 { 00760 int res = 0, digit = 3; 00761 struct ast_config *cfg, *ucfg; 00762 const char *dirintro; 00763 char *parse, *opts[OPT_ARG_ARRAY_SIZE] = { 0, }; 00764 struct ast_flags flags = { 0 }; 00765 struct ast_flags config_flags = { 0 }; 00766 enum { FIRST, LAST, BOTH } which = LAST; 00767 char digits[9] = "digits/3"; 00768 AST_DECLARE_APP_ARGS(args, 00769 AST_APP_ARG(vmcontext); 00770 AST_APP_ARG(dialcontext); 00771 AST_APP_ARG(options); 00772 ); 00773 00774 parse = ast_strdupa(data); 00775 00776 AST_STANDARD_APP_ARGS(args, parse); 00777 00778 if (args.options && ast_app_parse_options(directory_app_options, &flags, opts, args.options)) 00779 return -1; 00780 00781 if (!(cfg = realtime_directory(args.vmcontext))) { 00782 ast_log(LOG_ERROR, "Unable to read the configuration data!\n"); 00783 return -1; 00784 } 00785 00786 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) { 00787 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Aborting.\n"); 00788 ucfg = NULL; 00789 } 00790 00791 dirintro = ast_variable_retrieve(cfg, args.vmcontext, "directoryintro"); 00792 if (ast_strlen_zero(dirintro)) 00793 dirintro = ast_variable_retrieve(cfg, "general", "directoryintro"); 00794 /* the above prompts probably should be modified to include 0 for dialing operator 00795 and # for exiting (continues in dialplan) */ 00796 00797 if (ast_test_flag(&flags, OPT_LISTBYFIRSTNAME) && ast_test_flag(&flags, OPT_LISTBYLASTNAME)) { 00798 if (!ast_strlen_zero(opts[OPT_ARG_EITHER])) { 00799 digit = atoi(opts[OPT_ARG_EITHER]); 00800 } 00801 which = BOTH; 00802 } else if (ast_test_flag(&flags, OPT_LISTBYFIRSTNAME)) { 00803 if (!ast_strlen_zero(opts[OPT_ARG_FIRSTNAME])) { 00804 digit = atoi(opts[OPT_ARG_FIRSTNAME]); 00805 } 00806 which = FIRST; 00807 } else { 00808 if (!ast_strlen_zero(opts[OPT_ARG_LASTNAME])) { 00809 digit = atoi(opts[OPT_ARG_LASTNAME]); 00810 } 00811 which = LAST; 00812 } 00813 00814 /* If no options specified, search by last name */ 00815 if (!ast_test_flag(&flags, OPT_LISTBYFIRSTNAME) && !ast_test_flag(&flags, OPT_LISTBYLASTNAME)) { 00816 ast_set_flag(&flags, OPT_LISTBYLASTNAME); 00817 which = LAST; 00818 } 00819 00820 if (digit > 9) { 00821 digit = 9; 00822 } else if (digit < 1) { 00823 digit = 3; 00824 } 00825 digits[7] = digit + '0'; 00826 00827 if (chan->_state != AST_STATE_UP) { 00828 if (!ast_test_flag(&flags, OPT_NOANSWER)) { 00829 /* Otherwise answer unless we're supposed to read while on-hook */ 00830 res = ast_answer(chan); 00831 } 00832 } 00833 for (;;) { 00834 if (!ast_strlen_zero(dirintro) && !res) { 00835 res = ast_stream_and_wait(chan, dirintro, AST_DIGIT_ANY); 00836 } else if (!res) { 00837 /* Stop playing sounds as soon as we have a digit. */ 00838 res = ast_stream_and_wait(chan, "dir-welcome", AST_DIGIT_ANY); 00839 if (!res) { 00840 res = ast_stream_and_wait(chan, "dir-pls-enter", AST_DIGIT_ANY); 00841 } 00842 if (!res) { 00843 res = ast_stream_and_wait(chan, digits, AST_DIGIT_ANY); 00844 } 00845 if (!res) { 00846 res = ast_stream_and_wait(chan, 00847 which == FIRST ? "dir-first" : 00848 which == LAST ? "dir-last" : 00849 "dir-firstlast", AST_DIGIT_ANY); 00850 } 00851 if (!res) { 00852 res = ast_stream_and_wait(chan, "dir-usingkeypad", AST_DIGIT_ANY); 00853 } 00854 } 00855 ast_stopstream(chan); 00856 if (!res) 00857 res = ast_waitfordigit(chan, 5000); 00858 00859 if (res <= 0) 00860 break; 00861 00862 res = do_directory(chan, cfg, ucfg, args.vmcontext, args.dialcontext, res, digit, &flags, opts); 00863 if (res) 00864 break; 00865 00866 res = ast_waitstream(chan, AST_DIGIT_ANY); 00867 ast_stopstream(chan); 00868 00869 if (res) 00870 break; 00871 } 00872 00873 if (ucfg) 00874 ast_config_destroy(ucfg); 00875 ast_config_destroy(cfg); 00876 00877 return res < 0 ? -1 : 0; 00878 }
static int do_directory | ( | struct ast_channel * | chan, | |
struct ast_config * | vmcfg, | |||
struct ast_config * | ucfg, | |||
char * | context, | |||
char * | dialcontext, | |||
char | digit, | |||
int | digits, | |||
struct ast_flags * | flags, | |||
char * | opts[] | |||
) | [static] |
Definition at line 681 of file app_directory.c.
References ast_calloc, ast_debug, ast_free, AST_LIST_HEAD_NOLOCK_INIT_VALUE, AST_LIST_REMOVE_HEAD, AST_LIST_TRAVERSE, ast_readstring(), ast_streamfile(), ast_test_flag, directory_item::entry, ext, directory_item::exten, goto_exten(), ast_channel::language, directory_item::name, OPT_SELECTFROMMENU, option_debug, search_directory(), select_item_menu(), select_item_seq(), and sort_items().
Referenced by directory_exec().
00682 { 00683 /* Read in the first three digits.. "digit" is the first digit, already read */ 00684 int res = 0; 00685 itemlist alist = AST_LIST_HEAD_NOLOCK_INIT_VALUE; 00686 struct directory_item *item, **ptr, **sorted = NULL; 00687 int count, i; 00688 char ext[10] = ""; 00689 00690 if (digit == '0' && !goto_exten(chan, dialcontext, "o")) { 00691 return digit; 00692 } 00693 00694 if (digit == '*' && !goto_exten(chan, dialcontext, "a")) { 00695 return digit; 00696 } 00697 00698 ext[0] = digit; 00699 if (ast_readstring(chan, ext + 1, digits - 1, 3000, 3000, "#") < 0) 00700 return -1; 00701 00702 res = search_directory(context, vmcfg, ucfg, ext, *flags, &alist); 00703 if (res) 00704 goto exit; 00705 00706 /* Count items in the list */ 00707 count = 0; 00708 AST_LIST_TRAVERSE(&alist, item, entry) { 00709 count++; 00710 } 00711 00712 if (count < 1) { 00713 res = ast_streamfile(chan, "dir-nomatch", chan->language); 00714 goto exit; 00715 } 00716 00717 00718 /* Create plain array of pointers to items (for sorting) */ 00719 sorted = ast_calloc(count, sizeof(*sorted)); 00720 00721 ptr = sorted; 00722 AST_LIST_TRAVERSE(&alist, item, entry) { 00723 *ptr++ = item; 00724 } 00725 00726 /* Sort items */ 00727 sort_items(sorted, count); 00728 00729 if (option_debug) { 00730 ast_debug(2, "Listing matching entries:\n"); 00731 for (ptr = sorted, i = 0; i < count; i++, ptr++) { 00732 ast_debug(2, "%s: %s\n", ptr[0]->exten, ptr[0]->name); 00733 } 00734 } 00735 00736 if (ast_test_flag(flags, OPT_SELECTFROMMENU)) { 00737 /* Offer multiple entries at the same time */ 00738 res = select_item_menu(chan, sorted, count, dialcontext, flags, opts); 00739 } else { 00740 /* Offer entries one by one */ 00741 res = select_item_seq(chan, sorted, count, dialcontext, flags, opts); 00742 } 00743 00744 if (!res) { 00745 res = ast_streamfile(chan, "dir-nomore", chan->language); 00746 } 00747 00748 exit: 00749 if (sorted) 00750 ast_free(sorted); 00751 00752 while ((item = AST_LIST_REMOVE_HEAD(&alist, entry))) 00753 ast_free(item); 00754 00755 return res; 00756 }
static int goto_exten | ( | struct ast_channel * | chan, | |
const char * | dialcontext, | |||
char * | ext | |||
) | [static] |
Definition at line 249 of file app_directory.c.
References ast_goto_if_exists(), ast_log(), ast_strlen_zero(), ast_channel::context, LOG_WARNING, ast_channel::macrocontext, and S_OR.
Referenced by do_directory(), and select_item_seq().
00250 { 00251 if (!ast_goto_if_exists(chan, S_OR(dialcontext, chan->context), ext, 1) || 00252 (!ast_strlen_zero(chan->macrocontext) && 00253 !ast_goto_if_exists(chan, chan->macrocontext, ext, 1))) { 00254 return 0; 00255 } else { 00256 ast_log(LOG_WARNING, "Can't find extension '%s' in current context. " 00257 "Not Exiting the Directory!\n", ext); 00258 return -1; 00259 } 00260 }
static int load_module | ( | void | ) | [static] |
Definition at line 887 of file app_directory.c.
References ast_register_application_xml, and directory_exec().
00888 { 00889 return ast_register_application_xml(app, directory_exec); 00890 }
static int play_mailbox_owner | ( | struct ast_channel * | chan, | |
const char * | context, | |||
const char * | ext, | |||
const char * | name, | |||
struct ast_flags * | flags | |||
) | [static] |
Definition at line 267 of file app_directory.c.
References ast_app_sayname(), AST_DIGIT_ANY, ast_say_character_str(), ast_stopstream(), ast_stream_and_wait(), ast_strlen_zero(), ast_test_flag, ast_channel::language, OPT_SAYEXTENSION, and S_OR.
Referenced by select_item_menu(), and select_item_seq().
00269 { 00270 int res = 0; 00271 if ((res = ast_app_sayname(chan, ext, context)) >= 0) { 00272 ast_stopstream(chan); 00273 /* If Option 'e' was specified, also read the extension number with the name */ 00274 if (ast_test_flag(flags, OPT_SAYEXTENSION)) { 00275 ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY); 00276 res = ast_say_character_str(chan, ext, AST_DIGIT_ANY, chan->language); 00277 } 00278 } else { 00279 res = ast_say_character_str(chan, S_OR(name, ext), AST_DIGIT_ANY, chan->language); 00280 if (!ast_strlen_zero(name) && ast_test_flag(flags, OPT_SAYEXTENSION)) { 00281 ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY); 00282 res = ast_say_character_str(chan, ext, AST_DIGIT_ANY, chan->language); 00283 } 00284 } 00285 00286 return res; 00287 }
static struct ast_config* realtime_directory | ( | char * | context | ) | [static] |
Definition at line 430 of file app_directory.c.
References ast_category_append(), ast_category_browse(), ast_category_get(), ast_category_new(), ast_config_destroy(), ast_config_load, ast_load_realtime_multientry(), ast_log(), ast_strlen_zero(), ast_true(), ast_variable_append(), ast_variable_new(), ast_variable_retrieve(), config_flags, CONFIG_STATUS_FILEINVALID, LOG_ERROR, LOG_WARNING, mailbox, S_OR, SENTINEL, var, and VOICEMAIL_CONFIG.
Referenced by directory_exec().
00431 { 00432 struct ast_config *cfg; 00433 struct ast_config *rtdata; 00434 struct ast_category *cat; 00435 struct ast_variable *var; 00436 char *mailbox; 00437 const char *fullname; 00438 const char *hidefromdir, *searchcontexts = NULL; 00439 char tmp[100]; 00440 struct ast_flags config_flags = { 0 }; 00441 00442 /* Load flat file config. */ 00443 cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags); 00444 00445 if (!cfg) { 00446 /* Loading config failed. */ 00447 ast_log(LOG_WARNING, "Loading config failed.\n"); 00448 return NULL; 00449 } else if (cfg == CONFIG_STATUS_FILEINVALID) { 00450 ast_log(LOG_ERROR, "Config file %s is in an invalid format. Aborting.\n", VOICEMAIL_CONFIG); 00451 return NULL; 00452 } 00453 00454 /* Get realtime entries, categorized by their mailbox number 00455 and present in the requested context */ 00456 if (ast_strlen_zero(context) && (searchcontexts = ast_variable_retrieve(cfg, "general", "searchcontexts"))) { 00457 if (ast_true(searchcontexts)) { 00458 rtdata = ast_load_realtime_multientry("voicemail", "mailbox LIKE", "%", SENTINEL); 00459 context = NULL; 00460 } else { 00461 rtdata = ast_load_realtime_multientry("voicemail", "mailbox LIKE", "%", "context", "default", SENTINEL); 00462 context = "default"; 00463 } 00464 } else { 00465 rtdata = ast_load_realtime_multientry("voicemail", "mailbox LIKE", "%", "context", context, SENTINEL); 00466 } 00467 00468 /* if there are no results, just return the entries from the config file */ 00469 if (!rtdata) { 00470 return cfg; 00471 } 00472 00473 mailbox = NULL; 00474 while ( (mailbox = ast_category_browse(rtdata, mailbox)) ) { 00475 const char *context = ast_variable_retrieve(rtdata, mailbox, "context"); 00476 00477 fullname = ast_variable_retrieve(rtdata, mailbox, "fullname"); 00478 if (ast_true((hidefromdir = ast_variable_retrieve(rtdata, mailbox, "hidefromdir")))) { 00479 /* Skip hidden */ 00480 continue; 00481 } 00482 snprintf(tmp, sizeof(tmp), "no-password,%s", S_OR(fullname, "")); 00483 00484 /* Does the context exist within the config file? If not, make one */ 00485 if (!(cat = ast_category_get(cfg, context))) { 00486 if (!(cat = ast_category_new(context, "", 99999))) { 00487 ast_log(LOG_WARNING, "Out of memory\n"); 00488 ast_config_destroy(cfg); 00489 if (rtdata) { 00490 ast_config_destroy(rtdata); 00491 } 00492 return NULL; 00493 } 00494 ast_category_append(cfg, cat); 00495 } 00496 00497 if ((var = ast_variable_new(mailbox, tmp, ""))) { 00498 ast_variable_append(cat, var); 00499 } else { 00500 ast_log(LOG_WARNING, "Out of memory adding mailbox '%s'\n", mailbox); 00501 } 00502 } 00503 ast_config_destroy(rtdata); 00504 00505 return cfg; 00506 }
static int search_directory | ( | const char * | context, | |
struct ast_config * | vmcfg, | |||
struct ast_config * | ucfg, | |||
const char * | ext, | |||
struct ast_flags | flags, | |||
itemlist * | alist | |||
) | [static] |
Definition at line 630 of file app_directory.c.
References ast_category_browse(), ast_debug, ast_strlen_zero(), ast_true(), ast_variable_retrieve(), and search_directory_sub().
Referenced by do_directory().
00631 { 00632 const char *searchcontexts = ast_variable_retrieve(vmcfg, "general", "searchcontexts"); 00633 if (ast_strlen_zero(context)) { 00634 if (!ast_strlen_zero(searchcontexts) && ast_true(searchcontexts)) { 00635 /* Browse each context for a match */ 00636 int res; 00637 const char *catg; 00638 for (catg = ast_category_browse(vmcfg, NULL); catg; catg = ast_category_browse(vmcfg, catg)) { 00639 if (!strcmp(catg, "general") || !strcmp(catg, "zonemessages")) { 00640 continue; 00641 } 00642 00643 if ((res = search_directory_sub(catg, vmcfg, ucfg, ext, flags, alist))) { 00644 return res; 00645 } 00646 } 00647 return 0; 00648 } else { 00649 ast_debug(1, "Searching by category default\n"); 00650 return search_directory_sub("default", vmcfg, ucfg, ext, flags, alist); 00651 } 00652 } else { 00653 /* Browse only the listed context for a match */ 00654 ast_debug(1, "Searching by category %s\n", context); 00655 return search_directory_sub(context, vmcfg, ucfg, ext, flags, alist); 00656 } 00657 }
static int search_directory_sub | ( | const char * | context, | |
struct ast_config * | vmcfg, | |||
struct ast_config * | ucfg, | |||
const char * | ext, | |||
struct ast_flags | flags, | |||
itemlist * | alist | |||
) | [static] |
Definition at line 555 of file app_directory.c.
References ast_category_browse(), ast_config_option(), ast_copy_string(), ast_debug, AST_LIST_INSERT_TAIL, AST_MAX_EXTENSION, ast_strlen_zero(), ast_test_flag, ast_true(), ast_variable_browse(), ast_variable_retrieve(), check_match(), directory_item::entry, ast_variable::name, ast_variable::next, OPT_LISTBYFIRSTNAME, OPT_LISTBYLASTNAME, strcasestr(), strsep(), and ast_variable::value.
Referenced by search_directory().
00556 { 00557 struct ast_variable *v; 00558 char buf[AST_MAX_EXTENSION + 1], *pos, *bufptr, *cat; 00559 struct directory_item *item; 00560 int res; 00561 00562 ast_debug(2, "Pattern: %s\n", ext); 00563 00564 for (v = ast_variable_browse(vmcfg, context); v; v = v->next) { 00565 00566 /* Ignore hidden */ 00567 if (strcasestr(v->value, "hidefromdir=yes")) 00568 continue; 00569 00570 ast_copy_string(buf, v->value, sizeof(buf)); 00571 bufptr = buf; 00572 00573 /* password,Full Name,email,pager,options */ 00574 strsep(&bufptr, ","); 00575 pos = strsep(&bufptr, ","); 00576 00577 /* No name to compare against */ 00578 if (ast_strlen_zero(pos)) { 00579 continue; 00580 } 00581 00582 res = 0; 00583 if (ast_test_flag(&flags, OPT_LISTBYLASTNAME)) { 00584 res = check_match(&item, context, pos, v->name, ext, 0 /* use_first_name */); 00585 } 00586 if (!res && ast_test_flag(&flags, OPT_LISTBYFIRSTNAME)) { 00587 res = check_match(&item, context, pos, v->name, ext, 1 /* use_first_name */); 00588 } 00589 00590 if (!res) 00591 continue; 00592 else if (res < 0) 00593 return -1; 00594 00595 AST_LIST_INSERT_TAIL(alist, item, entry); 00596 } 00597 00598 if (ucfg) { 00599 for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) { 00600 const char *position; 00601 if (!strcasecmp(cat, "general")) 00602 continue; 00603 if (!ast_true(ast_config_option(ucfg, cat, "hasdirectory"))) 00604 continue; 00605 00606 /* Find all candidate extensions */ 00607 position = ast_variable_retrieve(ucfg, cat, "fullname"); 00608 if (!position) 00609 continue; 00610 00611 res = 0; 00612 if (ast_test_flag(&flags, OPT_LISTBYLASTNAME)) { 00613 res = check_match(&item, context, position, cat, ext, 0 /* use_first_name */); 00614 } 00615 if (!res && ast_test_flag(&flags, OPT_LISTBYFIRSTNAME)) { 00616 res = check_match(&item, context, position, cat, ext, 1 /* use_first_name */); 00617 } 00618 00619 if (!res) 00620 continue; 00621 else if (res < 0) 00622 return -1; 00623 00624 AST_LIST_INSERT_TAIL(alist, item, entry); 00625 } 00626 } 00627 return 0; 00628 }
static int select_entry | ( | struct ast_channel * | chan, | |
const char * | dialcontext, | |||
const struct directory_item * | item, | |||
struct ast_flags * | flags | |||
) | [static] |
Definition at line 289 of file app_directory.c.
References ast_copy_string(), ast_debug, ast_goto_if_exists(), ast_log(), ast_test_flag, directory_item::context, ast_channel::exten, directory_item::exten, LOG_WARNING, directory_item::name, OPT_FROMVOICEMAIL, and S_OR.
Referenced by select_item_menu(), and select_item_seq().
00290 { 00291 ast_debug(1, "Selecting '%s' - %s@%s\n", item->name, item->exten, S_OR(dialcontext, item->context)); 00292 00293 if (ast_test_flag(flags, OPT_FROMVOICEMAIL)) { 00294 /* We still want to set the exten though */ 00295 ast_copy_string(chan->exten, item->exten, sizeof(chan->exten)); 00296 } else if (ast_goto_if_exists(chan, S_OR(dialcontext, item->context), item->exten, 1)) { 00297 ast_log(LOG_WARNING, 00298 "Can't find extension '%s' in context '%s'. " 00299 "Did you pass the wrong context to Directory?\n", 00300 item->exten, S_OR(dialcontext, item->context)); 00301 return -1; 00302 } 00303 00304 return 0; 00305 }
static int select_item_menu | ( | struct ast_channel * | chan, | |
struct directory_item ** | items, | |||
int | count, | |||
const char * | dialcontext, | |||
struct ast_flags * | flags, | |||
char * | opts[] | |||
) | [static] |
Definition at line 367 of file app_directory.c.
References AST_DIGIT_ANY, ast_streamfile(), ast_waitfordigit(), ast_waitstream(), directory_item::context, directory_item::exten, ast_channel::language, directory_item::name, play_mailbox_owner(), select_entry(), and select_item_pause().
Referenced by do_directory().
00368 { 00369 struct directory_item **block, *item; 00370 int i, limit, res = 0; 00371 char buf[9]; 00372 00373 /* option p(n): cellphone pause option */ 00374 select_item_pause(chan, flags, opts); 00375 00376 for (block = items; count; block += limit, count -= limit) { 00377 limit = count; 00378 if (limit > 8) 00379 limit = 8; 00380 00381 for (i = 0; i < limit && !res; i++) { 00382 item = block[i]; 00383 00384 snprintf(buf, sizeof(buf), "digits/%d", i + 1); 00385 /* Press <num> for <name>, [ extension <ext> ] */ 00386 res = ast_streamfile(chan, "dir-multi1", chan->language); 00387 if (!res) 00388 res = ast_waitstream(chan, AST_DIGIT_ANY); 00389 if (!res) 00390 res = ast_streamfile(chan, buf, chan->language); 00391 if (!res) 00392 res = ast_waitstream(chan, AST_DIGIT_ANY); 00393 if (!res) 00394 res = ast_streamfile(chan, "dir-multi2", chan->language); 00395 if (!res) 00396 res = ast_waitstream(chan, AST_DIGIT_ANY); 00397 if (!res) 00398 res = play_mailbox_owner(chan, item->context, item->exten, item->name, flags); 00399 if (!res) 00400 res = ast_waitstream(chan, AST_DIGIT_ANY); 00401 if (!res) 00402 res = ast_waitfordigit(chan, 800); 00403 } 00404 00405 /* Press "9" for more names. */ 00406 if (!res && count > limit) { 00407 res = ast_streamfile(chan, "dir-multi9", chan->language); 00408 if (!res) 00409 res = ast_waitstream(chan, AST_DIGIT_ANY); 00410 } 00411 00412 if (!res) { 00413 res = ast_waitfordigit(chan, 3000); 00414 } 00415 00416 if (res && res > '0' && res < '1' + limit) { 00417 return select_entry(chan, dialcontext, block[res - '1'], flags) ? -1 : 1; 00418 } 00419 00420 if (res < 0) 00421 return -1; 00422 00423 res = 0; 00424 } 00425 00426 /* Nothing was selected */ 00427 return 0; 00428 }
static int select_item_pause | ( | struct ast_channel * | chan, | |
struct ast_flags * | flags, | |||
char * | opts[] | |||
) | [static] |
Definition at line 307 of file app_directory.c.
References ast_strlen_zero(), ast_test_flag, ast_waitfordigit(), OPT_ARG_PAUSE, and OPT_PAUSE.
Referenced by select_item_menu(), and select_item_seq().
00308 { 00309 int res = 0, opt_pause = 0; 00310 00311 if (ast_test_flag(flags, OPT_PAUSE) && !ast_strlen_zero(opts[OPT_ARG_PAUSE])) { 00312 opt_pause = atoi(opts[OPT_ARG_PAUSE]); 00313 if (opt_pause > 3000) { 00314 opt_pause = 3000; 00315 } 00316 res = ast_waitfordigit(chan, opt_pause); 00317 } 00318 return res; 00319 }
static int select_item_seq | ( | struct ast_channel * | chan, | |
struct directory_item ** | items, | |||
int | count, | |||
const char * | dialcontext, | |||
struct ast_flags * | flags, | |||
char * | opts[] | |||
) | [static] |
Definition at line 321 of file app_directory.c.
References AST_DIGIT_ANY, ast_stopstream(), ast_stream_and_wait(), ast_waitfordigit(), directory_item::context, directory_item::exten, goto_exten(), directory_item::name, play_mailbox_owner(), select_entry(), and select_item_pause().
Referenced by do_directory().
00322 { 00323 struct directory_item *item, **ptr; 00324 int i, res, loop; 00325 00326 /* option p(n): cellphone pause option */ 00327 /* allow early press of selection key */ 00328 res = select_item_pause(chan, flags, opts); 00329 00330 for (ptr = items, i = 0; i < count; i++, ptr++) { 00331 item = *ptr; 00332 00333 for (loop = 3 ; loop > 0; loop--) { 00334 if (!res) 00335 res = play_mailbox_owner(chan, item->context, item->exten, item->name, flags); 00336 if (!res) 00337 res = ast_stream_and_wait(chan, "dir-instr", AST_DIGIT_ANY); 00338 if (!res) 00339 res = ast_waitfordigit(chan, 3000); 00340 ast_stopstream(chan); 00341 00342 if (res == '0') { /* operator selected */ 00343 goto_exten(chan, dialcontext, "o"); 00344 return '0'; 00345 } else if (res == '1') { /* Name selected */ 00346 return select_entry(chan, dialcontext, item, flags) ? -1 : 1; 00347 } else if (res == '*') { 00348 /* Skip to next match in list */ 00349 break; 00350 } else if (res == '#') { 00351 /* Exit reading, continue in dialplan */ 00352 return res; 00353 } 00354 00355 if (res < 0) 00356 return -1; 00357 00358 res = 0; 00359 } 00360 res = 0; 00361 } 00362 00363 /* Nothing was selected */ 00364 return 0; 00365 }
static void sort_items | ( | struct directory_item ** | sorted, | |
int | count | |||
) | [static] |
Definition at line 659 of file app_directory.c.
References directory_item::key.
Referenced by do_directory().
00660 { 00661 int reordered, i; 00662 struct directory_item **ptr, *tmp; 00663 00664 if (count < 2) 00665 return; 00666 00667 /* Bubble-sort items by the key */ 00668 do { 00669 reordered = 0; 00670 for (ptr = sorted, i = 0; i < count - 1; i++, ptr++) { 00671 if (strcasecmp(ptr[0]->key, ptr[1]->key) > 0) { 00672 tmp = ptr[0]; 00673 ptr[0] = ptr[1]; 00674 ptr[1] = tmp; 00675 reordered++; 00676 } 00677 } 00678 } while (reordered); 00679 }
static int unload_module | ( | void | ) | [static] |
Definition at line 880 of file app_directory.c.
References ast_unregister_application().
00881 { 00882 int res; 00883 res = ast_unregister_application(app); 00884 return res; 00885 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Extension Directory" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "88eaa8f5c1bd988bedd71113385e0886" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, } [static] |
Definition at line 892 of file app_directory.c.
const char app[] = "Directory" [static] |
Definition at line 122 of file app_directory.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 892 of file app_directory.c.
struct ast_app_option directory_app_options[128] = { [ 'f' ] = { .flag = OPT_LISTBYFIRSTNAME , .arg_index = OPT_ARG_FIRSTNAME + 1 }, [ 'l' ] = { .flag = OPT_LISTBYLASTNAME , .arg_index = OPT_ARG_LASTNAME + 1 }, [ 'b' ] = { .flag = OPT_LISTBYEITHER , .arg_index = OPT_ARG_EITHER + 1 }, [ 'p' ] = { .flag = OPT_PAUSE , .arg_index = OPT_ARG_PAUSE + 1 }, [ 'e' ] = { .flag = OPT_SAYEXTENSION }, [ 'v' ] = { .flag = OPT_FROMVOICEMAIL }, [ 'm' ] = { .flag = OPT_SELECTFROMMENU }, [ 'n' ] = { .flag = OPT_NOANSWER },} [static] |