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: 165324 $")
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 res = 0;
00477 if (ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
00478 res = check_match(&item, pos, v->name, ext, 0 );
00479 }
00480 if (!res && ast_test_flag(&flags, OPT_LISTBYFIRSTNAME)) {
00481 res = check_match(&item, pos, v->name, ext, 1 );
00482 }
00483
00484 if (!res)
00485 continue;
00486 else if (res < 0)
00487 return -1;
00488
00489 AST_LIST_INSERT_TAIL(alist, item, entry);
00490 }
00491
00492 if (ucfg) {
00493 for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
00494 const char *position;
00495 if (!strcasecmp(cat, "general"))
00496 continue;
00497 if (!ast_true(ast_config_option(ucfg, cat, "hasdirectory")))
00498 continue;
00499
00500
00501 position = ast_variable_retrieve(ucfg, cat, "fullname");
00502 if (!position)
00503 continue;
00504
00505 res = 0;
00506 if (ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
00507 res = check_match(&item, position, cat, ext, 0 );
00508 }
00509 if (!res && ast_test_flag(&flags, OPT_LISTBYFIRSTNAME)) {
00510 res = check_match(&item, position, cat, ext, 1 );
00511 }
00512
00513 if (!res)
00514 continue;
00515 else if (res < 0)
00516 return -1;
00517
00518 AST_LIST_INSERT_TAIL(alist, item, entry);
00519 }
00520 }
00521 return 0;
00522 }
00523
00524 static void sort_items(struct directory_item **sorted, int count)
00525 {
00526 int reordered, i;
00527 struct directory_item **ptr, *tmp;
00528
00529 if (count < 2)
00530 return;
00531
00532
00533 do {
00534 reordered = 0;
00535 for (ptr = sorted, i = 0; i < count - 1; i++, ptr++) {
00536 if (strcasecmp(ptr[0]->key, ptr[1]->key) > 0) {
00537 tmp = ptr[0];
00538 ptr[0] = ptr[1];
00539 ptr[1] = tmp;
00540 reordered++;
00541 }
00542 }
00543 } while (reordered);
00544 }
00545
00546 static int goto_exten(struct ast_channel *chan, const char *dialcontext, char *ext)
00547 {
00548 if (!ast_goto_if_exists(chan, dialcontext, ext, 1) ||
00549 (!ast_strlen_zero(chan->macrocontext) &&
00550 !ast_goto_if_exists(chan, chan->macrocontext, ext, 1))) {
00551 return 0;
00552 } else {
00553 ast_log(LOG_WARNING, "Can't find extension '%s' in current context. "
00554 "Not Exiting the Directory!\n", ext);
00555 return -1;
00556 }
00557 }
00558
00559 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)
00560 {
00561
00562 int res = 0;
00563 itemlist alist = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
00564 struct directory_item *item, **ptr, **sorted = NULL;
00565 int count, i;
00566 char ext[10] = "";
00567
00568 if (ast_strlen_zero(context)) {
00569 ast_log(LOG_WARNING,
00570 "Directory must be called with an argument "
00571 "(context in which to interpret extensions)\n");
00572 return -1;
00573 }
00574
00575 if (digit == '0' && !goto_exten(chan, dialcontext, "o")) {
00576 return 0;
00577 }
00578
00579 if (digit == '*' && !goto_exten(chan, dialcontext, "a")) {
00580 return 0;
00581 }
00582
00583 ext[0] = digit;
00584 if (ast_readstring(chan, ext + 1, digits - 1, 3000, 3000, "#") < 0)
00585 return -1;
00586
00587 res = search_directory(context, vmcfg, ucfg, ext, *flags, &alist);
00588 if (res)
00589 goto exit;
00590
00591
00592 count = 0;
00593 AST_LIST_TRAVERSE(&alist, item, entry) {
00594 count++;
00595 }
00596
00597 if (count < 1) {
00598 res = ast_streamfile(chan, "dir-nomatch", chan->language);
00599 goto exit;
00600 }
00601
00602
00603
00604 sorted = ast_calloc(count, sizeof(*sorted));
00605
00606 ptr = sorted;
00607 AST_LIST_TRAVERSE(&alist, item, entry) {
00608 *ptr++ = item;
00609 }
00610
00611
00612 sort_items(sorted, count);
00613
00614 if (option_debug) {
00615 ast_debug(2, "Listing matching entries:\n");
00616 for (ptr = sorted, i = 0; i < count; i++, ptr++) {
00617 ast_log(LOG_DEBUG, "%s: %s\n", ptr[0]->exten, ptr[0]->name);
00618 }
00619 }
00620
00621 if (ast_test_flag(flags, OPT_SELECTFROMMENU)) {
00622
00623 res = select_item_menu(chan, sorted, count, context, dialcontext, flags);
00624 } else {
00625
00626 res = select_item_seq(chan, sorted, count, context, dialcontext, flags);
00627 }
00628
00629 if (!res) {
00630 res = ast_streamfile(chan, "dir-nomore", chan->language);
00631 }
00632
00633 exit:
00634 if (sorted)
00635 ast_free(sorted);
00636
00637 while ((item = AST_LIST_REMOVE_HEAD(&alist, entry)))
00638 ast_free(item);
00639
00640 return res;
00641 }
00642
00643 static int directory_exec(struct ast_channel *chan, void *data)
00644 {
00645 int res = 0, digit = 3;
00646 struct ast_config *cfg, *ucfg;
00647 const char *dirintro;
00648 char *parse, *opts[OPT_ARG_ARRAY_SIZE];
00649 struct ast_flags flags = { 0 };
00650 struct ast_flags config_flags = { 0 };
00651 enum { FIRST, LAST, BOTH } which = LAST;
00652 char digits[9] = "digits/3";
00653 AST_DECLARE_APP_ARGS(args,
00654 AST_APP_ARG(vmcontext);
00655 AST_APP_ARG(dialcontext);
00656 AST_APP_ARG(options);
00657 );
00658
00659 if (ast_strlen_zero(data)) {
00660 ast_log(LOG_WARNING, "Directory requires an argument (context[,dialcontext])\n");
00661 return -1;
00662 }
00663
00664 parse = ast_strdupa(data);
00665
00666 AST_STANDARD_APP_ARGS(args, parse);
00667
00668 if (args.options && ast_app_parse_options(directory_app_options, &flags, opts, args.options))
00669 return -1;
00670
00671 if (ast_strlen_zero(args.dialcontext))
00672 args.dialcontext = args.vmcontext;
00673
00674 cfg = realtime_directory(args.vmcontext);
00675 if (!cfg) {
00676 ast_log(LOG_ERROR, "Unable to read the configuration data!\n");
00677 return -1;
00678 }
00679
00680 ucfg = ast_config_load("users.conf", config_flags);
00681
00682 dirintro = ast_variable_retrieve(cfg, args.vmcontext, "directoryintro");
00683 if (ast_strlen_zero(dirintro))
00684 dirintro = ast_variable_retrieve(cfg, "general", "directoryintro");
00685
00686 if (ast_test_flag(&flags, OPT_LISTBYFIRSTNAME) && ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
00687 if (!ast_strlen_zero(opts[OPT_ARG_EITHER])) {
00688 digit = atoi(opts[OPT_ARG_EITHER]);
00689 }
00690 which = BOTH;
00691 } else if (ast_test_flag(&flags, OPT_LISTBYFIRSTNAME)) {
00692 if (!ast_strlen_zero(opts[OPT_ARG_FIRSTNAME])) {
00693 digit = atoi(opts[OPT_ARG_FIRSTNAME]);
00694 }
00695 which = FIRST;
00696 } else {
00697 if (!ast_strlen_zero(opts[OPT_ARG_LASTNAME])) {
00698 digit = atoi(opts[OPT_ARG_LASTNAME]);
00699 }
00700 which = LAST;
00701 }
00702
00703
00704 if (!ast_test_flag(&flags, OPT_LISTBYFIRSTNAME) && !ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
00705 ast_set_flag(&flags, OPT_LISTBYLASTNAME);
00706 which = LAST;
00707 }
00708
00709 if (digit > 9) {
00710 digit = 9;
00711 } else if (digit < 1) {
00712 digit = 3;
00713 }
00714 digits[7] = digit + '0';
00715
00716 if (chan->_state != AST_STATE_UP)
00717 res = ast_answer(chan);
00718
00719 for (;;) {
00720 if (!ast_strlen_zero(dirintro) && !res) {
00721 res = ast_stream_and_wait(chan, dirintro, AST_DIGIT_ANY);
00722 } else if (!res) {
00723
00724 res = ast_stream_and_wait(chan, "dir-welcome", AST_DIGIT_ANY);
00725 if (!res) {
00726 res = ast_stream_and_wait(chan, "dir-pls-enter", AST_DIGIT_ANY);
00727 }
00728 if (!res) {
00729 res = ast_stream_and_wait(chan, digits, AST_DIGIT_ANY);
00730 }
00731 if (!res) {
00732 res = ast_stream_and_wait(chan,
00733 which == FIRST ? "dir-first" :
00734 which == LAST ? "dir-last" :
00735 "dir-firstlast", AST_DIGIT_ANY);
00736 }
00737 if (!res) {
00738 ast_stream_and_wait(chan, "dir-usingkeypad", AST_DIGIT_ANY);
00739 }
00740 }
00741 ast_stopstream(chan);
00742 if (!res)
00743 res = ast_waitfordigit(chan, 5000);
00744
00745 if (res <= 0)
00746 break;
00747
00748 res = do_directory(chan, cfg, ucfg, args.vmcontext, args.dialcontext, res, digit, &flags);
00749 if (res)
00750 break;
00751
00752 res = ast_waitstream(chan, AST_DIGIT_ANY);
00753 ast_stopstream(chan);
00754
00755 if (res)
00756 break;
00757 }
00758
00759 if (ucfg)
00760 ast_config_destroy(ucfg);
00761 ast_config_destroy(cfg);
00762
00763 return res < 0 ? -1 : 0;
00764 }
00765
00766 static int unload_module(void)
00767 {
00768 int res;
00769 res = ast_unregister_application(app);
00770 return res;
00771 }
00772
00773 static int load_module(void)
00774 {
00775 return ast_register_application(app, directory_exec, synopsis, descrip);
00776 }
00777
00778 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Extension Directory");