00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include "asterisk.h"
00032
00033 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 249953 $")
00034
00035 #include <ctype.h>
00036
00037 #include "asterisk/paths.h"
00038 #include "asterisk/file.h"
00039 #include "asterisk/pbx.h"
00040 #include "asterisk/module.h"
00041 #include "asterisk/say.h"
00042 #include "asterisk/app.h"
00043 #include "asterisk/utils.h"
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117 static char *app = "Directory";
00118
00119
00120
00121
00122 #define VOICEMAIL_CONFIG "voicemail.conf"
00123
00124 enum {
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;
00133
00134 enum {
00135 OPT_ARG_FIRSTNAME = 0,
00136 OPT_ARG_LASTNAME = 1,
00137 OPT_ARG_EITHER = 2,
00138 OPT_ARG_PAUSE = 3,
00139
00140 OPT_ARG_ARRAY_SIZE = 4,
00141 };
00142
00143 struct directory_item {
00144 char exten[AST_MAX_EXTENSION + 1];
00145 char name[AST_MAX_EXTENSION + 1];
00146 char context[AST_MAX_CONTEXT + 1];
00147 char key[50];
00148
00149 AST_LIST_ENTRY(directory_item) entry;
00150 };
00151
00152 AST_APP_OPTIONS(directory_app_options, {
00153 AST_APP_OPTION_ARG('f', OPT_LISTBYFIRSTNAME, OPT_ARG_FIRSTNAME),
00154 AST_APP_OPTION_ARG('l', OPT_LISTBYLASTNAME, OPT_ARG_LASTNAME),
00155 AST_APP_OPTION_ARG('b', OPT_LISTBYEITHER, OPT_ARG_EITHER),
00156 AST_APP_OPTION_ARG('p', OPT_PAUSE, OPT_ARG_PAUSE),
00157 AST_APP_OPTION('e', OPT_SAYEXTENSION),
00158 AST_APP_OPTION('v', OPT_FROMVOICEMAIL),
00159 AST_APP_OPTION('m', OPT_SELECTFROMMENU),
00160 });
00161
00162 static int compare(const char *text, const char *template)
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 }
00241
00242
00243
00244
00245
00246
00247 static int play_mailbox_owner(struct ast_channel *chan, const char *context,
00248 const char *ext, const char *name, struct ast_flags *flags)
00249 {
00250 int res = 0;
00251 if ((res = ast_app_sayname(chan, ext, context)) >= 0) {
00252 ast_stopstream(chan);
00253
00254 if (ast_test_flag(flags, OPT_SAYEXTENSION)) {
00255 ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
00256 res = ast_say_character_str(chan, ext, AST_DIGIT_ANY, chan->language);
00257 }
00258 } else {
00259 res = ast_say_character_str(chan, S_OR(name, ext), AST_DIGIT_ANY, chan->language);
00260 if (!ast_strlen_zero(name) && ast_test_flag(flags, OPT_SAYEXTENSION)) {
00261 ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
00262 res = ast_say_character_str(chan, ext, AST_DIGIT_ANY, chan->language);
00263 }
00264 }
00265
00266 return res;
00267 }
00268
00269 static int select_entry(struct ast_channel *chan, const char *dialcontext, const struct directory_item *item, struct ast_flags *flags)
00270 {
00271 ast_debug(1, "Selecting '%s' - %s@%s\n", item->name, item->exten, S_OR(dialcontext, item->context));
00272
00273 if (ast_test_flag(flags, OPT_FROMVOICEMAIL)) {
00274
00275 ast_copy_string(chan->exten, item->exten, sizeof(chan->exten));
00276 } else if (ast_goto_if_exists(chan, S_OR(dialcontext, item->context), item->exten, 1)) {
00277 ast_log(LOG_WARNING,
00278 "Can't find extension '%s' in context '%s'. "
00279 "Did you pass the wrong context to Directory?\n",
00280 item->exten, S_OR(dialcontext, item->context));
00281 return -1;
00282 }
00283
00284 return 0;
00285 }
00286
00287 static int select_item_seq(struct ast_channel *chan, struct directory_item **items, int count, const char *dialcontext, struct ast_flags *flags)
00288 {
00289 struct directory_item *item, **ptr;
00290 int i, res, loop;
00291
00292 for (ptr = items, i = 0; i < count; i++, ptr++) {
00293 item = *ptr;
00294
00295 for (loop = 3 ; loop > 0; loop--) {
00296 res = play_mailbox_owner(chan, item->context, item->exten, item->name, flags);
00297
00298 if (!res)
00299 res = ast_stream_and_wait(chan, "dir-instr", AST_DIGIT_ANY);
00300 if (!res)
00301 res = ast_waitfordigit(chan, 3000);
00302 ast_stopstream(chan);
00303
00304 if (res == '1') {
00305 return select_entry(chan, dialcontext, item, flags) ? -1 : 1;
00306 } else if (res == '*') {
00307
00308 break;
00309 }
00310
00311 if (res < 0)
00312 return -1;
00313
00314 res = 0;
00315 }
00316 }
00317
00318
00319 return 0;
00320 }
00321
00322 static int select_item_menu(struct ast_channel *chan, struct directory_item **items, int count, const char *dialcontext, struct ast_flags *flags)
00323 {
00324 struct directory_item **block, *item;
00325 int i, limit, res = 0;
00326 char buf[9];
00327
00328 for (block = items; count; block += limit, count -= limit) {
00329 limit = count;
00330 if (limit > 8)
00331 limit = 8;
00332
00333 for (i = 0; i < limit && !res; i++) {
00334 item = block[i];
00335
00336 snprintf(buf, sizeof(buf), "digits/%d", i + 1);
00337
00338 res = ast_streamfile(chan, "dir-multi1", chan->language);
00339 if (!res)
00340 res = ast_waitstream(chan, AST_DIGIT_ANY);
00341 if (!res)
00342 res = ast_streamfile(chan, buf, chan->language);
00343 if (!res)
00344 res = ast_waitstream(chan, AST_DIGIT_ANY);
00345 if (!res)
00346 res = ast_streamfile(chan, "dir-multi2", chan->language);
00347 if (!res)
00348 res = ast_waitstream(chan, AST_DIGIT_ANY);
00349 if (!res)
00350 res = play_mailbox_owner(chan, item->context, item->exten, item->name, flags);
00351 if (!res)
00352 res = ast_waitstream(chan, AST_DIGIT_ANY);
00353 if (!res)
00354 res = ast_waitfordigit(chan, 800);
00355 }
00356
00357
00358 if (!res && count > limit) {
00359 res = ast_streamfile(chan, "dir-multi9", chan->language);
00360 if (!res)
00361 res = ast_waitstream(chan, AST_DIGIT_ANY);
00362 }
00363
00364 if (!res) {
00365 res = ast_waitfordigit(chan, 3000);
00366 }
00367
00368 if (res && res > '0' && res < '1' + limit) {
00369 return select_entry(chan, dialcontext, block[res - '1'], flags) ? -1 : 1;
00370 }
00371
00372 if (res < 0)
00373 return -1;
00374
00375 res = 0;
00376 }
00377
00378
00379 return 0;
00380 }
00381
00382 static struct ast_config *realtime_directory(char *context)
00383 {
00384 struct ast_config *cfg;
00385 struct ast_config *rtdata;
00386 struct ast_category *cat;
00387 struct ast_variable *var;
00388 char *mailbox;
00389 const char *fullname;
00390 const char *hidefromdir, *searchcontexts = NULL;
00391 char tmp[100];
00392 struct ast_flags config_flags = { 0 };
00393
00394
00395 cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags);
00396
00397 if (!cfg) {
00398
00399 ast_log(LOG_WARNING, "Loading config failed.\n");
00400 return NULL;
00401 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
00402 ast_log(LOG_ERROR, "Config file %s is in an invalid format. Aborting.\n", VOICEMAIL_CONFIG);
00403 return NULL;
00404 }
00405
00406
00407
00408 if (ast_strlen_zero(context) && (searchcontexts = ast_variable_retrieve(cfg, "general", "searchcontexts"))) {
00409 if (ast_true(searchcontexts)) {
00410 rtdata = ast_load_realtime_multientry("voicemail", "mailbox LIKE", "%", SENTINEL);
00411 context = NULL;
00412 } else {
00413 rtdata = ast_load_realtime_multientry("voicemail", "mailbox LIKE", "%", "context", "default", SENTINEL);
00414 context = "default";
00415 }
00416 } else {
00417 rtdata = ast_load_realtime_multientry("voicemail", "mailbox LIKE", "%", "context", context, SENTINEL);
00418 }
00419
00420
00421 if (!rtdata) {
00422 return cfg;
00423 }
00424
00425 mailbox = NULL;
00426 while ( (mailbox = ast_category_browse(rtdata, mailbox)) ) {
00427 const char *context = ast_variable_retrieve(rtdata, mailbox, "context");
00428
00429 fullname = ast_variable_retrieve(rtdata, mailbox, "fullname");
00430 if (ast_true((hidefromdir = ast_variable_retrieve(rtdata, mailbox, "hidefromdir")))) {
00431
00432 continue;
00433 }
00434 snprintf(tmp, sizeof(tmp), "no-password,%s", S_OR(fullname, ""));
00435
00436
00437 if (!(cat = ast_category_get(cfg, context))) {
00438 if (!(cat = ast_category_new(context, "", 99999))) {
00439 ast_log(LOG_WARNING, "Out of memory\n");
00440 ast_config_destroy(cfg);
00441 if (rtdata) {
00442 ast_config_destroy(rtdata);
00443 }
00444 return NULL;
00445 }
00446 ast_category_append(cfg, cat);
00447 }
00448
00449 if ((var = ast_variable_new(mailbox, tmp, ""))) {
00450 ast_variable_append(cat, var);
00451 } else {
00452 ast_log(LOG_WARNING, "Out of memory adding mailbox '%s'\n", mailbox);
00453 }
00454 }
00455 ast_config_destroy(rtdata);
00456
00457 return cfg;
00458 }
00459
00460 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)
00461 {
00462 struct directory_item *item;
00463 const char *key = NULL;
00464 int namelen;
00465
00466 if (ast_strlen_zero(item_fullname)) {
00467 return 0;
00468 }
00469
00470
00471 if (!use_first_name)
00472 key = strchr(item_fullname, ' ');
00473
00474 if (key)
00475 key++;
00476 else
00477 key = item_fullname;
00478
00479 if (compare(key, pattern_ext))
00480 return 0;
00481
00482 ast_debug(1, "Found match %s@%s\n", item_ext, item_context);
00483
00484
00485 item = ast_calloc(1, sizeof(*item));
00486 if (!item)
00487 return -1;
00488 ast_copy_string(item->context, item_context, sizeof(item->context));
00489 ast_copy_string(item->name, item_fullname, sizeof(item->name));
00490 ast_copy_string(item->exten, item_ext, sizeof(item->exten));
00491
00492 ast_copy_string(item->key, key, sizeof(item->key));
00493 if (key != item_fullname) {
00494
00495 namelen = key - item_fullname - 1;
00496 if (namelen > sizeof(item->key) - strlen(item->key) - 1)
00497 namelen = sizeof(item->key) - strlen(item->key) - 1;
00498 strncat(item->key, item_fullname, namelen);
00499 }
00500
00501 *result = item;
00502 return 1;
00503 }
00504
00505 typedef AST_LIST_HEAD_NOLOCK(, directory_item) itemlist;
00506
00507 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)
00508 {
00509 struct ast_variable *v;
00510 char buf[AST_MAX_EXTENSION + 1], *pos, *bufptr, *cat;
00511 struct directory_item *item;
00512 int res;
00513
00514 ast_debug(2, "Pattern: %s\n", ext);
00515
00516 for (v = ast_variable_browse(vmcfg, context); v; v = v->next) {
00517
00518
00519 if (strcasestr(v->value, "hidefromdir=yes"))
00520 continue;
00521
00522 ast_copy_string(buf, v->value, sizeof(buf));
00523 bufptr = buf;
00524
00525
00526 strsep(&bufptr, ",");
00527 pos = strsep(&bufptr, ",");
00528
00529
00530 if (ast_strlen_zero(pos)) {
00531 continue;
00532 }
00533
00534 res = 0;
00535 if (ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
00536 res = check_match(&item, context, pos, v->name, ext, 0 );
00537 }
00538 if (!res && ast_test_flag(&flags, OPT_LISTBYFIRSTNAME)) {
00539 res = check_match(&item, context, pos, v->name, ext, 1 );
00540 }
00541
00542 if (!res)
00543 continue;
00544 else if (res < 0)
00545 return -1;
00546
00547 AST_LIST_INSERT_TAIL(alist, item, entry);
00548 }
00549
00550 if (ucfg) {
00551 for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
00552 const char *position;
00553 if (!strcasecmp(cat, "general"))
00554 continue;
00555 if (!ast_true(ast_config_option(ucfg, cat, "hasdirectory")))
00556 continue;
00557
00558
00559 position = ast_variable_retrieve(ucfg, cat, "fullname");
00560 if (!position)
00561 continue;
00562
00563 res = 0;
00564 if (ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
00565 res = check_match(&item, context, position, cat, ext, 0 );
00566 }
00567 if (!res && ast_test_flag(&flags, OPT_LISTBYFIRSTNAME)) {
00568 res = check_match(&item, context, position, cat, ext, 1 );
00569 }
00570
00571 if (!res)
00572 continue;
00573 else if (res < 0)
00574 return -1;
00575
00576 AST_LIST_INSERT_TAIL(alist, item, entry);
00577 }
00578 }
00579 return 0;
00580 }
00581
00582 static int search_directory(const char *context, struct ast_config *vmcfg, struct ast_config *ucfg, const char *ext, struct ast_flags flags, itemlist *alist)
00583 {
00584 const char *searchcontexts = ast_variable_retrieve(vmcfg, "general", "searchcontexts");
00585 if (ast_strlen_zero(context)) {
00586 if (!ast_strlen_zero(searchcontexts) && ast_true(searchcontexts)) {
00587
00588 int res;
00589 const char *catg;
00590 for (catg = ast_category_browse(vmcfg, NULL); catg; catg = ast_category_browse(vmcfg, catg)) {
00591 if (!strcmp(catg, "general") || !strcmp(catg, "zonemessages")) {
00592 continue;
00593 }
00594
00595 if ((res = search_directory_sub(catg, vmcfg, ucfg, ext, flags, alist))) {
00596 return res;
00597 }
00598 }
00599 return 0;
00600 } else {
00601 ast_debug(1, "Searching by category default\n");
00602 return search_directory_sub("default", vmcfg, ucfg, ext, flags, alist);
00603 }
00604 } else {
00605
00606 ast_debug(1, "Searching by category %s\n", context);
00607 return search_directory_sub(context, vmcfg, ucfg, ext, flags, alist);
00608 }
00609 }
00610
00611 static void sort_items(struct directory_item **sorted, int count)
00612 {
00613 int reordered, i;
00614 struct directory_item **ptr, *tmp;
00615
00616 if (count < 2)
00617 return;
00618
00619
00620 do {
00621 reordered = 0;
00622 for (ptr = sorted, i = 0; i < count - 1; i++, ptr++) {
00623 if (strcasecmp(ptr[0]->key, ptr[1]->key) > 0) {
00624 tmp = ptr[0];
00625 ptr[0] = ptr[1];
00626 ptr[1] = tmp;
00627 reordered++;
00628 }
00629 }
00630 } while (reordered);
00631 }
00632
00633 static int goto_exten(struct ast_channel *chan, const char *dialcontext, char *ext)
00634 {
00635 if (!ast_goto_if_exists(chan, dialcontext, ext, 1) ||
00636 (!ast_strlen_zero(chan->macrocontext) &&
00637 !ast_goto_if_exists(chan, chan->macrocontext, ext, 1))) {
00638 return 0;
00639 } else {
00640 ast_log(LOG_WARNING, "Can't find extension '%s' in current context. "
00641 "Not Exiting the Directory!\n", ext);
00642 return -1;
00643 }
00644 }
00645
00646 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)
00647 {
00648
00649 int res = 0;
00650 itemlist alist = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
00651 struct directory_item *item, **ptr, **sorted = NULL;
00652 int count, i;
00653 char ext[10] = "";
00654
00655 if (digit == '0' && !goto_exten(chan, S_OR(dialcontext, "default"), "o")) {
00656 return digit;
00657 }
00658
00659 if (digit == '*' && !goto_exten(chan, S_OR(dialcontext, "default"), "a")) {
00660 return digit;
00661 }
00662
00663 ext[0] = digit;
00664 if (ast_readstring(chan, ext + 1, digits - 1, 3000, 3000, "#") < 0)
00665 return -1;
00666
00667 res = search_directory(context, vmcfg, ucfg, ext, *flags, &alist);
00668 if (res)
00669 goto exit;
00670
00671
00672 count = 0;
00673 AST_LIST_TRAVERSE(&alist, item, entry) {
00674 count++;
00675 }
00676
00677 if (count < 1) {
00678 res = ast_streamfile(chan, "dir-nomatch", chan->language);
00679 goto exit;
00680 }
00681
00682
00683
00684 sorted = ast_calloc(count, sizeof(*sorted));
00685
00686 ptr = sorted;
00687 AST_LIST_TRAVERSE(&alist, item, entry) {
00688 *ptr++ = item;
00689 }
00690
00691
00692 sort_items(sorted, count);
00693
00694 if (option_debug) {
00695 ast_debug(2, "Listing matching entries:\n");
00696 for (ptr = sorted, i = 0; i < count; i++, ptr++) {
00697 ast_debug(2, "%s: %s\n", ptr[0]->exten, ptr[0]->name);
00698 }
00699 }
00700
00701 if (ast_test_flag(flags, OPT_SELECTFROMMENU)) {
00702
00703 res = select_item_menu(chan, sorted, count, dialcontext, flags);
00704 } else {
00705
00706 res = select_item_seq(chan, sorted, count, dialcontext, flags);
00707 }
00708
00709 if (!res) {
00710 res = ast_streamfile(chan, "dir-nomore", chan->language);
00711 }
00712
00713 exit:
00714 if (sorted)
00715 ast_free(sorted);
00716
00717 while ((item = AST_LIST_REMOVE_HEAD(&alist, entry)))
00718 ast_free(item);
00719
00720 return res;
00721 }
00722
00723 static int directory_exec(struct ast_channel *chan, void *data)
00724 {
00725 int res = 0, digit = 3;
00726 struct ast_config *cfg, *ucfg;
00727 const char *dirintro;
00728 char *parse, *opts[OPT_ARG_ARRAY_SIZE] = { 0, };
00729 struct ast_flags flags = { 0 };
00730 struct ast_flags config_flags = { 0 };
00731 enum { FIRST, LAST, BOTH } which = LAST;
00732 char digits[9] = "digits/3";
00733 AST_DECLARE_APP_ARGS(args,
00734 AST_APP_ARG(vmcontext);
00735 AST_APP_ARG(dialcontext);
00736 AST_APP_ARG(options);
00737 );
00738
00739 parse = ast_strdupa(data);
00740
00741 AST_STANDARD_APP_ARGS(args, parse);
00742
00743 if (args.options && ast_app_parse_options(directory_app_options, &flags, opts, args.options))
00744 return -1;
00745
00746 if (!(cfg = realtime_directory(args.vmcontext))) {
00747 ast_log(LOG_ERROR, "Unable to read the configuration data!\n");
00748 return -1;
00749 }
00750
00751 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) {
00752 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Aborting.\n");
00753 ucfg = NULL;
00754 }
00755
00756 dirintro = ast_variable_retrieve(cfg, args.vmcontext, "directoryintro");
00757 if (ast_strlen_zero(dirintro))
00758 dirintro = ast_variable_retrieve(cfg, "general", "directoryintro");
00759
00760 if (ast_test_flag(&flags, OPT_LISTBYFIRSTNAME) && ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
00761 if (!ast_strlen_zero(opts[OPT_ARG_EITHER])) {
00762 digit = atoi(opts[OPT_ARG_EITHER]);
00763 }
00764 which = BOTH;
00765 } else if (ast_test_flag(&flags, OPT_LISTBYFIRSTNAME)) {
00766 if (!ast_strlen_zero(opts[OPT_ARG_FIRSTNAME])) {
00767 digit = atoi(opts[OPT_ARG_FIRSTNAME]);
00768 }
00769 which = FIRST;
00770 } else {
00771 if (!ast_strlen_zero(opts[OPT_ARG_LASTNAME])) {
00772 digit = atoi(opts[OPT_ARG_LASTNAME]);
00773 }
00774 which = LAST;
00775 }
00776
00777
00778 if (!ast_test_flag(&flags, OPT_LISTBYFIRSTNAME) && !ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
00779 ast_set_flag(&flags, OPT_LISTBYLASTNAME);
00780 which = LAST;
00781 }
00782
00783 if (digit > 9) {
00784 digit = 9;
00785 } else if (digit < 1) {
00786 digit = 3;
00787 }
00788 digits[7] = digit + '0';
00789
00790 if (chan->_state != AST_STATE_UP)
00791 res = ast_answer(chan);
00792
00793 for (;;) {
00794 if (!ast_strlen_zero(dirintro) && !res) {
00795 res = ast_stream_and_wait(chan, dirintro, AST_DIGIT_ANY);
00796 } else if (!res) {
00797
00798 res = ast_stream_and_wait(chan, "dir-welcome", AST_DIGIT_ANY);
00799 if (!res) {
00800 res = ast_stream_and_wait(chan, "dir-pls-enter", AST_DIGIT_ANY);
00801 }
00802 if (!res) {
00803 res = ast_stream_and_wait(chan, digits, AST_DIGIT_ANY);
00804 }
00805 if (!res) {
00806 res = ast_stream_and_wait(chan,
00807 which == FIRST ? "dir-first" :
00808 which == LAST ? "dir-last" :
00809 "dir-firstlast", AST_DIGIT_ANY);
00810 }
00811 if (!res) {
00812 res = ast_stream_and_wait(chan, "dir-usingkeypad", AST_DIGIT_ANY);
00813 }
00814 }
00815 ast_stopstream(chan);
00816 if (!res)
00817 res = ast_waitfordigit(chan, 5000);
00818
00819 if (res <= 0)
00820 break;
00821
00822 res = do_directory(chan, cfg, ucfg, args.vmcontext, args.dialcontext, res, digit, &flags);
00823 if (res)
00824 break;
00825
00826 res = ast_waitstream(chan, AST_DIGIT_ANY);
00827 ast_stopstream(chan);
00828
00829 if (res)
00830 break;
00831 }
00832
00833 if (ucfg)
00834 ast_config_destroy(ucfg);
00835 ast_config_destroy(cfg);
00836
00837 return res < 0 ? -1 : 0;
00838 }
00839
00840 static int unload_module(void)
00841 {
00842 int res;
00843 res = ast_unregister_application(app);
00844 return res;
00845 }
00846
00847 static int load_module(void)
00848 {
00849 return ast_register_application_xml(app, directory_exec);
00850 }
00851
00852 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Extension Directory");