Merge "Revert "PJSIP_CONTACT: add missing argument documentation""
[asterisk/asterisk.git] / apps / app_playback.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2005, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief Trivial application to playback a sound file
22  *
23  * \author Mark Spencer <markster@digium.com>
24  *
25  * \ingroup applications
26  */
27
28 /*** MODULEINFO
29         <support_level>core</support_level>
30  ***/
31
32 #include "asterisk.h"
33
34 #include "asterisk/file.h"
35 #include "asterisk/pbx.h"
36 #include "asterisk/module.h"
37 #include "asterisk/app.h"
38 /* This file provides config-file based 'say' functions, and implenents
39  * some CLI commands.
40  */
41 #include "asterisk/say.h"       /*!< provides config-file based 'say' functions */
42 #include "asterisk/cli.h"
43
44 /*** DOCUMENTATION
45         <application name="Playback" language="en_US">
46                 <synopsis>
47                         Play a file.
48                 </synopsis>
49                 <syntax>
50                         <parameter name="filenames" required="true" argsep="&amp;">
51                                 <argument name="filename" required="true" />
52                                 <argument name="filename2" multiple="true" />
53                         </parameter>
54                         <parameter name="options">
55                                 <para>Comma separated list of options</para>
56                                 <optionlist>
57                                         <option name="skip">
58                                                 <para>Do not play if not answered</para>
59                                         </option>
60                                         <option name="noanswer">
61                                                 <para>Playback without answering, otherwise the channel will
62                                                 be answered before the sound is played.</para>
63                                                 <note><para>Not all channel types support playing messages while still on hook.</para></note>
64                                         </option>
65                                 </optionlist>
66                         </parameter>
67                 </syntax>
68                 <description>
69                         <para>Plays back given filenames (do not put extension of wav/alaw etc).
70                         The playback command answer the channel if no options are specified.
71                         If the file is non-existant it will fail</para>
72                         <para>This application sets the following channel variable upon completion:</para>
73                         <variablelist>
74                                 <variable name="PLAYBACKSTATUS">
75                                         <para>The status of the playback attempt as a text string.</para>
76                                         <value name="SUCCESS"/>
77                                         <value name="FAILED"/>
78                                 </variable>
79                         </variablelist>
80                         <para>See Also: Background (application) -- for playing sound files that are interruptible</para>
81                         <para>WaitExten (application) -- wait for digits from caller, optionally play music on hold</para>
82                 </description>
83                 <see-also>
84                         <ref type="application">Background</ref>
85                         <ref type="application">WaitExten</ref>
86                         <ref type="application">ControlPlayback</ref>
87                         <ref type="agi">stream file</ref>
88                         <ref type="agi">control stream file</ref>
89                         <ref type="manager">ControlPlayback</ref>
90                 </see-also>
91         </application>
92  ***/
93
94 static char *app = "Playback";
95
96 static struct ast_config *say_cfg = NULL;
97
98 /*! \brief save the say' api calls.
99  * The first entry is NULL if we have the standard source,
100  * otherwise we are sourcing from here.
101  * 'say load [new|old]' will enable the new or old method, or report status
102  */
103 static const void *say_api_buf[40];
104 static const char * const say_old = "old";
105 static const char * const say_new = "new";
106
107 static void save_say_mode(const void *arg)
108 {
109         int i = 0;
110         say_api_buf[i++] = arg;
111
112         say_api_buf[i++] = ast_say_number_full;
113         say_api_buf[i++] = ast_say_enumeration_full;
114         say_api_buf[i++] = ast_say_digit_str_full;
115         say_api_buf[i++] = ast_say_character_str_full;
116         say_api_buf[i++] = ast_say_phonetic_str_full;
117         say_api_buf[i++] = ast_say_datetime;
118         say_api_buf[i++] = ast_say_time;
119         say_api_buf[i++] = ast_say_date;
120         say_api_buf[i++] = ast_say_datetime_from_now;
121         say_api_buf[i++] = ast_say_date_with_format;
122 }
123
124 static void restore_say_mode(void *arg)
125 {
126         int i = 0;
127         say_api_buf[i++] = arg;
128
129         ast_say_number_full = say_api_buf[i++];
130         ast_say_enumeration_full = say_api_buf[i++];
131         ast_say_digit_str_full = say_api_buf[i++];
132         ast_say_character_str_full = say_api_buf[i++];
133         ast_say_phonetic_str_full = say_api_buf[i++];
134         ast_say_datetime = say_api_buf[i++];
135         ast_say_time = say_api_buf[i++];
136         ast_say_date = say_api_buf[i++];
137         ast_say_datetime_from_now = say_api_buf[i++];
138         ast_say_date_with_format = say_api_buf[i++];
139 }
140
141 /*! \brief
142  * Typical 'say' arguments in addition to the date or number or string
143  * to say. We do not include 'options' because they may be different
144  * in recursive calls, and so they are better left as an external
145  * parameter.
146  */
147 typedef struct {
148         struct ast_channel *chan;
149         const char *ints;
150         const char *language;
151         int audiofd;
152         int ctrlfd;
153 } say_args_t;
154
155 static int s_streamwait3(const say_args_t *a, const char *fn)
156 {
157         int res = ast_streamfile(a->chan, fn, a->language);
158         if (res) {
159                 ast_log(LOG_WARNING, "Unable to play message %s\n", fn);
160                 return res;
161         }
162         res = (a->audiofd  > -1 && a->ctrlfd > -1) ?
163         ast_waitstream_full(a->chan, a->ints, a->audiofd, a->ctrlfd) :
164         ast_waitstream(a->chan, a->ints);
165         ast_stopstream(a->chan);
166         return res;
167 }
168
169 /*! \brief
170  * the string is 'prefix:data' or prefix:fmt:data'
171  * with ':' being invalid in strings.
172  */
173 static int do_say(say_args_t *a, const char *s, const char *options, int depth)
174 {
175         struct ast_variable *v;
176         char *lang;
177         char *x;
178         char *rule = NULL;
179         char *rule_head = NULL;
180         int ret = 0;
181         struct varshead head = { .first = NULL, .last = NULL };
182         struct ast_var_t *n;
183
184         ast_debug(2, "string <%s> depth <%d>\n", s, depth);
185         if (depth++ > 10) {
186                 ast_log(LOG_WARNING, "recursion too deep, exiting\n");
187                 return -1;
188         } else if (!say_cfg) {
189                 ast_log(LOG_WARNING, "no say.conf, cannot spell '%s'\n", s);
190                 return -1;
191         }
192
193         /* scan languages same as in file.c */
194         if (a->language == NULL)
195                 a->language = "en";     /* default */
196         ast_debug(2, "try <%s> in <%s>\n", s, a->language);
197         lang = ast_strdupa(a->language);
198         for (;;) {
199                 for (v = ast_variable_browse(say_cfg, lang); v ; v = v->next) {
200                         if (ast_extension_match(v->name, s)) {
201                                 rule_head = rule = ast_strdup(v->value);
202                                 break;
203                         }
204                 }
205                 if (rule)
206                         break;
207                 if ( (x = strchr(lang, '_')) )
208                         *x = '\0';      /* try without suffix */
209                 else if (strcmp(lang, "en"))
210                         lang = "en";    /* last resort, try 'en' if not done yet */
211                 else
212                         break;
213         }
214         if (!rule)
215                 return 0;
216
217         /* skip up to two prefixes to get the value */
218         if ( (x = strchr(s, ':')) )
219                 s = x + 1;
220         if ( (x = strchr(s, ':')) )
221                 s = x + 1;
222         ast_debug(2, "value is <%s>\n", s);
223         n = ast_var_assign("SAY", s);
224         if (!n) {
225                 ast_log(LOG_ERROR, "Memory allocation error in do_say\n");
226                 ast_free(rule_head);
227                 return -1;
228         }
229         AST_LIST_INSERT_HEAD(&head, n, entries);
230
231         /* scan the body, one piece at a time */
232         while ( !ret && (x = strsep(&rule, ",")) ) { /* exit on key */
233                 char fn[128];
234                 const char *p, *fmt, *data; /* format and data pointers */
235
236                 /* prepare a decent file name */
237                 x = ast_skip_blanks(x);
238                 ast_trim_blanks(x);
239
240                 /* replace variables */
241                 pbx_substitute_variables_varshead(&head, x, fn, sizeof(fn));
242                 ast_debug(2, "doing [%s]\n", fn);
243
244                 /* locate prefix and data, if any */
245                 fmt = strchr(fn, ':');
246                 if (!fmt || fmt == fn)  {       /* regular filename */
247                         ret = s_streamwait3(a, fn);
248                         continue;
249                 }
250                 fmt++;
251                 data = strchr(fmt, ':');        /* colon before data */
252                 if (!data || data == fmt) {     /* simple prefix-fmt */
253                         ret = do_say(a, fn, options, depth);
254                         continue;
255                 }
256                 /* prefix:fmt:data */
257                 for (p = fmt; p < data && ret <= 0; p++) {
258                         char fn2[sizeof(fn)];
259                         if (*p == ' ' || *p == '\t')    /* skip blanks */
260                                 continue;
261                         if (*p == '\'') {/* file name - we trim them */
262                                 char *y;
263                                 strcpy(fn2, ast_skip_blanks(p+1));      /* make a full copy */
264                                 y = strchr(fn2, '\'');
265                                 if (!y) {
266                                         p = data;       /* invalid. prepare to end */
267                                         break;
268                                 }
269                                 *y = '\0';
270                                 ast_trim_blanks(fn2);
271                                 p = strchr(p+1, '\'');
272                                 ret = s_streamwait3(a, fn2);
273                         } else {
274                                 int l = fmt-fn;
275                                 strcpy(fn2, fn); /* copy everything */
276                                 /* after prefix, append the format */
277                                 fn2[l++] = *p;
278                                 strcpy(fn2 + l, data);
279                                 ret = do_say(a, fn2, options, depth);
280                         }
281
282                         if (ret) {
283                                 break;
284                         }
285                 }
286         }
287         ast_var_delete(n);
288         ast_free(rule_head);
289         return ret;
290 }
291
292 static int say_full(struct ast_channel *chan, const char *string,
293         const char *ints, const char *lang, const char *options,
294         int audiofd, int ctrlfd)
295 {
296         say_args_t a = { chan, ints, lang, audiofd, ctrlfd };
297         return do_say(&a, string, options, 0);
298 }
299
300 static int say_number_full(struct ast_channel *chan, int num,
301         const char *ints, const char *lang, const char *options,
302         int audiofd, int ctrlfd)
303 {
304         char buf[64];
305         say_args_t a = { chan, ints, lang, audiofd, ctrlfd };
306         snprintf(buf, sizeof(buf), "num:%d", num);
307         return do_say(&a, buf, options, 0);
308 }
309
310 static int say_enumeration_full(struct ast_channel *chan, int num,
311         const char *ints, const char *lang, const char *options,
312         int audiofd, int ctrlfd)
313 {
314         char buf[64];
315         say_args_t a = { chan, ints, lang, audiofd, ctrlfd };
316         snprintf(buf, sizeof(buf), "enum:%d", num);
317         return do_say(&a, buf, options, 0);
318 }
319
320 static int say_date_generic(struct ast_channel *chan, time_t t,
321         const char *ints, const char *lang, const char *format, const char *timezonename, const char *prefix)
322 {
323         char buf[128];
324         struct ast_tm tm;
325         struct timeval when = { t, 0 };
326         say_args_t a = { chan, ints, lang, -1, -1 };
327         if (format == NULL)
328                 format = "";
329
330         ast_localtime(&when, &tm, timezonename);
331         snprintf(buf, sizeof(buf), "%s:%s:%04d%02d%02d%02d%02d.%02d-%d-%3d",
332                 prefix,
333                 format,
334                 tm.tm_year+1900,
335                 tm.tm_mon+1,
336                 tm.tm_mday,
337                 tm.tm_hour,
338                 tm.tm_min,
339                 tm.tm_sec,
340                 tm.tm_wday,
341                 tm.tm_yday);
342         return do_say(&a, buf, NULL, 0);
343 }
344
345 static int say_date_with_format(struct ast_channel *chan, time_t t,
346         const char *ints, const char *lang, const char *format, const char *timezonename)
347 {
348         return say_date_generic(chan, t, ints, lang, format, timezonename, "datetime");
349 }
350
351 static int say_date(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
352 {
353         return say_date_generic(chan, t, ints, lang, "", NULL, "date");
354 }
355
356 static int say_time(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
357 {
358         return say_date_generic(chan, t, ints, lang, "", NULL, "time");
359 }
360
361 static int say_datetime(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
362 {
363         return say_date_generic(chan, t, ints, lang, "", NULL, "datetime");
364 }
365
366 /*! \brief
367  * remap the 'say' functions to use those in this file
368  */
369 static int say_init_mode(const char *mode) {
370         if (!strcmp(mode, say_new)) {
371                 if (say_cfg == NULL) {
372                         ast_log(LOG_ERROR, "There is no say.conf file to use new mode\n");
373                         return -1;
374                 }
375                 save_say_mode(say_new);
376                 ast_say_number_full = say_number_full;
377
378                 ast_say_enumeration_full = say_enumeration_full;
379 #if 0
380                 /*! \todo XXX
381                    These functions doesn't exist.
382                    say.conf.sample indicates this is working...
383                 */
384                 ast_say_digits_full = say_digits_full;
385                 ast_say_digit_str_full = say_digit_str_full;
386                 ast_say_character_str_full = say_character_str_full;
387                 ast_say_phonetic_str_full = say_phonetic_str_full;
388                 ast_say_datetime_from_now = say_datetime_from_now;
389 #endif
390                 ast_say_datetime = say_datetime;
391                 ast_say_time = say_time;
392                 ast_say_date = say_date;
393                 ast_say_date_with_format = say_date_with_format;
394         } else if (!strcmp(mode, say_old) && say_api_buf[0] == say_new) {
395                 restore_say_mode(NULL);
396         } else if (strcmp(mode, say_old)) {
397                 ast_log(LOG_WARNING, "unrecognized mode %s\n", mode);
398                 return -1;
399         }
400
401         return 0;
402 }
403
404 static char *__say_cli_init(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
405 {
406         const char *old_mode = say_api_buf[0] ? say_new : say_old;
407         const char *mode;
408         switch (cmd) {
409         case CLI_INIT:
410                 e->command = "say load [new|old]";
411                 e->usage =
412                         "Usage: say load [new|old]\n"
413                         "       say load\n"
414                         "           Report status of current say mode\n"
415                         "       say load new\n"
416                         "           Set say method, configured in say.conf\n"
417                         "       say load old\n"
418                         "           Set old say method, coded in asterisk core\n";
419                 return NULL;
420         case CLI_GENERATE:
421                 return NULL;
422         }
423         if (a->argc == 2) {
424                 ast_cli(a->fd, "say mode is [%s]\n", old_mode);
425                 return CLI_SUCCESS;
426         } else if (a->argc != e->args)
427                 return CLI_SHOWUSAGE;
428         mode = a->argv[2];
429         if (!strcmp(mode, old_mode))
430                 ast_cli(a->fd, "say mode is %s already\n", mode);
431         else
432                 if (say_init_mode(mode) == 0)
433                         ast_cli(a->fd, "setting say mode from %s to %s\n", old_mode, mode);
434
435         return CLI_SUCCESS;
436 }
437
438 static struct ast_cli_entry cli_playback[] = {
439         AST_CLI_DEFINE(__say_cli_init, "Set or show the say mode"),
440 };
441
442 static int playback_exec(struct ast_channel *chan, const char *data)
443 {
444         int res = 0;
445         int mres = 0;
446         char *tmp;
447         int option_skip=0;
448         int option_say=0;
449         int option_noanswer = 0;
450
451         AST_DECLARE_APP_ARGS(args,
452                 AST_APP_ARG(filenames);
453                 AST_APP_ARG(options);
454         );
455
456         if (ast_strlen_zero(data)) {
457                 ast_log(LOG_WARNING, "Playback requires an argument (filename)\n");
458                 return -1;
459         }
460
461         tmp = ast_strdupa(data);
462         AST_STANDARD_APP_ARGS(args, tmp);
463
464         if (args.options) {
465                 if (strcasestr(args.options, "skip"))
466                         option_skip = 1;
467                 if (strcasestr(args.options, "say"))
468                         option_say = 1;
469                 if (strcasestr(args.options, "noanswer"))
470                         option_noanswer = 1;
471         }
472         if (ast_channel_state(chan) != AST_STATE_UP) {
473                 if (option_skip) {
474                         /* At the user's option, skip if the line is not up */
475                         goto done;
476                 } else if (!option_noanswer) {
477                         /* Otherwise answer unless we're supposed to send this while on-hook */
478                         res = ast_answer(chan);
479                 }
480         }
481         if (!res) {
482                 char *back = args.filenames;
483                 char *front;
484
485                 ast_stopstream(chan);
486                 while (!res && (front = strsep(&back, "&"))) {
487                         if (option_say)
488                                 res = say_full(chan, front, "", ast_channel_language(chan), NULL, -1, -1);
489                         else
490                                 res = ast_streamfile(chan, front, ast_channel_language(chan));
491                         if (!res) {
492                                 res = ast_waitstream(chan, "");
493                                 ast_stopstream(chan);
494                         }
495                         if (res) {
496                                 if (!ast_check_hangup(chan)) {
497                                         ast_log(LOG_WARNING, "Playback failed on %s for %s\n", ast_channel_name(chan), (char *)data);
498                                 }
499                                 res = 0;
500                                 mres = 1;
501                         }
502                 }
503         }
504 done:
505         pbx_builtin_setvar_helper(chan, "PLAYBACKSTATUS", mres ? "FAILED" : "SUCCESS");
506         return res;
507 }
508
509 static int reload(void)
510 {
511         struct ast_variable *v;
512         struct ast_flags config_flags = { CONFIG_FLAG_FILEUNCHANGED };
513         struct ast_config *newcfg;
514
515         if ((newcfg = ast_config_load("say.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
516                 return 0;
517         } else if (newcfg == CONFIG_STATUS_FILEINVALID) {
518                 ast_log(LOG_ERROR, "Config file say.conf is in an invalid format.  Aborting.\n");
519                 return 0;
520         }
521
522         if (say_cfg) {
523                 ast_config_destroy(say_cfg);
524                 ast_log(LOG_NOTICE, "Reloading say.conf\n");
525         }
526         say_cfg = newcfg;
527
528         if (say_cfg) {
529                 for (v = ast_variable_browse(say_cfg, "general"); v ; v = v->next) {
530                         if (ast_extension_match(v->name, "mode")) {
531                                 say_init_mode(v->value);
532                                 break;
533                         }
534                 }
535         }
536
537         /*! \todo
538          * XXX here we should sort rules according to the same order
539          * we have in pbx.c so we have the same matching behaviour.
540          */
541         return 0;
542 }
543
544 static int unload_module(void)
545 {
546         int res;
547
548         res = ast_unregister_application(app);
549
550         ast_cli_unregister_multiple(cli_playback, ARRAY_LEN(cli_playback));
551
552         if (say_cfg)
553                 ast_config_destroy(say_cfg);
554
555         return res;
556 }
557
558 static int load_module(void)
559 {
560         struct ast_variable *v;
561         struct ast_flags config_flags = { 0 };
562
563         say_cfg = ast_config_load("say.conf", config_flags);
564         if (say_cfg && say_cfg != CONFIG_STATUS_FILEINVALID) {
565                 for (v = ast_variable_browse(say_cfg, "general"); v ; v = v->next) {
566                         if (ast_extension_match(v->name, "mode")) {
567                                 say_init_mode(v->value);
568                                 break;
569                         }
570                 }
571         }
572
573         ast_cli_register_multiple(cli_playback, ARRAY_LEN(cli_playback));
574         return ast_register_application_xml(app, playback_exec);
575 }
576
577 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Sound File Playback Application",
578         .support_level = AST_MODULE_SUPPORT_CORE,
579         .load = load_module,
580         .unload = unload_module,
581         .reload = reload,
582 );