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