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: 234895 $")
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 static char *app = "Directory";
00046
00047 static char *synopsis = "Provide directory of voicemail extensions";
00048 static char *descrip =
00049 " Directory(vm-context[,dial-context[,options]]): This application will present\n"
00050 "the calling channel with a directory of extensions from which they can search\n"
00051 "by name. The list of names and corresponding extensions is retrieved from the\n"
00052 "voicemail configuration file, voicemail.conf.\n"
00053 " This application will immediately exit if one of the following DTMF digits are\n"
00054 "received and the extension to jump to exists:\n"
00055 " 0 - Jump to the 'o' extension, if it exists.\n"
00056 " * - Jump to the 'a' extension, if it exists.\n\n"
00057 " Parameters:\n"
00058 " vm-context - This is the context within voicemail.conf to use for the\n"
00059 " Directory.\n"
00060 " dial-context - This is the dialplan context to use when looking for an\n"
00061 " extension that the user has selected, or when jumping to the\n"
00062 " 'o' or 'a' extension.\n\n"
00063 " Options:\n"
00064 " e In addition to the name, also read the extension number to the\n"
00065 " caller before presenting dialing options.\n"
00066 " f[(<n>)] Allow the caller to enter the first name of a user in the\n"
00067 " directory instead of using the last name. If specified, the\n"
00068 " optional number argument will be used for the number of\n"
00069 " characters the user should enter.\n"
00070 " l[(<n>)] Allow the caller to enter the last name of a user in the\n"
00071 " directory. This is the default. If specified, the\n"
00072 " optional number argument will be used for the number of\n"
00073 " characters the user should enter.\n"
00074 " b[(<n>)] Allow the caller to enter either the first or the last name\n"
00075 " of a user in the directory. If specified, the optional number\n"
00076 " argument will be used for the number of characters the user\n"
00077 " should enter.\n"
00078 " m Instead of reading each name sequentially and asking for\n"
00079 " confirmation, create a menu of up to 8 names.\n"
00080 " p(<n>) Pause for n milliseconds after the digits are typed. This is\n"
00081 " helpful for people with cellphones, who are not holding the\n"
00082 " receiver to their ear while entering DTMF.\n"
00083 "\n"
00084 " Only one of the f, l, or b options may be specified. If more than one is\n"
00085 " specified, then Directory will act as if 'b' was specified. The number\n"
00086 " of characters for the user to type defaults to 3.\n";
00087
00088
00089
00090
00091 #define VOICEMAIL_CONFIG "voicemail.conf"
00092
00093 enum {
00094 OPT_LISTBYFIRSTNAME = (1 << 0),
00095 OPT_SAYEXTENSION = (1 << 1),
00096 OPT_FROMVOICEMAIL = (1 << 2),
00097 OPT_SELECTFROMMENU = (1 << 3),
00098 OPT_LISTBYLASTNAME = (1 << 4),
00099 OPT_LISTBYEITHER = OPT_LISTBYFIRSTNAME | OPT_LISTBYLASTNAME,
00100 OPT_PAUSE = (1 << 5),
00101 } directory_option_flags;
00102
00103 enum {
00104 OPT_ARG_FIRSTNAME = 0,
00105 OPT_ARG_LASTNAME = 1,
00106 OPT_ARG_EITHER = 2,
00107 OPT_ARG_PAUSE = 3,
00108
00109 OPT_ARG_ARRAY_SIZE = 4,
00110 };
00111
00112 struct directory_item {
00113 char exten[AST_MAX_EXTENSION + 1];
00114 char name[AST_MAX_EXTENSION + 1];
00115 char key[50];
00116
00117 AST_LIST_ENTRY(directory_item) entry;
00118 };
00119
00120 AST_APP_OPTIONS(directory_app_options, {
00121 AST_APP_OPTION_ARG('f', OPT_LISTBYFIRSTNAME, OPT_ARG_FIRSTNAME),
00122 AST_APP_OPTION_ARG('l', OPT_LISTBYLASTNAME, OPT_ARG_LASTNAME),
00123 AST_APP_OPTION_ARG('b', OPT_LISTBYEITHER, OPT_ARG_EITHER),
00124 AST_APP_OPTION_ARG('p', OPT_PAUSE, OPT_ARG_PAUSE),
00125 AST_APP_OPTION('e', OPT_SAYEXTENSION),
00126 AST_APP_OPTION('v', OPT_FROMVOICEMAIL),
00127 AST_APP_OPTION('m', OPT_SELECTFROMMENU),
00128 });
00129
00130 static int compare(const char *text, const char *template)
00131 {
00132 char digit;
00133
00134 if (ast_strlen_zero(text)) {
00135 return -1;
00136 }
00137
00138 while (*template) {
00139 digit = toupper(*text++);
00140 switch (digit) {
00141 case 0:
00142 return -1;
00143 case '1':
00144 digit = '1';
00145 break;
00146 case '2':
00147 case 'A':
00148 case 'B':
00149 case 'C':
00150 digit = '2';
00151 break;
00152 case '3':
00153 case 'D':
00154 case 'E':
00155 case 'F':
00156 digit = '3';
00157 break;
00158 case '4':
00159 case 'G':
00160 case 'H':
00161 case 'I':
00162 digit = '4';
00163 break;
00164 case '5':
00165 case 'J':
00166 case 'K':
00167 case 'L':
00168 digit = '5';
00169 break;
00170 case '6':
00171 case 'M':
00172 case 'N':
00173 case 'O':
00174 digit = '6';
00175 break;
00176 case '7':
00177 case 'P':
00178 case 'Q':
00179 case 'R':
00180 case 'S':
00181 digit = '7';
00182 break;
00183 case '8':
00184 case 'T':
00185 case 'U':
00186 case 'V':
00187 digit = '8';
00188 break;
00189 case '9':
00190 case 'W':
00191 case 'X':
00192 case 'Y':
00193 case 'Z':
00194 digit = '9';
00195 break;
00196
00197 default:
00198 if (digit > ' ')
00199 return -1;
00200 continue;
00201 }
00202
00203 if (*template++ != digit)
00204 return -1;
00205 }
00206
00207 return 0;
00208 }
00209
00210
00211
00212
00213
00214
00215 static int play_mailbox_owner(struct ast_channel *chan, const char *context,
00216 const char *ext, const char *name, struct ast_flags *flags)
00217 {
00218 int res = 0;
00219 if ((res = ast_app_sayname(chan, ext, context)) >= 0) {
00220 ast_stopstream(chan);
00221
00222 if (ast_test_flag(flags, OPT_SAYEXTENSION)) {
00223 ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
00224 res = ast_say_character_str(chan, ext, AST_DIGIT_ANY, chan->language);
00225 }
00226 } else {
00227 res = ast_say_character_str(chan, S_OR(name, ext), AST_DIGIT_ANY, chan->language);
00228 if (!ast_strlen_zero(name) && ast_test_flag(flags, OPT_SAYEXTENSION)) {
00229 ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
00230 res = ast_say_character_str(chan, ext, AST_DIGIT_ANY, chan->language);
00231 }
00232 }
00233
00234 return res;
00235 }
00236
00237 static int select_entry(struct ast_channel *chan, const char *context, const char *dialcontext, const struct directory_item *item, struct ast_flags *flags)
00238 {
00239 ast_debug(1, "Selecting '%s' - %s@%s\n", item->name, item->exten, dialcontext);
00240
00241 if (ast_test_flag(flags, OPT_FROMVOICEMAIL)) {
00242
00243 ast_copy_string(chan->exten, item->exten, sizeof(chan->exten));
00244 } else if (ast_goto_if_exists(chan, dialcontext, item->exten, 1)) {
00245 ast_log(LOG_WARNING,
00246 "Can't find extension '%s' in context '%s'. "
00247 "Did you pass the wrong context to Directory?\n",
00248 item->exten, dialcontext);
00249 return -1;
00250 }
00251
00252 return 0;
00253 }
00254
00255 static int select_item_seq(struct ast_channel *chan, struct directory_item **items, int count, const char *context, const char *dialcontext, struct ast_flags *flags)
00256 {
00257 struct directory_item *item, **ptr;
00258 int i, res, loop;
00259
00260 for (ptr = items, i = 0; i < count; i++, ptr++) {
00261 item = *ptr;
00262
00263 for (loop = 3 ; loop > 0; loop--) {
00264 res = play_mailbox_owner(chan, context, item->exten, item->name, flags);
00265
00266 if (!res)
00267 res = ast_stream_and_wait(chan, "dir-instr", AST_DIGIT_ANY);
00268 if (!res)
00269 res = ast_waitfordigit(chan, 3000);
00270 ast_stopstream(chan);
00271
00272 if (res == '1') {
00273 return select_entry(chan, context, dialcontext, item, flags) ? -1 : 1;
00274 } else if (res == '*') {
00275
00276 break;
00277 }
00278
00279 if (res < 0)
00280 return -1;
00281
00282 res = 0;
00283 }
00284 }
00285
00286
00287 return 0;
00288 }
00289
00290 static int select_item_menu(struct ast_channel *chan, struct directory_item **items, int count, const char *context, const char *dialcontext, struct ast_flags *flags)
00291 {
00292 struct directory_item **block, *item;
00293 int i, limit, res = 0;
00294 char buf[9];
00295
00296 for (block = items; count; block += limit, count -= limit) {
00297 limit = count;
00298 if (limit > 8)
00299 limit = 8;
00300
00301 for (i = 0; i < limit && !res; i++) {
00302 item = block[i];
00303
00304 snprintf(buf, sizeof(buf), "digits/%d", i + 1);
00305
00306 res = ast_streamfile(chan, "dir-multi1", chan->language);
00307 if (!res)
00308 res = ast_waitstream(chan, AST_DIGIT_ANY);
00309 if (!res)
00310 res = ast_streamfile(chan, buf, chan->language);
00311 if (!res)
00312 res = ast_waitstream(chan, AST_DIGIT_ANY);
00313 if (!res)
00314 res = ast_streamfile(chan, "dir-multi2", chan->language);
00315 if (!res)
00316 res = ast_waitstream(chan, AST_DIGIT_ANY);
00317 if (!res)
00318 res = play_mailbox_owner(chan, context, item->exten, item->name, flags);
00319 if (!res)
00320 res = ast_waitstream(chan, AST_DIGIT_ANY);
00321 if (!res)
00322 res = ast_waitfordigit(chan, 800);
00323 }
00324
00325
00326 if (!res && count > limit) {
00327 res = ast_streamfile(chan, "dir-multi9", chan->language);
00328 if (!res)
00329 res = ast_waitstream(chan, AST_DIGIT_ANY);
00330 }
00331
00332 if (!res) {
00333 res = ast_waitfordigit(chan, 3000);
00334 }
00335
00336 if (res && res > '0' && res < '1' + limit) {
00337 return select_entry(chan, context, dialcontext, block[res - '1'], flags) ? -1 : 1;
00338 }
00339
00340 if (res < 0)
00341 return -1;
00342
00343 res = 0;
00344 }
00345
00346
00347 return 0;
00348 }
00349
00350 static struct ast_config *realtime_directory(char *context)
00351 {
00352 struct ast_config *cfg;
00353 struct ast_config *rtdata;
00354 struct ast_category *cat;
00355 struct ast_variable *var;
00356 char *mailbox;
00357 const char *fullname;
00358 const char *hidefromdir;
00359 char tmp[100];
00360 struct ast_flags config_flags = { 0 };
00361
00362
00363 cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags);
00364
00365 if (!cfg) {
00366
00367 ast_log(LOG_WARNING, "Loading config failed.\n");
00368 return NULL;
00369 }
00370
00371
00372
00373 rtdata = ast_load_realtime_multientry("voicemail", "mailbox LIKE", "%", "context", context, SENTINEL);
00374
00375
00376 if (!rtdata)
00377 return cfg;
00378
00379
00380 cat = ast_category_get(cfg, context);
00381 if (!cat) {
00382 cat = ast_category_new(context, "", 99999);
00383 if (!cat) {
00384 ast_log(LOG_WARNING, "Out of memory\n");
00385 ast_config_destroy(cfg);
00386 if (rtdata) {
00387 ast_config_destroy(rtdata);
00388 }
00389 return NULL;
00390 }
00391 ast_category_append(cfg, cat);
00392 }
00393
00394 mailbox = NULL;
00395 while ( (mailbox = ast_category_browse(rtdata, mailbox)) ) {
00396 fullname = ast_variable_retrieve(rtdata, mailbox, "fullname");
00397 if (ast_true((hidefromdir = ast_variable_retrieve(rtdata, mailbox, "hidefromdir")))) {
00398
00399 continue;
00400 }
00401 snprintf(tmp, sizeof(tmp), "no-password,%s", S_OR(fullname, ""));
00402 var = ast_variable_new(mailbox, tmp, "");
00403 if (var)
00404 ast_variable_append(cat, var);
00405 else
00406 ast_log(LOG_WARNING, "Out of memory adding mailbox '%s'\n", mailbox);
00407 }
00408 ast_config_destroy(rtdata);
00409
00410 return cfg;
00411 }
00412
00413 static int check_match(struct directory_item **result, const char *item_fullname, const char *item_ext, const char *pattern_ext, int use_first_name)
00414 {
00415 struct directory_item *item;
00416 const char *key = NULL;
00417 int namelen;
00418
00419
00420
00421 if (!use_first_name)
00422 key = strchr(item_fullname, ' ');
00423
00424 if (key)
00425 key++;
00426 else
00427 key = item_fullname;
00428
00429 if (compare(key, pattern_ext))
00430 return 0;
00431
00432
00433 item = ast_calloc(1, sizeof(*item));
00434 if (!item)
00435 return -1;
00436 ast_copy_string(item->name, item_fullname, sizeof(item->name));
00437 ast_copy_string(item->exten, item_ext, sizeof(item->exten));
00438
00439 ast_copy_string(item->key, key, sizeof(item->key));
00440 if (key != item_fullname) {
00441
00442 namelen = key - item_fullname - 1;
00443 if (namelen > sizeof(item->key) - strlen(item->key) - 1)
00444 namelen = sizeof(item->key) - strlen(item->key) - 1;
00445 strncat(item->key, item_fullname, namelen);
00446 }
00447
00448 *result = item;
00449 return 1;
00450 }
00451
00452 typedef AST_LIST_HEAD_NOLOCK(, directory_item) itemlist;
00453
00454 static int search_directory(const char *context, struct ast_config *vmcfg, struct ast_config *ucfg, const char *ext, struct ast_flags flags, itemlist *alist)
00455 {
00456 struct ast_variable *v;
00457 char buf[AST_MAX_EXTENSION + 1], *pos, *bufptr, *cat;
00458 struct directory_item *item;
00459 int res;
00460
00461 ast_debug(2, "Pattern: %s\n", ext);
00462
00463 for (v = ast_variable_browse(vmcfg, context); v; v = v->next) {
00464
00465
00466 if (strcasestr(v->value, "hidefromdir=yes"))
00467 continue;
00468
00469 ast_copy_string(buf, v->value, sizeof(buf));
00470 bufptr = buf;
00471
00472
00473 strsep(&bufptr, ",");
00474 pos = strsep(&bufptr, ",");
00475
00476
00477 if (ast_strlen_zero(pos)) {
00478 continue;
00479 }
00480
00481 res = 0;
00482 if (ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
00483 res = check_match(&item, pos, v->name, ext, 0 );
00484 }
00485 if (!res && ast_test_flag(&flags, OPT_LISTBYFIRSTNAME)) {
00486 res = check_match(&item, pos, v->name, ext, 1 );
00487 }
00488
00489 if (!res)
00490 continue;
00491 else if (res < 0)
00492 return -1;
00493
00494 AST_LIST_INSERT_TAIL(alist, item, entry);
00495 }
00496
00497 if (ucfg) {
00498 for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
00499 const char *position;
00500 if (!strcasecmp(cat, "general"))
00501 continue;
00502 if (!ast_true(ast_config_option(ucfg, cat, "hasdirectory")))
00503 continue;
00504
00505
00506 position = ast_variable_retrieve(ucfg, cat, "fullname");
00507 if (!position)
00508 continue;
00509
00510 res = 0;
00511 if (ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
00512 res = check_match(&item, position, cat, ext, 0 );
00513 }
00514 if (!res && ast_test_flag(&flags, OPT_LISTBYFIRSTNAME)) {
00515 res = check_match(&item, position, cat, ext, 1 );
00516 }
00517
00518 if (!res)
00519 continue;
00520 else if (res < 0)
00521 return -1;
00522
00523 AST_LIST_INSERT_TAIL(alist, item, entry);
00524 }
00525 }
00526 return 0;
00527 }
00528
00529 static void sort_items(struct directory_item **sorted, int count)
00530 {
00531 int reordered, i;
00532 struct directory_item **ptr, *tmp;
00533
00534 if (count < 2)
00535 return;
00536
00537
00538 do {
00539 reordered = 0;
00540 for (ptr = sorted, i = 0; i < count - 1; i++, ptr++) {
00541 if (strcasecmp(ptr[0]->key, ptr[1]->key) > 0) {
00542 tmp = ptr[0];
00543 ptr[0] = ptr[1];
00544 ptr[1] = tmp;
00545 reordered++;
00546 }
00547 }
00548 } while (reordered);
00549 }
00550
00551 static int goto_exten(struct ast_channel *chan, const char *dialcontext, char *ext)
00552 {
00553 if (!ast_goto_if_exists(chan, dialcontext, ext, 1) ||
00554 (!ast_strlen_zero(chan->macrocontext) &&
00555 !ast_goto_if_exists(chan, chan->macrocontext, ext, 1))) {
00556 return 0;
00557 } else {
00558 ast_log(LOG_WARNING, "Can't find extension '%s' in current context. "
00559 "Not Exiting the Directory!\n", ext);
00560 return -1;
00561 }
00562 }
00563
00564 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)
00565 {
00566
00567 int res = 0;
00568 itemlist alist = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
00569 struct directory_item *item, **ptr, **sorted = NULL;
00570 int count, i;
00571 char ext[10] = "";
00572
00573 if (ast_strlen_zero(context)) {
00574 ast_log(LOG_WARNING,
00575 "Directory must be called with an argument "
00576 "(context in which to interpret extensions)\n");
00577 return -1;
00578 }
00579
00580 if (digit == '0' && !goto_exten(chan, dialcontext, "o")) {
00581 return digit;
00582 }
00583
00584 if (digit == '*' && !goto_exten(chan, dialcontext, "a")) {
00585 return digit;
00586 }
00587
00588 ext[0] = digit;
00589 if (ast_readstring(chan, ext + 1, digits - 1, 3000, 3000, "#") < 0)
00590 return -1;
00591
00592 res = search_directory(context, vmcfg, ucfg, ext, *flags, &alist);
00593 if (res)
00594 goto exit;
00595
00596
00597 count = 0;
00598 AST_LIST_TRAVERSE(&alist, item, entry) {
00599 count++;
00600 }
00601
00602 if (count < 1) {
00603 res = ast_streamfile(chan, "dir-nomatch", chan->language);
00604 goto exit;
00605 }
00606
00607
00608
00609 sorted = ast_calloc(count, sizeof(*sorted));
00610
00611 ptr = sorted;
00612 AST_LIST_TRAVERSE(&alist, item, entry) {
00613 *ptr++ = item;
00614 }
00615
00616
00617 sort_items(sorted, count);
00618
00619 if (option_debug) {
00620 ast_debug(2, "Listing matching entries:\n");
00621 for (ptr = sorted, i = 0; i < count; i++, ptr++) {
00622 ast_log(LOG_DEBUG, "%s: %s\n", ptr[0]->exten, ptr[0]->name);
00623 }
00624 }
00625
00626 if (ast_test_flag(flags, OPT_SELECTFROMMENU)) {
00627
00628 res = select_item_menu(chan, sorted, count, context, dialcontext, flags);
00629 } else {
00630
00631 res = select_item_seq(chan, sorted, count, context, dialcontext, flags);
00632 }
00633
00634 if (!res) {
00635 res = ast_streamfile(chan, "dir-nomore", chan->language);
00636 }
00637
00638 exit:
00639 if (sorted)
00640 ast_free(sorted);
00641
00642 while ((item = AST_LIST_REMOVE_HEAD(&alist, entry)))
00643 ast_free(item);
00644
00645 return res;
00646 }
00647
00648 static int directory_exec(struct ast_channel *chan, void *data)
00649 {
00650 int res = 0, digit = 3;
00651 struct ast_config *cfg, *ucfg;
00652 const char *dirintro;
00653 char *parse, *opts[OPT_ARG_ARRAY_SIZE] = { "", };
00654 struct ast_flags flags = { 0 };
00655 struct ast_flags config_flags = { 0 };
00656 enum { FIRST, LAST, BOTH } which = LAST;
00657 char digits[9] = "digits/3";
00658 AST_DECLARE_APP_ARGS(args,
00659 AST_APP_ARG(vmcontext);
00660 AST_APP_ARG(dialcontext);
00661 AST_APP_ARG(options);
00662 );
00663
00664 if (ast_strlen_zero(data)) {
00665 ast_log(LOG_WARNING, "Directory requires an argument (context[,dialcontext])\n");
00666 return -1;
00667 }
00668
00669 parse = ast_strdupa(data);
00670
00671 AST_STANDARD_APP_ARGS(args, parse);
00672
00673 if (args.options && ast_app_parse_options(directory_app_options, &flags, opts, args.options))
00674 return -1;
00675
00676 if (ast_strlen_zero(args.dialcontext))
00677 args.dialcontext = args.vmcontext;
00678
00679 cfg = realtime_directory(args.vmcontext);
00680 if (!cfg) {
00681 ast_log(LOG_ERROR, "Unable to read the configuration data!\n");
00682 return -1;
00683 }
00684
00685 ucfg = ast_config_load("users.conf", config_flags);
00686
00687 dirintro = ast_variable_retrieve(cfg, args.vmcontext, "directoryintro");
00688 if (ast_strlen_zero(dirintro))
00689 dirintro = ast_variable_retrieve(cfg, "general", "directoryintro");
00690
00691 if (ast_test_flag(&flags, OPT_LISTBYFIRSTNAME) && ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
00692 if (!ast_strlen_zero(opts[OPT_ARG_EITHER])) {
00693 digit = atoi(opts[OPT_ARG_EITHER]);
00694 }
00695 which = BOTH;
00696 } else if (ast_test_flag(&flags, OPT_LISTBYFIRSTNAME)) {
00697 if (!ast_strlen_zero(opts[OPT_ARG_FIRSTNAME])) {
00698 digit = atoi(opts[OPT_ARG_FIRSTNAME]);
00699 }
00700 which = FIRST;
00701 } else {
00702 if (!ast_strlen_zero(opts[OPT_ARG_LASTNAME])) {
00703 digit = atoi(opts[OPT_ARG_LASTNAME]);
00704 }
00705 which = LAST;
00706 }
00707
00708
00709 if (!ast_test_flag(&flags, OPT_LISTBYFIRSTNAME) && !ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
00710 ast_set_flag(&flags, OPT_LISTBYLASTNAME);
00711 which = LAST;
00712 }
00713
00714 if (digit > 9) {
00715 digit = 9;
00716 } else if (digit < 1) {
00717 digit = 3;
00718 }
00719 digits[7] = digit + '0';
00720
00721 if (chan->_state != AST_STATE_UP)
00722 res = ast_answer(chan);
00723
00724 for (;;) {
00725 if (!ast_strlen_zero(dirintro) && !res) {
00726 res = ast_stream_and_wait(chan, dirintro, AST_DIGIT_ANY);
00727 } else if (!res) {
00728
00729 res = ast_stream_and_wait(chan, "dir-welcome", AST_DIGIT_ANY);
00730 if (!res) {
00731 res = ast_stream_and_wait(chan, "dir-pls-enter", AST_DIGIT_ANY);
00732 }
00733 if (!res) {
00734 res = ast_stream_and_wait(chan, digits, AST_DIGIT_ANY);
00735 }
00736 if (!res) {
00737 res = ast_stream_and_wait(chan,
00738 which == FIRST ? "dir-first" :
00739 which == LAST ? "dir-last" :
00740 "dir-firstlast", AST_DIGIT_ANY);
00741 }
00742 if (!res) {
00743 res = ast_stream_and_wait(chan, "dir-usingkeypad", AST_DIGIT_ANY);
00744 }
00745 }
00746 ast_stopstream(chan);
00747 if (!res)
00748 res = ast_waitfordigit(chan, 5000);
00749
00750 if (res <= 0)
00751 break;
00752
00753 res = do_directory(chan, cfg, ucfg, args.vmcontext, args.dialcontext, res, digit, &flags);
00754 if (res)
00755 break;
00756
00757 res = ast_waitstream(chan, AST_DIGIT_ANY);
00758 ast_stopstream(chan);
00759
00760 if (res)
00761 break;
00762 }
00763
00764 if (ucfg)
00765 ast_config_destroy(ucfg);
00766 ast_config_destroy(cfg);
00767
00768 return res < 0 ? -1 : 0;
00769 }
00770
00771 static int unload_module(void)
00772 {
00773 int res;
00774 res = ast_unregister_application(app);
00775 return res;
00776 }
00777
00778 static int load_module(void)
00779 {
00780 return ast_register_application(app, directory_exec, synopsis, descrip);
00781 }
00782
00783 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Extension Directory");