#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"
Include dependency graph for app_directory.c:
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 187 of file app_directory.c.
References ast_malloc, and NUMDIGITS.
Referenced by do_directory().
00188 { 00189 char *tmp; 00190 int lcount = 0; 00191 tmp = ast_malloc(NUMDIGITS + 1); 00192 if (tmp) { 00193 while((*lastname > 32) && lcount < NUMDIGITS) { 00194 switch(toupper(*lastname)) { 00195 case '1': 00196 tmp[lcount++] = '1'; 00197 break; 00198 case '2': 00199 case 'A': 00200 case 'B': 00201 case 'C': 00202 tmp[lcount++] = '2'; 00203 break; 00204 case '3': 00205 case 'D': 00206 case 'E': 00207 case 'F': 00208 tmp[lcount++] = '3'; 00209 break; 00210 case '4': 00211 case 'G': 00212 case 'H': 00213 case 'I': 00214 tmp[lcount++] = '4'; 00215 break; 00216 case '5': 00217 case 'J': 00218 case 'K': 00219 case 'L': 00220 tmp[lcount++] = '5'; 00221 break; 00222 case '6': 00223 case 'M': 00224 case 'N': 00225 case 'O': 00226 tmp[lcount++] = '6'; 00227 break; 00228 case '7': 00229 case 'P': 00230 case 'Q': 00231 case 'R': 00232 case 'S': 00233 tmp[lcount++] = '7'; 00234 break; 00235 case '8': 00236 case 'T': 00237 case 'U': 00238 case 'V': 00239 tmp[lcount++] = '8'; 00240 break; 00241 case '9': 00242 case 'W': 00243 case 'X': 00244 case 'Y': 00245 case 'Z': 00246 tmp[lcount++] = '9'; 00247 break; 00248 } 00249 lastname++; 00250 } 00251 tmp[lcount] = '\0'; 00252 } 00253 return tmp; 00254 }
static int directory_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 570 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().
00571 { 00572 int res = 0; 00573 struct ast_module_user *u; 00574 struct ast_config *cfg, *ucfg; 00575 int last = 1; 00576 int readext = 0; 00577 int fromappvm = 0; 00578 const char *dirintro; 00579 char *parse; 00580 AST_DECLARE_APP_ARGS(args, 00581 AST_APP_ARG(vmcontext); 00582 AST_APP_ARG(dialcontext); 00583 AST_APP_ARG(options); 00584 ); 00585 00586 if (ast_strlen_zero(data)) { 00587 ast_log(LOG_WARNING, "Directory requires an argument (context[,dialcontext])\n"); 00588 return -1; 00589 } 00590 00591 u = ast_module_user_add(chan); 00592 00593 parse = ast_strdupa(data); 00594 00595 AST_STANDARD_APP_ARGS(args, parse); 00596 00597 if (args.options) { 00598 if (strchr(args.options, 'f')) 00599 last = 0; 00600 if (strchr(args.options, 'e')) 00601 readext = 1; 00602 if (strchr(args.options, 'v')) 00603 fromappvm = 1; 00604 } 00605 00606 if (ast_strlen_zero(args.dialcontext)) 00607 args.dialcontext = args.vmcontext; 00608 00609 cfg = realtime_directory(args.vmcontext); 00610 if (!cfg) { 00611 ast_log(LOG_ERROR, "Unable to read the configuration data!\n"); 00612 ast_module_user_remove(u); 00613 return -1; 00614 } 00615 00616 ucfg = ast_config_load("users.conf"); 00617 00618 dirintro = ast_variable_retrieve(cfg, args.vmcontext, "directoryintro"); 00619 if (ast_strlen_zero(dirintro)) 00620 dirintro = ast_variable_retrieve(cfg, "general", "directoryintro"); 00621 if (ast_strlen_zero(dirintro)) 00622 dirintro = last ? "dir-intro" : "dir-intro-fn"; 00623 00624 if (chan->_state != AST_STATE_UP) 00625 res = ast_answer(chan); 00626 00627 for (;;) { 00628 if (!res) 00629 res = ast_stream_and_wait(chan, dirintro, chan->language, AST_DIGIT_ANY); 00630 ast_stopstream(chan); 00631 if (!res) 00632 res = ast_waitfordigit(chan, 5000); 00633 if (res > 0) { 00634 res = do_directory(chan, cfg, ucfg, args.vmcontext, args.dialcontext, res, last, readext, fromappvm); 00635 if (res > 0) { 00636 res = ast_waitstream(chan, AST_DIGIT_ANY); 00637 ast_stopstream(chan); 00638 if (res >= 0) 00639 continue; 00640 } 00641 } 00642 break; 00643 } 00644 if (ucfg) 00645 ast_config_destroy(ucfg); 00646 ast_config_destroy(cfg); 00647 ast_module_user_remove(u); 00648 return res; 00649 }
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 400 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, name, NUMDIGITS, play_mailbox_owner(), strcasestr(), strdup, and strsep().
Referenced by directory_exec().
00401 { 00402 /* Read in the first three digits.. "digit" is the first digit, already read */ 00403 char ext[NUMDIGITS + 1], *cat; 00404 char name[80] = ""; 00405 struct ast_variable *v; 00406 int res; 00407 int found=0; 00408 int lastuserchoice = 0; 00409 char *start, *conv, *stringp = NULL; 00410 const char *pos; 00411 00412 if (ast_strlen_zero(context)) { 00413 ast_log(LOG_WARNING, 00414 "Directory must be called with an argument " 00415 "(context in which to interpret extensions)\n"); 00416 return -1; 00417 } 00418 if (digit == '0') { 00419 if (!ast_goto_if_exists(chan, dialcontext, "o", 1) || 00420 (!ast_strlen_zero(chan->macrocontext) && 00421 !ast_goto_if_exists(chan, chan->macrocontext, "o", 1))) { 00422 return 0; 00423 } else { 00424 ast_log(LOG_WARNING, "Can't find extension 'o' in current context. " 00425 "Not Exiting the Directory!\n"); 00426 res = 0; 00427 } 00428 } 00429 if (digit == '*') { 00430 if (!ast_goto_if_exists(chan, dialcontext, "a", 1) || 00431 (!ast_strlen_zero(chan->macrocontext) && 00432 !ast_goto_if_exists(chan, chan->macrocontext, "a", 1))) { 00433 return 0; 00434 } else { 00435 ast_log(LOG_WARNING, "Can't find extension 'a' in current context. " 00436 "Not Exiting the Directory!\n"); 00437 res = 0; 00438 } 00439 } 00440 memset(ext, 0, sizeof(ext)); 00441 ext[0] = digit; 00442 res = 0; 00443 if (ast_readstring(chan, ext + 1, NUMDIGITS - 1, 3000, 3000, "#") < 0) res = -1; 00444 if (!res) { 00445 /* Search for all names which start with those digits */ 00446 v = ast_variable_browse(cfg, context); 00447 while(v && !res) { 00448 /* Find all candidate extensions */ 00449 while(v) { 00450 /* Find a candidate extension */ 00451 start = strdup(v->value); 00452 if (start && !strcasestr(start, "hidefromdir=yes")) { 00453 stringp=start; 00454 strsep(&stringp, ","); 00455 pos = strsep(&stringp, ","); 00456 if (pos) { 00457 ast_copy_string(name, pos, sizeof(name)); 00458 /* Grab the last name */ 00459 if (last && strrchr(pos,' ')) 00460 pos = strrchr(pos, ' ') + 1; 00461 conv = convert(pos); 00462 if (conv) { 00463 if (!strncmp(conv, ext, strlen(ext))) { 00464 /* Match! */ 00465 found++; 00466 free(conv); 00467 free(start); 00468 break; 00469 } 00470 free(conv); 00471 } 00472 } 00473 free(start); 00474 } 00475 v = v->next; 00476 } 00477 00478 if (v) { 00479 /* We have a match -- play a greeting if they have it */ 00480 res = play_mailbox_owner(chan, context, dialcontext, v->name, name, readext, fromappvm); 00481 switch (res) { 00482 case -1: 00483 /* user pressed '1' but extension does not exist, or 00484 * user hungup 00485 */ 00486 lastuserchoice = 0; 00487 break; 00488 case '1': 00489 /* user pressed '1' and extensions exists; 00490 play_mailbox_owner will already have done 00491 a goto() on the channel 00492 */ 00493 lastuserchoice = res; 00494 break; 00495 case '*': 00496 /* user pressed '*' to skip something found */ 00497 lastuserchoice = res; 00498 res = 0; 00499 break; 00500 default: 00501 break; 00502 } 00503 v = v->next; 00504 } 00505 } 00506 00507 if (!res && ucfg) { 00508 /* Search users.conf for all names which start with those digits */ 00509 for (cat = ast_category_browse(ucfg, NULL); cat && !res ; cat = ast_category_browse(ucfg, cat)) { 00510 if (!strcasecmp(cat, "general")) 00511 continue; 00512 if (!ast_true(ast_config_option(ucfg, cat, "hasdirectory"))) 00513 continue; 00514 00515 /* Find all candidate extensions */ 00516 if ((pos = ast_variable_retrieve(ucfg, cat, "fullname"))) { 00517 ast_copy_string(name, pos, sizeof(name)); 00518 /* Grab the last name */ 00519 if (last && strrchr(pos,' ')) 00520 pos = strrchr(pos, ' ') + 1; 00521 conv = convert(pos); 00522 if (conv) { 00523 if (!strcmp(conv, ext)) { 00524 /* Match! */ 00525 found++; 00526 /* We have a match -- play a greeting if they have it */ 00527 res = play_mailbox_owner(chan, context, dialcontext, cat, name, readext, fromappvm); 00528 switch (res) { 00529 case -1: 00530 /* user pressed '1' but extension does not exist, or 00531 * user hungup 00532 */ 00533 lastuserchoice = 0; 00534 break; 00535 case '1': 00536 /* user pressed '1' and extensions exists; 00537 play_mailbox_owner will already have done 00538 a goto() on the channel 00539 */ 00540 lastuserchoice = res; 00541 break; 00542 case '*': 00543 /* user pressed '*' to skip something found */ 00544 lastuserchoice = res; 00545 res = 0; 00546 break; 00547 default: 00548 break; 00549 } 00550 free(conv); 00551 break; 00552 } 00553 free(conv); 00554 } 00555 } 00556 } 00557 } 00558 00559 if (lastuserchoice != '1') { 00560 res = ast_streamfile(chan, found ? "dir-nomore" : "dir-nomatch", chan->language); 00561 if (!res) 00562 res = 1; 00563 return res; 00564 } 00565 return 0; 00566 } 00567 return res; 00568 }
static int load_module | ( | void | ) | [static] |
Definition at line 658 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.
00659 { 00660 #ifdef ODBC_STORAGE 00661 struct ast_config *cfg = ast_config_load(VOICEMAIL_CONFIG); 00662 const char *tmp; 00663 00664 if (cfg) { 00665 if ((tmp = ast_variable_retrieve(cfg, "general", "odbcstorage"))) { 00666 ast_copy_string(odbc_database, tmp, sizeof(odbc_database)); 00667 } 00668 if ((tmp = ast_variable_retrieve(cfg, "general", "odbctable"))) { 00669 ast_copy_string(odbc_table, tmp, sizeof(odbc_table)); 00670 } 00671 if ((tmp = ast_variable_retrieve(cfg, "general", "format"))) { 00672 ast_copy_string(vmfmts, tmp, sizeof(vmfmts)); 00673 } 00674 ast_config_destroy(cfg); 00675 } else 00676 ast_log(LOG_WARNING, "Unable to load " VOICEMAIL_CONFIG " - ODBC defaults will be used\n"); 00677 #endif 00678 00679 return ast_register_application(app, directory_exec, synopsis, descrip); 00680 }
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 261 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().
00264 { 00265 int res = 0; 00266 int loop; 00267 char fn[256]; 00268 #ifdef ODBC_STORAGE 00269 char fn2[256]; 00270 #endif 00271 00272 /* Check for the VoiceMail2 greeting first */ 00273 snprintf(fn, sizeof(fn), "%s/voicemail/%s/%s/greet", 00274 ast_config_AST_SPOOL_DIR, context, ext); 00275 #ifdef ODBC_STORAGE 00276 retrieve_file(fn); 00277 #endif 00278 00279 if (ast_fileexists(fn, NULL, chan->language) <= 0) { 00280 /* no file, check for an old-style Voicemail greeting */ 00281 snprintf(fn, sizeof(fn), "%s/vm/%s/greet", 00282 ast_config_AST_SPOOL_DIR, ext); 00283 } 00284 #ifdef ODBC_STORAGE 00285 retrieve_file(fn2); 00286 #endif 00287 00288 if (ast_fileexists(fn, NULL, chan->language) > 0) { 00289 res = ast_stream_and_wait(chan, fn, chan->language, AST_DIGIT_ANY); 00290 ast_stopstream(chan); 00291 /* If Option 'e' was specified, also read the extension number with the name */ 00292 if (readext) { 00293 ast_stream_and_wait(chan, "vm-extension", chan->language, AST_DIGIT_ANY); 00294 res = ast_say_character_str(chan, ext, AST_DIGIT_ANY, chan->language); 00295 } 00296 } else { 00297 res = ast_say_character_str(chan, S_OR(name, ext), AST_DIGIT_ANY, chan->language); 00298 if (!ast_strlen_zero(name) && readext) { 00299 ast_stream_and_wait(chan, "vm-extension", chan->language, AST_DIGIT_ANY); 00300 res = ast_say_character_str(chan, ext, AST_DIGIT_ANY, chan->language); 00301 } 00302 } 00303 #ifdef ODBC_STORAGE 00304 ast_filedelete(fn, NULL); 00305 ast_filedelete(fn2, NULL); 00306 #endif 00307 00308 for (loop = 3 ; loop > 0; loop--) { 00309 if (!res) 00310 res = ast_stream_and_wait(chan, "dir-instr", chan->language, AST_DIGIT_ANY); 00311 if (!res) 00312 res = ast_waitfordigit(chan, 3000); 00313 ast_stopstream(chan); 00314 00315 if (res < 0) /* User hungup, so jump out now */ 00316 break; 00317 if (res == '1') { /* Name selected */ 00318 if (fromappvm) { 00319 /* We still want to set the exten though */ 00320 ast_copy_string(chan->exten, ext, sizeof(chan->exten)); 00321 } else { 00322 if (ast_goto_if_exists(chan, dialcontext, ext, 1)) { 00323 ast_log(LOG_WARNING, 00324 "Can't find extension '%s' in context '%s'. " 00325 "Did you pass the wrong context to Directory?\n", 00326 ext, dialcontext); 00327 res = -1; 00328 } 00329 } 00330 break; 00331 } 00332 if (res == '*') /* Skip to next match in list */ 00333 break; 00334 00335 /* Not '1', or '*', so decrement number of tries */ 00336 res = 0; 00337 } 00338 00339 return(res); 00340 }
static struct ast_config* realtime_directory | ( | char * | context | ) | [static] |
Definition at line 342 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().
00343 { 00344 struct ast_config *cfg; 00345 struct ast_config *rtdata; 00346 struct ast_category *cat; 00347 struct ast_variable *var; 00348 char *mailbox; 00349 const char *fullname; 00350 const char *hidefromdir; 00351 char tmp[100]; 00352 00353 /* Load flat file config. */ 00354 cfg = ast_config_load(VOICEMAIL_CONFIG); 00355 00356 if (!cfg) { 00357 /* Loading config failed. */ 00358 ast_log(LOG_WARNING, "Loading config failed.\n"); 00359 return NULL; 00360 } 00361 00362 /* Get realtime entries, categorized by their mailbox number 00363 and present in the requested context */ 00364 rtdata = ast_load_realtime_multientry("voicemail", "mailbox LIKE", "%", "context", context, NULL); 00365 00366 /* if there are no results, just return the entries from the config file */ 00367 if (!rtdata) 00368 return cfg; 00369 00370 /* Does the context exist within the config file? If not, make one */ 00371 cat = ast_category_get(cfg, context); 00372 if (!cat) { 00373 cat = ast_category_new(context); 00374 if (!cat) { 00375 ast_log(LOG_WARNING, "Out of memory\n"); 00376 ast_config_destroy(cfg); 00377 return NULL; 00378 } 00379 ast_category_append(cfg, cat); 00380 } 00381 00382 mailbox = NULL; 00383 while ( (mailbox = ast_category_browse(rtdata, mailbox)) ) { 00384 fullname = ast_variable_retrieve(rtdata, mailbox, "fullname"); 00385 hidefromdir = ast_variable_retrieve(rtdata, mailbox, "hidefromdir"); 00386 snprintf(tmp, sizeof(tmp), "no-password,%s,hidefromdir=%s", 00387 fullname ? fullname : "", 00388 hidefromdir ? hidefromdir : "no"); 00389 var = ast_variable_new(mailbox, tmp); 00390 if (var) 00391 ast_variable_append(cat, var); 00392 else 00393 ast_log(LOG_WARNING, "Out of memory adding mailbox '%s'\n", mailbox); 00394 } 00395 ast_config_destroy(rtdata); 00396 00397 return cfg; 00398 }
static int unload_module | ( | void | ) | [static] |
Definition at line 651 of file app_directory.c.
References ast_unregister_application().
00652 { 00653 int res; 00654 res = ast_unregister_application(app); 00655 return res; 00656 }
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.