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: 251820 $")
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_pause(struct ast_channel *chan, struct ast_flags *flags, char *opts[])
00288 {
00289 int res = 0, opt_pause = 0;
00290
00291 if (ast_test_flag(flags, OPT_PAUSE) && !ast_strlen_zero(opts[OPT_ARG_PAUSE])) {
00292 opt_pause = atoi(opts[OPT_ARG_PAUSE]);
00293 if (opt_pause > 3000) {
00294 opt_pause = 3000;
00295 }
00296 res = ast_waitfordigit(chan, opt_pause);
00297 }
00298 return res;
00299 }
00300
00301 static int select_item_seq(struct ast_channel *chan, struct directory_item **items, int count, const char *dialcontext, struct ast_flags *flags, char *opts[])
00302 {
00303 struct directory_item *item, **ptr;
00304 int i, res, loop;
00305
00306
00307
00308 res = select_item_pause(chan, flags, opts);
00309
00310 for (ptr = items, i = 0; i < count; i++, ptr++) {
00311 item = *ptr;
00312
00313 for (loop = 3 ; loop > 0; loop--) {
00314 if (!res)
00315 res = play_mailbox_owner(chan, item->context, item->exten, item->name, flags);
00316 if (!res)
00317 res = ast_stream_and_wait(chan, "dir-instr", AST_DIGIT_ANY);
00318 if (!res)
00319 res = ast_waitfordigit(chan, 3000);
00320 ast_stopstream(chan);
00321
00322 if (res == '1') {
00323 return select_entry(chan, dialcontext, item, flags) ? -1 : 1;
00324 } else if (res == '*') {
00325
00326 break;
00327 }
00328
00329 if (res < 0)
00330 return -1;
00331
00332 res = 0;
00333 }
00334 res = 0;
00335 }
00336
00337
00338 return 0;
00339 }
00340
00341 static int select_item_menu(struct ast_channel *chan, struct directory_item **items, int count, const char *dialcontext, struct ast_flags *flags, char *opts[])
00342 {
00343 struct directory_item **block, *item;
00344 int i, limit, res = 0;
00345 char buf[9];
00346
00347
00348 select_item_pause(chan, flags, opts);
00349
00350 for (block = items; count; block += limit, count -= limit) {
00351 limit = count;
00352 if (limit > 8)
00353 limit = 8;
00354
00355 for (i = 0; i < limit && !res; i++) {
00356 item = block[i];
00357
00358 snprintf(buf, sizeof(buf), "digits/%d", i + 1);
00359
00360 res = ast_streamfile(chan, "dir-multi1", chan->language);
00361 if (!res)
00362 res = ast_waitstream(chan, AST_DIGIT_ANY);
00363 if (!res)
00364 res = ast_streamfile(chan, buf, chan->language);
00365 if (!res)
00366 res = ast_waitstream(chan, AST_DIGIT_ANY);
00367 if (!res)
00368 res = ast_streamfile(chan, "dir-multi2", chan->language);
00369 if (!res)
00370 res = ast_waitstream(chan, AST_DIGIT_ANY);
00371 if (!res)
00372 res = play_mailbox_owner(chan, item->context, item->exten, item->name, flags);
00373 if (!res)
00374 res = ast_waitstream(chan, AST_DIGIT_ANY);
00375 if (!res)
00376 res = ast_waitfordigit(chan, 800);
00377 }
00378
00379
00380 if (!res && count > limit) {
00381 res = ast_streamfile(chan, "dir-multi9", chan->language);
00382 if (!res)
00383 res = ast_waitstream(chan, AST_DIGIT_ANY);
00384 }
00385
00386 if (!res) {
00387 res = ast_waitfordigit(chan, 3000);
00388 }
00389
00390 if (res && res > '0' && res < '1' + limit) {
00391 return select_entry(chan, dialcontext, block[res - '1'], flags) ? -1 : 1;
00392 }
00393
00394 if (res < 0)
00395 return -1;
00396
00397 res = 0;
00398 }
00399
00400
00401 return 0;
00402 }
00403
00404 static struct ast_config *realtime_directory(char *context)
00405 {
00406 struct ast_config *cfg;
00407 struct ast_config *rtdata;
00408 struct ast_category *cat;
00409 struct ast_variable *var;
00410 char *mailbox;
00411 const char *fullname;
00412 const char *hidefromdir, *searchcontexts = NULL;
00413 char tmp[100];
00414 struct ast_flags config_flags = { 0 };
00415
00416
00417 cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags);
00418
00419 if (!cfg) {
00420
00421 ast_log(LOG_WARNING, "Loading config failed.\n");
00422 return NULL;
00423 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
00424 ast_log(LOG_ERROR, "Config file %s is in an invalid format. Aborting.\n", VOICEMAIL_CONFIG);
00425 return NULL;
00426 }
00427
00428
00429
00430 if (ast_strlen_zero(context) && (searchcontexts = ast_variable_retrieve(cfg, "general", "searchcontexts"))) {
00431 if (ast_true(searchcontexts)) {
00432 rtdata = ast_load_realtime_multientry("voicemail", "mailbox LIKE", "%", SENTINEL);
00433 context = NULL;
00434 } else {
00435 rtdata = ast_load_realtime_multientry("voicemail", "mailbox LIKE", "%", "context", "default", SENTINEL);
00436 context = "default";
00437 }
00438 } else {
00439 rtdata = ast_load_realtime_multientry("voicemail", "mailbox LIKE", "%", "context", context, SENTINEL);
00440 }
00441
00442
00443 if (!rtdata) {
00444 return cfg;
00445 }
00446
00447 mailbox = NULL;
00448 while ( (mailbox = ast_category_browse(rtdata, mailbox)) ) {
00449 const char *context = ast_variable_retrieve(rtdata, mailbox, "context");
00450
00451 fullname = ast_variable_retrieve(rtdata, mailbox, "fullname");
00452 if (ast_true((hidefromdir = ast_variable_retrieve(rtdata, mailbox, "hidefromdir")))) {
00453
00454 continue;
00455 }
00456 snprintf(tmp, sizeof(tmp), "no-password,%s", S_OR(fullname, ""));
00457
00458
00459 if (!(cat = ast_category_get(cfg, context))) {
00460 if (!(cat = ast_category_new(context, "", 99999))) {
00461 ast_log(LOG_WARNING, "Out of memory\n");
00462 ast_config_destroy(cfg);
00463 if (rtdata) {
00464 ast_config_destroy(rtdata);
00465 }
00466 return NULL;
00467 }
00468 ast_category_append(cfg, cat);
00469 }
00470
00471 if ((var = ast_variable_new(mailbox, tmp, ""))) {
00472 ast_variable_append(cat, var);
00473 } else {
00474 ast_log(LOG_WARNING, "Out of memory adding mailbox '%s'\n", mailbox);
00475 }
00476 }
00477 ast_config_destroy(rtdata);
00478
00479 return cfg;
00480 }
00481
00482 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)
00483 {
00484 struct directory_item *item;
00485 const char *key = NULL;
00486 int namelen;
00487
00488 if (ast_strlen_zero(item_fullname)) {
00489 return 0;
00490 }
00491
00492
00493 if (!use_first_name)
00494 key = strchr(item_fullname, ' ');
00495
00496 if (key)
00497 key++;
00498 else
00499 key = item_fullname;
00500
00501 if (compare(key, pattern_ext))
00502 return 0;
00503
00504 ast_debug(1, "Found match %s@%s\n", item_ext, item_context);
00505
00506
00507 item = ast_calloc(1, sizeof(*item));
00508 if (!item)
00509 return -1;
00510 ast_copy_string(item->context, item_context, sizeof(item->context));
00511 ast_copy_string(item->name, item_fullname, sizeof(item->name));
00512 ast_copy_string(item->exten, item_ext, sizeof(item->exten));
00513
00514 ast_copy_string(item->key, key, sizeof(item->key));
00515 if (key != item_fullname) {
00516
00517 namelen = key - item_fullname - 1;
00518 if (namelen > sizeof(item->key) - strlen(item->key) - 1)
00519 namelen = sizeof(item->key) - strlen(item->key) - 1;
00520 strncat(item->key, item_fullname, namelen);
00521 }
00522
00523 *result = item;
00524 return 1;
00525 }
00526
00527 typedef AST_LIST_HEAD_NOLOCK(, directory_item) itemlist;
00528
00529 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)
00530 {
00531 struct ast_variable *v;
00532 char buf[AST_MAX_EXTENSION + 1], *pos, *bufptr, *cat;
00533 struct directory_item *item;
00534 int res;
00535
00536 ast_debug(2, "Pattern: %s\n", ext);
00537
00538 for (v = ast_variable_browse(vmcfg, context); v; v = v->next) {
00539
00540
00541 if (strcasestr(v->value, "hidefromdir=yes"))
00542 continue;
00543
00544 ast_copy_string(buf, v->value, sizeof(buf));
00545 bufptr = buf;
00546
00547
00548 strsep(&bufptr, ",");
00549 pos = strsep(&bufptr, ",");
00550
00551
00552 if (ast_strlen_zero(pos)) {
00553 continue;
00554 }
00555
00556 res = 0;
00557 if (ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
00558 res = check_match(&item, context, pos, v->name, ext, 0 );
00559 }
00560 if (!res && ast_test_flag(&flags, OPT_LISTBYFIRSTNAME)) {
00561 res = check_match(&item, context, pos, v->name, ext, 1 );
00562 }
00563
00564 if (!res)
00565 continue;
00566 else if (res < 0)
00567 return -1;
00568
00569 AST_LIST_INSERT_TAIL(alist, item, entry);
00570 }
00571
00572 if (ucfg) {
00573 for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
00574 const char *position;
00575 if (!strcasecmp(cat, "general"))
00576 continue;
00577 if (!ast_true(ast_config_option(ucfg, cat, "hasdirectory")))
00578 continue;
00579
00580
00581 position = ast_variable_retrieve(ucfg, cat, "fullname");
00582 if (!position)
00583 continue;
00584
00585 res = 0;
00586 if (ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
00587 res = check_match(&item, context, position, cat, ext, 0 );
00588 }
00589 if (!res && ast_test_flag(&flags, OPT_LISTBYFIRSTNAME)) {
00590 res = check_match(&item, context, position, cat, ext, 1 );
00591 }
00592
00593 if (!res)
00594 continue;
00595 else if (res < 0)
00596 return -1;
00597
00598 AST_LIST_INSERT_TAIL(alist, item, entry);
00599 }
00600 }
00601 return 0;
00602 }
00603
00604 static int search_directory(const char *context, struct ast_config *vmcfg, struct ast_config *ucfg, const char *ext, struct ast_flags flags, itemlist *alist)
00605 {
00606 const char *searchcontexts = ast_variable_retrieve(vmcfg, "general", "searchcontexts");
00607 if (ast_strlen_zero(context)) {
00608 if (!ast_strlen_zero(searchcontexts) && ast_true(searchcontexts)) {
00609
00610 int res;
00611 const char *catg;
00612 for (catg = ast_category_browse(vmcfg, NULL); catg; catg = ast_category_browse(vmcfg, catg)) {
00613 if (!strcmp(catg, "general") || !strcmp(catg, "zonemessages")) {
00614 continue;
00615 }
00616
00617 if ((res = search_directory_sub(catg, vmcfg, ucfg, ext, flags, alist))) {
00618 return res;
00619 }
00620 }
00621 return 0;
00622 } else {
00623 ast_debug(1, "Searching by category default\n");
00624 return search_directory_sub("default", vmcfg, ucfg, ext, flags, alist);
00625 }
00626 } else {
00627
00628 ast_debug(1, "Searching by category %s\n", context);
00629 return search_directory_sub(context, vmcfg, ucfg, ext, flags, alist);
00630 }
00631 }
00632
00633 static void sort_items(struct directory_item **sorted, int count)
00634 {
00635 int reordered, i;
00636 struct directory_item **ptr, *tmp;
00637
00638 if (count < 2)
00639 return;
00640
00641
00642 do {
00643 reordered = 0;
00644 for (ptr = sorted, i = 0; i < count - 1; i++, ptr++) {
00645 if (strcasecmp(ptr[0]->key, ptr[1]->key) > 0) {
00646 tmp = ptr[0];
00647 ptr[0] = ptr[1];
00648 ptr[1] = tmp;
00649 reordered++;
00650 }
00651 }
00652 } while (reordered);
00653 }
00654
00655 static int goto_exten(struct ast_channel *chan, const char *dialcontext, char *ext)
00656 {
00657 if (!ast_goto_if_exists(chan, dialcontext, ext, 1) ||
00658 (!ast_strlen_zero(chan->macrocontext) &&
00659 !ast_goto_if_exists(chan, chan->macrocontext, ext, 1))) {
00660 return 0;
00661 } else {
00662 ast_log(LOG_WARNING, "Can't find extension '%s' in current context. "
00663 "Not Exiting the Directory!\n", ext);
00664 return -1;
00665 }
00666 }
00667
00668 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[])
00669 {
00670
00671 int res = 0;
00672 itemlist alist = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
00673 struct directory_item *item, **ptr, **sorted = NULL;
00674 int count, i;
00675 char ext[10] = "";
00676
00677 if (digit == '0' && !goto_exten(chan, S_OR(dialcontext, "default"), "o")) {
00678 return digit;
00679 }
00680
00681 if (digit == '*' && !goto_exten(chan, S_OR(dialcontext, "default"), "a")) {
00682 return digit;
00683 }
00684
00685 ext[0] = digit;
00686 if (ast_readstring(chan, ext + 1, digits - 1, 3000, 3000, "#") < 0)
00687 return -1;
00688
00689 res = search_directory(context, vmcfg, ucfg, ext, *flags, &alist);
00690 if (res)
00691 goto exit;
00692
00693
00694 count = 0;
00695 AST_LIST_TRAVERSE(&alist, item, entry) {
00696 count++;
00697 }
00698
00699 if (count < 1) {
00700 res = ast_streamfile(chan, "dir-nomatch", chan->language);
00701 goto exit;
00702 }
00703
00704
00705
00706 sorted = ast_calloc(count, sizeof(*sorted));
00707
00708 ptr = sorted;
00709 AST_LIST_TRAVERSE(&alist, item, entry) {
00710 *ptr++ = item;
00711 }
00712
00713
00714 sort_items(sorted, count);
00715
00716 if (option_debug) {
00717 ast_debug(2, "Listing matching entries:\n");
00718 for (ptr = sorted, i = 0; i < count; i++, ptr++) {
00719 ast_debug(2, "%s: %s\n", ptr[0]->exten, ptr[0]->name);
00720 }
00721 }
00722
00723 if (ast_test_flag(flags, OPT_SELECTFROMMENU)) {
00724
00725 res = select_item_menu(chan, sorted, count, dialcontext, flags, opts);
00726 } else {
00727
00728 res = select_item_seq(chan, sorted, count, dialcontext, flags, opts);
00729 }
00730
00731 if (!res) {
00732 res = ast_streamfile(chan, "dir-nomore", chan->language);
00733 }
00734
00735 exit:
00736 if (sorted)
00737 ast_free(sorted);
00738
00739 while ((item = AST_LIST_REMOVE_HEAD(&alist, entry)))
00740 ast_free(item);
00741
00742 return res;
00743 }
00744
00745 static int directory_exec(struct ast_channel *chan, void *data)
00746 {
00747 int res = 0, digit = 3;
00748 struct ast_config *cfg, *ucfg;
00749 const char *dirintro;
00750 char *parse, *opts[OPT_ARG_ARRAY_SIZE] = { 0, };
00751 struct ast_flags flags = { 0 };
00752 struct ast_flags config_flags = { 0 };
00753 enum { FIRST, LAST, BOTH } which = LAST;
00754 char digits[9] = "digits/3";
00755 AST_DECLARE_APP_ARGS(args,
00756 AST_APP_ARG(vmcontext);
00757 AST_APP_ARG(dialcontext);
00758 AST_APP_ARG(options);
00759 );
00760
00761 parse = ast_strdupa(data);
00762
00763 AST_STANDARD_APP_ARGS(args, parse);
00764
00765 if (args.options && ast_app_parse_options(directory_app_options, &flags, opts, args.options))
00766 return -1;
00767
00768 if (!(cfg = realtime_directory(args.vmcontext))) {
00769 ast_log(LOG_ERROR, "Unable to read the configuration data!\n");
00770 return -1;
00771 }
00772
00773 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) {
00774 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Aborting.\n");
00775 ucfg = NULL;
00776 }
00777
00778 dirintro = ast_variable_retrieve(cfg, args.vmcontext, "directoryintro");
00779 if (ast_strlen_zero(dirintro))
00780 dirintro = ast_variable_retrieve(cfg, "general", "directoryintro");
00781
00782 if (ast_test_flag(&flags, OPT_LISTBYFIRSTNAME) && ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
00783 if (!ast_strlen_zero(opts[OPT_ARG_EITHER])) {
00784 digit = atoi(opts[OPT_ARG_EITHER]);
00785 }
00786 which = BOTH;
00787 } else if (ast_test_flag(&flags, OPT_LISTBYFIRSTNAME)) {
00788 if (!ast_strlen_zero(opts[OPT_ARG_FIRSTNAME])) {
00789 digit = atoi(opts[OPT_ARG_FIRSTNAME]);
00790 }
00791 which = FIRST;
00792 } else {
00793 if (!ast_strlen_zero(opts[OPT_ARG_LASTNAME])) {
00794 digit = atoi(opts[OPT_ARG_LASTNAME]);
00795 }
00796 which = LAST;
00797 }
00798
00799
00800 if (!ast_test_flag(&flags, OPT_LISTBYFIRSTNAME) && !ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
00801 ast_set_flag(&flags, OPT_LISTBYLASTNAME);
00802 which = LAST;
00803 }
00804
00805 if (digit > 9) {
00806 digit = 9;
00807 } else if (digit < 1) {
00808 digit = 3;
00809 }
00810 digits[7] = digit + '0';
00811
00812 if (chan->_state != AST_STATE_UP)
00813 res = ast_answer(chan);
00814
00815 for (;;) {
00816 if (!ast_strlen_zero(dirintro) && !res) {
00817 res = ast_stream_and_wait(chan, dirintro, AST_DIGIT_ANY);
00818 } else if (!res) {
00819
00820 res = ast_stream_and_wait(chan, "dir-welcome", AST_DIGIT_ANY);
00821 if (!res) {
00822 res = ast_stream_and_wait(chan, "dir-pls-enter", AST_DIGIT_ANY);
00823 }
00824 if (!res) {
00825 res = ast_stream_and_wait(chan, digits, AST_DIGIT_ANY);
00826 }
00827 if (!res) {
00828 res = ast_stream_and_wait(chan,
00829 which == FIRST ? "dir-first" :
00830 which == LAST ? "dir-last" :
00831 "dir-firstlast", AST_DIGIT_ANY);
00832 }
00833 if (!res) {
00834 res = ast_stream_and_wait(chan, "dir-usingkeypad", AST_DIGIT_ANY);
00835 }
00836 }
00837 ast_stopstream(chan);
00838 if (!res)
00839 res = ast_waitfordigit(chan, 5000);
00840
00841 if (res <= 0)
00842 break;
00843
00844 res = do_directory(chan, cfg, ucfg, args.vmcontext, args.dialcontext, res, digit, &flags, opts);
00845 if (res)
00846 break;
00847
00848 res = ast_waitstream(chan, AST_DIGIT_ANY);
00849 ast_stopstream(chan);
00850
00851 if (res)
00852 break;
00853 }
00854
00855 if (ucfg)
00856 ast_config_destroy(ucfg);
00857 ast_config_destroy(cfg);
00858
00859 return res < 0 ? -1 : 0;
00860 }
00861
00862 static int unload_module(void)
00863 {
00864 int res;
00865 res = ast_unregister_application(app);
00866 return res;
00867 }
00868
00869 static int load_module(void)
00870 {
00871 return ast_register_application_xml(app, directory_exec);
00872 }
00873
00874 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Extension Directory");