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