#include "asterisk.h"
#include <string.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/translate.h"
#include "asterisk/utils.h"
#include "asterisk/options.h"
#include "asterisk/app.h"
#include "asterisk/cli.h"
#include "asterisk/localtime.h"
#include "asterisk/say.h"
Go to the source code of this file.
Data Structures | |
struct | say_args_t |
Functions | |
static int | __say_init (int fd, int argc, char *argv[]) |
AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT,"Sound File Playback Application",.load=load_module,.unload=unload_module,.reload=reload,) | |
static int | do_say (say_args_t *a, const char *s, const char *options, int depth) |
static int | load_module (void) |
static int | playback_exec (struct ast_channel *chan, void *data) |
static int | reload (void) |
static void | restore_say_mode (void *arg) |
static int | s_streamwait3 (const say_args_t *a, const char *fn) |
static void | save_say_mode (const void *arg) |
static int | say_date (struct ast_channel *chan, time_t t, const char *ints, const char *lang) |
static int | say_date_generic (struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *timezone, const char *prefix) |
static int | say_date_with_format (struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *timezone) |
static int | say_datetime (struct ast_channel *chan, time_t t, const char *ints, const char *lang) |
static int | say_enumeration_full (struct ast_channel *chan, int num, const char *ints, const char *lang, const char *options, int audiofd, int ctrlfd) |
static int | say_full (struct ast_channel *chan, const char *string, const char *ints, const char *lang, const char *options, int audiofd, int ctrlfd) |
static int | say_number_full (struct ast_channel *chan, int num, const char *ints, const char *lang, const char *options, int audiofd, int ctrlfd) |
static int | say_time (struct ast_channel *chan, time_t t, const char *ints, const char *lang) |
static int | unload_module (void) |
Variables | |
static char * | app = "Playback" |
static struct ast_cli_entry | cli_playback [] |
static char * | descrip |
static const void * | say_api_buf [40] |
static struct ast_config * | say_cfg = NULL |
static const char * | say_new = "new" |
static const char * | say_old = "old" |
static char * | synopsis = "Play a file" |
Definition in file app_playback.c.
static int __say_init | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 332 of file app_playback.c.
References ast_cli(), ast_config_load(), ast_log(), ast_say_character_str_full, ast_say_date, ast_say_date_with_format, ast_say_datetime, ast_say_datetime_from_now, ast_say_digit_str_full, ast_say_digits_full(), ast_say_enumeration_full, ast_say_number_full, ast_say_phonetic_str_full, ast_say_time, LOG_WARNING, restore_say_mode(), RESULT_SHOWUSAGE, RESULT_SUCCESS, save_say_mode(), say_cfg, say_character_str_full(), say_date(), say_date_with_format(), say_datetime(), say_datetime_from_now(), say_digit_str_full(), say_enumeration_full(), say_number_full(), say_phonetic_str_full(), and say_time().
00333 { 00334 const char *old_mode = say_api_buf[0] ? say_new : say_old; 00335 char *mode; 00336 00337 if (argc == 2) { 00338 ast_cli(fd, "say mode is [%s]\n", old_mode); 00339 return RESULT_SUCCESS; 00340 } else if (argc != 3) 00341 return RESULT_SHOWUSAGE; 00342 mode = argv[2]; 00343 00344 ast_log(LOG_WARNING, "init say.c from %s to %s\n", old_mode, mode); 00345 00346 if (!strcmp(mode, old_mode)) { 00347 ast_log(LOG_WARNING, "say mode is %s already\n", mode); 00348 } else if (!strcmp(mode, say_new)) { 00349 if (say_cfg == NULL) 00350 say_cfg = ast_config_load("say.conf"); 00351 save_say_mode(say_new); 00352 ast_say_number_full = say_number_full; 00353 00354 ast_say_enumeration_full = say_enumeration_full; 00355 #if 0 00356 ast_say_digits_full = say_digits_full; 00357 ast_say_digit_str_full = say_digit_str_full; 00358 ast_say_character_str_full = say_character_str_full; 00359 ast_say_phonetic_str_full = say_phonetic_str_full; 00360 ast_say_datetime_from_now = say_datetime_from_now; 00361 #endif 00362 ast_say_datetime = say_datetime; 00363 ast_say_time = say_time; 00364 ast_say_date = say_date; 00365 ast_say_date_with_format = say_date_with_format; 00366 } else if (!strcmp(mode, say_old) && say_api_buf[0] == say_new) { 00367 restore_say_mode(NULL); 00368 } else { 00369 ast_log(LOG_WARNING, "unrecognized mode %s\n", mode); 00370 } 00371 return RESULT_SUCCESS; 00372 }
AST_MODULE_INFO | ( | ASTERISK_GPL_KEY | , | |
AST_MODFLAG_DEFAULT | , | |||
"Sound File Playback Application" | , | |||
. | load = load_module , |
|||
. | unload = unload_module , |
|||
. | reload = reload | |||
) |
static int do_say | ( | say_args_t * | a, | |
const char * | s, | |||
const char * | options, | |||
int | depth | |||
) | [static] |
Definition at line 149 of file app_playback.c.
References ast_extension_match(), ast_log(), ast_strdupa, ast_variable_browse(), say_args_t::language, LOG_WARNING, ast_variable::name, ast_variable::next, say_cfg, and ast_variable::value.
Referenced by say_date_generic(), say_enumeration_full(), say_full(), and say_number_full().
00150 { 00151 struct ast_variable *v; 00152 char *lang, *x, *rule = NULL; 00153 int ret = 0; 00154 struct varshead head = { .first = NULL, .last = NULL }; 00155 struct ast_var_t *n; 00156 00157 if (depth++ > 10) { 00158 ast_log(LOG_WARNING, "recursion too deep, exiting\n"); 00159 return -1; 00160 } else if (!say_cfg) { 00161 ast_log(LOG_WARNING, "no say.conf, cannot spell '%s'\n", s); 00162 return -1; 00163 } 00164 00165 /* scan languages same as in file.c */ 00166 if (a->language == NULL) 00167 a->language = "en"; /* default */ 00168 lang = ast_strdupa(a->language); 00169 for (;;) { 00170 for (v = ast_variable_browse(say_cfg, lang); v ; v = v->next) { 00171 if (ast_extension_match(v->name, s)) { 00172 rule = ast_strdupa(v->value); 00173 break; 00174 } 00175 } 00176 if (rule) 00177 break; 00178 if ( (x = strchr(lang, '_')) ) 00179 *x = '\0'; /* try without suffix */ 00180 else if (strcmp(lang, "en")) 00181 lang = "en"; /* last resort, try 'en' if not done yet */ 00182 else 00183 break; 00184 } 00185 if (!rule) 00186 return 0; 00187 00188 /* skip up to two prefixes to get the value */ 00189 if ( (x = strchr(s, ':')) ) 00190 s = x + 1; 00191 if ( (x = strchr(s, ':')) ) 00192 s = x + 1; 00193 n = ast_var_assign("SAY", s); 00194 AST_LIST_INSERT_HEAD(&head, n, entries); 00195 00196 /* scan the body, one piece at a time */ 00197 while ( !ret && (x = strsep(&rule, ",")) ) { /* exit on key */ 00198 char fn[128]; 00199 const char *p, *fmt, *data; /* format and data pointers */ 00200 00201 /* prepare a decent file name */ 00202 x = ast_skip_blanks(x); 00203 ast_trim_blanks(x); 00204 00205 /* replace variables */ 00206 memset(fn, 0, sizeof(fn)); /* XXX why isn't done in pbx_substitute_variables_helper! */ 00207 pbx_substitute_variables_varshead(&head, x, fn, sizeof(fn)); 00208 00209 /* locate prefix and data, if any */ 00210 fmt = index(fn, ':'); 00211 if (!fmt || fmt == fn) { /* regular filename */ 00212 ret = s_streamwait3(a, fn); 00213 continue; 00214 } 00215 fmt++; 00216 data = index(fmt, ':'); /* colon before data */ 00217 if (!data || data == fmt) { /* simple prefix-fmt */ 00218 ret = do_say(a, fn, options, depth); 00219 continue; 00220 } 00221 /* prefix:fmt:data */ 00222 for (p = fmt; p < data && ret <= 0; p++) { 00223 char fn2[sizeof(fn)]; 00224 if (*p == ' ' || *p == '\t') /* skip blanks */ 00225 continue; 00226 if (*p == '\'') {/* file name - we trim them */ 00227 char *y; 00228 strcpy(fn2, ast_skip_blanks(p+1)); /* make a full copy */ 00229 y = index(fn2, '\''); 00230 if (!y) { 00231 p = data; /* invalid. prepare to end */ 00232 break; 00233 } 00234 *y = '\0'; 00235 ast_trim_blanks(fn2); 00236 p = index(p+1, '\''); 00237 ret = s_streamwait3(a, fn2); 00238 } else { 00239 int l = fmt-fn; 00240 strcpy(fn2, fn); /* copy everything */ 00241 /* after prefix, append the format */ 00242 fn2[l++] = *p; 00243 strcpy(fn2 + l, data); 00244 ret = do_say(a, fn2, options, depth); 00245 } 00246 00247 if (ret) { 00248 break; 00249 } 00250 } 00251 } 00252 ast_var_delete(n); 00253 return ret; 00254 }
static int load_module | ( | void | ) | [static] |
Definition at line 483 of file app_playback.c.
References ast_cli_register_multiple(), ast_config_load(), ast_register_application(), cli_playback, playback_exec(), and say_cfg.
00484 { 00485 say_cfg = ast_config_load("say.conf"); 00486 ast_cli_register_multiple(cli_playback, sizeof(cli_playback) / sizeof(struct ast_cli_entry)); 00487 return ast_register_application(app, playback_exec, synopsis, descrip); 00488 }
static int playback_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 380 of file app_playback.c.
References ast_channel::_state, ast_answer(), AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_goto_if_exists(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_opt_priority_jumping, AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_stopstream(), ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_waitstream(), ast_module_user::chan, ast_channel::context, LOG_WARNING, pbx_builtin_setvar_helper(), say_full(), strcasestr(), and strsep().
Referenced by load_module().
00381 { 00382 int res = 0; 00383 int mres = 0; 00384 struct ast_module_user *u; 00385 char *tmp; 00386 int option_skip=0; 00387 int option_say=0; 00388 int option_noanswer = 0; 00389 int priority_jump = 0; 00390 00391 AST_DECLARE_APP_ARGS(args, 00392 AST_APP_ARG(filenames); 00393 AST_APP_ARG(options); 00394 ); 00395 00396 if (ast_strlen_zero(data)) { 00397 ast_log(LOG_WARNING, "Playback requires an argument (filename)\n"); 00398 return -1; 00399 } 00400 00401 tmp = ast_strdupa(data); 00402 00403 u = ast_module_user_add(chan); 00404 AST_STANDARD_APP_ARGS(args, tmp); 00405 00406 if (args.options) { 00407 if (strcasestr(args.options, "skip")) 00408 option_skip = 1; 00409 if (strcasestr(args.options, "say")) 00410 option_say = 1; 00411 if (strcasestr(args.options, "noanswer")) 00412 option_noanswer = 1; 00413 if (strchr(args.options, 'j')) 00414 priority_jump = 1; 00415 } 00416 00417 if (chan->_state != AST_STATE_UP) { 00418 if (option_skip) { 00419 /* At the user's option, skip if the line is not up */ 00420 goto done; 00421 } else if (!option_noanswer) 00422 /* Otherwise answer unless we're supposed to send this while on-hook */ 00423 res = ast_answer(chan); 00424 } 00425 if (!res) { 00426 char *back = args.filenames; 00427 char *front; 00428 00429 ast_stopstream(chan); 00430 while (!res && (front = strsep(&back, "&"))) { 00431 if (option_say) 00432 res = say_full(chan, front, "", chan->language, NULL, -1, -1); 00433 else 00434 res = ast_streamfile(chan, front, chan->language); 00435 if (!res) { 00436 res = ast_waitstream(chan, ""); 00437 ast_stopstream(chan); 00438 } else { 00439 ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char *)data); 00440 if (priority_jump || ast_opt_priority_jumping) 00441 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101); 00442 res = 0; 00443 mres = 1; 00444 } 00445 } 00446 } 00447 done: 00448 pbx_builtin_setvar_helper(chan, "PLAYBACKSTATUS", mres ? "FAILED" : "SUCCESS"); 00449 ast_module_user_remove(u); 00450 return res; 00451 }
static int reload | ( | void | ) | [static] |
Definition at line 453 of file app_playback.c.
References ast_config_destroy(), ast_config_load(), ast_log(), LOG_NOTICE, and say_cfg.
00454 { 00455 if (say_cfg) { 00456 ast_config_destroy(say_cfg); 00457 ast_log(LOG_NOTICE, "Reloading say.conf\n"); 00458 } 00459 say_cfg = ast_config_load("say.conf"); 00460 /* 00461 * XXX here we should sort rules according to the same order 00462 * we have in pbx.c so we have the same matching behaviour. 00463 */ 00464 return 0; 00465 }
static void restore_say_mode | ( | void * | arg | ) | [static] |
Definition at line 100 of file app_playback.c.
References ast_say_character_str_full, ast_say_date, ast_say_date_with_format, ast_say_datetime, ast_say_datetime_from_now, ast_say_digit_str_full, ast_say_enumeration_full, ast_say_number_full, ast_say_phonetic_str_full, and ast_say_time.
Referenced by __say_init().
00101 { 00102 int i = 0; 00103 say_api_buf[i++] = arg; 00104 00105 ast_say_number_full = say_api_buf[i++]; 00106 ast_say_enumeration_full = say_api_buf[i++]; 00107 ast_say_digit_str_full = say_api_buf[i++]; 00108 ast_say_character_str_full = say_api_buf[i++]; 00109 ast_say_phonetic_str_full = say_api_buf[i++]; 00110 ast_say_datetime = say_api_buf[i++]; 00111 ast_say_time = say_api_buf[i++]; 00112 ast_say_date = say_api_buf[i++]; 00113 ast_say_datetime_from_now = say_api_buf[i++]; 00114 ast_say_date_with_format = say_api_buf[i++]; 00115 }
static int s_streamwait3 | ( | const say_args_t * | a, | |
const char * | fn | |||
) | [static] |
Definition at line 131 of file app_playback.c.
References ast_log(), ast_stopstream(), ast_streamfile(), ast_waitstream(), ast_waitstream_full(), say_args_t::audiofd, say_args_t::chan, say_args_t::ctrlfd, say_args_t::ints, say_args_t::language, and LOG_WARNING.
00132 { 00133 int res = ast_streamfile(a->chan, fn, a->language); 00134 if (res) { 00135 ast_log(LOG_WARNING, "Unable to play message %s\n", fn); 00136 return res; 00137 } 00138 res = (a->audiofd > -1 && a->ctrlfd > -1) ? 00139 ast_waitstream_full(a->chan, a->ints, a->audiofd, a->ctrlfd) : 00140 ast_waitstream(a->chan, a->ints); 00141 ast_stopstream(a->chan); 00142 return res; 00143 }
static void save_say_mode | ( | const void * | arg | ) | [static] |
Definition at line 83 of file app_playback.c.
References ast_say_character_str_full, ast_say_date, ast_say_date_with_format, ast_say_datetime, ast_say_datetime_from_now, ast_say_digit_str_full, ast_say_enumeration_full, ast_say_number_full, ast_say_phonetic_str_full, and ast_say_time.
Referenced by __say_init().
00084 { 00085 int i = 0; 00086 say_api_buf[i++] = arg; 00087 00088 say_api_buf[i++] = ast_say_number_full; 00089 say_api_buf[i++] = ast_say_enumeration_full; 00090 say_api_buf[i++] = ast_say_digit_str_full; 00091 say_api_buf[i++] = ast_say_character_str_full; 00092 say_api_buf[i++] = ast_say_phonetic_str_full; 00093 say_api_buf[i++] = ast_say_datetime; 00094 say_api_buf[i++] = ast_say_time; 00095 say_api_buf[i++] = ast_say_date; 00096 say_api_buf[i++] = ast_say_datetime_from_now; 00097 say_api_buf[i++] = ast_say_date_with_format; 00098 }
static int say_date | ( | struct ast_channel * | chan, | |
time_t | t, | |||
const char * | ints, | |||
const char * | lang | |||
) | [static] |
Definition at line 314 of file app_playback.c.
References say_date_generic().
00315 { 00316 return say_date_generic(chan, t, ints, lang, "", NULL, "date"); 00317 }
static int say_date_generic | ( | struct ast_channel * | chan, | |
time_t | t, | |||
const char * | ints, | |||
const char * | lang, | |||
const char * | format, | |||
const char * | timezone, | |||
const char * | prefix | |||
) | [static] |
Definition at line 284 of file app_playback.c.
References ast_localtime(), and do_say().
Referenced by say_date(), say_date_with_format(), say_datetime(), and say_time().
00286 { 00287 char buf[128]; 00288 struct tm tm; 00289 say_args_t a = { chan, ints, lang, -1, -1 }; 00290 if (format == NULL) 00291 format = ""; 00292 00293 ast_localtime(&t, &tm, NULL); 00294 snprintf(buf, sizeof(buf), "%s:%s:%04d%02d%02d%02d%02d.%02d-%d-%3d", 00295 prefix, 00296 format, 00297 tm.tm_year+1900, 00298 tm.tm_mon+1, 00299 tm.tm_mday, 00300 tm.tm_hour, 00301 tm.tm_min, 00302 tm.tm_sec, 00303 tm.tm_wday, 00304 tm.tm_yday); 00305 return do_say(&a, buf, NULL, 0); 00306 }
static int say_date_with_format | ( | struct ast_channel * | chan, | |
time_t | t, | |||
const char * | ints, | |||
const char * | lang, | |||
const char * | format, | |||
const char * | timezone | |||
) | [static] |
Definition at line 308 of file app_playback.c.
References say_date_generic().
00310 { 00311 return say_date_generic(chan, t, ints, lang, format, timezone, "datetime"); 00312 }
static int say_datetime | ( | struct ast_channel * | chan, | |
time_t | t, | |||
const char * | ints, | |||
const char * | lang | |||
) | [static] |
Definition at line 324 of file app_playback.c.
References say_date_generic().
00325 { 00326 return say_date_generic(chan, t, ints, lang, "", NULL, "datetime"); 00327 }
static int say_enumeration_full | ( | struct ast_channel * | chan, | |
int | num, | |||
const char * | ints, | |||
const char * | lang, | |||
const char * | options, | |||
int | audiofd, | |||
int | ctrlfd | |||
) | [static] |
Definition at line 274 of file app_playback.c.
References do_say().
00277 { 00278 char buf[64]; 00279 say_args_t a = { chan, ints, lang, audiofd, ctrlfd }; 00280 snprintf(buf, sizeof(buf), "enum:%d", num); 00281 return do_say(&a, buf, options, 0); 00282 }
static int say_full | ( | struct ast_channel * | chan, | |
const char * | string, | |||
const char * | ints, | |||
const char * | lang, | |||
const char * | options, | |||
int | audiofd, | |||
int | ctrlfd | |||
) | [static] |
Definition at line 256 of file app_playback.c.
References do_say().
Referenced by playback_exec().
00259 { 00260 say_args_t a = { chan, ints, lang, audiofd, ctrlfd }; 00261 return do_say(&a, string, options, 0); 00262 }
static int say_number_full | ( | struct ast_channel * | chan, | |
int | num, | |||
const char * | ints, | |||
const char * | lang, | |||
const char * | options, | |||
int | audiofd, | |||
int | ctrlfd | |||
) | [static] |
Definition at line 264 of file app_playback.c.
References do_say().
00267 { 00268 char buf[64]; 00269 say_args_t a = { chan, ints, lang, audiofd, ctrlfd }; 00270 snprintf(buf, sizeof(buf), "num:%d", num); 00271 return do_say(&a, buf, options, 0); 00272 }
static int say_time | ( | struct ast_channel * | chan, | |
time_t | t, | |||
const char * | ints, | |||
const char * | lang | |||
) | [static] |
Definition at line 319 of file app_playback.c.
References say_date_generic().
00320 { 00321 return say_date_generic(chan, t, ints, lang, "", NULL, "time"); 00322 }
static int unload_module | ( | void | ) | [static] |
Definition at line 467 of file app_playback.c.
References ast_cli_unregister_multiple(), ast_config_destroy(), ast_module_user_hangup_all, ast_unregister_application(), cli_playback, and say_cfg.
00468 { 00469 int res; 00470 00471 res = ast_unregister_application(app); 00472 00473 ast_cli_unregister_multiple(cli_playback, sizeof(cli_playback) / sizeof(struct ast_cli_entry)); 00474 00475 ast_module_user_hangup_all(); 00476 00477 if (say_cfg) 00478 ast_config_destroy(say_cfg); 00479 00480 return res; 00481 }
char* app = "Playback" [static] |
Definition at line 50 of file app_playback.c.
struct ast_cli_entry cli_playback[] [static] |
Initial value:
{ { { "say", "load", NULL }, __say_init, "set/show the say mode", "Usage: say load [new|old]\n Set/show the say mode\n" }, }
Definition at line 374 of file app_playback.c.
Referenced by load_module(), and unload_module().
char* descrip [static] |
Definition at line 54 of file app_playback.c.
const void* say_api_buf[40] [static] |
Definition at line 79 of file app_playback.c.
struct ast_config* say_cfg = NULL [static] |
Definition at line 73 of file app_playback.c.
Referenced by __say_init(), do_say(), load_module(), reload(), and unload_module().
const char* say_new = "new" [static] |
Definition at line 81 of file app_playback.c.
const char* say_old = "old" [static] |
Definition at line 80 of file app_playback.c.
Definition at line 52 of file app_playback.c.