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: 263807 $")
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
00118
00119
00120 static const char app[] = "Directory";
00121
00122
00123
00124
00125 #define VOICEMAIL_CONFIG "voicemail.conf"
00126
00127 enum {
00128 OPT_LISTBYFIRSTNAME = (1 << 0),
00129 OPT_SAYEXTENSION = (1 << 1),
00130 OPT_FROMVOICEMAIL = (1 << 2),
00131 OPT_SELECTFROMMENU = (1 << 3),
00132 OPT_LISTBYLASTNAME = (1 << 4),
00133 OPT_LISTBYEITHER = OPT_LISTBYFIRSTNAME | OPT_LISTBYLASTNAME,
00134 OPT_PAUSE = (1 << 5),
00135 OPT_NOANSWER = (1 << 6),
00136 };
00137
00138 enum {
00139 OPT_ARG_FIRSTNAME = 0,
00140 OPT_ARG_LASTNAME = 1,
00141 OPT_ARG_EITHER = 2,
00142 OPT_ARG_PAUSE = 3,
00143
00144 OPT_ARG_ARRAY_SIZE = 4,
00145 };
00146
00147 struct directory_item {
00148 char exten[AST_MAX_EXTENSION + 1];
00149 char name[AST_MAX_EXTENSION + 1];
00150 char context[AST_MAX_CONTEXT + 1];
00151 char key[50];
00152
00153 AST_LIST_ENTRY(directory_item) entry;
00154 };
00155
00156 AST_APP_OPTIONS(directory_app_options, {
00157 AST_APP_OPTION_ARG('f', OPT_LISTBYFIRSTNAME, OPT_ARG_FIRSTNAME),
00158 AST_APP_OPTION_ARG('l', OPT_LISTBYLASTNAME, OPT_ARG_LASTNAME),
00159 AST_APP_OPTION_ARG('b', OPT_LISTBYEITHER, OPT_ARG_EITHER),
00160 AST_APP_OPTION_ARG('p', OPT_PAUSE, OPT_ARG_PAUSE),
00161 AST_APP_OPTION('e', OPT_SAYEXTENSION),
00162 AST_APP_OPTION('v', OPT_FROMVOICEMAIL),
00163 AST_APP_OPTION('m', OPT_SELECTFROMMENU),
00164 AST_APP_OPTION('n', OPT_NOANSWER),
00165 });
00166
00167 static int compare(const char *text, const char *template)
00168 {
00169 char digit;
00170
00171 if (ast_strlen_zero(text)) {
00172 return -1;
00173 }
00174
00175 while (*template) {
00176 digit = toupper(*text++);
00177 switch (digit) {
00178 case 0:
00179 return -1;
00180 case '1':
00181 digit = '1';
00182 break;
00183 case '2':
00184 case 'A':
00185 case 'B':
00186 case 'C':
00187 digit = '2';
00188 break;
00189 case '3':
00190 case 'D':
00191 case 'E':
00192 case 'F':
00193 digit = '3';
00194 break;
00195 case '4':
00196 case 'G':
00197 case 'H':
00198 case 'I':
00199 digit = '4';
00200 break;
00201 case '5':
00202 case 'J':
00203 case 'K':
00204 case 'L':
00205 digit = '5';
00206 break;
00207 case '6':
00208 case 'M':
00209 case 'N':
00210 case 'O':
00211 digit = '6';
00212 break;
00213 case '7':
00214 case 'P':
00215 case 'Q':
00216 case 'R':
00217 case 'S':
00218 digit = '7';
00219 break;
00220 case '8':
00221 case 'T':
00222 case 'U':
00223 case 'V':
00224 digit = '8';
00225 break;
00226 case '9':
00227 case 'W':
00228 case 'X':
00229 case 'Y':
00230 case 'Z':
00231 digit = '9';
00232 break;
00233
00234 default:
00235 if (digit > ' ')
00236 return -1;
00237 continue;
00238 }
00239
00240 if (*template++ != digit)
00241 return -1;
00242 }
00243
00244 return 0;
00245 }
00246
00247 static int goto_exten(struct ast_channel *chan, const char *dialcontext, char *ext)
00248 {
00249 if (!ast_goto_if_exists(chan, dialcontext, ext, 1) ||
00250 (!ast_strlen_zero(chan->macrocontext) &&
00251 !ast_goto_if_exists(chan, chan->macrocontext, ext, 1))) {
00252 return 0;
00253 } else {
00254 ast_log(LOG_WARNING, "Can't find extension '%s' in current context. "
00255 "Not Exiting the Directory!\n", ext);
00256 return -1;
00257 }
00258 }
00259
00260
00261
00262
00263
00264
00265 static int play_mailbox_owner(struct ast_channel *chan, const char *context,
00266 const char *ext, const char *name, struct ast_flags *flags)
00267 {
00268 int res = 0;
00269 if ((res = ast_app_sayname(chan, ext, context)) >= 0) {
00270 ast_stopstream(chan);
00271
00272 if (ast_test_flag(flags, OPT_SAYEXTENSION)) {
00273 ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
00274 res = ast_say_character_str(chan, ext, AST_DIGIT_ANY, chan->language);
00275 }
00276 } else {
00277 res = ast_say_character_str(chan, S_OR(name, ext), AST_DIGIT_ANY, chan->language);
00278 if (!ast_strlen_zero(name) && ast_test_flag(flags, OPT_SAYEXTENSION)) {
00279 ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
00280 res = ast_say_character_str(chan, ext, AST_DIGIT_ANY, chan->language);
00281 }
00282 }
00283
00284 return res;
00285 }
00286
00287 static int select_entry(struct ast_channel *chan, const char *dialcontext, const struct directory_item *item, struct ast_flags *flags)
00288 {
00289 ast_debug(1, "Selecting '%s' - %s@%s\n", item->name, item->exten, S_OR(dialcontext, item->context));
00290
00291 if (ast_test_flag(flags, OPT_FROMVOICEMAIL)) {
00292
00293 ast_copy_string(chan->exten, item->exten, sizeof(chan->exten));
00294 } else if (ast_goto_if_exists(chan, S_OR(dialcontext, item->context), item->exten, 1)) {
00295 ast_log(LOG_WARNING,
00296 "Can't find extension '%s' in context '%s'. "
00297 "Did you pass the wrong context to Directory?\n",
00298 item->exten, S_OR(dialcontext, item->context));
00299 return -1;
00300 }
00301
00302 return 0;
00303 }
00304
00305 static int select_item_pause(struct ast_channel *chan, struct ast_flags *flags, char *opts[])
00306 {
00307 int res = 0, opt_pause = 0;
00308
00309 if (ast_test_flag(flags, OPT_PAUSE) && !ast_strlen_zero(opts[OPT_ARG_PAUSE])) {
00310 opt_pause = atoi(opts[OPT_ARG_PAUSE]);
00311 if (opt_pause > 3000) {
00312 opt_pause = 3000;
00313 }
00314 res = ast_waitfordigit(chan, opt_pause);
00315 }
00316 return res;
00317 }
00318
00319 static int select_item_seq(struct ast_channel *chan, struct directory_item **items, int count, const char *dialcontext, struct ast_flags *flags, char *opts[])
00320 {
00321 struct directory_item *item, **ptr;
00322 int i, res, loop;
00323
00324
00325
00326 res = select_item_pause(chan, flags, opts);
00327
00328 for (ptr = items, i = 0; i < count; i++, ptr++) {
00329 item = *ptr;
00330
00331 for (loop = 3 ; loop > 0; loop--) {
00332 if (!res)
00333 res = play_mailbox_owner(chan, item->context, item->exten, item->name, flags);
00334 if (!res)
00335 res = ast_stream_and_wait(chan, "dir-instr", AST_DIGIT_ANY);
00336 if (!res)
00337 res = ast_waitfordigit(chan, 3000);
00338 ast_stopstream(chan);
00339
00340 if (res == '0') {
00341 goto_exten(chan, dialcontext, "o");
00342 return '0';
00343 } else if (res == '1') {
00344 return select_entry(chan, dialcontext, item, flags) ? -1 : 1;
00345 } else if (res == '*') {
00346
00347 break;
00348 } else if (res == '#') {
00349
00350 return res;
00351 }
00352
00353 if (res < 0)
00354 return -1;
00355
00356 res = 0;
00357 }
00358 res = 0;
00359 }
00360
00361
00362 return 0;
00363 }
00364
00365 static int select_item_menu(struct ast_channel *chan, struct directory_item **items, int count, const char *dialcontext, struct ast_flags *flags, char *opts[])
00366 {
00367 struct directory_item **block, *item;
00368 int i, limit, res = 0;
00369 char buf[9];
00370
00371
00372 select_item_pause(chan, flags, opts);
00373
00374 for (block = items; count; block += limit, count -= limit) {
00375 limit = count;
00376 if (limit > 8)
00377 limit = 8;
00378
00379 for (i = 0; i < limit && !res; i++) {
00380 item = block[i];
00381
00382 snprintf(buf, sizeof(buf), "digits/%d", i + 1);
00383
00384 res = ast_streamfile(chan, "dir-multi1", chan->language);
00385 if (!res)
00386 res = ast_waitstream(chan, AST_DIGIT_ANY);
00387 if (!res)
00388 res = ast_streamfile(chan, buf, chan->language);
00389 if (!res)
00390 res = ast_waitstream(chan, AST_DIGIT_ANY);
00391 if (!res)
00392 res = ast_streamfile(chan, "dir-multi2", chan->language);
00393 if (!res)
00394 res = ast_waitstream(chan, AST_DIGIT_ANY);
00395 if (!res)
00396 res = play_mailbox_owner(chan, item->context, item->exten, item->name, flags);
00397 if (!res)
00398 res = ast_waitstream(chan, AST_DIGIT_ANY);
00399 if (!res)
00400 res = ast_waitfordigit(chan, 800);
00401 }
00402
00403
00404 if (!res && count > limit) {
00405 res = ast_streamfile(chan, "dir-multi9", chan->language);
00406 if (!res)
00407 res = ast_waitstream(chan, AST_DIGIT_ANY);
00408 }
00409
00410 if (!res) {
00411 res = ast_waitfordigit(chan, 3000);
00412 }
00413
00414 if (res && res > '0' && res < '1' + limit) {
00415 return select_entry(chan, dialcontext, block[res - '1'], flags) ? -1 : 1;
00416 }
00417
00418 if (res < 0)
00419 return -1;
00420
00421 res = 0;
00422 }
00423
00424
00425 return 0;
00426 }
00427
00428 static struct ast_config *realtime_directory(char *context)
00429 {
00430 struct ast_config *cfg;
00431 struct ast_config *rtdata;
00432 struct ast_category *cat;
00433 struct ast_variable *var;
00434 char *mailbox;
00435 const char *fullname;
00436 const char *hidefromdir, *searchcontexts = NULL;
00437 char tmp[100];
00438 struct ast_flags config_flags = { 0 };
00439
00440
00441 cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags);
00442
00443 if (!cfg) {
00444
00445 ast_log(LOG_WARNING, "Loading config failed.\n");
00446 return NULL;
00447 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
00448 ast_log(LOG_ERROR, "Config file %s is in an invalid format. Aborting.\n", VOICEMAIL_CONFIG);
00449 return NULL;
00450 }
00451
00452
00453
00454 if (ast_strlen_zero(context) && (searchcontexts = ast_variable_retrieve(cfg, "general", "searchcontexts"))) {
00455 if (ast_true(searchcontexts)) {
00456 rtdata = ast_load_realtime_multientry("voicemail", "mailbox LIKE", "%", SENTINEL);
00457 context = NULL;
00458 } else {
00459 rtdata = ast_load_realtime_multientry("voicemail", "mailbox LIKE", "%", "context", "default", SENTINEL);
00460 context = "default";
00461 }
00462 } else {
00463 rtdata = ast_load_realtime_multientry("voicemail", "mailbox LIKE", "%", "context", context, SENTINEL);
00464 }
00465
00466
00467 if (!rtdata) {
00468 return cfg;
00469 }
00470
00471 mailbox = NULL;
00472 while ( (mailbox = ast_category_browse(rtdata, mailbox)) ) {
00473 const char *context = ast_variable_retrieve(rtdata, mailbox, "context");
00474
00475 fullname = ast_variable_retrieve(rtdata, mailbox, "fullname");
00476 if (ast_true((hidefromdir = ast_variable_retrieve(rtdata, mailbox, "hidefromdir")))) {
00477
00478 continue;
00479 }
00480 snprintf(tmp, sizeof(tmp), "no-password,%s", S_OR(fullname, ""));
00481
00482
00483 if (!(cat = ast_category_get(cfg, context))) {
00484 if (!(cat = ast_category_new(context, "", 99999))) {
00485 ast_log(LOG_WARNING, "Out of memory\n");
00486 ast_config_destroy(cfg);
00487 if (rtdata) {
00488 ast_config_destroy(rtdata);
00489 }
00490 return NULL;
00491 }
00492 ast_category_append(cfg, cat);
00493 }
00494
00495 if ((var = ast_variable_new(mailbox, tmp, ""))) {
00496 ast_variable_append(cat, var);
00497 } else {
00498 ast_log(LOG_WARNING, "Out of memory adding mailbox '%s'\n", mailbox);
00499 }
00500 }
00501 ast_config_destroy(rtdata);
00502
00503 return cfg;
00504 }
00505
00506 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)
00507 {
00508 struct directory_item *item;
00509 const char *key = NULL;
00510 int namelen;
00511
00512 if (ast_strlen_zero(item_fullname)) {
00513 return 0;
00514 }
00515
00516
00517 if (!use_first_name)
00518 key = strchr(item_fullname, ' ');
00519
00520 if (key)
00521 key++;
00522 else
00523 key = item_fullname;
00524
00525 if (compare(key, pattern_ext))
00526 return 0;
00527
00528 ast_debug(1, "Found match %s@%s\n", item_ext, item_context);
00529
00530
00531 item = ast_calloc(1, sizeof(*item));
00532 if (!item)
00533 return -1;
00534 ast_copy_string(item->context, item_context, sizeof(item->context));
00535 ast_copy_string(item->name, item_fullname, sizeof(item->name));
00536 ast_copy_string(item->exten, item_ext, sizeof(item->exten));
00537
00538 ast_copy_string(item->key, key, sizeof(item->key));
00539 if (key != item_fullname) {
00540
00541 namelen = key - item_fullname - 1;
00542 if (namelen > sizeof(item->key) - strlen(item->key) - 1)
00543 namelen = sizeof(item->key) - strlen(item->key) - 1;
00544 strncat(item->key, item_fullname, namelen);
00545 }
00546
00547 *result = item;
00548 return 1;
00549 }
00550
00551 typedef AST_LIST_HEAD_NOLOCK(, directory_item) itemlist;
00552
00553 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)
00554 {
00555 struct ast_variable *v;
00556 char buf[AST_MAX_EXTENSION + 1], *pos, *bufptr, *cat;
00557 struct directory_item *item;
00558 int res;
00559
00560 ast_debug(2, "Pattern: %s\n", ext);
00561
00562 for (v = ast_variable_browse(vmcfg, context); v; v = v->next) {
00563
00564
00565 if (strcasestr(v->value, "hidefromdir=yes"))
00566 continue;
00567
00568 ast_copy_string(buf, v->value, sizeof(buf));
00569 bufptr = buf;
00570
00571
00572 strsep(&bufptr, ",");
00573 pos = strsep(&bufptr, ",");
00574
00575
00576 if (ast_strlen_zero(pos)) {
00577 continue;
00578 }
00579
00580 res = 0;
00581 if (ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
00582 res = check_match(&item, context, pos, v->name, ext, 0 );
00583 }
00584 if (!res && ast_test_flag(&flags, OPT_LISTBYFIRSTNAME)) {
00585 res = check_match(&item, context, pos, v->name, ext, 1 );
00586 }
00587
00588 if (!res)
00589 continue;
00590 else if (res < 0)
00591 return -1;
00592
00593 AST_LIST_INSERT_TAIL(alist, item, entry);
00594 }
00595
00596 if (ucfg) {
00597 for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
00598 const char *position;
00599 if (!strcasecmp(cat, "general"))
00600 continue;
00601 if (!ast_true(ast_config_option(ucfg, cat, "hasdirectory")))
00602 continue;
00603
00604
00605 position = ast_variable_retrieve(ucfg, cat, "fullname");
00606 if (!position)
00607 continue;
00608
00609 res = 0;
00610 if (ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
00611 res = check_match(&item, context, position, cat, ext, 0 );
00612 }
00613 if (!res && ast_test_flag(&flags, OPT_LISTBYFIRSTNAME)) {
00614 res = check_match(&item, context, position, cat, ext, 1 );
00615 }
00616
00617 if (!res)
00618 continue;
00619 else if (res < 0)
00620 return -1;
00621
00622 AST_LIST_INSERT_TAIL(alist, item, entry);
00623 }
00624 }
00625 return 0;
00626 }
00627
00628 static int search_directory(const char *context, struct ast_config *vmcfg, struct ast_config *ucfg, const char *ext, struct ast_flags flags, itemlist *alist)
00629 {
00630 const char *searchcontexts = ast_variable_retrieve(vmcfg, "general", "searchcontexts");
00631 if (ast_strlen_zero(context)) {
00632 if (!ast_strlen_zero(searchcontexts) && ast_true(searchcontexts)) {
00633
00634 int res;
00635 const char *catg;
00636 for (catg = ast_category_browse(vmcfg, NULL); catg; catg = ast_category_browse(vmcfg, catg)) {
00637 if (!strcmp(catg, "general") || !strcmp(catg, "zonemessages")) {
00638 continue;
00639 }
00640
00641 if ((res = search_directory_sub(catg, vmcfg, ucfg, ext, flags, alist))) {
00642 return res;
00643 }
00644 }
00645 return 0;
00646 } else {
00647 ast_debug(1, "Searching by category default\n");
00648 return search_directory_sub("default", vmcfg, ucfg, ext, flags, alist);
00649 }
00650 } else {
00651
00652 ast_debug(1, "Searching by category %s\n", context);
00653 return search_directory_sub(context, vmcfg, ucfg, ext, flags, alist);
00654 }
00655 }
00656
00657 static void sort_items(struct directory_item **sorted, int count)
00658 {
00659 int reordered, i;
00660 struct directory_item **ptr, *tmp;
00661
00662 if (count < 2)
00663 return;
00664
00665
00666 do {
00667 reordered = 0;
00668 for (ptr = sorted, i = 0; i < count - 1; i++, ptr++) {
00669 if (strcasecmp(ptr[0]->key, ptr[1]->key) > 0) {
00670 tmp = ptr[0];
00671 ptr[0] = ptr[1];
00672 ptr[1] = tmp;
00673 reordered++;
00674 }
00675 }
00676 } while (reordered);
00677 }
00678
00679 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[])
00680 {
00681
00682 int res = 0;
00683 itemlist alist = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
00684 struct directory_item *item, **ptr, **sorted = NULL;
00685 int count, i;
00686 char ext[10] = "";
00687
00688 if (digit == '0' && !goto_exten(chan, S_OR(dialcontext, "default"), "o")) {
00689 return digit;
00690 }
00691
00692 if (digit == '*' && !goto_exten(chan, S_OR(dialcontext, "default"), "a")) {
00693 return digit;
00694 }
00695
00696 ext[0] = digit;
00697 if (ast_readstring(chan, ext + 1, digits - 1, 3000, 3000, "#") < 0)
00698 return -1;
00699
00700 res = search_directory(context, vmcfg, ucfg, ext, *flags, &alist);
00701 if (res)
00702 goto exit;
00703
00704
00705 count = 0;
00706 AST_LIST_TRAVERSE(&alist, item, entry) {
00707 count++;
00708 }
00709
00710 if (count < 1) {
00711 res = ast_streamfile(chan, "dir-nomatch", chan->language);
00712 goto exit;
00713 }
00714
00715
00716
00717 sorted = ast_calloc(count, sizeof(*sorted));
00718
00719 ptr = sorted;
00720 AST_LIST_TRAVERSE(&alist, item, entry) {
00721 *ptr++ = item;
00722 }
00723
00724
00725 sort_items(sorted, count);
00726
00727 if (option_debug) {
00728 ast_debug(2, "Listing matching entries:\n");
00729 for (ptr = sorted, i = 0; i < count; i++, ptr++) {
00730 ast_debug(2, "%s: %s\n", ptr[0]->exten, ptr[0]->name);
00731 }
00732 }
00733
00734 if (ast_test_flag(flags, OPT_SELECTFROMMENU)) {
00735
00736 res = select_item_menu(chan, sorted, count, dialcontext, flags, opts);
00737 } else {
00738
00739 res = select_item_seq(chan, sorted, count, dialcontext, flags, opts);
00740 }
00741
00742 if (!res) {
00743 res = ast_streamfile(chan, "dir-nomore", chan->language);
00744 }
00745
00746 exit:
00747 if (sorted)
00748 ast_free(sorted);
00749
00750 while ((item = AST_LIST_REMOVE_HEAD(&alist, entry)))
00751 ast_free(item);
00752
00753 return res;
00754 }
00755
00756 static int directory_exec(struct ast_channel *chan, const char *data)
00757 {
00758 int res = 0, digit = 3;
00759 struct ast_config *cfg, *ucfg;
00760 const char *dirintro;
00761 char *parse, *opts[OPT_ARG_ARRAY_SIZE] = { 0, };
00762 struct ast_flags flags = { 0 };
00763 struct ast_flags config_flags = { 0 };
00764 enum { FIRST, LAST, BOTH } which = LAST;
00765 char digits[9] = "digits/3";
00766 AST_DECLARE_APP_ARGS(args,
00767 AST_APP_ARG(vmcontext);
00768 AST_APP_ARG(dialcontext);
00769 AST_APP_ARG(options);
00770 );
00771
00772 parse = ast_strdupa(data);
00773
00774 AST_STANDARD_APP_ARGS(args, parse);
00775
00776 if (args.options && ast_app_parse_options(directory_app_options, &flags, opts, args.options))
00777 return -1;
00778
00779 if (!(cfg = realtime_directory(args.vmcontext))) {
00780 ast_log(LOG_ERROR, "Unable to read the configuration data!\n");
00781 return -1;
00782 }
00783
00784 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) {
00785 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Aborting.\n");
00786 ucfg = NULL;
00787 }
00788
00789 dirintro = ast_variable_retrieve(cfg, args.vmcontext, "directoryintro");
00790 if (ast_strlen_zero(dirintro))
00791 dirintro = ast_variable_retrieve(cfg, "general", "directoryintro");
00792
00793
00794
00795 if (ast_test_flag(&flags, OPT_LISTBYFIRSTNAME) && ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
00796 if (!ast_strlen_zero(opts[OPT_ARG_EITHER])) {
00797 digit = atoi(opts[OPT_ARG_EITHER]);
00798 }
00799 which = BOTH;
00800 } else if (ast_test_flag(&flags, OPT_LISTBYFIRSTNAME)) {
00801 if (!ast_strlen_zero(opts[OPT_ARG_FIRSTNAME])) {
00802 digit = atoi(opts[OPT_ARG_FIRSTNAME]);
00803 }
00804 which = FIRST;
00805 } else {
00806 if (!ast_strlen_zero(opts[OPT_ARG_LASTNAME])) {
00807 digit = atoi(opts[OPT_ARG_LASTNAME]);
00808 }
00809 which = LAST;
00810 }
00811
00812
00813 if (!ast_test_flag(&flags, OPT_LISTBYFIRSTNAME) && !ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
00814 ast_set_flag(&flags, OPT_LISTBYLASTNAME);
00815 which = LAST;
00816 }
00817
00818 if (digit > 9) {
00819 digit = 9;
00820 } else if (digit < 1) {
00821 digit = 3;
00822 }
00823 digits[7] = digit + '0';
00824
00825 if (chan->_state != AST_STATE_UP) {
00826 if (!ast_test_flag(&flags, OPT_NOANSWER)) {
00827
00828 res = ast_answer(chan);
00829 }
00830 }
00831 for (;;) {
00832 if (!ast_strlen_zero(dirintro) && !res) {
00833 res = ast_stream_and_wait(chan, dirintro, AST_DIGIT_ANY);
00834 } else if (!res) {
00835
00836 res = ast_stream_and_wait(chan, "dir-welcome", AST_DIGIT_ANY);
00837 if (!res) {
00838 res = ast_stream_and_wait(chan, "dir-pls-enter", AST_DIGIT_ANY);
00839 }
00840 if (!res) {
00841 res = ast_stream_and_wait(chan, digits, AST_DIGIT_ANY);
00842 }
00843 if (!res) {
00844 res = ast_stream_and_wait(chan,
00845 which == FIRST ? "dir-first" :
00846 which == LAST ? "dir-last" :
00847 "dir-firstlast", AST_DIGIT_ANY);
00848 }
00849 if (!res) {
00850 res = ast_stream_and_wait(chan, "dir-usingkeypad", AST_DIGIT_ANY);
00851 }
00852 }
00853 ast_stopstream(chan);
00854 if (!res)
00855 res = ast_waitfordigit(chan, 5000);
00856
00857 if (res <= 0)
00858 break;
00859
00860 res = do_directory(chan, cfg, ucfg, args.vmcontext, args.dialcontext, res, digit, &flags, opts);
00861 if (res)
00862 break;
00863
00864 res = ast_waitstream(chan, AST_DIGIT_ANY);
00865 ast_stopstream(chan);
00866
00867 if (res)
00868 break;
00869 }
00870
00871 if (ucfg)
00872 ast_config_destroy(ucfg);
00873 ast_config_destroy(cfg);
00874
00875 return res < 0 ? -1 : 0;
00876 }
00877
00878 static int unload_module(void)
00879 {
00880 int res;
00881 res = ast_unregister_application(app);
00882 return res;
00883 }
00884
00885 static int load_module(void)
00886 {
00887 return ast_register_application_xml(app, directory_exec);
00888 }
00889
00890 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Extension Directory");