#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 = "6989f2ec67f8497e38c12890500c525b" , .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 707 of file app_directory.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 707 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 595 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().
00596 { 00597 int res = 0; 00598 struct ast_module_user *u; 00599 struct ast_config *cfg, *ucfg; 00600 int last = 1; 00601 int readext = 0; 00602 int fromappvm = 0; 00603 const char *dirintro; 00604 char *parse; 00605 AST_DECLARE_APP_ARGS(args, 00606 AST_APP_ARG(vmcontext); 00607 AST_APP_ARG(dialcontext); 00608 AST_APP_ARG(options); 00609 ); 00610 00611 if (ast_strlen_zero(data)) { 00612 ast_log(LOG_WARNING, "Directory requires an argument (context[,dialcontext])\n"); 00613 return -1; 00614 } 00615 00616 u = ast_module_user_add(chan); 00617 00618 parse = ast_strdupa(data); 00619 00620 AST_STANDARD_APP_ARGS(args, parse); 00621 00622 if (args.options) { 00623 if (strchr(args.options, 'f')) 00624 last = 0; 00625 if (strchr(args.options, 'e')) 00626 readext = 1; 00627 if (strchr(args.options, 'v')) 00628 fromappvm = 1; 00629 } 00630 00631 if (ast_strlen_zero(args.dialcontext)) 00632 args.dialcontext = args.vmcontext; 00633 00634 cfg = realtime_directory(args.vmcontext); 00635 if (!cfg) { 00636 ast_log(LOG_ERROR, "Unable to read the configuration data!\n"); 00637 ast_module_user_remove(u); 00638 return -1; 00639 } 00640 00641 ucfg = ast_config_load("users.conf"); 00642 00643 dirintro = ast_variable_retrieve(cfg, args.vmcontext, "directoryintro"); 00644 if (ast_strlen_zero(dirintro)) 00645 dirintro = ast_variable_retrieve(cfg, "general", "directoryintro"); 00646 if (ast_strlen_zero(dirintro)) 00647 dirintro = last ? "dir-intro" : "dir-intro-fn"; 00648 00649 if (chan->_state != AST_STATE_UP) 00650 res = ast_answer(chan); 00651 00652 for (;;) { 00653 if (!res) 00654 res = ast_stream_and_wait(chan, dirintro, chan->language, AST_DIGIT_ANY); 00655 ast_stopstream(chan); 00656 if (!res) 00657 res = ast_waitfordigit(chan, 5000); 00658 if (res > 0) { 00659 res = do_directory(chan, cfg, ucfg, args.vmcontext, args.dialcontext, res, last, readext, fromappvm); 00660 if (res > 0) { 00661 res = ast_waitstream(chan, AST_DIGIT_ANY); 00662 ast_stopstream(chan); 00663 if (res >= 0) 00664 continue; 00665 } 00666 } 00667 break; 00668 } 00669 if (ucfg) 00670 ast_config_destroy(ucfg); 00671 ast_config_destroy(cfg); 00672 ast_module_user_remove(u); 00673 return res; 00674 }
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 418 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().
00419 { 00420 /* Read in the first three digits.. "digit" is the first digit, already read */ 00421 char ext[NUMDIGITS + 1], *cat; 00422 char name[80] = ""; 00423 struct ast_variable *v; 00424 int res; 00425 int found=0; 00426 int lastuserchoice = 0; 00427 char *start, *conv, *stringp = NULL; 00428 const char *pos; 00429 int breakout = 0; 00430 00431 if (ast_strlen_zero(context)) { 00432 ast_log(LOG_WARNING, 00433 "Directory must be called with an argument " 00434 "(context in which to interpret extensions)\n"); 00435 return -1; 00436 } 00437 if (digit == '0') { 00438 if (!ast_goto_if_exists(chan, dialcontext, "o", 1) || 00439 (!ast_strlen_zero(chan->macrocontext) && 00440 !ast_goto_if_exists(chan, chan->macrocontext, "o", 1))) { 00441 return 0; 00442 } else { 00443 ast_log(LOG_WARNING, "Can't find extension 'o' in current context. " 00444 "Not Exiting the Directory!\n"); 00445 res = 0; 00446 } 00447 } 00448 if (digit == '*') { 00449 if (!ast_goto_if_exists(chan, dialcontext, "a", 1) || 00450 (!ast_strlen_zero(chan->macrocontext) && 00451 !ast_goto_if_exists(chan, chan->macrocontext, "a", 1))) { 00452 return 0; 00453 } else { 00454 ast_log(LOG_WARNING, "Can't find extension 'a' in current context. " 00455 "Not Exiting the Directory!\n"); 00456 res = 0; 00457 } 00458 } 00459 memset(ext, 0, sizeof(ext)); 00460 ext[0] = digit; 00461 res = 0; 00462 if (ast_readstring(chan, ext + 1, NUMDIGITS - 1, 3000, 3000, "#") < 0) res = -1; 00463 if (!res) { 00464 /* Search for all names which start with those digits */ 00465 v = ast_variable_browse(cfg, context); 00466 while(v && !res) { 00467 /* Find all candidate extensions */ 00468 while(v) { 00469 /* Find a candidate extension */ 00470 start = strdup(v->value); 00471 if (start && !strcasestr(start, "hidefromdir=yes")) { 00472 stringp=start; 00473 strsep(&stringp, ","); 00474 pos = strsep(&stringp, ","); 00475 if (pos) { 00476 ast_copy_string(name, pos, sizeof(name)); 00477 /* Grab the last name */ 00478 if (last && strrchr(pos,' ')) 00479 pos = strrchr(pos, ' ') + 1; 00480 conv = convert(pos); 00481 if (conv) { 00482 if (!strncmp(conv, ext, strlen(ext))) { 00483 /* Match! */ 00484 found++; 00485 free(conv); 00486 free(start); 00487 break; 00488 } 00489 free(conv); 00490 } 00491 } 00492 free(start); 00493 } 00494 v = v->next; 00495 } 00496 00497 if (v) { 00498 /* We have a match -- play a greeting if they have it */ 00499 res = play_mailbox_owner(chan, context, dialcontext, v->name, name, readext, fromappvm); 00500 switch (res) { 00501 case -1: 00502 /* user pressed '1' but extension does not exist, or 00503 * user hungup 00504 */ 00505 lastuserchoice = 0; 00506 break; 00507 case '1': 00508 /* user pressed '1' and extensions exists; 00509 play_mailbox_owner will already have done 00510 a goto() on the channel 00511 */ 00512 lastuserchoice = res; 00513 break; 00514 case '*': 00515 /* user pressed '*' to skip something found */ 00516 lastuserchoice = res; 00517 res = 0; 00518 break; 00519 default: 00520 break; 00521 } 00522 v = v->next; 00523 } 00524 } 00525 00526 if (!res && ucfg) { 00527 /* Search users.conf for all names which start with those digits */ 00528 for (cat = ast_category_browse(ucfg, NULL); cat && !res ; cat = ast_category_browse(ucfg, cat)) { 00529 if (!strcasecmp(cat, "general")) 00530 continue; 00531 if (!ast_true(ast_config_option(ucfg, cat, "hasdirectory"))) 00532 continue; 00533 00534 /* Find all candidate extensions */ 00535 if ((pos = ast_variable_retrieve(ucfg, cat, "fullname"))) { 00536 ast_copy_string(name, pos, sizeof(name)); 00537 /* Grab the last name */ 00538 if (last && strrchr(pos,' ')) 00539 pos = strrchr(pos, ' ') + 1; 00540 conv = convert(pos); 00541 if (conv) { 00542 if (!strcmp(conv, ext)) { 00543 /* Match! */ 00544 found++; 00545 /* We have a match -- play a greeting if they have it */ 00546 res = play_mailbox_owner(chan, context, dialcontext, cat, name, readext, fromappvm); 00547 switch (res) { 00548 case -1: 00549 /* user pressed '1' but extension does not exist, or 00550 * user hungup 00551 */ 00552 lastuserchoice = 0; 00553 breakout = 1; 00554 break; 00555 case '1': 00556 /* user pressed '1' and extensions exists; 00557 play_mailbox_owner will already have done 00558 a goto() on the channel 00559 */ 00560 lastuserchoice = res; 00561 breakout = 1; 00562 break; 00563 case '*': 00564 /* user pressed '*' to skip something found */ 00565 lastuserchoice = res; 00566 breakout = 0; 00567 res = 0; 00568 break; 00569 default: 00570 breakout = 1; 00571 break; 00572 } 00573 free(conv); 00574 if (breakout) 00575 break; 00576 } 00577 else 00578 free(conv); 00579 } 00580 } 00581 } 00582 } 00583 00584 if (lastuserchoice != '1') { 00585 res = ast_streamfile(chan, found ? "dir-nomore" : "dir-nomatch", chan->language); 00586 if (!res) 00587 res = 1; 00588 return res; 00589 } 00590 return 0; 00591 } 00592 return res; 00593 }
static int load_module | ( | void | ) | [static] |
Definition at line 683 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.
00684 { 00685 #ifdef ODBC_STORAGE 00686 struct ast_config *cfg = ast_config_load(VOICEMAIL_CONFIG); 00687 const char *tmp; 00688 00689 if (cfg) { 00690 if ((tmp = ast_variable_retrieve(cfg, "general", "odbcstorage"))) { 00691 ast_copy_string(odbc_database, tmp, sizeof(odbc_database)); 00692 } 00693 if ((tmp = ast_variable_retrieve(cfg, "general", "odbctable"))) { 00694 ast_copy_string(odbc_table, tmp, sizeof(odbc_table)); 00695 } 00696 if ((tmp = ast_variable_retrieve(cfg, "general", "format"))) { 00697 ast_copy_string(vmfmts, tmp, sizeof(vmfmts)); 00698 } 00699 ast_config_destroy(cfg); 00700 } else 00701 ast_log(LOG_WARNING, "Unable to load " VOICEMAIL_CONFIG " - ODBC defaults will be used\n"); 00702 #endif 00703 00704 return ast_register_application(app, directory_exec, synopsis, descrip); 00705 }
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, 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] |
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 if (rtdata) { 00393 ast_config_destroy(rtdata); 00394 } 00395 return NULL; 00396 } 00397 ast_category_append(cfg, cat); 00398 } 00399 00400 mailbox = NULL; 00401 while ( (mailbox = ast_category_browse(rtdata, mailbox)) ) { 00402 fullname = ast_variable_retrieve(rtdata, mailbox, "fullname"); 00403 hidefromdir = ast_variable_retrieve(rtdata, mailbox, "hidefromdir"); 00404 snprintf(tmp, sizeof(tmp), "no-password,%s,hidefromdir=%s", 00405 fullname ? fullname : "", 00406 hidefromdir ? hidefromdir : "no"); 00407 var = ast_variable_new(mailbox, tmp); 00408 if (var) 00409 ast_variable_append(cat, var); 00410 else 00411 ast_log(LOG_WARNING, "Out of memory adding mailbox '%s'\n", mailbox); 00412 } 00413 ast_config_destroy(rtdata); 00414 00415 return cfg; 00416 }
static int unload_module | ( | void | ) | [static] |
Definition at line 676 of file app_directory.c.
References ast_unregister_application().
00677 { 00678 int res; 00679 res = ast_unregister_application(app); 00680 return res; 00681 }
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 = "6989f2ec67f8497e38c12890500c525b" , .load = load_module, .unload = unload_module, } [static] |
Definition at line 707 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 707 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.