#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 | |
AST_MODULE_INFO_STANDARD (ASTERISK_GPL_KEY,"Extension Directory") | |
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 char * | app = "Directory" |
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().
AST_MODULE_INFO_STANDARD | ( | ASTERISK_GPL_KEY | , | |
"Extension Directory" | ||||
) |
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 592 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(), last, LOG_ERROR, LOG_WARNING, parse(), and realtime_directory().
Referenced by load_module().
00593 { 00594 int res = 0; 00595 struct ast_module_user *u; 00596 struct ast_config *cfg, *ucfg; 00597 int last = 1; 00598 int readext = 0; 00599 int fromappvm = 0; 00600 const char *dirintro; 00601 char *parse; 00602 AST_DECLARE_APP_ARGS(args, 00603 AST_APP_ARG(vmcontext); 00604 AST_APP_ARG(dialcontext); 00605 AST_APP_ARG(options); 00606 ); 00607 00608 if (ast_strlen_zero(data)) { 00609 ast_log(LOG_WARNING, "Directory requires an argument (context[,dialcontext])\n"); 00610 return -1; 00611 } 00612 00613 u = ast_module_user_add(chan); 00614 00615 parse = ast_strdupa(data); 00616 00617 AST_STANDARD_APP_ARGS(args, parse); 00618 00619 if (args.options) { 00620 if (strchr(args.options, 'f')) 00621 last = 0; 00622 if (strchr(args.options, 'e')) 00623 readext = 1; 00624 if (strchr(args.options, 'v')) 00625 fromappvm = 1; 00626 } 00627 00628 if (ast_strlen_zero(args.dialcontext)) 00629 args.dialcontext = args.vmcontext; 00630 00631 cfg = realtime_directory(args.vmcontext); 00632 if (!cfg) { 00633 ast_log(LOG_ERROR, "Unable to read the configuration data!\n"); 00634 ast_module_user_remove(u); 00635 return -1; 00636 } 00637 00638 ucfg = ast_config_load("users.conf"); 00639 00640 dirintro = ast_variable_retrieve(cfg, args.vmcontext, "directoryintro"); 00641 if (ast_strlen_zero(dirintro)) 00642 dirintro = ast_variable_retrieve(cfg, "general", "directoryintro"); 00643 if (ast_strlen_zero(dirintro)) 00644 dirintro = last ? "dir-intro" : "dir-intro-fn"; 00645 00646 if (chan->_state != AST_STATE_UP) 00647 res = ast_answer(chan); 00648 00649 for (;;) { 00650 if (!res) 00651 res = ast_stream_and_wait(chan, dirintro, chan->language, AST_DIGIT_ANY); 00652 ast_stopstream(chan); 00653 if (!res) 00654 res = ast_waitfordigit(chan, 5000); 00655 if (res > 0) { 00656 res = do_directory(chan, cfg, ucfg, args.vmcontext, args.dialcontext, res, last, readext, fromappvm); 00657 if (res > 0) { 00658 res = ast_waitstream(chan, AST_DIGIT_ANY); 00659 ast_stopstream(chan); 00660 if (res >= 0) 00661 continue; 00662 } 00663 } 00664 break; 00665 } 00666 if (ucfg) 00667 ast_config_destroy(ucfg); 00668 ast_config_destroy(cfg); 00669 ast_module_user_remove(u); 00670 return res; 00671 }
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 415 of file app_directory.c.
References ast_category_browse(), ast_config_option(), ast_goto_if_exists(), ast_log(), ast_readstring(), ast_streamfile(), ast_strlen_zero(), ast_true(), ast_variable_browse(), ast_variable_retrieve(), convert(), ext, free, LOG_WARNING, ast_channel::macrocontext, ast_variable::name, name, ast_variable::next, NUMDIGITS, play_mailbox_owner(), strcasestr(), strdup, strsep(), and ast_variable::value.
Referenced by directory_exec().
00416 { 00417 /* Read in the first three digits.. "digit" is the first digit, already read */ 00418 char ext[NUMDIGITS + 1], *cat; 00419 char name[80] = ""; 00420 struct ast_variable *v; 00421 int res; 00422 int found=0; 00423 int lastuserchoice = 0; 00424 char *start, *conv, *stringp = NULL; 00425 const char *pos; 00426 int breakout = 0; 00427 00428 if (ast_strlen_zero(context)) { 00429 ast_log(LOG_WARNING, 00430 "Directory must be called with an argument " 00431 "(context in which to interpret extensions)\n"); 00432 return -1; 00433 } 00434 if (digit == '0') { 00435 if (!ast_goto_if_exists(chan, dialcontext, "o", 1) || 00436 (!ast_strlen_zero(chan->macrocontext) && 00437 !ast_goto_if_exists(chan, chan->macrocontext, "o", 1))) { 00438 return 0; 00439 } else { 00440 ast_log(LOG_WARNING, "Can't find extension 'o' in current context. " 00441 "Not Exiting the Directory!\n"); 00442 res = 0; 00443 } 00444 } 00445 if (digit == '*') { 00446 if (!ast_goto_if_exists(chan, dialcontext, "a", 1) || 00447 (!ast_strlen_zero(chan->macrocontext) && 00448 !ast_goto_if_exists(chan, chan->macrocontext, "a", 1))) { 00449 return 0; 00450 } else { 00451 ast_log(LOG_WARNING, "Can't find extension 'a' in current context. " 00452 "Not Exiting the Directory!\n"); 00453 res = 0; 00454 } 00455 } 00456 memset(ext, 0, sizeof(ext)); 00457 ext[0] = digit; 00458 res = 0; 00459 if (ast_readstring(chan, ext + 1, NUMDIGITS - 1, 3000, 3000, "#") < 0) res = -1; 00460 if (!res) { 00461 /* Search for all names which start with those digits */ 00462 v = ast_variable_browse(cfg, context); 00463 while(v && !res) { 00464 /* Find all candidate extensions */ 00465 while(v) { 00466 /* Find a candidate extension */ 00467 start = strdup(v->value); 00468 if (start && !strcasestr(start, "hidefromdir=yes")) { 00469 stringp=start; 00470 strsep(&stringp, ","); 00471 pos = strsep(&stringp, ","); 00472 if (pos) { 00473 ast_copy_string(name, pos, sizeof(name)); 00474 /* Grab the last name */ 00475 if (last && strrchr(pos,' ')) 00476 pos = strrchr(pos, ' ') + 1; 00477 conv = convert(pos); 00478 if (conv) { 00479 if (!strncmp(conv, ext, strlen(ext))) { 00480 /* Match! */ 00481 found++; 00482 free(conv); 00483 free(start); 00484 break; 00485 } 00486 free(conv); 00487 } 00488 } 00489 free(start); 00490 } 00491 v = v->next; 00492 } 00493 00494 if (v) { 00495 /* We have a match -- play a greeting if they have it */ 00496 res = play_mailbox_owner(chan, context, dialcontext, v->name, name, readext, fromappvm); 00497 switch (res) { 00498 case -1: 00499 /* user pressed '1' but extension does not exist, or 00500 * user hungup 00501 */ 00502 lastuserchoice = 0; 00503 break; 00504 case '1': 00505 /* user pressed '1' and extensions exists; 00506 play_mailbox_owner will already have done 00507 a goto() on the channel 00508 */ 00509 lastuserchoice = res; 00510 break; 00511 case '*': 00512 /* user pressed '*' to skip something found */ 00513 lastuserchoice = res; 00514 res = 0; 00515 break; 00516 default: 00517 break; 00518 } 00519 v = v->next; 00520 } 00521 } 00522 00523 if (!res && ucfg) { 00524 /* Search users.conf for all names which start with those digits */ 00525 for (cat = ast_category_browse(ucfg, NULL); cat && !res ; cat = ast_category_browse(ucfg, cat)) { 00526 if (!strcasecmp(cat, "general")) 00527 continue; 00528 if (!ast_true(ast_config_option(ucfg, cat, "hasdirectory"))) 00529 continue; 00530 00531 /* Find all candidate extensions */ 00532 if ((pos = ast_variable_retrieve(ucfg, cat, "fullname"))) { 00533 ast_copy_string(name, pos, sizeof(name)); 00534 /* Grab the last name */ 00535 if (last && strrchr(pos,' ')) 00536 pos = strrchr(pos, ' ') + 1; 00537 conv = convert(pos); 00538 if (conv) { 00539 if (!strcmp(conv, ext)) { 00540 /* Match! */ 00541 found++; 00542 /* We have a match -- play a greeting if they have it */ 00543 res = play_mailbox_owner(chan, context, dialcontext, cat, name, readext, fromappvm); 00544 switch (res) { 00545 case -1: 00546 /* user pressed '1' but extension does not exist, or 00547 * user hungup 00548 */ 00549 lastuserchoice = 0; 00550 breakout = 1; 00551 break; 00552 case '1': 00553 /* user pressed '1' and extensions exists; 00554 play_mailbox_owner will already have done 00555 a goto() on the channel 00556 */ 00557 lastuserchoice = res; 00558 breakout = 1; 00559 break; 00560 case '*': 00561 /* user pressed '*' to skip something found */ 00562 lastuserchoice = res; 00563 breakout = 0; 00564 res = 0; 00565 break; 00566 default: 00567 breakout = 1; 00568 break; 00569 } 00570 free(conv); 00571 if (breakout) 00572 break; 00573 } 00574 else 00575 free(conv); 00576 } 00577 } 00578 } 00579 } 00580 00581 if (lastuserchoice != '1') { 00582 res = ast_streamfile(chan, found ? "dir-nomore" : "dir-nomatch", chan->language); 00583 if (!res) 00584 res = 1; 00585 return res; 00586 } 00587 return 0; 00588 } 00589 return res; 00590 }
static int load_module | ( | void | ) | [static] |
Definition at line 680 of file app_directory.c.
References ast_config_destroy(), ast_config_load(), ast_log(), ast_register_application(), ast_variable_retrieve(), directory_exec(), LOG_WARNING, and VOICEMAIL_CONFIG.
00681 { 00682 #ifdef ODBC_STORAGE 00683 struct ast_config *cfg = ast_config_load(VOICEMAIL_CONFIG); 00684 const char *tmp; 00685 00686 if (cfg) { 00687 if ((tmp = ast_variable_retrieve(cfg, "general", "odbcstorage"))) { 00688 ast_copy_string(odbc_database, tmp, sizeof(odbc_database)); 00689 } 00690 if ((tmp = ast_variable_retrieve(cfg, "general", "odbctable"))) { 00691 ast_copy_string(odbc_table, tmp, sizeof(odbc_table)); 00692 } 00693 if ((tmp = ast_variable_retrieve(cfg, "general", "format"))) { 00694 ast_copy_string(vmfmts, tmp, sizeof(vmfmts)); 00695 } 00696 ast_config_destroy(cfg); 00697 } else 00698 ast_log(LOG_WARNING, "Unable to load " VOICEMAIL_CONFIG " - ODBC defaults will be used\n"); 00699 #endif 00700 00701 return ast_register_application(app, directory_exec, synopsis, descrip); 00702 }
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_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, LOG_WARNING, 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 == '1') { /* Name selected */ 00333 if (fromappvm) { 00334 /* We still want to set the exten though */ 00335 ast_copy_string(chan->exten, ext, sizeof(chan->exten)); 00336 } else { 00337 if (ast_goto_if_exists(chan, dialcontext, ext, 1)) { 00338 ast_log(LOG_WARNING, 00339 "Can't find extension '%s' in context '%s'. " 00340 "Did you pass the wrong context to Directory?\n", 00341 ext, dialcontext); 00342 res = -1; 00343 } 00344 } 00345 break; 00346 } 00347 if (res == '*') /* Skip to next match in list */ 00348 break; 00349 00350 /* Not '1', or '*', so decrement number of tries */ 00351 res = 0; 00352 } 00353 00354 return(res); 00355 }
static struct ast_config* realtime_directory | ( | char * | context | ) | [static, read] |
Definition at line 357 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().
00358 { 00359 struct ast_config *cfg; 00360 struct ast_config *rtdata; 00361 struct ast_category *cat; 00362 struct ast_variable *var; 00363 char *mailbox; 00364 const char *fullname; 00365 const char *hidefromdir; 00366 char tmp[100]; 00367 00368 /* Load flat file config. */ 00369 cfg = ast_config_load(VOICEMAIL_CONFIG); 00370 00371 if (!cfg) { 00372 /* Loading config failed. */ 00373 ast_log(LOG_WARNING, "Loading config failed.\n"); 00374 return NULL; 00375 } 00376 00377 /* Get realtime entries, categorized by their mailbox number 00378 and present in the requested context */ 00379 rtdata = ast_load_realtime_multientry("voicemail", "mailbox LIKE", "%", "context", context, NULL); 00380 00381 /* if there are no results, just return the entries from the config file */ 00382 if (!rtdata) 00383 return cfg; 00384 00385 /* Does the context exist within the config file? If not, make one */ 00386 cat = ast_category_get(cfg, context); 00387 if (!cat) { 00388 cat = ast_category_new(context); 00389 if (!cat) { 00390 ast_log(LOG_WARNING, "Out of memory\n"); 00391 ast_config_destroy(cfg); 00392 return NULL; 00393 } 00394 ast_category_append(cfg, cat); 00395 } 00396 00397 mailbox = NULL; 00398 while ( (mailbox = ast_category_browse(rtdata, mailbox)) ) { 00399 fullname = ast_variable_retrieve(rtdata, mailbox, "fullname"); 00400 hidefromdir = ast_variable_retrieve(rtdata, mailbox, "hidefromdir"); 00401 snprintf(tmp, sizeof(tmp), "no-password,%s,hidefromdir=%s", 00402 fullname ? fullname : "", 00403 hidefromdir ? hidefromdir : "no"); 00404 var = ast_variable_new(mailbox, tmp); 00405 if (var) 00406 ast_variable_append(cat, var); 00407 else 00408 ast_log(LOG_WARNING, "Out of memory adding mailbox '%s'\n", mailbox); 00409 } 00410 ast_config_destroy(rtdata); 00411 00412 return cfg; 00413 }
static int unload_module | ( | void | ) | [static] |
Definition at line 673 of file app_directory.c.
References ast_unregister_application().
00674 { 00675 int res; 00676 res = ast_unregister_application(app); 00677 return res; 00678 }
char* app = "Directory" [static] |
Definition at line 58 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.