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: 263809 $")
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 static int goto_exten(struct ast_channel *chan, const char *dialcontext, char *ext)
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 }
00254
00255
00256
00257
00258
00259
00260 static int play_mailbox_owner(struct ast_channel *chan, const char *context,
00261 const char *ext, const char *name, struct ast_flags *flags)
00262 {
00263 int res = 0;
00264 if ((res = ast_app_sayname(chan, ext, context)) >= 0) {
00265 ast_stopstream(chan);
00266
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 }
00281
00282 static int select_entry(struct ast_channel *chan, const char *dialcontext, const struct directory_item *item, struct ast_flags *flags)
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
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 }
00299
00300 static int select_item_pause(struct ast_channel *chan, struct ast_flags *flags, char *opts[])
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 }
00313
00314 static int select_item_seq(struct ast_channel *chan, struct directory_item **items, int count, const char *dialcontext, struct ast_flags *flags, char *opts[])
00315 {
00316 struct directory_item *item, **ptr;
00317 int i, res, loop;
00318
00319
00320
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') {
00336 goto_exten(chan, dialcontext, "o");
00337 return '0';
00338 } else if (res == '1') {
00339 return select_entry(chan, dialcontext, item, flags) ? -1 : 1;
00340 } else if (res == '*') {
00341
00342 break;
00343 } else if (res == '#') {
00344
00345 return res;
00346 }
00347
00348 if (res < 0)
00349 return -1;
00350
00351 res = 0;
00352 }
00353 res = 0;
00354 }
00355
00356
00357 return 0;
00358 }
00359
00360 static int select_item_menu(struct ast_channel *chan, struct directory_item **items, int count, const char *dialcontext, struct ast_flags *flags, char *opts[])
00361 {
00362 struct directory_item **block, *item;
00363 int i, limit, res = 0;
00364 char buf[9];
00365
00366
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
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
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
00420 return 0;
00421 }
00422
00423 static struct ast_config *realtime_directory(char *context)
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
00436 cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags);
00437
00438 if (!cfg) {
00439
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
00448
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
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
00473 continue;
00474 }
00475 snprintf(tmp, sizeof(tmp), "no-password,%s", S_OR(fullname, ""));
00476
00477
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 }
00500
00501 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)
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
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
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
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 }
00545
00546 typedef AST_LIST_HEAD_NOLOCK(, directory_item) itemlist;
00547
00548 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)
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
00560 if (strcasestr(v->value, "hidefromdir=yes"))
00561 continue;
00562
00563 ast_copy_string(buf, v->value, sizeof(buf));
00564 bufptr = buf;
00565
00566
00567 strsep(&bufptr, ",");
00568 pos = strsep(&bufptr, ",");
00569
00570
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 );
00578 }
00579 if (!res && ast_test_flag(&flags, OPT_LISTBYFIRSTNAME)) {
00580 res = check_match(&item, context, pos, v->name, ext, 1 );
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
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 );
00607 }
00608 if (!res && ast_test_flag(&flags, OPT_LISTBYFIRSTNAME)) {
00609 res = check_match(&item, context, position, cat, ext, 1 );
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 }
00622
00623 static int search_directory(const char *context, struct ast_config *vmcfg, struct ast_config *ucfg, const char *ext, struct ast_flags flags, itemlist *alist)
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
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
00647 ast_debug(1, "Searching by category %s\n", context);
00648 return search_directory_sub(context, vmcfg, ucfg, ext, flags, alist);
00649 }
00650 }
00651
00652 static void sort_items(struct directory_item **sorted, int count)
00653 {
00654 int reordered, i;
00655 struct directory_item **ptr, *tmp;
00656
00657 if (count < 2)
00658 return;
00659
00660
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 }
00673
00674 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[])
00675 {
00676
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
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
00712 sorted = ast_calloc(count, sizeof(*sorted));
00713
00714 ptr = sorted;
00715 AST_LIST_TRAVERSE(&alist, item, entry) {
00716 *ptr++ = item;
00717 }
00718
00719
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
00731 res = select_item_menu(chan, sorted, count, dialcontext, flags, opts);
00732 } else {
00733
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 }
00750
00751 static int directory_exec(struct ast_channel *chan, void *data)
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
00788
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
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
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 }
00869
00870 static int unload_module(void)
00871 {
00872 int res;
00873 res = ast_unregister_application(app);
00874 return res;
00875 }
00876
00877 static int load_module(void)
00878 {
00879 return ast_register_application_xml(app, directory_exec);
00880 }
00881
00882 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Extension Directory");