Asterisk - The Open Source Telephony Project  21.4.1
func_sayfiles.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2021, Naveen Albert <asterisk@phreaknet.org>
5  *
6  * See http://www.asterisk.org for more information about
7  * the Asterisk project. Please do not directly contact
8  * any of the maintainers of this project for assistance;
9  * the project provides a web site, mailing lists and IRC
10  * channels for your use.
11  *
12  * This program is free software, distributed under the terms of
13  * the GNU General Public License Version 2. See the LICENSE file
14  * at the top of the source tree.
15  */
16 
17 /*! \file
18  *
19  * \brief Returns files played by Say applications
20  *
21  * \author Naveen Albert <asterisk@phreaknet.org>
22  * \ingroup functions
23  */
24 
25 /*** MODULEINFO
26  <support_level>extended</support_level>
27  ***/
28 
29 #include "asterisk.h"
30 
31 #include "asterisk/pbx.h"
32 #include "asterisk/file.h"
33 #include "asterisk/channel.h"
34 #include "asterisk/say.h"
35 #include "asterisk/lock.h"
36 #include "asterisk/localtime.h"
37 #include "asterisk/utils.h"
38 #include "asterisk/app.h"
39 #include "asterisk/test.h"
40 #include "asterisk/module.h"
41 #include "asterisk/conversions.h"
42 
43 /*** DOCUMENTATION
44  <function name="SAYFILES" language="en_US">
45  <since>
46  <version>16.21.0</version>
47  <version>18.7.0</version>
48  <version>19.0.0</version>
49  </since>
50  <synopsis>
51  Returns the ampersand-delimited file names that would be played by the Say applications (e.g. SayAlpha, SayDigits).
52  </synopsis>
53  <syntax>
54  <parameter name="value" required="true">
55  <para>The value to be translated to filenames.</para>
56  </parameter>
57  <parameter name="type">
58  <para>Say application type.</para>
59  <enumlist>
60  <enum name="alpha">
61  <para>Files played by SayAlpha(). Default if none is specified.</para>
62  </enum>
63  <enum name="digits">
64  <para>Files played by SayDigits().</para>
65  </enum>
66  <enum name="money">
67  <para>Files played by SayMoney(). Currently supported for English and US dollars only.</para>
68  </enum>
69  <enum name="number">
70  <para>Files played by SayNumber(). Currently supported for English only.</para>
71  </enum>
72  <enum name="ordinal">
73  <para>Files played by SayOrdinal(). Currently supported for English only.</para>
74  </enum>
75  <enum name="phonetic">
76  <para>Files played by SayPhonetic().</para>
77  </enum>
78  </enumlist>
79  </parameter>
80  </syntax>
81  <description>
82  <para>Returns the files that would be played by a Say application. These filenames could then be
83  passed directly into Playback, BackGround, Read, Queue, or any application which supports
84  playback of multiple ampersand-delimited files.</para>
85  <example title="Read using the number 123">
86  same => n,Read(response,${SAYFILES(123,number)})
87  </example>
88  </description>
89  <see-also>
90  <ref type="application">SayAlpha</ref>
91  <ref type="application">SayDigits</ref>
92  <ref type="application">SayMoney</ref>
93  <ref type="application">SayNumber</ref>
94  <ref type="application">SayOrdinal</ref>
95  <ref type="application">SayPhonetic</ref>
96  </see-also>
97  </function>
98  ***/
99 static int sayfile_exec(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
100 {
101  char *value, *type, *files;
102  const char *lang;
103  struct ast_str *filenames = NULL;
105  AST_APP_ARG(value);
106  AST_APP_ARG(type);
107  );
108 
109  if (ast_strlen_zero(data)) {
110  ast_log(LOG_WARNING, "SAYFILES requires an argument\n");
111  return 0;
112  }
113 
114  AST_STANDARD_APP_ARGS(args, data);
115 
116  value = args.value;
117  type = (ast_strlen_zero(args.type) ? "alpha" : args.type);
118  lang = (chan ? ast_channel_language(chan) : "en"); /* No chan for unit tests */
119 
120  if (!strcmp(type, "alpha")) {
121  filenames = ast_get_character_str(value, lang, AST_SAY_CASE_NONE);
122  } else if (!strcmp(type, "phonetic")) {
123  filenames = ast_get_phonetic_str(value, lang);
124  } else if (!strcmp(type, "digits")) {
125  filenames = ast_get_digit_str(value, lang);
126  } else if (!strcmp(type, "number")) {
127  int num;
128  if (ast_str_to_int(value, &num)) {
129  ast_log(LOG_WARNING, "Invalid numeric argument: %s\n", value);
130  } else {
131  filenames = ast_get_number_str(num, lang);
132  }
133  } else if (!strcmp(type, "ordinal")) {
134  int num;
135  if (ast_str_to_int(value, &num)) {
136  ast_log(LOG_WARNING, "Invalid numeric argument: %s\n", value);
137  } else {
138  filenames = ast_get_ordinal_str(num, lang);
139  }
140  } else if (!strcmp(type, "money")) {
141  filenames = ast_get_money_str(value, lang);
142  } else {
143  ast_log(LOG_WARNING, "Invalid say type specified: %s\n", type);
144  }
145 
146  if (!filenames) {
147  return -1;
148  }
149 
150  files = ast_str_buffer(filenames);
151  snprintf(buf, len, "%s", files);
152  ast_free(filenames);
153 
154  return 0;
155 }
156 
157 static struct ast_custom_function sayfiles = {
158  .name = "SAYFILES",
159  .read = sayfile_exec,
160 };
161 
162 #ifdef TEST_FRAMEWORK
163 AST_TEST_DEFINE(test_SAYFILES_function)
164 {
165  enum ast_test_result_state res = AST_TEST_PASS;
166  struct ast_str *expr, *result;
167 
168  switch (cmd) {
169  case TEST_INIT:
170  info->name = "test_SAYFILES_function";
171  info->category = "/funcs/func_sayfiles/";
172  info->summary = "Test SAYFILES function substitution";
173  info->description =
174  "Executes a series of variable substitutions using the SAYFILES function and ensures that the expected results are received.";
175  return AST_TEST_NOT_RUN;
176  case TEST_EXECUTE:
177  break;
178  }
179 
180  ast_test_status_update(test, "Testing SAYFILES() substitution ...\n");
181 
182  if (!(expr = ast_str_create(16))) {
183  return AST_TEST_FAIL;
184  }
185  if (!(result = ast_str_create(16))) {
186  ast_free(expr);
187  return AST_TEST_FAIL;
188  }
189 
190  ast_str_set(&expr, 0, "${SAYFILES(hi Th3re,alpha)}");
191  ast_str_substitute_variables(&result, 0, NULL, ast_str_buffer(expr));
192  if (strcmp(ast_str_buffer(result), "letters/h&letters/i&letters/space&letters/t&letters/h&digits/3&letters/r&letters/e") != 0) {
193  ast_test_status_update(test, "SAYFILES(hi Th3re,alpha) test failed ('%s')\n",
194  ast_str_buffer(result));
195  res = AST_TEST_FAIL;
196  }
197 
198  ast_str_set(&expr, 0, "${SAYFILES(phreak,phonetic)}");
199  ast_str_substitute_variables(&result, 0, NULL, ast_str_buffer(expr));
200  if (strcmp(ast_str_buffer(result), "phonetic/p_p&phonetic/h_p&phonetic/r_p&phonetic/e_p&phonetic/a_p&phonetic/k_p") != 0) {
201  ast_test_status_update(test, "SAYFILES(phreak,phonetic) test failed ('%s')\n",
202  ast_str_buffer(result));
203  res = AST_TEST_FAIL;
204  }
205 
206  ast_str_set(&expr, 0, "${SAYFILES(35,digits)}");
207  ast_str_substitute_variables(&result, 0, NULL, ast_str_buffer(expr));
208  if (strcmp(ast_str_buffer(result), "digits/3&digits/5") != 0) {
209  ast_test_status_update(test, "SAYFILES(35,digits) test failed ('%s')\n",
210  ast_str_buffer(result));
211  res = AST_TEST_FAIL;
212  }
213 
214  /* + should be ignored and there should not be a leading & */
215  ast_str_set(&expr, 0, "${SAYFILES(+18005551212,digits)}");
216  ast_str_substitute_variables(&result, 0, NULL, ast_str_buffer(expr));
217  if (strcmp(ast_str_buffer(result), "digits/1&digits/8&digits/0&digits/0&digits/5&digits/5&digits/5&digits/1&digits/2&digits/1&digits/2") != 0) {
218  ast_test_status_update(test, "SAYFILES(+18005551212,digits) test failed ('%s')\n",
219  ast_str_buffer(result));
220  res = AST_TEST_FAIL;
221  }
222 
223  ast_str_set(&expr, 0, "${SAYFILES(35,number)}");
224  ast_str_substitute_variables(&result, 0, NULL, ast_str_buffer(expr));
225  if (strcmp(ast_str_buffer(result), "digits/30&digits/5") != 0) {
226  ast_test_status_update(test, "SAYFILES(35,number) test failed ('%s')\n",
227  ast_str_buffer(result));
228  res = AST_TEST_FAIL;
229  }
230 
231  ast_str_set(&expr, 0, "${SAYFILES(747,number)}");
232  ast_str_substitute_variables(&result, 0, NULL, ast_str_buffer(expr));
233  if (strcmp(ast_str_buffer(result), "digits/7&digits/hundred&digits/40&digits/7") != 0) {
234  ast_test_status_update(test, "SAYFILES(747,number) test failed ('%s')\n",
235  ast_str_buffer(result));
236  res = AST_TEST_FAIL;
237  }
238 
239  ast_str_set(&expr, 0, "${SAYFILES(1042,number)}");
240  ast_str_substitute_variables(&result, 0, NULL, ast_str_buffer(expr));
241  if (strcmp(ast_str_buffer(result), "digits/1&digits/thousand&digits/40&digits/2") != 0) {
242  ast_test_status_update(test, "SAYFILES(1042,number) test failed ('%s')\n",
243  ast_str_buffer(result));
244  res = AST_TEST_FAIL;
245  }
246 
247  ast_str_set(&expr, 0, "${SAYFILES(0,number)}");
248  ast_str_substitute_variables(&result, 0, NULL, ast_str_buffer(expr));
249  if (strcmp(ast_str_buffer(result), "digits/0") != 0) {
250  ast_test_status_update(test, "SAYFILES(0,digits) test failed ('%s')\n",
251  ast_str_buffer(result));
252  res = AST_TEST_FAIL;
253  }
254 
255  ast_str_set(&expr, 0, "${SAYFILES(2001000001,number)}");
256  ast_str_substitute_variables(&result, 0, NULL, ast_str_buffer(expr));
257  if (strcmp(ast_str_buffer(result), "digits/2&digits/billion&digits/1&digits/million&digits/1") != 0) {
258  ast_test_status_update(test, "SAYFILES(2001000001,number) test failed ('%s')\n",
259  ast_str_buffer(result));
260  res = AST_TEST_FAIL;
261  }
262 
263  ast_str_set(&expr, 0, "${SAYFILES(7,ordinal)}");
264  ast_str_substitute_variables(&result, 0, NULL, ast_str_buffer(expr));
265  if (strcmp(ast_str_buffer(result), "digits/h-7") != 0) {
266  ast_test_status_update(test, "SAYFILES(7,ordinal) test failed ('%s')\n",
267  ast_str_buffer(result));
268  res = AST_TEST_FAIL;
269  }
270 
271  ast_str_set(&expr, 0, "${SAYFILES(35,ordinal)}");
272  ast_str_substitute_variables(&result, 0, NULL, ast_str_buffer(expr));
273  if (strcmp(ast_str_buffer(result), "digits/30&digits/h-5") != 0) {
274  ast_test_status_update(test, "SAYFILES(35,ordinal) test failed ('%s')\n",
275  ast_str_buffer(result));
276  res = AST_TEST_FAIL;
277  }
278 
279  ast_str_set(&expr, 0, "${SAYFILES(1042,ordinal)}");
280  ast_str_substitute_variables(&result, 0, NULL, ast_str_buffer(expr));
281  if (strcmp(ast_str_buffer(result), "digits/1&digits/thousand&digits/40&digits/h-2") != 0) {
282  ast_test_status_update(test, "SAYFILES(1042,ordinal) test failed ('%s')\n",
283  ast_str_buffer(result));
284  res = AST_TEST_FAIL;
285  }
286 
287  ast_str_set(&expr, 0, "${SAYFILES(11042,ordinal)}");
288  ast_str_substitute_variables(&result, 0, NULL, ast_str_buffer(expr));
289  if (strcmp(ast_str_buffer(result), "digits/11&digits/thousand&digits/40&digits/h-2") != 0) {
290  ast_test_status_update(test, "SAYFILES(11042,ordinal) test failed ('%s')\n",
291  ast_str_buffer(result));
292  res = AST_TEST_FAIL;
293  }
294 
295  ast_str_set(&expr, 0, "${SAYFILES(40000,ordinal)}");
296  ast_str_substitute_variables(&result, 0, NULL, ast_str_buffer(expr));
297  if (strcmp(ast_str_buffer(result), "digits/40&digits/h-thousand") != 0) {
298  ast_test_status_update(test, "SAYFILES(40000,ordinal) test failed ('%s')\n",
299  ast_str_buffer(result));
300  res = AST_TEST_FAIL;
301  }
302 
303  ast_str_set(&expr, 0, "${SAYFILES(43638,ordinal)}");
304  ast_str_substitute_variables(&result, 0, NULL, ast_str_buffer(expr));
305  if (strcmp(ast_str_buffer(result), "digits/40&digits/3&digits/thousand&digits/6&digits/hundred&digits/30&digits/h-8") != 0) {
306  ast_test_status_update(test, "SAYFILES(43638,ordinal) test failed ('%s')\n",
307  ast_str_buffer(result));
308  res = AST_TEST_FAIL;
309  }
310 
311  ast_str_set(&expr, 0, "${SAYFILES(1000000,ordinal)}");
312  ast_str_substitute_variables(&result, 0, NULL, ast_str_buffer(expr));
313  if (strcmp(ast_str_buffer(result), "digits/1&digits/h-million") != 0) {
314  ast_test_status_update(test, "SAYFILES(1000000,ordinal) test failed ('%s')\n",
315  ast_str_buffer(result));
316  res = AST_TEST_FAIL;
317  }
318 
319  ast_str_set(&expr, 0, "${SAYFILES(1000001,ordinal)}");
320  ast_str_substitute_variables(&result, 0, NULL, ast_str_buffer(expr));
321  if (strcmp(ast_str_buffer(result), "digits/1&digits/million&digits/h-1") != 0) {
322  ast_test_status_update(test, "SAYFILES(1000001,ordinal) test failed ('%s')\n",
323  ast_str_buffer(result));
324  res = AST_TEST_FAIL;
325  }
326 
327  ast_str_set(&expr, 0, "${SAYFILES(2001000001,ordinal)}");
328  ast_str_substitute_variables(&result, 0, NULL, ast_str_buffer(expr));
329  if (strcmp(ast_str_buffer(result), "digits/2&digits/billion&digits/1&digits/million&digits/h-1") != 0) {
330  ast_test_status_update(test, "SAYFILES(2001000001,ordinal) test failed ('%s')\n",
331  ast_str_buffer(result));
332  res = AST_TEST_FAIL;
333  }
334 
335  ast_str_set(&expr, 0, "${SAYFILES(0,money)}");
336  ast_str_substitute_variables(&result, 0, NULL, ast_str_buffer(expr));
337  if (strcmp(ast_str_buffer(result), "digits/0&cents") != 0) {
338  ast_test_status_update(test, "SAYFILES(0,money) test failed ('%s')\n",
339  ast_str_buffer(result));
340  res = AST_TEST_FAIL;
341  }
342 
343  ast_str_set(&expr, 0, "${SAYFILES(0.01,money)}");
344  ast_str_substitute_variables(&result, 0, NULL, ast_str_buffer(expr));
345  if (strcmp(ast_str_buffer(result), "digits/1&cent") != 0) {
346  ast_test_status_update(test, "SAYFILES(0.01,money) test failed ('%s')\n",
347  ast_str_buffer(result));
348  res = AST_TEST_FAIL;
349  }
350 
351  ast_str_set(&expr, 0, "${SAYFILES(0.42,money)}");
352  ast_str_substitute_variables(&result, 0, NULL, ast_str_buffer(expr));
353  if (strcmp(ast_str_buffer(result), "digits/40&digits/2&cents") != 0) {
354  ast_test_status_update(test, "SAYFILES(0.42,money) test failed ('%s')\n",
355  ast_str_buffer(result));
356  res = AST_TEST_FAIL;
357  }
358 
359  ast_str_set(&expr, 0, "${SAYFILES(.42,money)}");
360  ast_str_substitute_variables(&result, 0, NULL, ast_str_buffer(expr));
361  if (strcmp(ast_str_buffer(result), "digits/40&digits/2&cents") != 0) {
362  ast_test_status_update(test, "SAYFILES(.42,money) test failed ('%s')\n",
363  ast_str_buffer(result));
364  res = AST_TEST_FAIL;
365  }
366 
367  ast_str_set(&expr, 0, "${SAYFILES(1.00,money)}");
368  ast_str_substitute_variables(&result, 0, NULL, ast_str_buffer(expr));
369  if (strcmp(ast_str_buffer(result), "digits/1&letters/dollar") != 0) {
370  ast_test_status_update(test, "SAYFILES(1.00,money) test failed ('%s')\n",
371  ast_str_buffer(result));
372  res = AST_TEST_FAIL;
373  }
374 
375  ast_str_set(&expr, 0, "${SAYFILES(1.42,money)}");
376  ast_str_substitute_variables(&result, 0, NULL, ast_str_buffer(expr));
377  if (strcmp(ast_str_buffer(result), "digits/1&letters/dollar_&and&digits/40&digits/2&cents") != 0) {
378  ast_test_status_update(test, "SAYFILES(1.42,money) test failed ('%s')\n",
379  ast_str_buffer(result));
380  res = AST_TEST_FAIL;
381  }
382 
383  ast_str_set(&expr, 0, "${SAYFILES(2.00,money)}");
384  ast_str_substitute_variables(&result, 0, NULL, ast_str_buffer(expr));
385  if (strcmp(ast_str_buffer(result), "digits/2&dollars") != 0) {
386  ast_test_status_update(test, "SAYFILES(2.00,money) test failed ('%s')\n",
387  ast_str_buffer(result));
388  res = AST_TEST_FAIL;
389  }
390 
391  ast_str_set(&expr, 0, "${SAYFILES(2,money)}");
392  ast_str_substitute_variables(&result, 0, NULL, ast_str_buffer(expr));
393  if (strcmp(ast_str_buffer(result), "digits/2&dollars") != 0) {
394  ast_test_status_update(test, "SAYFILES(2,money) test failed ('%s')\n",
395  ast_str_buffer(result));
396  res = AST_TEST_FAIL;
397  }
398 
399  ast_str_set(&expr, 0, "${SAYFILES(2.42,money)}");
400  ast_str_substitute_variables(&result, 0, NULL, ast_str_buffer(expr));
401  if (strcmp(ast_str_buffer(result), "digits/2&dollars&and&digits/40&digits/2&cents") != 0) {
402  ast_test_status_update(test, "SAYFILES(2.42,money) test failed ('%s')\n",
403  ast_str_buffer(result));
404  res = AST_TEST_FAIL;
405  }
406 
407  ast_str_set(&expr, 0, "${SAYFILES(2.05,money)}");
408  ast_str_substitute_variables(&result, 0, NULL, ast_str_buffer(expr));
409  if (strcmp(ast_str_buffer(result), "digits/2&dollars&and&digits/5&cents") != 0) {
410  ast_test_status_update(test, "SAYFILES(2.05,money) test failed ('%s')\n",
411  ast_str_buffer(result));
412  res = AST_TEST_FAIL;
413  }
414 
415  ast_str_set(&expr, 0, "${SAYFILES(2.051,money)}");
416  ast_str_substitute_variables(&result, 0, NULL, ast_str_buffer(expr));
417  if (strcmp(ast_str_buffer(result), "digits/2&dollars&and&digits/5&cents") != 0) {
418  ast_test_status_update(test, "SAYFILES(2.051,money) test failed ('%s')\n",
419  ast_str_buffer(result));
420  res = AST_TEST_FAIL;
421  }
422 
423  /* Invalid amounts */
424  ast_str_set(&expr, 0, "${SAYFILES(blah,money)}");
425  ast_str_substitute_variables(&result, 0, NULL, ast_str_buffer(expr));
426  if (strcmp(ast_str_buffer(result), "digits/0&cents") != 0) {
427  ast_test_status_update(test, "SAYFILES(blah,money) test failed ('%s')\n",
428  ast_str_buffer(result));
429  res = AST_TEST_FAIL;
430  }
431 
432  ast_str_set(&expr, 0, "${SAYFILES(2blah.05,money)}");
433  ast_str_substitute_variables(&result, 0, NULL, ast_str_buffer(expr));
434  if (strcmp(ast_str_buffer(result), "digits/2&dollars") != 0) {
435  ast_test_status_update(test, "SAYFILES(2blah.05,money) test failed ('%s')\n",
436  ast_str_buffer(result));
437  res = AST_TEST_FAIL;
438  }
439 
440  ast_str_set(&expr, 0, "${SAYFILES(2.-05,money)}");
441  ast_str_substitute_variables(&result, 0, NULL, ast_str_buffer(expr));
442  if (strcmp(ast_str_buffer(result), "digits/2&dollars") != 0) {
443  ast_test_status_update(test, "SAYFILES(2.-05,money) test failed ('%s')\n",
444  ast_str_buffer(result));
445  res = AST_TEST_FAIL;
446  }
447 
448  ast_str_set(&expr, 0, "${SAYFILES(2. 05,money)}");
449  ast_str_substitute_variables(&result, 0, NULL, ast_str_buffer(expr));
450  if (strcmp(ast_str_buffer(result), "digits/2&dollars") != 0) {
451  ast_test_status_update(test, "SAYFILES(2. 05,money) test failed ('%s')\n",
452  ast_str_buffer(result));
453  res = AST_TEST_FAIL;
454  }
455 
456  ast_str_set(&expr, 0, "${SAYFILES(. 05,money)}");
457  ast_str_substitute_variables(&result, 0, NULL, ast_str_buffer(expr));
458  if (strcmp(ast_str_buffer(result), "digits/0&cents") != 0) {
459  ast_test_status_update(test, "SAYFILES(. 05,money) test failed ('%s')\n",
460  ast_str_buffer(result));
461  res = AST_TEST_FAIL;
462  }
463 
464  ast_free(expr);
465  ast_free(result);
466 
467  return res;
468 }
469 #endif
470 
471 static int unload_module(void)
472 {
473  AST_TEST_UNREGISTER(test_SAYFILES_function);
474  return ast_custom_function_unregister(&sayfiles);
475 }
476 
477 static int load_module(void)
478 {
479  AST_TEST_REGISTER(test_SAYFILES_function);
480  return ast_custom_function_register(&sayfiles);
481 }
482 
483 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Say application files");
const char * name
Definition: pbx.h:119
Main Channel structure associated with a channel.
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
struct ast_str * ast_get_ordinal_str(int num, const char *lang)
Returns an ast_str of files for SayOrdinal playback.
Definition: say.c:686
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
struct ast_str * ast_get_number_str(int num, const char *lang)
Returns an ast_str of files for SayNumber playback.
Definition: say.c:566
void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
Test Framework API.
struct ast_str * ast_get_phonetic_str(const char *str, const char *lang)
Returns an ast_str of files for SayPhonetic playback.
Definition: say.c:216
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
Utility functions.
struct ast_str * ast_get_money_str(const char *str, const char *lang)
Returns an ast_str of files for SayMoney playback.
Definition: say.c:449
Custom localtime functions for multiple timezones.
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1113
General Asterisk PBX channel definitions.
struct ast_str * ast_get_digit_str(const char *str, const char *lang)
Returns an ast_str of files for SayDigits playback.
Definition: say.c:300
Data structure associated with a custom dialplan function.
Definition: pbx.h:118
Conversion utility functions.
Core PBX routines and definitions.
int ast_str_to_int(const char *str, int *res)
Convert the given string to a signed integer.
Definition: conversions.c:44
Support for dynamic strings.
Definition: strings.h:623
struct ast_str * ast_get_character_str(const char *str, const char *lang, enum ast_say_case_sensitivity sensitivity)
Returns an ast_str of files for SayAlpha playback.
Definition: say.c:64
#define AST_TEST_DEFINE(hdr)
Definition: test.h:126
Say numbers and dates (maybe words one day too)
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
Asterisk module definitions.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1558
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
#define AST_APP_ARG(name)
Define an application argument.