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