#include "asterisk.h"
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/config.h"
#include "asterisk/say.h"
#include "asterisk/utils.h"
#include "asterisk/app.h"
Go to the source code of this file.
Defines | |
#define | NUMDIGITS 3 |
#define | VOICEMAIL_CONFIG "voicemail.conf" |
Functions | |
static void | __reg_module (void) |
static void | __unreg_module (void) |
static char * | convert (const char *lastname) |
static int | directory_exec (struct ast_channel *chan, void *data) |
static int | do_directory (struct ast_channel *chan, struct ast_config *cfg, struct ast_config *ucfg, char *context, char *dialcontext, char digit, int last, int readext, int fromappvm) |
static int | load_module (void) |
static int | play_mailbox_owner (struct ast_channel *chan, char *context, char *dialcontext, char *ext, char *name, int readext, int fromappvm) |
static struct ast_config * | realtime_directory (char *context) |
static int | unload_module (void) |
Variables | |
static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT | AST_MODFLAG_BUILDSUM, .description = "Extension Directory" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, } |
static char * | app = "Directory" |
static const struct ast_module_info * | ast_module_info = &__mod_info |
static char * | descrip |
static char * | synopsis = "Provide directory of voicemail extensions" |
Definition in file app_directory.c.
#define NUMDIGITS 3 |
#define VOICEMAIL_CONFIG "voicemail.conf" |
Definition at line 85 of file app_directory.c.
Referenced by load_config(), load_module(), realtime_directory(), and vm_change_password().
static void __reg_module | ( | void | ) | [static] |
Definition at line 722 of file app_directory.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 722 of file app_directory.c.
static char* convert | ( | const char * | lastname | ) | [static] |
Definition at line 206 of file app_directory.c.
References ast_malloc, and NUMDIGITS.
Referenced by do_directory().
00207 { 00208 char *tmp; 00209 int lcount = 0; 00210 tmp = ast_malloc(NUMDIGITS + 1); 00211 if (tmp) { 00212 while((*lastname > 32) && lcount < NUMDIGITS) { 00213 switch(toupper(*lastname)) { 00214 case '1': 00215 tmp[lcount++] = '1'; 00216 break; 00217 case '2': 00218 case 'A': 00219 case 'B': 00220 case 'C': 00221 tmp[lcount++] = '2'; 00222 break; 00223 case '3': 00224 case 'D': 00225 case 'E': 00226 case 'F': 00227 tmp[lcount++] = '3'; 00228 break; 00229 case '4': 00230 case 'G': 00231 case 'H': 00232 case 'I': 00233 tmp[lcount++] = '4'; 00234 break; 00235 case '5': 00236 case 'J': 00237 case 'K': 00238 case 'L': 00239 tmp[lcount++] = '5'; 00240 break; 00241 case '6': 00242 case 'M': 00243 case 'N': 00244 case 'O': 00245 tmp[lcount++] = '6'; 00246 break; 00247 case '7': 00248 case 'P': 00249 case 'Q': 00250 case 'R': 00251 case 'S': 00252 tmp[lcount++] = '7'; 00253 break; 00254 case '8': 00255 case 'T': 00256 case 'U': 00257 case 'V': 00258 tmp[lcount++] = '8'; 00259 break; 00260 case '9': 00261 case 'W': 00262 case 'X': 00263 case 'Y': 00264 case 'Z': 00265 tmp[lcount++] = '9'; 00266 break; 00267 } 00268 lastname++; 00269 } 00270 tmp[lcount] = '\0'; 00271 } 00272 return tmp; 00273 }
static int directory_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 608 of file app_directory.c.
References ast_channel::_state, ast_answer(), AST_APP_ARG, ast_config_destroy(), ast_config_load(), AST_DECLARE_APP_ARGS, AST_DIGIT_ANY, ast_log(), ast_module_user_add, ast_module_user_remove, AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_stopstream(), ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_variable_retrieve(), ast_waitfordigit(), ast_waitstream(), dialcontext, do_directory(), ast_channel::language, last, LOG_ERROR, LOG_WARNING, parse(), and realtime_directory().
Referenced by load_module().
00609 { 00610 int res = 0; 00611 struct ast_module_user *u; 00612 struct ast_config *cfg, *ucfg; 00613 int last = 1; 00614 int readext = 0; 00615 int fromappvm = 0; 00616 const char *dirintro; 00617 char *parse; 00618 AST_DECLARE_APP_ARGS(args, 00619 AST_APP_ARG(vmcontext); 00620 AST_APP_ARG(dialcontext); 00621 AST_APP_ARG(options); 00622 ); 00623 00624 if (ast_strlen_zero(data)) { 00625 ast_log(LOG_WARNING, "Directory requires an argument (context[,dialcontext])\n"); 00626 return -1; 00627 } 00628 00629 u = ast_module_user_add(chan); 00630 00631 parse = ast_strdupa(data); 00632 00633 AST_STANDARD_APP_ARGS(args, parse); 00634 00635 if (args.options) { 00636 if (strchr(args.options, 'f')) 00637 last = 0; 00638 if (strchr(args.options, 'e')) 00639 readext = 1; 00640 if (strchr(args.options, 'v')) 00641 fromappvm = 1; 00642 } 00643 00644 if (ast_strlen_zero(args.dialcontext)) 00645 args.dialcontext = args.vmcontext; 00646 00647 cfg = realtime_directory(args.vmcontext); 00648 if (!cfg) { 00649 ast_log(LOG_ERROR, "Unable to read the configuration data!\n"); 00650 ast_module_user_remove(u); 00651 return -1; 00652 } 00653 00654 ucfg = ast_config_load("users.conf"); 00655 00656 dirintro = ast_variable_retrieve(cfg, args.vmcontext, "directoryintro"); 00657 if (ast_strlen_zero(dirintro)) 00658 dirintro = ast_variable_retrieve(cfg, "general", "directoryintro"); 00659 if (ast_strlen_zero(dirintro)) 00660 dirintro = last ? "dir-intro" : "dir-intro-fn"; 00661 /* the above prompts probably should be modified to include 0 for dialing operator 00662 and # for exiting (continues in dialplan) */ 00663 00664 if (chan->_state != AST_STATE_UP) 00665 res = ast_answer(chan); 00666 00667 for (;;) { 00668 if (!res) 00669 res = ast_stream_and_wait(chan, dirintro, chan->language, AST_DIGIT_ANY); 00670 ast_stopstream(chan); 00671 if (!res) 00672 res = ast_waitfordigit(chan, 5000); 00673 if (res > 0) { 00674 res = do_directory(chan, cfg, ucfg, args.vmcontext, args.dialcontext, res, last, readext, fromappvm); 00675 if (res > 0) { 00676 res = ast_waitstream(chan, AST_DIGIT_ANY); 00677 ast_stopstream(chan); 00678 if (res >= 0) 00679 continue; 00680 } 00681 } 00682 break; 00683 } 00684 if (ucfg) 00685 ast_config_destroy(ucfg); 00686 ast_config_destroy(cfg); 00687 ast_module_user_remove(u); 00688 return res; 00689 }
static int do_directory | ( | struct ast_channel * | chan, | |
struct ast_config * | cfg, | |||
struct ast_config * | ucfg, | |||
char * | context, | |||
char * | dialcontext, | |||
char | digit, | |||
int | last, | |||
int | readext, | |||
int | fromappvm | |||
) | [static] |
Definition at line 428 of file app_directory.c.
References ast_category_browse(), ast_config_option(), ast_copy_string(), ast_goto_if_exists(), ast_log(), ast_readstring(), ast_streamfile(), ast_strlen_zero(), ast_true(), ast_variable_browse(), ast_variable_retrieve(), convert(), ext, free, ast_channel::language, LOG_WARNING, ast_channel::macrocontext, ast_channel::name, name, NUMDIGITS, play_mailbox_owner(), and strdup.
Referenced by directory_exec().
00429 { 00430 /* Read in the first three digits.. "digit" is the first digit, already read */ 00431 char ext[NUMDIGITS + 1], *cat; 00432 char name[80] = ""; 00433 struct ast_variable *v; 00434 int res; 00435 int found=0; 00436 int lastuserchoice = 0; 00437 char *start, *conv, *stringp = NULL; 00438 const char *pos; 00439 int breakout = 0; 00440 00441 if (ast_strlen_zero(context)) { 00442 ast_log(LOG_WARNING, 00443 "Directory must be called with an argument " 00444 "(context in which to interpret extensions)\n"); 00445 return -1; 00446 } 00447 if (digit == '0') { 00448 if (!ast_goto_if_exists(chan, dialcontext, "o", 1) || 00449 (!ast_strlen_zero(chan->macrocontext) && 00450 !ast_goto_if_exists(chan, chan->macrocontext, "o", 1))) { 00451 return 0; 00452 } else { 00453 ast_log(LOG_WARNING, "Can't find extension 'o' in current context. " 00454 "Not Exiting the Directory!\n"); 00455 res = 0; 00456 } 00457 } 00458 if (digit == '*') { 00459 if (!ast_goto_if_exists(chan, dialcontext, "a", 1) || 00460 (!ast_strlen_zero(chan->macrocontext) && 00461 !ast_goto_if_exists(chan, chan->macrocontext, "a", 1))) { 00462 return 0; 00463 } else { 00464 ast_log(LOG_WARNING, "Can't find extension 'a' in current context. " 00465 "Not Exiting the Directory!\n"); 00466 res = 0; 00467 } 00468 } 00469 memset(ext, 0, sizeof(ext)); 00470 ext[0] = digit; 00471 res = 0; 00472 if (ast_readstring(chan, ext + 1, NUMDIGITS - 1, 3000, 3000, "#") < 0) res = -1; 00473 if (!res) { 00474 /* Search for all names which start with those digits */ 00475 v = ast_variable_browse(cfg, context); 00476 while(v && !res) { 00477 /* Find all candidate extensions */ 00478 while(v) { 00479 /* Find a candidate extension */ 00480 start = strdup(v->value); 00481 if (start && !strcasestr(start, "hidefromdir=yes")) { 00482 stringp=start; 00483 strsep(&stringp, ","); 00484 pos = strsep(&stringp, ","); 00485 if (pos) { 00486 ast_copy_string(name, pos, sizeof(name)); 00487 /* Grab the last name */ 00488 if (last && strrchr(pos,' ')) 00489 pos = strrchr(pos, ' ') + 1; 00490 conv = convert(pos); 00491 if (conv) { 00492 if (!strncmp(conv, ext, strlen(ext))) { 00493 /* Match! */ 00494 found++; 00495 free(conv); 00496 free(start); 00497 break; 00498 } 00499 free(conv); 00500 } 00501 } 00502 free(start); 00503 } 00504 v = v->next; 00505 } 00506 00507 if (v) { 00508 /* We have a match -- play a greeting if they have it */ 00509 res = play_mailbox_owner(chan, context, dialcontext, v->name, name, readext, fromappvm); 00510 switch (res) { 00511 case -1: 00512 /* user pressed '1' but extension does not exist, or 00513 * user hungup 00514 */ 00515 lastuserchoice = 0; 00516 break; 00517 case '1': 00518 /* user pressed '1' and extensions exists; 00519 play_mailbox_owner will already have done 00520 a goto() on the channel 00521 */ 00522 lastuserchoice = res; 00523 break; 00524 case '*': 00525 /* user pressed '*' to skip something found */ 00526 lastuserchoice = res; 00527 res = 0; 00528 break; 00529 case '#': 00530 lastuserchoice = res; 00531 return 0; 00532 default: 00533 break; 00534 } 00535 v = v->next; 00536 } 00537 } 00538 00539 if (!res && ucfg) { 00540 /* Search users.conf for all names which start with those digits */ 00541 for (cat = ast_category_browse(ucfg, NULL); cat && !res ; cat = ast_category_browse(ucfg, cat)) { 00542 if (!strcasecmp(cat, "general")) 00543 continue; 00544 if (!ast_true(ast_config_option(ucfg, cat, "hasdirectory"))) 00545 continue; 00546 00547 /* Find all candidate extensions */ 00548 if ((pos = ast_variable_retrieve(ucfg, cat, "fullname"))) { 00549 ast_copy_string(name, pos, sizeof(name)); 00550 /* Grab the last name */ 00551 if (last && strrchr(pos,' ')) 00552 pos = strrchr(pos, ' ') + 1; 00553 conv = convert(pos); 00554 if (conv) { 00555 if (!strcmp(conv, ext)) { 00556 /* Match! */ 00557 found++; 00558 /* We have a match -- play a greeting if they have it */ 00559 res = play_mailbox_owner(chan, context, dialcontext, cat, name, readext, fromappvm); 00560 switch (res) { 00561 case -1: 00562 /* user pressed '1' but extension does not exist, or 00563 * user hungup 00564 */ 00565 lastuserchoice = 0; 00566 breakout = 1; 00567 break; 00568 case '1': 00569 /* user pressed '1' and extensions exists; 00570 play_mailbox_owner will already have done 00571 a goto() on the channel 00572 */ 00573 lastuserchoice = res; 00574 breakout = 1; 00575 break; 00576 case '*': 00577 /* user pressed '*' to skip something found */ 00578 lastuserchoice = res; 00579 breakout = 0; 00580 res = 0; 00581 break; 00582 default: 00583 breakout = 1; 00584 break; 00585 } 00586 free(conv); 00587 if (breakout) 00588 break; 00589 } 00590 else 00591 free(conv); 00592 } 00593 } 00594 } 00595 } 00596 00597 if (lastuserchoice != '1') { 00598 res = ast_streamfile(chan, found ? "dir-nomore" : "dir-nomatch", chan->language); 00599 if (!res) 00600 res = 1; 00601 return res; 00602 } 00603 return 0; 00604 } 00605 return res; 00606 }
static int load_module | ( | void | ) | [static] |
Definition at line 698 of file app_directory.c.
References ast_config_destroy(), ast_config_load(), ast_copy_string(), ast_log(), ast_register_application(), ast_variable_retrieve(), directory_exec(), LOG_WARNING, and VOICEMAIL_CONFIG.
00699 { 00700 #ifdef ODBC_STORAGE 00701 struct ast_config *cfg = ast_config_load(VOICEMAIL_CONFIG); 00702 const char *tmp; 00703 00704 if (cfg) { 00705 if ((tmp = ast_variable_retrieve(cfg, "general", "odbcstorage"))) { 00706 ast_copy_string(odbc_database, tmp, sizeof(odbc_database)); 00707 } 00708 if ((tmp = ast_variable_retrieve(cfg, "general", "odbctable"))) { 00709 ast_copy_string(odbc_table, tmp, sizeof(odbc_table)); 00710 } 00711 if ((tmp = ast_variable_retrieve(cfg, "general", "format"))) { 00712 ast_copy_string(vmfmts, tmp, sizeof(vmfmts)); 00713 } 00714 ast_config_destroy(cfg); 00715 } else 00716 ast_log(LOG_WARNING, "Unable to load " VOICEMAIL_CONFIG " - ODBC defaults will be used\n"); 00717 #endif 00718 00719 return ast_register_application(app, directory_exec, synopsis, descrip); 00720 }
static int play_mailbox_owner | ( | struct ast_channel * | chan, | |
char * | context, | |||
char * | dialcontext, | |||
char * | ext, | |||
char * | name, | |||
int | readext, | |||
int | fromappvm | |||
) | [static] |
Definition at line 280 of file app_directory.c.
References ast_config_AST_SPOOL_DIR, ast_copy_string(), AST_DIGIT_ANY, ast_filedelete(), ast_fileexists(), ast_goto_if_exists(), ast_log(), ast_say_character_str(), ast_stopstream(), ast_stream_and_wait(), ast_strlen_zero(), ast_waitfordigit(), ast_channel::exten, ast_channel::language, LOG_WARNING, ast_channel::macrocontext, and S_OR.
Referenced by do_directory().
00283 { 00284 int res = 0; 00285 int loop; 00286 char fn[256]; 00287 00288 /* Check for the VoiceMail2 greeting first */ 00289 snprintf(fn, sizeof(fn), "%s/voicemail/%s/%s/greet", 00290 ast_config_AST_SPOOL_DIR, context, ext); 00291 #ifdef ODBC_STORAGE 00292 retrieve_file(fn); 00293 #endif 00294 00295 if (ast_fileexists(fn, NULL, chan->language) <= 0) { 00296 /* no file, check for an old-style Voicemail greeting */ 00297 snprintf(fn, sizeof(fn), "%s/vm/%s/greet", 00298 ast_config_AST_SPOOL_DIR, ext); 00299 } 00300 #ifdef ODBC_STORAGE 00301 retrieve_file(fn); 00302 #endif 00303 00304 if (ast_fileexists(fn, NULL, chan->language) > 0) { 00305 res = ast_stream_and_wait(chan, fn, chan->language, AST_DIGIT_ANY); 00306 ast_stopstream(chan); 00307 /* If Option 'e' was specified, also read the extension number with the name */ 00308 if (readext) { 00309 ast_stream_and_wait(chan, "vm-extension", chan->language, AST_DIGIT_ANY); 00310 res = ast_say_character_str(chan, ext, AST_DIGIT_ANY, chan->language); 00311 } 00312 } else { 00313 res = ast_say_character_str(chan, S_OR(name, ext), AST_DIGIT_ANY, chan->language); 00314 if (!ast_strlen_zero(name) && readext) { 00315 ast_stream_and_wait(chan, "vm-extension", chan->language, AST_DIGIT_ANY); 00316 res = ast_say_character_str(chan, ext, AST_DIGIT_ANY, chan->language); 00317 } 00318 } 00319 #ifdef ODBC_STORAGE 00320 ast_filedelete(fn, NULL); 00321 #endif 00322 00323 for (loop = 3 ; loop > 0; loop--) { 00324 if (!res) 00325 res = ast_stream_and_wait(chan, "dir-instr", chan->language, AST_DIGIT_ANY); 00326 if (!res) 00327 res = ast_waitfordigit(chan, 3000); 00328 ast_stopstream(chan); 00329 00330 if (res < 0) /* User hungup, so jump out now */ 00331 break; 00332 if (res == '0') { 00333 if (!ast_goto_if_exists(chan, dialcontext, "o", 1) || 00334 (!ast_strlen_zero(chan->macrocontext) && 00335 !ast_goto_if_exists(chan, chan->macrocontext, "o", 1))) { 00336 /* return 1 to indicate goto has been performed */ 00337 return '1'; 00338 } 00339 } 00340 if (res == '1') { /* Name selected */ 00341 if (fromappvm) { 00342 /* We still want to set the exten though */ 00343 ast_copy_string(chan->exten, ext, sizeof(chan->exten)); 00344 } else { 00345 if (ast_goto_if_exists(chan, dialcontext, ext, 1)) { 00346 ast_log(LOG_WARNING, 00347 "Can't find extension '%s' in context '%s'. " 00348 "Did you pass the wrong context to Directory?\n", 00349 ext, dialcontext); 00350 res = -1; 00351 } 00352 } 00353 break; 00354 } 00355 if (res == '*') /* Skip to next match in list */ 00356 break; 00357 if (res == '#') 00358 break; 00359 00360 /* Not '1', or '*', so decrement number of tries */ 00361 res = 0; 00362 } 00363 00364 return(res); 00365 }
static struct ast_config* realtime_directory | ( | char * | context | ) | [static] |
Definition at line 367 of file app_directory.c.
References ast_category_append(), ast_category_browse(), ast_category_get(), ast_category_new(), ast_config_destroy(), ast_config_load(), ast_load_realtime_multientry(), ast_log(), ast_variable_append(), ast_variable_new(), ast_variable_retrieve(), LOG_WARNING, mailbox, var, and VOICEMAIL_CONFIG.
Referenced by directory_exec().
00368 { 00369 struct ast_config *cfg; 00370 struct ast_config *rtdata; 00371 struct ast_category *cat; 00372 struct ast_variable *var; 00373 char *mailbox; 00374 const char *fullname; 00375 const char *hidefromdir; 00376 char tmp[100]; 00377 00378 /* Load flat file config. */ 00379 cfg = ast_config_load(VOICEMAIL_CONFIG); 00380 00381 if (!cfg) { 00382 /* Loading config failed. */ 00383 ast_log(LOG_WARNING, "Loading config failed.\n"); 00384 return NULL; 00385 } 00386 00387 /* Get realtime entries, categorized by their mailbox number 00388 and present in the requested context */ 00389 rtdata = ast_load_realtime_multientry("voicemail", "mailbox LIKE", "%", "context", context, NULL); 00390 00391 /* if there are no results, just return the entries from the config file */ 00392 if (!rtdata) 00393 return cfg; 00394 00395 /* Does the context exist within the config file? If not, make one */ 00396 cat = ast_category_get(cfg, context); 00397 if (!cat) { 00398 cat = ast_category_new(context); 00399 if (!cat) { 00400 ast_log(LOG_WARNING, "Out of memory\n"); 00401 ast_config_destroy(cfg); 00402 if (rtdata) { 00403 ast_config_destroy(rtdata); 00404 } 00405 return NULL; 00406 } 00407 ast_category_append(cfg, cat); 00408 } 00409 00410 mailbox = NULL; 00411 while ( (mailbox = ast_category_browse(rtdata, mailbox)) ) { 00412 fullname = ast_variable_retrieve(rtdata, mailbox, "fullname"); 00413 hidefromdir = ast_variable_retrieve(rtdata, mailbox, "hidefromdir"); 00414 snprintf(tmp, sizeof(tmp), "no-password,%s,hidefromdir=%s", 00415 fullname ? fullname : "", 00416 hidefromdir ? hidefromdir : "no"); 00417 var = ast_variable_new(mailbox, tmp); 00418 if (var) 00419 ast_variable_append(cat, var); 00420 else 00421 ast_log(LOG_WARNING, "Out of memory adding mailbox '%s'\n", mailbox); 00422 } 00423 ast_config_destroy(rtdata); 00424 00425 return cfg; 00426 }
static int unload_module | ( | void | ) | [static] |
Definition at line 691 of file app_directory.c.
References ast_unregister_application().
00692 { 00693 int res; 00694 res = ast_unregister_application(app); 00695 return res; 00696 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT | AST_MODFLAG_BUILDSUM, .description = "Extension Directory" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, } [static] |
Definition at line 722 of file app_directory.c.
char* app = "Directory" [static] |
Definition at line 58 of file app_directory.c.
const struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 722 of file app_directory.c.
char* descrip [static] |
Definition at line 61 of file app_directory.c.
char* synopsis = "Provide directory of voicemail extensions" [static] |
Definition at line 60 of file app_directory.c.