Asterisk - The Open Source Telephony Project  GIT-master-8beac82
main/app.c
Go to the documentation of this file.
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 Convenient Application Routines
22  *
23  * \author Mark Spencer <markster@digium.com>
24  */
25 
26 /** \example
27  * \par This is an example of how to develop an app.
28  * Application Skeleton is an example of creating an application for Asterisk.
29  * \verbinclude app_skel.c
30  */
31 
32 /*** MODULEINFO
33  <support_level>core</support_level>
34  ***/
35 
36 #include "asterisk.h"
37 
38 #ifdef HAVE_SYS_STAT_H
39 #include <sys/stat.h>
40 #endif
41 #include <regex.h> /* for regcomp(3) */
42 #include <sys/file.h> /* for flock(2) */
43 #include <signal.h> /* for pthread_sigmask(3) */
44 #include <stdlib.h> /* for closefrom(3) */
45 #include <sys/types.h>
46 #include <sys/wait.h> /* for waitpid(2) */
47 #ifndef HAVE_CLOSEFROM
48 #include <dirent.h> /* for opendir(3) */
49 #endif
50 #ifdef HAVE_CAP
51 #include <sys/capability.h>
52 #endif /* HAVE_CAP */
53 
54 #include "asterisk/paths.h" /* use ast_config_AST_DATA_DIR */
55 #include "asterisk/channel.h"
56 #include "asterisk/pbx.h"
57 #include "asterisk/file.h"
58 #include "asterisk/app.h"
59 #include "asterisk/dsp.h"
60 #include "asterisk/utils.h"
61 #include "asterisk/lock.h"
62 #include "asterisk/indications.h"
63 #include "asterisk/linkedlists.h"
64 #include "asterisk/threadstorage.h"
65 #include "asterisk/test.h"
66 #include "asterisk/module.h"
67 #include "asterisk/astobj2.h"
68 #include "asterisk/stasis.h"
70 #include "asterisk/json.h"
71 #include "asterisk/format_cache.h"
72 
73 AST_THREADSTORAGE_PUBLIC(ast_str_thread_global_buf);
74 
76 
77 struct zombie {
78  pid_t pid;
80 };
81 
83 
84 #ifdef HAVE_CAP
85 static cap_t child_cap;
86 #endif
87 /*
88  * @{ \brief Define \ref stasis topic objects
89  */
92 /* @} */
93 
94 static void *shaun_of_the_dead(void *data)
95 {
96  struct zombie *cur;
97  int status;
98  for (;;) {
99  if (!AST_LIST_EMPTY(&zombies)) {
100  /* Don't allow cancellation while we have a lock. */
101  pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
104  if (waitpid(cur->pid, &status, WNOHANG) != 0) {
106  ast_free(cur);
107  }
108  }
111  pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
112  }
113  pthread_testcancel();
114  /* Wait for 60 seconds, without engaging in a busy loop. */
115  ast_poll(NULL, 0, AST_LIST_FIRST(&zombies) ? 5000 : 60000);
116  }
117  return NULL;
118 }
119 
120 
121 #define AST_MAX_FORMATS 10
122 
124 
125 /*!
126  * \brief This function presents a dialtone and reads an extension into 'collect'
127  * which must be a pointer to a **pre-initialized** array of char having a
128  * size of 'size' suitable for writing to. It will collect no more than the smaller
129  * of 'maxlen' or 'size' minus the original strlen() of collect digits.
130  * \param chan struct.
131  * \param context
132  * \param collect
133  * \param size
134  * \param maxlen
135  * \param timeout timeout in milliseconds
136  *
137  * \return 0 if extension does not exist, 1 if extension exists
138 */
139 int ast_app_dtget(struct ast_channel *chan, const char *context, char *collect, size_t size, int maxlen, int timeout)
140 {
141  struct ast_tone_zone_sound *ts;
142  int res = 0, x = 0;
143 
144  if (maxlen > size) {
145  maxlen = size;
146  }
147 
148  if (!timeout) {
149  if (ast_channel_pbx(chan) && ast_channel_pbx(chan)->dtimeoutms) {
150  timeout = ast_channel_pbx(chan)->dtimeoutms;
151  } else {
152  timeout = 5000;
153  }
154  }
155 
156  if ((ts = ast_get_indication_tone(ast_channel_zone(chan), "dial"))) {
157  res = ast_playtones_start(chan, 0, ts->data, 0);
158  ts = ast_tone_zone_sound_unref(ts);
159  } else {
160  ast_log(LOG_NOTICE, "Huh....? no dial for indications?\n");
161  }
162 
163  for (x = strlen(collect); x < maxlen; ) {
164  res = ast_waitfordigit(chan, timeout);
165  if (!ast_ignore_pattern(context, collect)) {
166  ast_playtones_stop(chan);
167  }
168  if (res < 1) {
169  break;
170  }
171  if (res == '#') {
172  break;
173  }
174  collect[x++] = res;
175  if (!ast_matchmore_extension(chan, context, collect, 1,
176  S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
177  break;
178  }
179  }
180 
181  if (res >= 0) {
182  res = ast_exists_extension(chan, context, collect, 1,
183  S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL)) ? 1 : 0;
184  }
185 
186  return res;
187 }
188 
189 /*!
190  * \brief ast_app_getdata
191  * \param c The channel to read from
192  * \param prompt The file to stream to the channel
193  * \param s The string to read in to. Must be at least the size of your length
194  * \param maxlen How many digits to read (maximum)
195  * \param timeout set timeout to 0 for "standard" timeouts. Set timeout to -1 for
196  * "ludicrous time" (essentially never times out)
197  */
198 enum ast_getdata_result ast_app_getdata(struct ast_channel *c, const char *prompt, char *s, int maxlen, int timeout)
199 {
200  return ast_app_getdata_terminator(c, prompt, s, maxlen, timeout, NULL);
201 }
202 
203 /*!
204  * \brief ast_app_getdata
205  * \param c The channel to read from
206  * \param prompt The file to stream to the channel
207  * \param s The string to read in to. Must be at least the size of your length
208  * \param maxlen How many digits to read (maximum)
209  * \param timeout set timeout to 0 for "standard" timeouts. Set timeout to -1 for
210  * "ludicrous time" (essentially never times out)
211  * \param terminator A string of characters that may be used as terminators to end input. Default if NULL is "#"
212  */
214  int maxlen, int timeout, char *terminator)
215 {
216  int res = 0, to, fto;
217  char *front, *filename;
218 
219  /* XXX Merge with full version? XXX */
220 
221  if (maxlen)
222  s[0] = '\0';
223 
224  if (!prompt)
225  prompt = "";
226 
227  filename = ast_strdupa(prompt);
228  while ((front = strsep(&filename, "&"))) {
229  if (!ast_strlen_zero(front)) {
230  res = ast_streamfile(c, front, ast_channel_language(c));
231  if (res)
232  continue;
233  }
234  if (ast_strlen_zero(filename)) {
235  /* set timeouts for the last prompt */
236  fto = ast_channel_pbx(c) ? ast_channel_pbx(c)->rtimeoutms : 6000;
237  to = ast_channel_pbx(c) ? ast_channel_pbx(c)->dtimeoutms : 2000;
238 
239  if (timeout > 0) {
240  fto = to = timeout;
241  }
242  if (timeout < 0) {
243  fto = to = 1000000000;
244  }
245  } else {
246  /* there is more than one prompt, so
247  * get rid of the long timeout between
248  * prompts, and make it 50ms */
249  fto = 50;
250  to = ast_channel_pbx(c) ? ast_channel_pbx(c)->dtimeoutms : 2000;
251  }
252  res = ast_readstring(c, s, maxlen, to, fto, S_OR(terminator, "#"));
254  return res;
255  }
256  if (!ast_strlen_zero(s)) {
257  return res;
258  }
259  }
260 
261  return res;
262 }
263 
264 /* The lock type used by ast_lock_path() / ast_unlock_path() */
266 
267 int ast_app_getdata_full(struct ast_channel *c, const char *prompt, char *s, int maxlen, int timeout, int audiofd, int ctrlfd)
268 {
269  int res, to = 2000, fto = 6000;
270 
271  if (!ast_strlen_zero(prompt)) {
272  res = ast_streamfile(c, prompt, ast_channel_language(c));
273  if (res < 0) {
274  return res;
275  }
276  }
277 
278  if (timeout > 0) {
279  fto = to = timeout;
280  }
281  if (timeout < 0) {
282  fto = to = 1000000000;
283  }
284 
285  res = ast_readstring_full(c, s, maxlen, to, fto, "#", audiofd, ctrlfd);
286 
287  return res;
288 }
289 
290 int ast_app_exec_macro(struct ast_channel *autoservice_chan, struct ast_channel *macro_chan, const char *macro_args)
291 {
292  struct ast_app *macro_app;
293  int res;
294 
295  macro_app = pbx_findapp("Macro");
296  if (!macro_app) {
298  "Cannot run 'Macro(%s)'. The application is not available.\n", macro_args);
299  return -1;
300  }
301  if (autoservice_chan) {
302  ast_autoservice_start(autoservice_chan);
303  }
304 
305  ast_debug(4, "%s Original location: %s,%s,%d\n", ast_channel_name(macro_chan),
306  ast_channel_context(macro_chan), ast_channel_exten(macro_chan),
307  ast_channel_priority(macro_chan));
308 
309  res = pbx_exec(macro_chan, macro_app, macro_args);
310  ast_debug(4, "Macro exited with status %d\n", res);
311 
312  /*
313  * Assume anything negative from Macro is an error.
314  * Anything else is success.
315  */
316  if (res < 0) {
317  res = -1;
318  } else {
319  res = 0;
320  }
321 
322  ast_debug(4, "%s Ending location: %s,%s,%d\n", ast_channel_name(macro_chan),
323  ast_channel_context(macro_chan), ast_channel_exten(macro_chan),
324  ast_channel_priority(macro_chan));
325 
326  if (autoservice_chan) {
327  ast_autoservice_stop(autoservice_chan);
328  }
329 
330  if (ast_check_hangup_locked(macro_chan)) {
331  ast_queue_hangup(macro_chan);
332  }
333 
334  return res;
335 }
336 
337 int ast_app_run_macro(struct ast_channel *autoservice_chan, struct ast_channel *macro_chan, const char *macro_name, const char *macro_args)
338 {
339  int res;
340  char *args_str;
341  size_t args_len;
342 
343  if (ast_strlen_zero(macro_args)) {
344  return ast_app_exec_macro(autoservice_chan, macro_chan, macro_name);
345  }
346 
347  /* Create the Macro application argument string. */
348  args_len = strlen(macro_name) + strlen(macro_args) + 2;
349  args_str = ast_malloc(args_len);
350  if (!args_str) {
351  return -1;
352  }
353  snprintf(args_str, args_len, "%s,%s", macro_name, macro_args);
354 
355  res = ast_app_exec_macro(autoservice_chan, macro_chan, args_str);
356  ast_free(args_str);
357  return res;
358 }
359 
360 /* BUGBUG this is not thread safe. */
362 
364 {
365  app_stack_callbacks = funcs;
366 }
367 
368 const char *ast_app_expand_sub_args(struct ast_channel *chan, const char *args)
369 {
370  const struct ast_app_stack_funcs *funcs;
371  const char *new_args;
372 
373  funcs = app_stack_callbacks;
374  if (!funcs || !funcs->expand_sub_args || !ast_module_running_ref(funcs->module)) {
376  "Cannot expand 'Gosub(%s)' arguments. The app_stack module is not available.\n",
377  args);
378  return NULL;
379  }
380 
381  new_args = funcs->expand_sub_args(chan, args);
382  ast_module_unref(funcs->module);
383 
384  return new_args;
385 }
386 
387 int ast_app_exec_sub(struct ast_channel *autoservice_chan, struct ast_channel *sub_chan, const char *sub_args, int ignore_hangup)
388 {
389  const struct ast_app_stack_funcs *funcs;
390  int res;
391 
392  funcs = app_stack_callbacks;
393  if (!funcs || !funcs->run_sub || !ast_module_running_ref(funcs->module)) {
395  "Cannot run 'Gosub(%s)'. The app_stack module is not available.\n",
396  sub_args);
397  return -1;
398  }
399 
400  if (autoservice_chan) {
401  ast_autoservice_start(autoservice_chan);
402  }
403 
404  res = funcs->run_sub(sub_chan, sub_args, ignore_hangup);
405  ast_module_unref(funcs->module);
406 
407  if (autoservice_chan) {
408  ast_autoservice_stop(autoservice_chan);
409  }
410 
411  if (!ignore_hangup && ast_check_hangup_locked(sub_chan)) {
412  ast_queue_hangup(sub_chan);
413  }
414 
415  return res;
416 }
417 
418 int ast_app_run_sub(struct ast_channel *autoservice_chan, struct ast_channel *sub_chan, const char *sub_location, const char *sub_args, int ignore_hangup)
419 {
420  int res;
421  char *args_str;
422  size_t args_len;
423 
424  if (ast_strlen_zero(sub_args)) {
425  return ast_app_exec_sub(autoservice_chan, sub_chan, sub_location, ignore_hangup);
426  }
427 
428  /* Create the Gosub application argument string. */
429  args_len = strlen(sub_location) + strlen(sub_args) + 3;
430  args_str = ast_malloc(args_len);
431  if (!args_str) {
432  return -1;
433  }
434  snprintf(args_str, args_len, "%s(%s)", sub_location, sub_args);
435 
436  res = ast_app_exec_sub(autoservice_chan, sub_chan, args_str, ignore_hangup);
437  ast_free(args_str);
438  return res;
439 }
440 
441 /*! \brief The container for the voicemail provider */
442 static AO2_GLOBAL_OBJ_STATIC(vm_provider);
443 
444 /*! Voicemail not registered warning */
445 static int vm_warnings;
446 
448 {
449  struct ast_vm_functions *table;
450  int is_registered;
451 
452  table = ao2_global_obj_ref(vm_provider);
453  is_registered = table ? 1 : 0;
454  ao2_cleanup(table);
455  return is_registered;
456 }
457 
459 {
461 
462  if (!vm_table->module_name) {
463  ast_log(LOG_ERROR, "Voicemail provider missing required information.\n");
464  return -1;
465  }
466  if (vm_table->module_version != VM_MODULE_VERSION) {
467  ast_log(LOG_ERROR, "Voicemail provider '%s' has incorrect version\n",
468  vm_table->module_name);
469  return -1;
470  }
471 
472  table = ao2_global_obj_ref(vm_provider);
473  if (table) {
474  ast_log(LOG_WARNING, "Voicemail provider already registered by %s.\n",
475  table->module_name);
477  }
478 
480  if (!table) {
481  return -1;
482  }
483  *table = *vm_table;
484  table->module = module;
485 
486  ao2_global_obj_replace_unref(vm_provider, table);
487  return 0;
488 }
489 
491 {
492  struct ast_vm_functions *table;
493 
494  table = ao2_global_obj_ref(vm_provider);
495  if (table && !strcmp(table->module_name, module_name)) {
496  ao2_global_obj_release(vm_provider);
497  }
498  ao2_cleanup(table);
499 }
500 
501 #ifdef TEST_FRAMEWORK
502 /*! \brief Holding container for the voicemail provider used while testing */
503 static AO2_GLOBAL_OBJ_STATIC(vm_provider_holder);
504 static int provider_is_swapped = 0;
505 
506 void ast_vm_test_swap_table_in(const struct ast_vm_functions *vm_table)
507 {
508  RAII_VAR(struct ast_vm_functions *, holding_table, NULL, ao2_cleanup);
509  RAII_VAR(struct ast_vm_functions *, new_table, NULL, ao2_cleanup);
510 
511  if (provider_is_swapped) {
512  ast_log(LOG_ERROR, "Attempted to swap in test function table without swapping out old test table.\n");
513  return;
514  }
515 
516  holding_table = ao2_global_obj_ref(vm_provider);
517 
518  if (holding_table) {
519  ao2_global_obj_replace_unref(vm_provider_holder, holding_table);
520  }
521 
522  new_table = ao2_alloc_options(sizeof(*new_table), NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
523  if (!new_table) {
524  return;
525  }
526  *new_table = *vm_table;
527 
528  ao2_global_obj_replace_unref(vm_provider, new_table);
529  provider_is_swapped = 1;
530 }
531 
532 void ast_vm_test_swap_table_out(void)
533 {
534  RAII_VAR(struct ast_vm_functions *, held_table, NULL, ao2_cleanup);
535 
536  if (!provider_is_swapped) {
537  ast_log(LOG_ERROR, "Attempted to swap out test function table, but none is currently installed.\n");
538  return;
539  }
540 
541  held_table = ao2_global_obj_ref(vm_provider_holder);
542  if (!held_table) {
543  return;
544  }
545 
546  ao2_global_obj_replace_unref(vm_provider, held_table);
547  ao2_global_obj_release(vm_provider_holder);
548  provider_is_swapped = 0;
549 }
550 #endif
551 
552 /*! \brief The container for the voicemail greeter provider */
553 static AO2_GLOBAL_OBJ_STATIC(vm_greeter_provider);
554 
555 /*! Voicemail greeter not registered warning */
557 
559 {
561  int is_registered;
562 
563  table = ao2_global_obj_ref(vm_greeter_provider);
564  is_registered = table ? 1 : 0;
565  ao2_cleanup(table);
566  return is_registered;
567 }
568 
570 {
572 
573  if (!vm_table->module_name) {
574  ast_log(LOG_ERROR, "Voicemail greeter provider missing required information.\n");
575  return -1;
576  }
577  if (vm_table->module_version != VM_GREETER_MODULE_VERSION) {
578  ast_log(LOG_ERROR, "Voicemail greeter provider '%s' has incorrect version\n",
579  vm_table->module_name);
580  return -1;
581  }
582 
583  table = ao2_global_obj_ref(vm_greeter_provider);
584  if (table) {
585  ast_log(LOG_WARNING, "Voicemail greeter provider already registered by %s.\n",
586  table->module_name);
588  }
589 
591  if (!table) {
592  return -1;
593  }
594  *table = *vm_table;
595  table->module = module;
596 
597  ao2_global_obj_replace_unref(vm_greeter_provider, table);
598  return 0;
599 }
600 
602 {
604 
605  table = ao2_global_obj_ref(vm_greeter_provider);
606  if (table && !strcmp(table->module_name, module_name)) {
607  ao2_global_obj_release(vm_greeter_provider);
608  }
609  ao2_cleanup(table);
610 }
611 
612 #ifdef TEST_FRAMEWORK
613 static ast_vm_test_create_user_fn *ast_vm_test_create_user_func = NULL;
614 static ast_vm_test_destroy_user_fn *ast_vm_test_destroy_user_func = NULL;
615 
616 void ast_install_vm_test_functions(ast_vm_test_create_user_fn *vm_test_create_user_func,
617  ast_vm_test_destroy_user_fn *vm_test_destroy_user_func)
618 {
619  ast_vm_test_create_user_func = vm_test_create_user_func;
620  ast_vm_test_destroy_user_func = vm_test_destroy_user_func;
621 }
622 
623 void ast_uninstall_vm_test_functions(void)
624 {
625  ast_vm_test_create_user_func = NULL;
626  ast_vm_test_destroy_user_func = NULL;
627 }
628 #endif
629 
630 static void vm_warn_no_provider(void)
631 {
632  if (vm_warnings++ % 10 == 0) {
633  ast_verb(3, "No voicemail provider registered.\n");
634  }
635 }
636 
637 #define VM_API_CALL(res, api_call, api_parms) \
638  do { \
639  struct ast_vm_functions *table; \
640  table = ao2_global_obj_ref(vm_provider); \
641  if (!table) { \
642  vm_warn_no_provider(); \
643  } else if (table->api_call) { \
644  ast_module_ref(table->module); \
645  (res) = table->api_call api_parms; \
646  ast_module_unref(table->module); \
647  } \
648  ao2_cleanup(table); \
649  } while (0)
650 
652 {
653  if (vm_greeter_warnings++ % 10 == 0) {
654  ast_verb(3, "No voicemail greeter provider registered.\n");
655  }
656 }
657 
658 #define VM_GREETER_API_CALL(res, api_call, api_parms) \
659  do { \
660  struct ast_vm_greeter_functions *table; \
661  table = ao2_global_obj_ref(vm_greeter_provider); \
662  if (!table) { \
663  vm_greeter_warn_no_provider(); \
664  } else if (table->api_call) { \
665  ast_module_ref(table->module); \
666  (res) = table->api_call api_parms; \
667  ast_module_unref(table->module); \
668  } \
669  ao2_cleanup(table); \
670  } while (0)
671 
672 int ast_app_has_voicemail(const char *mailboxes, const char *folder)
673 {
674  int res = 0;
675 
676  VM_API_CALL(res, has_voicemail, (mailboxes, folder));
677  return res;
678 }
679 
680 /*!
681  * \internal
682  * \brief Function used as a callback for ast_copy_recording_to_vm when a real one isn't installed.
683  * \param vm_rec_data Stores crucial information about the voicemail that will basically just be used
684  * to figure out what the name of the recipient was supposed to be
685  */
687 {
688  int res = -1;
689 
690  VM_API_CALL(res, copy_recording_to_vm, (vm_rec_data));
691  return res;
692 }
693 
694 int ast_app_inboxcount(const char *mailboxes, int *newmsgs, int *oldmsgs)
695 {
696  int res = 0;
697 
698  if (newmsgs) {
699  *newmsgs = 0;
700  }
701  if (oldmsgs) {
702  *oldmsgs = 0;
703  }
704 
705  VM_API_CALL(res, inboxcount, (mailboxes, newmsgs, oldmsgs));
706  return res;
707 }
708 
709 int ast_app_inboxcount2(const char *mailboxes, int *urgentmsgs, int *newmsgs, int *oldmsgs)
710 {
711  int res = 0;
712 
713  if (newmsgs) {
714  *newmsgs = 0;
715  }
716  if (oldmsgs) {
717  *oldmsgs = 0;
718  }
719  if (urgentmsgs) {
720  *urgentmsgs = 0;
721  }
722 
723  VM_API_CALL(res, inboxcount2, (mailboxes, urgentmsgs, newmsgs, oldmsgs));
724  return res;
725 }
726 
727 int ast_app_sayname(struct ast_channel *chan, const char *mailbox_id)
728 {
729  int res = -1;
730 
731  VM_GREETER_API_CALL(res, sayname, (chan, mailbox_id));
732  return res;
733 }
734 
735 int ast_app_messagecount(const char *mailbox_id, const char *folder)
736 {
737  int res = 0;
738 
739  VM_API_CALL(res, messagecount, (mailbox_id, folder));
740  return res;
741 }
742 
743 const char *ast_vm_index_to_foldername(int id)
744 {
745  const char *res = NULL;
746 
747  VM_API_CALL(res, index_to_foldername, (id));
748  return res;
749 }
750 
752  const char *context,
753  const char *folder,
754  int descending,
755  enum ast_vm_snapshot_sort_val sort_val,
756  int combine_INBOX_and_OLD)
757 {
758  struct ast_vm_mailbox_snapshot *res = NULL;
759 
760  VM_API_CALL(res, mailbox_snapshot_create, (mailbox, context, folder, descending,
761  sort_val, combine_INBOX_and_OLD));
762  return res;
763 }
764 
766 {
767  struct ast_vm_mailbox_snapshot *res = NULL;
768 
769  VM_API_CALL(res, mailbox_snapshot_destroy, (mailbox_snapshot));
770  return res;
771 }
772 
773 int ast_vm_msg_move(const char *mailbox,
774  const char *context,
775  size_t num_msgs,
776  const char *oldfolder,
777  const char *old_msg_ids[],
778  const char *newfolder)
779 {
780  int res = 0;
781 
782  VM_API_CALL(res, msg_move, (mailbox, context, num_msgs, oldfolder, old_msg_ids,
783  newfolder));
784  return res;
785 }
786 
787 int ast_vm_msg_remove(const char *mailbox,
788  const char *context,
789  size_t num_msgs,
790  const char *folder,
791  const char *msgs[])
792 {
793  int res = 0;
794 
795  VM_API_CALL(res, msg_remove, (mailbox, context, num_msgs, folder, msgs));
796  return res;
797 }
798 
800  const char *from_context,
801  const char *from_folder,
802  const char *to_mailbox,
803  const char *to_context,
804  const char *to_folder,
805  size_t num_msgs,
806  const char *msg_ids[],
807  int delete_old)
808 {
809  int res = 0;
810 
811  VM_API_CALL(res, msg_forward, (from_mailbox, from_context, from_folder, to_mailbox,
812  to_context, to_folder, num_msgs, msg_ids, delete_old));
813  return res;
814 }
815 
816 int ast_vm_msg_play(struct ast_channel *chan,
817  const char *mailbox,
818  const char *context,
819  const char *folder,
820  const char *msg_num,
821  ast_vm_msg_play_cb *cb)
822 {
823  int res = 0;
824 
825  VM_API_CALL(res, msg_play, (chan, mailbox, context, folder, msg_num, cb));
826  return res;
827 }
828 
829 #ifdef TEST_FRAMEWORK
830 int ast_vm_test_create_user(const char *context, const char *mailbox)
831 {
832  if (ast_vm_test_create_user_func) {
833  return ast_vm_test_create_user_func(context, mailbox);
834  }
835  return 0;
836 }
837 
838 int ast_vm_test_destroy_user(const char *context, const char *mailbox)
839 {
840  if (ast_vm_test_destroy_user_func) {
841  return ast_vm_test_destroy_user_func(context, mailbox);
842  }
843  return 0;
844 }
845 #endif
846 
847 static int external_sleep(struct ast_channel *chan, int ms)
848 {
849  usleep(ms * 1000);
850  return 0;
851 }
852 
853 static int dtmf_stream(struct ast_channel *chan, const char *digits, int between, unsigned int duration, int is_external)
854 {
855  const char *ptr;
856  int res;
857  struct ast_silence_generator *silgen = NULL;
858  int (*my_sleep)(struct ast_channel *chan, int ms);
859  int (*my_senddigit)(struct ast_channel *chan, char digit, unsigned int duration);
860 
861  if (is_external) {
862  my_sleep = external_sleep;
863  my_senddigit = ast_senddigit_external;
864  } else {
865  my_sleep = ast_safe_sleep;
866  my_senddigit = ast_senddigit;
867  }
868 
869  if (!between) {
870  between = 100;
871  }
872 
873  /* Need a quiet time before sending digits. */
876  }
877  res = my_sleep(chan, 100);
878  if (res) {
879  goto dtmf_stream_cleanup;
880  }
881 
882  for (ptr = digits; *ptr; ptr++) {
883  if (*ptr == 'w') {
884  /* 'w' -- wait half a second */
885  res = my_sleep(chan, 500);
886  if (res) {
887  break;
888  }
889  } else if (*ptr == 'W') {
890  /* 'W' -- wait a second */
891  res = my_sleep(chan, 1000);
892  if (res) {
893  break;
894  }
895  } else if (strchr("0123456789*#abcdfABCDF", *ptr)) {
896  if (*ptr == 'f' || *ptr == 'F') {
897  /* ignore return values if not supported by channel */
899  } else {
900  /* Character represents valid DTMF */
901  my_senddigit(chan, *ptr, duration);
902  }
903  /* pause between digits */
904  res = my_sleep(chan, between);
905  if (res) {
906  break;
907  }
908  } else {
909  ast_log(LOG_WARNING, "Illegal DTMF character '%c' in string. (0-9*#aAbBcCdD allowed)\n", *ptr);
910  }
911  }
912 
913 dtmf_stream_cleanup:
914  if (silgen) {
916  }
917 
918  return res;
919 }
920 
921 int ast_dtmf_stream(struct ast_channel *chan, struct ast_channel *peer, const char *digits, int between, unsigned int duration)
922 {
923  int res;
924 
925  if (peer && ast_autoservice_start(peer)) {
926  return -1;
927  }
928  res = dtmf_stream(chan, digits, between, duration, 0);
929  if (peer && ast_autoservice_stop(peer)) {
930  res = -1;
931  }
932 
933  return res;
934 }
935 
936 void ast_dtmf_stream_external(struct ast_channel *chan, const char *digits, int between, unsigned int duration)
937 {
938  dtmf_stream(chan, digits, between, duration, 1);
939 }
940 
941 struct linear_state {
942  int fd;
946 };
947 
948 static void linear_release(struct ast_channel *chan, void *params)
949 {
950  struct linear_state *ls = params;
951 
952  if (ls->origwfmt && ast_set_write_format(chan, ls->origwfmt)) {
953  ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%s'\n",
955  }
956  ao2_cleanup(ls->origwfmt);
957 
958  if (ls->autoclose) {
959  close(ls->fd);
960  }
961 
962  ast_free(params);
963 }
964 
965 static int linear_generator(struct ast_channel *chan, void *data, int len, int samples)
966 {
967  short buf[2048 + AST_FRIENDLY_OFFSET / 2];
968  struct linear_state *ls = data;
969  struct ast_frame f = {
971  .data.ptr = buf + AST_FRIENDLY_OFFSET / 2,
972  .offset = AST_FRIENDLY_OFFSET,
973  };
974  int res;
975 
977 
978  len = samples * 2;
979  if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) {
980  ast_log(LOG_WARNING, "Can't generate %d bytes of data!\n" , len);
981  len = sizeof(buf) - AST_FRIENDLY_OFFSET;
982  }
983  res = read(ls->fd, buf + AST_FRIENDLY_OFFSET/2, len);
984  if (res > 0) {
985  f.datalen = res;
986  f.samples = res / 2;
987  ast_write(chan, &f);
988  if (res == len) {
989  return 0;
990  }
991  }
992  return -1;
993 }
994 
995 static void *linear_alloc(struct ast_channel *chan, void *params)
996 {
997  struct linear_state *ls = params;
998 
999  if (!params) {
1000  return NULL;
1001  }
1002 
1003  /* In this case, params is already malloc'd */
1004  if (ls->allowoverride) {
1006  } else {
1008  }
1009 
1011 
1013  ast_log(LOG_WARNING, "Unable to set '%s' to linear format (write)\n", ast_channel_name(chan));
1014  ao2_cleanup(ls->origwfmt);
1015  ast_free(ls);
1016  ls = params = NULL;
1017  }
1018 
1019  return params;
1020 }
1021 
1023 {
1024  .alloc = linear_alloc,
1025  .release = linear_release,
1026  .generate = linear_generator,
1027 };
1028 
1029 int ast_linear_stream(struct ast_channel *chan, const char *filename, int fd, int allowoverride)
1030 {
1031  struct linear_state *lin;
1032  char tmpf[256];
1033  int autoclose = 0;
1034 
1035  if (fd < 0) {
1036  if (ast_strlen_zero(filename)) {
1037  return -1;
1038  }
1039 
1040  autoclose = 1;
1041 
1042  if (filename[0] == '/') {
1043  ast_copy_string(tmpf, filename, sizeof(tmpf));
1044  } else {
1045  snprintf(tmpf, sizeof(tmpf), "%s/%s/%s", ast_config_AST_DATA_DIR, "sounds", filename);
1046  }
1047 
1048  fd = open(tmpf, O_RDONLY);
1049  if (fd < 0) {
1050  ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", tmpf, strerror(errno));
1051  return -1;
1052  }
1053  }
1054 
1055  lin = ast_calloc(1, sizeof(*lin));
1056  if (!lin) {
1057  if (autoclose) {
1058  close(fd);
1059  }
1060 
1061  return -1;
1062  }
1063 
1064  lin->fd = fd;
1066  lin->autoclose = autoclose;
1067 
1068  return ast_activate_generator(chan, &linearstream, lin);
1069 }
1070 
1071 static int control_streamfile(struct ast_channel *chan,
1072  const char *file,
1073  const char *fwd,
1074  const char *rev,
1075  const char *stop,
1076  const char *suspend,
1077  const char *restart,
1078  int skipms,
1079  long *offsetms,
1080  const char *lang,
1082 {
1083  char *breaks = NULL;
1084  char *end = NULL;
1085  int blen = 2;
1086  int res;
1087  long pause_restart_point = 0;
1088  long offset = 0;
1089  struct ast_silence_generator *silgen = NULL;
1090 
1091  if (!file) {
1092  return -1;
1093  }
1094  if (offsetms) {
1095  offset = *offsetms * 8; /* XXX Assumes 8kHz */
1096  }
1097  if (lang == NULL) {
1098  lang = ast_channel_language(chan);
1099  }
1100 
1101  if (stop) {
1102  blen += strlen(stop);
1103  }
1104  if (suspend) {
1105  blen += strlen(suspend);
1106  }
1107  if (restart) {
1108  blen += strlen(restart);
1109  }
1110 
1111  if (blen > 2) {
1112  breaks = ast_alloca(blen + 1);
1113  breaks[0] = '\0';
1114  if (stop) {
1115  strcat(breaks, stop);
1116  }
1117  if (suspend) {
1118  strcat(breaks, suspend);
1119  }
1120  if (restart) {
1121  strcat(breaks, restart);
1122  }
1123  }
1124 
1125  if ((end = strchr(file, ':'))) {
1126  if (!strcasecmp(end, ":end")) {
1127  *end = '\0';
1128  end++;
1129  } else {
1130  end = NULL;
1131  }
1132  }
1133 
1134  for (;;) {
1135  ast_stopstream(chan);
1136  res = ast_streamfile(chan, file, lang);
1137  if (!res) {
1138  if (pause_restart_point) {
1139  ast_seekstream(ast_channel_stream(chan), pause_restart_point, SEEK_SET);
1140  pause_restart_point = 0;
1141  }
1142  else if (end || offset < 0) {
1143  if (offset == -8) {
1144  offset = 0;
1145  }
1146  ast_verb(3, "ControlPlayback seek to offset %ld from end\n", offset);
1147 
1148  ast_seekstream(ast_channel_stream(chan), offset, SEEK_END);
1149  end = NULL;
1150  offset = 0;
1151  } else if (offset) {
1152  ast_verb(3, "ControlPlayback seek to offset %ld\n", offset);
1153  ast_seekstream(ast_channel_stream(chan), offset, SEEK_SET);
1154  offset = 0;
1155  }
1156  if (cb) {
1157  res = ast_waitstream_fr_w_cb(chan, breaks, fwd, rev, skipms, cb);
1158  } else {
1159  res = ast_waitstream_fr(chan, breaks, fwd, rev, skipms);
1160  }
1161  }
1162 
1163  if (res < 1) {
1164  break;
1165  }
1166 
1167  /* We go at next loop if we got the restart char */
1168  if ((restart && strchr(restart, res)) || res == AST_CONTROL_STREAM_RESTART) {
1169  ast_debug(1, "we'll restart the stream here at next loop\n");
1170  pause_restart_point = 0;
1171  ast_test_suite_event_notify("PLAYBACK","Channel: %s\r\n"
1172  "Control: %s\r\n",
1173  ast_channel_name(chan),
1174  "Restart");
1175  continue;
1176  }
1177 
1178  if ((suspend && strchr(suspend, res)) || res == AST_CONTROL_STREAM_SUSPEND) {
1179  pause_restart_point = ast_tellstream(ast_channel_stream(chan));
1180 
1182  silgen = ast_channel_start_silence_generator(chan);
1183  }
1184  ast_test_suite_event_notify("PLAYBACK","Channel: %s\r\n"
1185  "Control: %s\r\n",
1186  ast_channel_name(chan),
1187  "Pause");
1188  for (;;) {
1189  ast_stopstream(chan);
1190  if (!(res = ast_waitfordigit(chan, 1000))) {
1191  continue;
1192  } else if (res == -1 || (suspend && strchr(suspend, res)) || (stop && strchr(stop, res))
1194  break;
1195  }
1196  }
1197  if (silgen) {
1198  ast_channel_stop_silence_generator(chan, silgen);
1199  silgen = NULL;
1200  }
1201 
1202  if ((suspend && (res == *suspend)) || res == AST_CONTROL_STREAM_SUSPEND) {
1203  res = 0;
1204  ast_test_suite_event_notify("PLAYBACK","Channel: %s\r\n"
1205  "Control: %s\r\n",
1206  ast_channel_name(chan),
1207  "Unpause");
1208  continue;
1209  }
1210  }
1211 
1212  if (res == -1) {
1213  break;
1214  }
1215 
1216  /* if we get one of our stop chars, return it to the calling function */
1217  if ((stop && strchr(stop, res)) || res == AST_CONTROL_STREAM_STOP) {
1218  ast_test_suite_event_notify("PLAYBACK","Channel: %s\r\n"
1219  "Control: %s\r\n",
1220  ast_channel_name(chan),
1221  "Stop");
1222  break;
1223  }
1224  }
1225 
1226  if (pause_restart_point) {
1227  offset = pause_restart_point;
1228  } else {
1229  if (ast_channel_stream(chan)) {
1230  offset = ast_tellstream(ast_channel_stream(chan));
1231  } else {
1232  offset = -8; /* indicate end of file */
1233  }
1234  }
1235 
1236  if (offsetms) {
1237  *offsetms = offset / 8; /* samples --> ms ... XXX Assumes 8 kHz */
1238  }
1239 
1240  ast_stopstream(chan);
1241 
1242  return res;
1243 }
1244 
1246  const char *file,
1247  const char *fwd,
1248  const char *rev,
1249  const char *stop,
1250  const char *suspend,
1251  const char *restart,
1252  int skipms,
1253  long *offsetms,
1255 {
1256  return control_streamfile(chan, file, fwd, rev, stop, suspend, restart, skipms, offsetms, NULL, cb);
1257 }
1258 
1259 int ast_control_streamfile(struct ast_channel *chan, const char *file,
1260  const char *fwd, const char *rev,
1261  const char *stop, const char *suspend,
1262  const char *restart, int skipms, long *offsetms)
1263 {
1264  return control_streamfile(chan, file, fwd, rev, stop, suspend, restart, skipms, offsetms, NULL, NULL);
1265 }
1266 
1267 int ast_control_streamfile_lang(struct ast_channel *chan, const char *file,
1268  const char *fwd, const char *rev, const char *stop, const char *suspend,
1269  const char *restart, int skipms, const char *lang, long *offsetms)
1270 {
1271  return control_streamfile(chan, file, fwd, rev, stop, suspend, restart, skipms, offsetms, lang, NULL);
1272 }
1273 
1278 };
1279 
1280 static enum control_tone_frame_response_result control_tone_frame_response(struct ast_channel *chan, struct ast_frame *fr, struct ast_tone_zone_sound *ts, const char *tone, int *paused)
1281 {
1282  switch (fr->subclass.integer) {
1284  ast_playtones_stop(chan);
1287  if (*paused) {
1288  *paused = 0;
1289  if (ast_playtones_start(chan, 0, ts ? ts->data : tone, 0)) {
1291  }
1292  } else {
1293  *paused = 1;
1294  ast_playtones_stop(chan);
1295  }
1298  ast_playtones_stop(chan);
1299  if (ast_playtones_start(chan, 0, ts ? ts->data : tone, 0)) {
1301  }
1304  ast_log(LOG_NOTICE, "Media control operation 'reverse' not supported for media type 'tone'\n");
1307  ast_log(LOG_NOTICE, "Media control operation 'forward' not supported for media type 'tone'\n");
1309  case AST_CONTROL_HANGUP:
1310  case AST_CONTROL_BUSY:
1313  }
1314 
1316 }
1317 
1318 static int parse_tone_uri(char *tone_parser,
1319  const char **tone_indication,
1320  const char **tone_zone)
1321 {
1322  *tone_indication = strsep(&tone_parser, ";");
1323 
1324  if (ast_strlen_zero(tone_parser)) {
1325  /* Only the indication is included */
1326  return 0;
1327  }
1328 
1329  if (!(strncmp(tone_parser, "tonezone=", 9))) {
1330  *tone_zone = tone_parser + 9;
1331  } else {
1332  ast_log(LOG_ERROR, "Unexpected Tone URI component: %s\n", tone_parser);
1333  return -1;
1334  }
1335 
1336  return 0;
1337 }
1338 
1339 int ast_control_tone(struct ast_channel *chan, const char *tone)
1340 {
1341  struct ast_tone_zone *zone = NULL;
1342  struct ast_tone_zone_sound *ts;
1343  int paused = 0;
1344  int res = 0;
1345 
1346  const char *tone_indication = NULL;
1347  const char *tone_zone = NULL;
1348  char *tone_uri_parser;
1349 
1350  if (ast_strlen_zero(tone)) {
1351  return -1;
1352  }
1353 
1354  tone_uri_parser = ast_strdupa(tone);
1355 
1356  if (parse_tone_uri(tone_uri_parser, &tone_indication, &tone_zone)) {
1357  return -1;
1358  }
1359 
1360  if (tone_zone) {
1361  zone = ast_get_indication_zone(tone_zone);
1362  }
1363 
1364  ts = ast_get_indication_tone(zone ? zone : ast_channel_zone(chan), tone_indication);
1365 
1366  if (ast_playtones_start(chan, 0, ts ? ts->data : tone_indication, 0)) {
1367  res = -1;
1368  }
1369 
1370  while (!res) {
1371  struct ast_frame *fr;
1372 
1373  if (ast_waitfor(chan, -1) < 0) {
1374  res = -1;
1375  break;
1376  }
1377 
1378  fr = ast_read_noaudio(chan);
1379 
1380  if (!fr) {
1381  res = -1;
1382  break;
1383  }
1384 
1385  if (fr->frametype != AST_FRAME_CONTROL) {
1386  continue;
1387  }
1388 
1389  res = control_tone_frame_response(chan, fr, ts, tone_indication, &paused);
1390  if (res == CONTROL_TONE_RESPONSE_FINISHED) {
1391  res = 0;
1392  break;
1393  } else if (res == CONTROL_TONE_RESPONSE_FAILED) {
1394  res = -1;
1395  break;
1396  }
1397  }
1398 
1399  if (ts) {
1401  }
1402 
1403  if (zone) {
1404  ast_tone_zone_unref(zone);
1405  }
1406 
1407  return res;
1408 }
1409 
1410 int ast_play_and_wait(struct ast_channel *chan, const char *fn)
1411 {
1412  int d = 0;
1413 
1414  if ((d = ast_streamfile(chan, fn, ast_channel_language(chan)))) {
1415  return d;
1416  }
1417 
1418  d = ast_waitstream(chan, AST_DIGIT_ANY);
1419 
1420  ast_stopstream(chan);
1421 
1422  return d;
1423 }
1424 
1425 /*!
1426  * \brief Construct a silence frame of the same duration as \a orig.
1427  *
1428  * The \a orig frame must be \ref AST_FORMAT_SLINEAR.
1429  *
1430  * \param orig Frame as basis for silence to generate.
1431  * \return New frame of silence; free with ast_frfree().
1432  * \return \c NULL on error.
1433  */
1434 static struct ast_frame *make_silence(const struct ast_frame *orig)
1435 {
1436  struct ast_frame *silence;
1437  size_t size;
1438  size_t datalen;
1439  size_t samples = 0;
1440 
1441  if (!orig) {
1442  return NULL;
1443  }
1444  do {
1446  ast_log(LOG_WARNING, "Attempting to silence non-slin frame\n");
1447  return NULL;
1448  }
1449 
1450  samples += orig->samples;
1451 
1452  orig = AST_LIST_NEXT(orig, frame_list);
1453  } while (orig);
1454 
1455  ast_verb(4, "Silencing %zu samples\n", samples);
1456 
1457 
1458  datalen = sizeof(short) * samples;
1459  size = sizeof(*silence) + datalen;
1460  silence = ast_calloc(1, size);
1461  if (!silence) {
1462  return NULL;
1463  }
1464 
1465  silence->mallocd = AST_MALLOCD_HDR;
1466  silence->frametype = AST_FRAME_VOICE;
1467  silence->data.ptr = (void *)(silence + 1);
1468  silence->samples = samples;
1469  silence->datalen = datalen;
1470 
1472 
1473  return silence;
1474 }
1475 
1476 /*!
1477  * \brief Sets a channel's read format to \ref AST_FORMAT_SLINEAR, recording
1478  * its original format.
1479  *
1480  * \param chan Channel to modify.
1481  * \param[out] orig_format Output variable to store channel's original read
1482  * format.
1483  * \return 0 on success.
1484  * \return -1 on error.
1485  */
1486 static int set_read_to_slin(struct ast_channel *chan, struct ast_format **orig_format)
1487 {
1488  if (!chan || !orig_format) {
1489  return -1;
1490  }
1491  *orig_format = ao2_bump(ast_channel_readformat(chan));
1492  return ast_set_read_format(chan, ast_format_slin);
1493 }
1494 
1495 static int global_silence_threshold = 128;
1496 static int global_maxsilence = 0;
1497 
1498 /*! Optionally play a sound file or a beep, then record audio and video from the channel.
1499  * \param chan Channel to playback to/record from.
1500  * \param playfile Filename of sound to play before recording begins.
1501  * \param recordfile Filename to record to.
1502  * \param maxtime Maximum length of recording (in seconds).
1503  * \param fmt Format(s) to record message in. Multiple formats may be specified by separating them with a '|'.
1504  * \param duration Where to store actual length of the recorded message (in milliseconds).
1505  * \param sound_duration Where to store the length of the recorded message (in milliseconds), minus any silence
1506  * \param beep Whether to play a beep before starting to record.
1507  * \param silencethreshold
1508  * \param maxsilence Length of silence that will end a recording (in milliseconds).
1509  * \param path Optional filesystem path to unlock.
1510  * \param prepend If true, prepend the recorded audio to an existing file and follow prepend mode recording rules
1511  * \param acceptdtmf DTMF digits that will end the recording.
1512  * \param canceldtmf DTMF digits that will cancel the recording.
1513  * \param skip_confirmation_sound If true, don't play auth-thankyou at end. Nice for custom recording prompts in apps.
1514  *
1515  * \retval -1 failure or hangup
1516  * \retval 'S' Recording ended from silence timeout
1517  * \retval 't' Recording ended from the message exceeding the maximum duration, or via DTMF in prepend mode
1518  * \retval dtmfchar Recording ended via the return value's DTMF character for either cancel or accept.
1519  */
1520 static int __ast_play_and_record(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, int *sound_duration, int beep, int silencethreshold, int maxsilence, const char *path, int prepend, const char *acceptdtmf, const char *canceldtmf, int skip_confirmation_sound, enum ast_record_if_exists if_exists)
1521 {
1522  int d = 0;
1523  char *fmts;
1524  char comment[256];
1525  int x, fmtcnt = 1, res = -1, outmsg = 0;
1526  struct ast_filestream *others[AST_MAX_FORMATS];
1527  const char *sfmt[AST_MAX_FORMATS];
1528  char *stringp = NULL;
1529  time_t start, end;
1530  struct ast_dsp *sildet = NULL; /* silence detector dsp */
1531  int totalsilence = 0;
1532  int dspsilence = 0;
1533  int olddspsilence = 0;
1534  struct ast_format *rfmt = NULL;
1535  struct ast_silence_generator *silgen = NULL;
1536  char prependfile[PATH_MAX];
1537  int ioflags; /* IO flags for writing output file */
1538 
1539  ioflags = O_CREAT|O_WRONLY;
1540 
1541  switch (if_exists) {
1543  ioflags |= O_EXCL;
1544  break;
1546  ioflags |= O_TRUNC;
1547  break;
1549  ioflags |= O_APPEND;
1550  break;
1552  ast_assert(0);
1553  break;
1554  }
1555 
1556  if (silencethreshold < 0) {
1557  silencethreshold = global_silence_threshold;
1558  }
1559 
1560  if (maxsilence < 0) {
1561  maxsilence = global_maxsilence;
1562  }
1563 
1564  /* barf if no pointer passed to store duration in */
1565  if (!duration) {
1566  ast_log(LOG_WARNING, "Error play_and_record called without duration pointer\n");
1567  return -1;
1568  }
1569 
1570  ast_debug(1, "play_and_record: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt);
1571  snprintf(comment, sizeof(comment), "Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, ast_channel_name(chan));
1572 
1573  if (playfile || beep) {
1574  if (!beep) {
1575  d = ast_play_and_wait(chan, playfile);
1576  }
1577  if (d > -1) {
1578  d = ast_stream_and_wait(chan, "beep", "");
1579  }
1580  if (d < 0) {
1581  return -1;
1582  }
1583  }
1584 
1585  if (prepend) {
1586  ast_copy_string(prependfile, recordfile, sizeof(prependfile));
1587  strncat(prependfile, "-prepend", sizeof(prependfile) - strlen(prependfile) - 1);
1588  }
1589 
1590  fmts = ast_strdupa(fmt);
1591 
1592  stringp = fmts;
1593  strsep(&stringp, "|");
1594  ast_debug(1, "Recording Formats: sfmts=%s\n", fmts);
1595  sfmt[0] = ast_strdupa(fmts);
1596 
1597  while ((fmt = strsep(&stringp, "|"))) {
1598  if (fmtcnt > AST_MAX_FORMATS - 1) {
1599  ast_log(LOG_WARNING, "Please increase AST_MAX_FORMATS in file.h\n");
1600  break;
1601  }
1602  /*
1603  * Storage for 'fmt' is on the stack and held by 'fmts', which is maintained for
1604  * the rest of this function. So okay to not duplicate 'fmt' here, but only keep
1605  * a pointer to it.
1606  */
1607  sfmt[fmtcnt++] = fmt;
1608  }
1609 
1610  end = start = time(NULL); /* pre-initialize end to be same as start in case we never get into loop */
1611  for (x = 0; x < fmtcnt; x++) {
1612  others[x] = ast_writefile(prepend ? prependfile : recordfile, sfmt[x], comment, ioflags, 0, AST_FILE_MODE);
1613  ast_verb(3, "x=%d, open writing: %s format: %s, %p\n", x, prepend ? prependfile : recordfile, sfmt[x], others[x]);
1614 
1615  if (!others[x]) {
1616  break;
1617  }
1618  }
1619 
1620  if (path) {
1621  ast_unlock_path(path);
1622  }
1623 
1624  if (maxsilence > 0) {
1625  sildet = ast_dsp_new(); /* Create the silence detector */
1626  if (!sildet) {
1627  ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
1628  return -1;
1629  }
1630  ast_dsp_set_threshold(sildet, silencethreshold);
1631  res = set_read_to_slin(chan, &rfmt);
1632  if (res < 0) {
1633  ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
1634  ast_dsp_free(sildet);
1635  ao2_cleanup(rfmt);
1636  return -1;
1637  }
1638  }
1639 
1640  if (!prepend) {
1641  /* Request a video update */
1643 
1645  silgen = ast_channel_start_silence_generator(chan);
1646  }
1647  }
1648 
1649  if (x == fmtcnt) {
1650  /* Loop, writing the packets we read to the writer(s), until
1651  * we have reason to stop. */
1652  struct ast_frame *f;
1653  int paused = 0;
1654  int muted = 0;
1655  time_t pause_start = 0;
1656  int paused_secs = 0;
1657  int pausedsilence = 0;
1658 
1659  for (;;) {
1660  if (!(res = ast_waitfor(chan, 2000))) {
1661  ast_debug(1, "One waitfor failed, trying another\n");
1662  /* Try one more time in case of masq */
1663  if (!(res = ast_waitfor(chan, 2000))) {
1664  ast_log(LOG_WARNING, "No audio available on %s??\n", ast_channel_name(chan));
1665  res = -1;
1666  }
1667  }
1668 
1669  if (res < 0) {
1670  f = NULL;
1671  break;
1672  }
1673  if (!(f = ast_read(chan))) {
1674  break;
1675  }
1676  if (f->frametype == AST_FRAME_VOICE) {
1677  /* write each format */
1678  if (paused) {
1679  /* It's all good */
1680  res = 0;
1681  } else {
1682  struct ast_frame *silence = NULL;
1683  struct ast_frame *orig = f;
1684 
1685  if (muted) {
1686  silence = make_silence(orig);
1687  if (!silence) {
1688  ast_log(LOG_WARNING, "Error creating silence\n");
1689  break;
1690  }
1691  f = silence;
1692  }
1693  for (x = 0; x < fmtcnt; x++) {
1694  if (prepend && !others[x]) {
1695  break;
1696  }
1697  res = ast_writestream(others[x], f);
1698  }
1699  ast_frame_dtor(silence);
1700  f = orig;
1701  }
1702 
1703  /* Silence Detection */
1704  if (maxsilence > 0) {
1705  dspsilence = 0;
1706  ast_dsp_silence(sildet, f, &dspsilence);
1707  if (olddspsilence > dspsilence) {
1708  totalsilence += olddspsilence;
1709  }
1710  olddspsilence = dspsilence;
1711 
1712  if (paused) {
1713  /* record how much silence there was while we are paused */
1714  pausedsilence = dspsilence;
1715  } else if (dspsilence > pausedsilence) {
1716  /* ignore the paused silence */
1717  dspsilence -= pausedsilence;
1718  } else {
1719  /* dspsilence has reset, reset pausedsilence */
1720  pausedsilence = 0;
1721  }
1722 
1723  if (dspsilence > maxsilence) {
1724  /* Ended happily with silence */
1725  ast_verb(3, "Recording automatically stopped after a silence of %d seconds\n", dspsilence/1000);
1726  res = 'S';
1727  outmsg = 2;
1728  break;
1729  }
1730  }
1731  /* Exit on any error */
1732  if (res) {
1733  ast_log(LOG_WARNING, "Error writing frame\n");
1734  break;
1735  }
1736  } else if (f->frametype == AST_FRAME_VIDEO) {
1737  /* Write only once */
1738  ast_writestream(others[0], f);
1739  } else if (f->frametype == AST_FRAME_DTMF) {
1740  if (prepend) {
1741  /* stop recording with any digit */
1742  ast_verb(3, "User ended message by pressing %c\n", f->subclass.integer);
1743  res = 't';
1744  outmsg = 2;
1745  break;
1746  }
1747  if (strchr(acceptdtmf, f->subclass.integer)) {
1748  ast_verb(3, "User ended message by pressing %c\n", f->subclass.integer);
1749  res = f->subclass.integer;
1750  outmsg = 2;
1751  break;
1752  }
1753  if (strchr(canceldtmf, f->subclass.integer)) {
1754  ast_verb(3, "User canceled message by pressing %c\n", f->subclass.integer);
1755  res = f->subclass.integer;
1756  outmsg = 0;
1757  break;
1758  }
1759  } else if (f->frametype == AST_FRAME_CONTROL) {
1761  ast_verb(3, "Message canceled by control\n");
1762  outmsg = 0; /* cancels the recording */
1763  res = 0;
1764  break;
1765  } else if (f->subclass.integer == AST_CONTROL_RECORD_STOP) {
1766  ast_verb(3, "Message ended by control\n");
1767  res = 0;
1768  break;
1769  } else if (f->subclass.integer == AST_CONTROL_RECORD_SUSPEND) {
1770  paused = !paused;
1771  ast_verb(3, "Message %spaused by control\n",
1772  paused ? "" : "un");
1773  if (paused) {
1774  pause_start = time(NULL);
1775  } else {
1776  paused_secs += time(NULL) - pause_start;
1777  }
1778  } else if (f->subclass.integer == AST_CONTROL_RECORD_MUTE) {
1779  muted = !muted;
1780  ast_verb(3, "Message %smuted by control\n",
1781  muted ? "" : "un");
1782  /* We can only silence slin frames, so
1783  * set the mode, if we haven't already
1784  * for sildet
1785  */
1786  if (muted && !rfmt) {
1787  ast_verb(3, "Setting read format to linear mode\n");
1788  res = set_read_to_slin(chan, &rfmt);
1789  if (res < 0) {
1790  ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
1791  break;
1792  }
1793  }
1794  }
1795  }
1796  if (maxtime && !paused) {
1797  end = time(NULL);
1798  if (maxtime < (end - start - paused_secs)) {
1799  ast_verb(3, "Took too long, cutting it short...\n");
1800  res = 't';
1801  outmsg = 2;
1802  break;
1803  }
1804  }
1805  ast_frfree(f);
1806  }
1807  if (!f) {
1808  ast_verb(3, "User hung up\n");
1809  res = -1;
1810  outmsg = 1;
1811  } else {
1812  ast_frfree(f);
1813  }
1814  } else {
1815  ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", recordfile, sfmt[x]);
1816  }
1817 
1818  if (!prepend) {
1819  if (silgen) {
1820  ast_channel_stop_silence_generator(chan, silgen);
1821  }
1822  }
1823 
1824  /*!\note
1825  * Instead of asking how much time passed (end - start), calculate the number
1826  * of seconds of audio which actually went into the file. This fixes a
1827  * problem where audio is stopped up on the network and never gets to us.
1828  *
1829  * Note that we still want to use the number of seconds passed for the max
1830  * message, otherwise we could get a situation where this stream is never
1831  * closed (which would create a resource leak).
1832  */
1833  *duration = others[0] ? ast_tellstream(others[0]) / 8000 : 0;
1834  if (sound_duration) {
1835  *sound_duration = *duration;
1836  }
1837 
1838  if (!prepend) {
1839  /* Reduce duration by a total silence amount */
1840  if (olddspsilence <= dspsilence) {
1841  totalsilence += dspsilence;
1842  }
1843 
1844  if (sound_duration) {
1845  if (totalsilence > 0) {
1846  *sound_duration -= (totalsilence - 200) / 1000;
1847  }
1848  if (*sound_duration < 0) {
1849  *sound_duration = 0;
1850  }
1851  }
1852 
1853  if (dspsilence > 0) {
1854  *duration -= (dspsilence - 200) / 1000;
1855  }
1856 
1857  if (*duration < 0) {
1858  *duration = 0;
1859  }
1860 
1861  for (x = 0; x < fmtcnt; x++) {
1862  if (!others[x]) {
1863  break;
1864  }
1865  /*!\note
1866  * If we ended with silence, trim all but the first 200ms of silence
1867  * off the recording. However, if we ended with '#', we don't want
1868  * to trim ANY part of the recording.
1869  */
1870  if (res > 0 && dspsilence) {
1871  /* rewind only the trailing silence */
1872  ast_stream_rewind(others[x], dspsilence - 200);
1873  }
1874  ast_truncstream(others[x]);
1875  ast_closestream(others[x]);
1876  }
1877  } else if (prepend && outmsg) {
1878  struct ast_filestream *realfiles[AST_MAX_FORMATS];
1879  struct ast_frame *fr;
1880 
1881  for (x = 0; x < fmtcnt; x++) {
1882  snprintf(comment, sizeof(comment), "Opening the real file %s.%s\n", recordfile, sfmt[x]);
1883  realfiles[x] = ast_readfile(recordfile, sfmt[x], comment, O_RDONLY, 0, 0);
1884  if (!others[x]) {
1885  break;
1886  }
1887  if (!realfiles[x]) {
1888  ast_closestream(others[x]);
1889  continue;
1890  }
1891  /*!\note Same logic as above. */
1892  if (dspsilence) {
1893  ast_stream_rewind(others[x], dspsilence - 200);
1894  }
1895  ast_truncstream(others[x]);
1896  /* add the original file too */
1897  while ((fr = ast_readframe(realfiles[x]))) {
1898  ast_writestream(others[x], fr);
1899  ast_frfree(fr);
1900  }
1901  ast_closestream(others[x]);
1902  ast_closestream(realfiles[x]);
1903  ast_filerename(prependfile, recordfile, sfmt[x]);
1904  ast_verb(4, "Recording Format: sfmts=%s, prependfile %s, recordfile %s\n", sfmt[x], prependfile, recordfile);
1905  ast_filedelete(prependfile, sfmt[x]);
1906  }
1907  } else {
1908  for (x = 0; x < fmtcnt; x++) {
1909  if (!others[x]) {
1910  break;
1911  }
1912  ast_closestream(others[x]);
1913  }
1914  }
1915 
1916  if (rfmt && ast_set_read_format(chan, rfmt)) {
1917  ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_format_get_name(rfmt), ast_channel_name(chan));
1918  }
1919  ao2_cleanup(rfmt);
1920  if ((outmsg == 2) && (!skip_confirmation_sound)) {
1921  ast_stream_and_wait(chan, "auth-thankyou", "");
1922  }
1923  if (sildet) {
1924  ast_dsp_free(sildet);
1925  }
1926  return res;
1927 }
1928 
1929 static const char default_acceptdtmf[] = "#";
1930 static const char default_canceldtmf[] = "";
1931 
1932 int ast_play_and_record_full(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, int *sound_duration, int beep, int silencethreshold, int maxsilence, const char *path, const char *acceptdtmf, const char *canceldtmf, int skip_confirmation_sound, enum ast_record_if_exists if_exists)
1933 {
1934  return __ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, sound_duration, beep, silencethreshold, maxsilence, path, 0, S_OR(acceptdtmf, ""), S_OR(canceldtmf, default_canceldtmf), skip_confirmation_sound, if_exists);
1935 }
1936 
1937 int ast_play_and_record(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, int *sound_duration, int silencethreshold, int maxsilence, const char *path)
1938 {
1939  return __ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, sound_duration, 0, silencethreshold, maxsilence, path, 0, default_acceptdtmf, default_canceldtmf, 0, AST_RECORD_IF_EXISTS_OVERWRITE);
1940 }
1941 
1942 int ast_play_and_prepend(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int *duration, int *sound_duration, int beep, int silencethreshold, int maxsilence)
1943 {
1944  return __ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, sound_duration, beep, silencethreshold, maxsilence, NULL, 1, default_acceptdtmf, default_canceldtmf, 1, AST_RECORD_IF_EXISTS_OVERWRITE);
1945 }
1946 
1947 /* Channel group core functions */
1948 
1949 int ast_app_group_split_group(const char *data, char *group, int group_max, char *category, int category_max)
1950 {
1951  int res = 0;
1952  char tmp[256];
1953  char *grp = NULL, *cat = NULL;
1954 
1955  if (!ast_strlen_zero(data)) {
1956  ast_copy_string(tmp, data, sizeof(tmp));
1957  grp = tmp;
1958  if ((cat = strchr(tmp, '@'))) {
1959  *cat++ = '\0';
1960  }
1961  }
1962 
1963  if (!ast_strlen_zero(grp)) {
1964  ast_copy_string(group, grp, group_max);
1965  } else {
1966  *group = '\0';
1967  }
1968 
1969  if (!ast_strlen_zero(cat)) {
1970  ast_copy_string(category, cat, category_max);
1971  }
1972 
1973  return res;
1974 }
1975 
1976 int ast_app_group_set_channel(struct ast_channel *chan, const char *data)
1977 {
1978  int res = 0;
1979  char group[80] = "", category[80] = "";
1980  struct ast_group_info *gi = NULL;
1981  size_t len = 0;
1982 
1983  if (ast_app_group_split_group(data, group, sizeof(group), category, sizeof(category))) {
1984  return -1;
1985  }
1986 
1987  /* Calculate memory we will need if this is new */
1988  len = sizeof(*gi) + strlen(group) + 1;
1989  if (!ast_strlen_zero(category)) {
1990  len += strlen(category) + 1;
1991  }
1992 
1995  if ((gi->chan == chan) && ((ast_strlen_zero(category) && ast_strlen_zero(gi->category)) || (!ast_strlen_zero(gi->category) && !strcasecmp(gi->category, category)))) {
1997  ast_free(gi);
1998  break;
1999  }
2000  }
2002 
2003  if (ast_strlen_zero(group)) {
2004  /* Enable unsetting the group */
2005  } else if ((gi = ast_calloc(1, len))) {
2006  gi->chan = chan;
2007  gi->group = (char *) gi + sizeof(*gi);
2008  strcpy(gi->group, group);
2009  if (!ast_strlen_zero(category)) {
2010  gi->category = (char *) gi + sizeof(*gi) + strlen(group) + 1;
2011  strcpy(gi->category, category);
2012  }
2014  } else {
2015  res = -1;
2016  }
2017 
2019 
2020  return res;
2021 }
2022 
2023 int ast_app_group_get_count(const char *group, const char *category)
2024 {
2025  struct ast_group_info *gi = NULL;
2026  int count = 0;
2027 
2028  if (ast_strlen_zero(group)) {
2029  return 0;
2030  }
2031 
2034  if (!strcasecmp(gi->group, group) && (ast_strlen_zero(category) || (!ast_strlen_zero(gi->category) && !strcasecmp(gi->category, category)))) {
2035  count++;
2036  }
2037  }
2039 
2040  return count;
2041 }
2042 
2043 int ast_app_group_match_get_count(const char *groupmatch, const char *category)
2044 {
2045  struct ast_group_info *gi = NULL;
2046  regex_t regexbuf_group;
2047  regex_t regexbuf_category;
2048  int count = 0;
2049 
2050  if (ast_strlen_zero(groupmatch)) {
2051  ast_log(LOG_NOTICE, "groupmatch empty\n");
2052  return 0;
2053  }
2054 
2055  /* if regex compilation fails, return zero matches */
2056  if (regcomp(&regexbuf_group, groupmatch, REG_EXTENDED | REG_NOSUB)) {
2057  ast_log(LOG_ERROR, "Regex compile failed on: %s\n", groupmatch);
2058  return 0;
2059  }
2060 
2061  if (!ast_strlen_zero(category) && regcomp(&regexbuf_category, category, REG_EXTENDED | REG_NOSUB)) {
2062  ast_log(LOG_ERROR, "Regex compile failed on: %s\n", category);
2063  regfree(&regexbuf_group);
2064  return 0;
2065  }
2066 
2069  if (!regexec(&regexbuf_group, gi->group, 0, NULL, 0) && (ast_strlen_zero(category) || (!ast_strlen_zero(gi->category) && !regexec(&regexbuf_category, gi->category, 0, NULL, 0)))) {
2070  count++;
2071  }
2072  }
2074 
2075  regfree(&regexbuf_group);
2076  if (!ast_strlen_zero(category)) {
2077  regfree(&regexbuf_category);
2078  }
2079 
2080  return count;
2081 }
2082 
2083 int ast_app_group_update(struct ast_channel *old, struct ast_channel *new)
2084 {
2085  struct ast_group_info *gi = NULL;
2086 
2089  if (gi->chan == old) {
2090  gi->chan = new;
2091  } else if (gi->chan == new) {
2093  ast_free(gi);
2094  }
2095  }
2098 
2099  return 0;
2100 }
2101 
2103 {
2104  struct ast_group_info *gi = NULL;
2105 
2108  if (gi->chan == chan) {
2110  ast_free(gi);
2111  }
2112  }
2115 
2116  return 0;
2117 }
2118 
2120 {
2121  return AST_RWLIST_WRLOCK(&groups);
2122 }
2123 
2125 {
2126  return AST_RWLIST_RDLOCK(&groups);
2127 }
2128 
2130 {
2131  return AST_RWLIST_FIRST(&groups);
2132 }
2133 
2135 {
2136  return AST_RWLIST_UNLOCK(&groups);
2137 }
2138 
2139 unsigned int __ast_app_separate_args(char *buf, char delim, int remove_chars, char **array, int arraylen)
2140 {
2141  int argc;
2142  char *scan, *wasdelim = NULL;
2143  int paren = 0, quote = 0, bracket = 0;
2144 
2145  if (!array || !arraylen) {
2146  return 0;
2147  }
2148 
2149  memset(array, 0, arraylen * sizeof(*array));
2150 
2151  if (!buf) {
2152  return 0;
2153  }
2154 
2155  scan = buf;
2156 
2157  for (argc = 0; *scan && (argc < arraylen - 1); argc++) {
2158  array[argc] = scan;
2159  for (; *scan; scan++) {
2160  if (*scan == '(') {
2161  paren++;
2162  } else if (*scan == ')') {
2163  if (paren) {
2164  paren--;
2165  }
2166  } else if (*scan == '[') {
2167  bracket++;
2168  } else if (*scan == ']') {
2169  if (bracket) {
2170  bracket--;
2171  }
2172  } else if (*scan == '"' && delim != '"') {
2173  quote = quote ? 0 : 1;
2174  if (remove_chars) {
2175  /* Remove quote character from argument */
2176  memmove(scan, scan + 1, strlen(scan));
2177  scan--;
2178  }
2179  } else if (*scan == '\\') {
2180  if (remove_chars) {
2181  /* Literal character, don't parse */
2182  memmove(scan, scan + 1, strlen(scan));
2183  } else {
2184  scan++;
2185  }
2186  } else if ((*scan == delim) && !paren && !quote && !bracket) {
2187  wasdelim = scan;
2188  *scan++ = '\0';
2189  break;
2190  }
2191  }
2192  }
2193 
2194  /* If the last character in the original string was the delimiter, then
2195  * there is one additional argument. */
2196  if (*scan || (scan > buf && (scan - 1) == wasdelim)) {
2197  array[argc++] = scan;
2198  }
2199 
2200  return argc;
2201 }
2202 
2203 static enum AST_LOCK_RESULT ast_lock_path_lockfile(const char *path)
2204 {
2205  char *s;
2206  char *fs;
2207  int res;
2208  int fd;
2209  int lp = strlen(path);
2210  time_t start;
2211 
2212  s = ast_alloca(lp + 10);
2213  fs = ast_alloca(lp + 20);
2214 
2215  snprintf(fs, strlen(path) + 19, "%s/.lock-%08lx", path, (unsigned long)ast_random());
2216  fd = open(fs, O_WRONLY | O_CREAT | O_EXCL, AST_FILE_MODE);
2217  if (fd < 0) {
2218  ast_log(LOG_ERROR, "Unable to create lock file '%s': %s\n", path, strerror(errno));
2219  return AST_LOCK_PATH_NOT_FOUND;
2220  }
2221  close(fd);
2222 
2223  snprintf(s, strlen(path) + 9, "%s/.lock", path);
2224  start = time(NULL);
2225  while (((res = link(fs, s)) < 0) && (errno == EEXIST) && (time(NULL) - start < 5)) {
2226  sched_yield();
2227  }
2228 
2229  unlink(fs);
2230 
2231  if (res) {
2232  ast_log(LOG_WARNING, "Failed to lock path '%s': %s\n", path, strerror(errno));
2233  return AST_LOCK_TIMEOUT;
2234  } else {
2235  ast_debug(1, "Locked path '%s'\n", path);
2236  return AST_LOCK_SUCCESS;
2237  }
2238 }
2239 
2240 static int ast_unlock_path_lockfile(const char *path)
2241 {
2242  char *s;
2243  int res;
2244 
2245  s = ast_alloca(strlen(path) + 10);
2246 
2247  snprintf(s, strlen(path) + 9, "%s/%s", path, ".lock");
2248 
2249  if ((res = unlink(s))) {
2250  ast_log(LOG_ERROR, "Could not unlock path '%s': %s\n", path, strerror(errno));
2251  } else {
2252  ast_debug(1, "Unlocked path '%s'\n", path);
2253  }
2254 
2255  return res;
2256 }
2257 
2258 struct path_lock {
2260  int fd;
2261  char *path;
2262 };
2263 
2265 
2266 static void path_lock_destroy(struct path_lock *obj)
2267 {
2268  if (obj->fd >= 0) {
2269  close(obj->fd);
2270  }
2271  if (obj->path) {
2272  ast_free(obj->path);
2273  }
2274  ast_free(obj);
2275 }
2276 
2277 static enum AST_LOCK_RESULT ast_lock_path_flock(const char *path)
2278 {
2279  char *fs;
2280  int res;
2281  int fd;
2282  time_t start;
2283  struct path_lock *pl;
2284  struct stat st, ost;
2285 
2286  fs = ast_alloca(strlen(path) + 20);
2287 
2288  snprintf(fs, strlen(path) + 19, "%s/lock", path);
2289  if (lstat(fs, &st) == 0) {
2290  if ((st.st_mode & S_IFMT) == S_IFLNK) {
2291  ast_log(LOG_WARNING, "Unable to create lock file "
2292  "'%s': it's already a symbolic link\n",
2293  fs);
2294  return AST_LOCK_FAILURE;
2295  }
2296  if (st.st_nlink > 1) {
2297  ast_log(LOG_WARNING, "Unable to create lock file "
2298  "'%s': %u hard links exist\n",
2299  fs, (unsigned int) st.st_nlink);
2300  return AST_LOCK_FAILURE;
2301  }
2302  }
2303  if ((fd = open(fs, O_WRONLY | O_CREAT, 0600)) < 0) {
2304  ast_log(LOG_WARNING, "Unable to create lock file '%s': %s\n",
2305  fs, strerror(errno));
2306  return AST_LOCK_PATH_NOT_FOUND;
2307  }
2308  if (!(pl = ast_calloc(1, sizeof(*pl)))) {
2309  /* We don't unlink the lock file here, on the possibility that
2310  * someone else created it - better to leave a little mess
2311  * than create a big one by destroying someone else's lock
2312  * and causing something to be corrupted.
2313  */
2314  close(fd);
2315  return AST_LOCK_FAILURE;
2316  }
2317  pl->fd = fd;
2318  pl->path = ast_strdup(path);
2319 
2320  time(&start);
2321  while (
2322  #ifdef SOLARIS
2323  ((res = fcntl(pl->fd, F_SETLK, fcntl(pl->fd, F_GETFL) | O_NONBLOCK)) < 0) &&
2324  #else
2325  ((res = flock(pl->fd, LOCK_EX | LOCK_NB)) < 0) &&
2326  #endif
2327  (errno == EWOULDBLOCK) &&
2328  (time(NULL) - start < 5))
2329  usleep(1000);
2330  if (res) {
2331  ast_log(LOG_WARNING, "Failed to lock path '%s': %s\n",
2332  path, strerror(errno));
2333  /* No unlinking of lock done, since we tried and failed to
2334  * flock() it.
2335  */
2336  path_lock_destroy(pl);
2337  return AST_LOCK_TIMEOUT;
2338  }
2339 
2340  /* Check for the race where the file is recreated or deleted out from
2341  * underneath us.
2342  */
2343  if (lstat(fs, &st) != 0 && fstat(pl->fd, &ost) != 0 &&
2344  st.st_dev != ost.st_dev &&
2345  st.st_ino != ost.st_ino) {
2346  ast_log(LOG_WARNING, "Unable to create lock file '%s': "
2347  "file changed underneath us\n", fs);
2348  path_lock_destroy(pl);
2349  return AST_LOCK_FAILURE;
2350  }
2351 
2352  /* Success: file created, flocked, and is the one we started with */
2356 
2357  ast_debug(1, "Locked path '%s'\n", path);
2358 
2359  return AST_LOCK_SUCCESS;
2360 }
2361 
2362 static int ast_unlock_path_flock(const char *path)
2363 {
2364  char *s;
2365  struct path_lock *p;
2366 
2367  s = ast_alloca(strlen(path) + 20);
2368 
2371  if (!strcmp(p->path, path)) {
2373  break;
2374  }
2375  }
2378 
2379  if (p) {
2380  snprintf(s, strlen(path) + 19, "%s/lock", path);
2381  unlink(s);
2382  path_lock_destroy(p);
2383  ast_debug(1, "Unlocked path '%s'\n", path);
2384  } else {
2385  ast_debug(1, "Failed to unlock path '%s': "
2386  "lock not found\n", path);
2387  }
2388 
2389  return 0;
2390 }
2391 
2393 {
2394  ast_lock_type = type;
2395 }
2396 
2398 {
2400 
2401  switch (ast_lock_type) {
2403  r = ast_lock_path_lockfile(path);
2404  break;
2405  case AST_LOCK_TYPE_FLOCK:
2406  r = ast_lock_path_flock(path);
2407  break;
2408  }
2409 
2410  return r;
2411 }
2412 
2413 int ast_unlock_path(const char *path)
2414 {
2415  int r = 0;
2416 
2417  switch (ast_lock_type) {
2419  r = ast_unlock_path_lockfile(path);
2420  break;
2421  case AST_LOCK_TYPE_FLOCK:
2422  r = ast_unlock_path_flock(path);
2423  break;
2424  }
2425 
2426  return r;
2427 }
2428 
2429 int ast_record_review(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, const char *path)
2430 {
2431  int silencethreshold;
2432  int maxsilence = 0;
2433  int res = 0;
2434  int cmd = 0;
2435  int max_attempts = 3;
2436  int attempts = 0;
2437  int recorded = 0;
2438  int message_exists = 0;
2439  /* Note that urgent and private are for flagging messages as such in the future */
2440 
2441  /* barf if no pointer passed to store duration in */
2442  if (!duration) {
2443  ast_log(LOG_WARNING, "Error ast_record_review called without duration pointer\n");
2444  return -1;
2445  }
2446 
2447  cmd = '3'; /* Want to start by recording */
2448 
2450 
2451  while ((cmd >= 0) && (cmd != 't')) {
2452  switch (cmd) {
2453  case '1':
2454  if (!message_exists) {
2455  /* In this case, 1 is to record a message */
2456  cmd = '3';
2457  break;
2458  } else {
2459  ast_stream_and_wait(chan, "vm-msgsaved", "");
2460  cmd = 't';
2461  return res;
2462  }
2463  case '2':
2464  /* Review */
2465  ast_verb(3, "Reviewing the recording\n");
2466  cmd = ast_stream_and_wait(chan, recordfile, AST_DIGIT_ANY);
2467  break;
2468  case '3':
2469  message_exists = 0;
2470  /* Record */
2471  ast_verb(3, "R%secording\n", recorded == 1 ? "e-r" : "");
2472  recorded = 1;
2473  if ((cmd = ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, NULL, silencethreshold, maxsilence, path)) == -1) {
2474  /* User has hung up, no options to give */
2475  return cmd;
2476  }
2477  if (cmd == '0') {
2478  break;
2479  } else if (cmd == '*') {
2480  break;
2481  } else {
2482  /* If all is well, a message exists */
2483  message_exists = 1;
2484  cmd = 0;
2485  }
2486  break;
2487  case '4':
2488  case '5':
2489  case '6':
2490  case '7':
2491  case '8':
2492  case '9':
2493  case '*':
2494  case '#':
2495  cmd = ast_play_and_wait(chan, "vm-sorry");
2496  break;
2497  default:
2498  if (message_exists) {
2499  cmd = ast_play_and_wait(chan, "vm-review");
2500  } else {
2501  if (!(cmd = ast_play_and_wait(chan, "vm-torerecord"))) {
2502  cmd = ast_waitfordigit(chan, 600);
2503  }
2504  }
2505 
2506  if (!cmd) {
2507  cmd = ast_waitfordigit(chan, 6000);
2508  }
2509  if (!cmd) {
2510  attempts++;
2511  }
2512  if (attempts > max_attempts) {
2513  cmd = 't';
2514  }
2515  }
2516  }
2517  if (cmd == 't') {
2518  cmd = 0;
2519  }
2520  return cmd;
2521 }
2522 
2523 #define RES_UPONE (1 << 16)
2524 #define RES_EXIT (1 << 17)
2525 #define RES_REPEAT (1 << 18)
2526 #define RES_RESTART ((1 << 19) | RES_REPEAT)
2527 
2528 static int ast_ivr_menu_run_internal(struct ast_channel *chan, struct ast_ivr_menu *menu, void *cbdata);
2529 
2530 static int ivr_dispatch(struct ast_channel *chan, struct ast_ivr_option *option, char *exten, void *cbdata)
2531 {
2532  int res;
2533  int (*ivr_func)(struct ast_channel *, void *);
2534  char *c;
2535  char *n;
2536 
2537  switch (option->action) {
2538  case AST_ACTION_UPONE:
2539  return RES_UPONE;
2540  case AST_ACTION_EXIT:
2541  return RES_EXIT | (((unsigned long)(option->adata)) & 0xffff);
2542  case AST_ACTION_REPEAT:
2543  return RES_REPEAT | (((unsigned long)(option->adata)) & 0xffff);
2544  case AST_ACTION_RESTART:
2545  return RES_RESTART ;
2546  case AST_ACTION_NOOP:
2547  return 0;
2548  case AST_ACTION_BACKGROUND:
2549  res = ast_stream_and_wait(chan, (char *)option->adata, AST_DIGIT_ANY);
2550  if (res < 0) {
2551  ast_log(LOG_NOTICE, "Unable to find file '%s'!\n", (char *)option->adata);
2552  res = 0;
2553  }
2554  return res;
2555  case AST_ACTION_PLAYBACK:
2556  res = ast_stream_and_wait(chan, (char *)option->adata, "");
2557  if (res < 0) {
2558  ast_log(LOG_NOTICE, "Unable to find file '%s'!\n", (char *)option->adata);
2559  res = 0;
2560  }
2561  return res;
2562  case AST_ACTION_MENU:
2563  if ((res = ast_ivr_menu_run_internal(chan, (struct ast_ivr_menu *)option->adata, cbdata)) == -2) {
2564  /* Do not pass entry errors back up, treat as though it was an "UPONE" */
2565  res = 0;
2566  }
2567  return res;
2568  case AST_ACTION_WAITOPTION:
2569  if (!(res = ast_waitfordigit(chan, ast_channel_pbx(chan) ? ast_channel_pbx(chan)->rtimeoutms : 10000))) {
2570  return 't';
2571  }
2572  return res;
2573  case AST_ACTION_CALLBACK:
2574  ivr_func = option->adata;
2575  res = ivr_func(chan, cbdata);
2576  return res;
2577  case AST_ACTION_TRANSFER:
2578  res = ast_parseable_goto(chan, option->adata);
2579  return 0;
2580  case AST_ACTION_PLAYLIST:
2581  case AST_ACTION_BACKLIST:
2582  res = 0;
2583  c = ast_strdupa(option->adata);
2584  while ((n = strsep(&c, ";"))) {
2585  if ((res = ast_stream_and_wait(chan, n,
2586  (option->action == AST_ACTION_BACKLIST) ? AST_DIGIT_ANY : ""))) {
2587  break;
2588  }
2589  }
2590  ast_stopstream(chan);
2591  return res;
2592  default:
2593  ast_log(LOG_NOTICE, "Unknown dispatch function %u, ignoring!\n", option->action);
2594  return 0;
2595  }
2596  return -1;
2597 }
2598 
2599 static int option_exists(struct ast_ivr_menu *menu, char *option)
2600 {
2601  int x;
2602  for (x = 0; menu->options[x].option; x++) {
2603  if (!strcasecmp(menu->options[x].option, option)) {
2604  return x;
2605  }
2606  }
2607  return -1;
2608 }
2609 
2610 static int option_matchmore(struct ast_ivr_menu *menu, char *option)
2611 {
2612  int x;
2613  for (x = 0; menu->options[x].option; x++) {
2614  if ((!strncasecmp(menu->options[x].option, option, strlen(option))) &&
2615  (menu->options[x].option[strlen(option)])) {
2616  return x;
2617  }
2618  }
2619  return -1;
2620 }
2621 
2622 static int read_newoption(struct ast_channel *chan, struct ast_ivr_menu *menu, char *exten, int maxexten)
2623 {
2624  int res = 0;
2625  int ms;
2626  while (option_matchmore(menu, exten)) {
2627  ms = ast_channel_pbx(chan) ? ast_channel_pbx(chan)->dtimeoutms : 5000;
2628  if (strlen(exten) >= maxexten - 1) {
2629  break;
2630  }
2631  if ((res = ast_waitfordigit(chan, ms)) < 1) {
2632  break;
2633  }
2634  exten[strlen(exten) + 1] = '\0';
2635  exten[strlen(exten)] = res;
2636  }
2637  return res > 0 ? 0 : res;
2638 }
2639 
2640 static int ast_ivr_menu_run_internal(struct ast_channel *chan, struct ast_ivr_menu *menu, void *cbdata)
2641 {
2642  /* Execute an IVR menu structure */
2643  int res = 0;
2644  int pos = 0;
2645  int retries = 0;
2646  char exten[AST_MAX_EXTENSION] = "s";
2647  if (option_exists(menu, "s") < 0) {
2648  strcpy(exten, "g");
2649  if (option_exists(menu, "g") < 0) {
2650  ast_log(LOG_WARNING, "No 's' nor 'g' extension in menu '%s'!\n", menu->title);
2651  return -1;
2652  }
2653  }
2654  while (!res) {
2655  while (menu->options[pos].option) {
2656  if (!strcasecmp(menu->options[pos].option, exten)) {
2657  res = ivr_dispatch(chan, menu->options + pos, exten, cbdata);
2658  ast_debug(1, "IVR Dispatch of '%s' (pos %d) yields %d\n", exten, pos, res);
2659  if (res < 0) {
2660  break;
2661  } else if (res & RES_UPONE) {
2662  return 0;
2663  } else if (res & RES_EXIT) {
2664  return res;
2665  } else if (res & RES_REPEAT) {
2666  int maxretries = res & 0xffff;
2667  if ((res & RES_RESTART) == RES_RESTART) {
2668  retries = 0;
2669  } else {
2670  retries++;
2671  }
2672  if (!maxretries) {
2673  maxretries = 3;
2674  }
2675  if ((maxretries > 0) && (retries >= maxretries)) {
2676  ast_debug(1, "Max retries %d exceeded\n", maxretries);
2677  return -2;
2678  } else {
2679  if (option_exists(menu, "g") > -1) {
2680  strcpy(exten, "g");
2681  } else if (option_exists(menu, "s") > -1) {
2682  strcpy(exten, "s");
2683  }
2684  }
2685  pos = 0;
2686  continue;
2687  } else if (res && strchr(AST_DIGIT_ANY, res)) {
2688  ast_debug(1, "Got start of extension, %c\n", res);
2689  exten[1] = '\0';
2690  exten[0] = res;
2691  if ((res = read_newoption(chan, menu, exten, sizeof(exten)))) {
2692  break;
2693  }
2694  if (option_exists(menu, exten) < 0) {
2695  if (option_exists(menu, "i")) {
2696  ast_debug(1, "Invalid extension entered, going to 'i'!\n");
2697  strcpy(exten, "i");
2698  pos = 0;
2699  continue;
2700  } else {
2701  ast_debug(1, "Aborting on invalid entry, with no 'i' option!\n");
2702  res = -2;
2703  break;
2704  }
2705  } else {
2706  ast_debug(1, "New existing extension: %s\n", exten);
2707  pos = 0;
2708  continue;
2709  }
2710  }
2711  }
2712  pos++;
2713  }
2714  ast_debug(1, "Stopping option '%s', res is %d\n", exten, res);
2715  pos = 0;
2716  if (!strcasecmp(exten, "s")) {
2717  strcpy(exten, "g");
2718  } else {
2719  break;
2720  }
2721  }
2722  return res;
2723 }
2724 
2725 int ast_ivr_menu_run(struct ast_channel *chan, struct ast_ivr_menu *menu, void *cbdata)
2726 {
2727  int res = ast_ivr_menu_run_internal(chan, menu, cbdata);
2728  /* Hide internal coding */
2729  return res > 0 ? 0 : res;
2730 }
2731 
2732 char *ast_read_textfile(const char *filename)
2733 {
2734  int fd, count = 0, res;
2735  char *output = NULL;
2736  struct stat filesize;
2737 
2738  if (stat(filename, &filesize) == -1) {
2739  ast_log(LOG_WARNING, "Error can't stat %s\n", filename);
2740  return NULL;
2741  }
2742 
2743  count = filesize.st_size + 1;
2744 
2745  if ((fd = open(filename, O_RDONLY)) < 0) {
2746  ast_log(LOG_WARNING, "Cannot open file '%s' for reading: %s\n", filename, strerror(errno));
2747  return NULL;
2748  }
2749 
2750  if ((output = ast_malloc(count))) {
2751  res = read(fd, output, count - 1);
2752  if (res == count - 1) {
2753  output[res] = '\0';
2754  } else {
2755  ast_log(LOG_WARNING, "Short read of %s (%d of %d): %s\n", filename, res, count - 1, strerror(errno));
2756  ast_free(output);
2757  output = NULL;
2758  }
2759  }
2760 
2761  close(fd);
2762 
2763  return output;
2764 }
2765 
2766 static int parse_options(const struct ast_app_option *options, void *_flags, char **args, char *optstr, int flaglen)
2767 {
2768  char *s, *arg;
2769  int curarg, res = 0;
2770  unsigned int argloc;
2771  struct ast_flags *flags = _flags;
2772  struct ast_flags64 *flags64 = _flags;
2773 
2774  if (flaglen == 32) {
2775  ast_clear_flag(flags, AST_FLAGS_ALL);
2776  } else {
2777  flags64->flags = 0;
2778  }
2779 
2780  if (!optstr) {
2781  return 0;
2782  }
2783 
2784  s = optstr;
2785  while (*s) {
2786  curarg = *s++ & 0x7f; /* the array (in app.h) has 128 entries */
2787  argloc = options[curarg].arg_index;
2788  if (*s == '(') {
2789  int paren = 1, quote = 0;
2790  int parsequotes = (s[1] == '"') ? 1 : 0;
2791 
2792  /* Has argument */
2793  arg = ++s;
2794  for (; *s; s++) {
2795  if (*s == '(' && !quote) {
2796  paren++;
2797  } else if (*s == ')' && !quote) {
2798  /* Count parentheses, unless they're within quotes (or backslashed, below) */
2799  paren--;
2800  } else if (*s == '"' && parsequotes) {
2801  /* Leave embedded quotes alone, unless they are the first character */
2802  quote = quote ? 0 : 1;
2803  ast_copy_string(s, s + 1, INT_MAX);
2804  s--;
2805  } else if (*s == '\\') {
2806  if (!quote) {
2807  /* If a backslash is found outside of quotes, remove it */
2808  ast_copy_string(s, s + 1, INT_MAX);
2809  } else if (quote && s[1] == '"') {
2810  /* Backslash for a quote character within quotes, remove the backslash */
2811  ast_copy_string(s, s + 1, INT_MAX);
2812  } else {
2813  /* Backslash within quotes, keep both characters */
2814  s++;
2815  }
2816  }
2817 
2818  if (paren == 0) {
2819  break;
2820  }
2821  }
2822  /* This will find the closing paren we found above, or none, if the string ended before we found one. */
2823  if ((s = strchr(s, ')'))) {
2824  if (argloc) {
2825  args[argloc - 1] = arg;
2826  }
2827  *s++ = '\0';
2828  } else {
2829  ast_log(LOG_WARNING, "Missing closing parenthesis for argument '%c' in string '%s'\n", curarg, arg);
2830  res = -1;
2831  break;
2832  }
2833  } else if (argloc) {
2834  args[argloc - 1] = "";
2835  }
2836  if (flaglen == 32) {
2837  ast_set_flag(flags, options[curarg].flag);
2838  } else {
2839  ast_set_flag64(flags64, options[curarg].flag);
2840  }
2841  }
2842 
2843  return res;
2844 }
2845 
2846 int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
2847 {
2848  return parse_options(options, flags, args, optstr, 32);
2849 }
2850 
2851 int ast_app_parse_options64(const struct ast_app_option *options, struct ast_flags64 *flags, char **args, char *optstr)
2852 {
2853  return parse_options(options, flags, args, optstr, 64);
2854 }
2855 
2856 void ast_app_options2str64(const struct ast_app_option *options, struct ast_flags64 *flags, char *buf, size_t len)
2857 {
2858  unsigned int i, found = 0;
2859  for (i = 32; i < 128 && found < len; i++) {
2860  if (ast_test_flag64(flags, options[i].flag)) {
2861  buf[found++] = i;
2862  }
2863  }
2864  buf[found] = '\0';
2865 }
2866 
2867 int ast_get_encoded_char(const char *stream, char *result, size_t *consumed)
2868 {
2869  int i;
2870  *consumed = 1;
2871  *result = 0;
2872  if (ast_strlen_zero(stream)) {
2873  *consumed = 0;
2874  return -1;
2875  }
2876 
2877  if (*stream == '\\') {
2878  *consumed = 2;
2879  switch (*(stream + 1)) {
2880  case 'n':
2881  *result = '\n';
2882  break;
2883  case 'r':
2884  *result = '\r';
2885  break;
2886  case 't':
2887  *result = '\t';
2888  break;
2889  case 'x':
2890  /* Hexadecimal */
2891  if (strchr("0123456789ABCDEFabcdef", *(stream + 2)) && *(stream + 2) != '\0') {
2892  *consumed = 3;
2893  if (*(stream + 2) <= '9') {
2894  *result = *(stream + 2) - '0';
2895  } else if (*(stream + 2) <= 'F') {
2896  *result = *(stream + 2) - 'A' + 10;
2897  } else {
2898  *result = *(stream + 2) - 'a' + 10;
2899  }
2900  } else {
2901  ast_log(LOG_ERROR, "Illegal character '%c' in hexadecimal string\n", *(stream + 2));
2902  return -1;
2903  }
2904 
2905  if (strchr("0123456789ABCDEFabcdef", *(stream + 3)) && *(stream + 3) != '\0') {
2906  *consumed = 4;
2907  *result <<= 4;
2908  if (*(stream + 3) <= '9') {
2909  *result += *(stream + 3) - '0';
2910  } else if (*(stream + 3) <= 'F') {
2911  *result += *(stream + 3) - 'A' + 10;
2912  } else {
2913  *result += *(stream + 3) - 'a' + 10;
2914  }
2915  }
2916  break;
2917  case '0':
2918  /* Octal */
2919  *consumed = 2;
2920  for (i = 2; ; i++) {
2921  if (strchr("01234567", *(stream + i)) && *(stream + i) != '\0') {
2922  (*consumed)++;
2923  ast_debug(5, "result was %d, ", *result);
2924  *result <<= 3;
2925  *result += *(stream + i) - '0';
2926  ast_debug(5, "is now %d\n", *result);
2927  } else {
2928  break;
2929  }
2930  }
2931  break;
2932  default:
2933  *result = *(stream + 1);
2934  }
2935  } else {
2936  *result = *stream;
2937  *consumed = 1;
2938  }
2939  return 0;
2940 }
2941 
2942 char *ast_get_encoded_str(const char *stream, char *result, size_t result_size)
2943 {
2944  char *cur = result;
2945  size_t consumed;
2946 
2947  while (cur < result + result_size - 1 && !ast_get_encoded_char(stream, cur, &consumed)) {
2948  cur++;
2949  stream += consumed;
2950  }
2951  *cur = '\0';
2952  return result;
2953 }
2954 
2955 int ast_str_get_encoded_str(struct ast_str **str, int maxlen, const char *stream)
2956 {
2957  char next, *buf;
2958  size_t offset = 0;
2959  size_t consumed;
2960 
2961  if (strchr(stream, '\\')) {
2962  while (!ast_get_encoded_char(stream, &next, &consumed)) {
2963  if (offset + 2 > ast_str_size(*str) && maxlen > -1) {
2964  ast_str_make_space(str, maxlen > 0 ? maxlen : (ast_str_size(*str) + 48) * 2 - 48);
2965  }
2966  if (offset + 2 > ast_str_size(*str)) {
2967  break;
2968  }
2969  buf = ast_str_buffer(*str);
2970  buf[offset++] = next;
2971  stream += consumed;
2972  }
2973  buf = ast_str_buffer(*str);
2974  buf[offset++] = '\0';
2975  ast_str_update(*str);
2976  } else {
2977  ast_str_set(str, maxlen, "%s", stream);
2978  }
2979  return 0;
2980 }
2981 
2983 {
2984  closefrom(n + 1);
2985 }
2986 
2987 int ast_safe_fork(int stop_reaper)
2988 {
2989  sigset_t signal_set, old_set;
2990  int pid;
2991 
2992  /* Don't let the default signal handler for children reap our status */
2993  if (stop_reaper) {
2995  }
2996 
2997  /* GCC 4.9 gives a bogus "right-hand operand of comma expression has
2998  * no effect" warning */
2999  (void) sigfillset(&signal_set);
3000  pthread_sigmask(SIG_BLOCK, &signal_set, &old_set);
3001 
3002  pid = fork();
3003 
3004  if (pid != 0) {
3005  /* Fork failed or parent */
3006  pthread_sigmask(SIG_SETMASK, &old_set, NULL);
3007  if (!stop_reaper && pid > 0) {
3008  struct zombie *cur = ast_calloc(1, sizeof(*cur));
3009  if (cur) {
3010  cur->pid = pid;
3016  ast_log(LOG_ERROR, "Shaun of the Dead wants to kill zombies, but can't?!!\n");
3018  }
3019  }
3020  }
3021  }
3022  return pid;
3023  } else {
3024  /* Child */
3025 #ifdef HAVE_CAP
3026  cap_set_proc(child_cap);
3027 #endif
3028 
3029  /* Before we unblock our signals, return our trapped signals back to the defaults */
3030  signal(SIGHUP, SIG_DFL);
3031  signal(SIGCHLD, SIG_DFL);
3032  signal(SIGINT, SIG_DFL);
3033  signal(SIGURG, SIG_DFL);
3034  signal(SIGTERM, SIG_DFL);
3035  signal(SIGPIPE, SIG_DFL);
3036  signal(SIGXFSZ, SIG_DFL);
3037 
3038  /* unblock important signal handlers */
3039  if (pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL)) {
3040  ast_log(LOG_WARNING, "unable to unblock signals: %s\n", strerror(errno));
3041  _exit(1);
3042  }
3043 
3044  return pid;
3045  }
3046 }
3047 
3049 {
3051 }
3052 
3053 int ast_app_parse_timelen(const char *timestr, int *result, enum ast_timelen unit)
3054 {
3055  int res;
3056  char u[10];
3057 #ifdef HAVE_LONG_DOUBLE_WIDER
3058  long double amount;
3059  #define FMT "%30Lf%9s"
3060 #else
3061  double amount;
3062  #define FMT "%30lf%9s"
3063 #endif
3064  if (!timestr) {
3065  return -1;
3066  }
3067 
3068  res = sscanf(timestr, FMT, &amount, u);
3069 
3070  if (res == 0 || res == EOF) {
3071 #undef FMT
3072  return -1;
3073  } else if (res == 2) {
3074  switch (u[0]) {
3075  case 'h':
3076  case 'H':
3077  unit = TIMELEN_HOURS;
3078  if (u[1] != '\0') {
3079  return -1;
3080  }
3081  break;
3082  case 's':
3083  case 'S':
3084  unit = TIMELEN_SECONDS;
3085  if (u[1] != '\0') {
3086  return -1;
3087  }
3088  break;
3089  case 'm':
3090  case 'M':
3091  if (toupper(u[1]) == 'S') {
3092  unit = TIMELEN_MILLISECONDS;
3093  if (u[2] != '\0') {
3094  return -1;
3095  }
3096  } else if (u[1] == '\0') {
3097  unit = TIMELEN_MINUTES;
3098  } else {
3099  return -1;
3100  }
3101  break;
3102  default:
3103  return -1;
3104  }
3105  }
3106 
3107  switch (unit) {
3108  case TIMELEN_HOURS:
3109  amount *= 60;
3110  /* fall-through */
3111  case TIMELEN_MINUTES:
3112  amount *= 60;
3113  /* fall-through */
3114  case TIMELEN_SECONDS:
3115  amount *= 1000;
3116  /* fall-through */
3117  case TIMELEN_MILLISECONDS:
3118  ;
3119  }
3120  *result = amount > INT_MAX ? INT_MAX : (int) amount;
3121  return 0;
3122 }
3123 
3125 {
3126  return queue_topic_all;
3127 }
3128 
3129 struct stasis_topic *ast_queue_topic(const char *queuename)
3130 {
3131  return stasis_topic_pool_get_topic(queue_topic_pool, queuename);
3132 }
3133 
3134 static void app_cleanup(void)
3135 {
3136 #ifdef HAS_CAP
3137  cap_free(child_cap);
3138 #endif
3139  ao2_cleanup(queue_topic_pool);
3140  queue_topic_pool = NULL;
3141  ao2_cleanup(queue_topic_all);
3142  queue_topic_all = NULL;
3143 }
3144 
3145 int app_init(void)
3146 {
3148 #ifdef HAVE_CAP
3149  child_cap = cap_from_text("cap_net_admin-eip");
3150 #endif
3151  queue_topic_all = stasis_topic_create("queue:all");
3152  if (!queue_topic_all) {
3153  return -1;
3154  }
3155  queue_topic_pool = stasis_topic_pool_create(queue_topic_all);
3156  if (!queue_topic_pool) {
3157  return -1;
3158  }
3159  return 0;
3160 }
unsigned int module_version
The version of this function table.
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
enum ast_getdata_result ast_app_getdata_terminator(struct ast_channel *c, const char *prompt, char *s, int maxlen, int timeout, char *terminator)
ast_app_getdata
Definition: main/app.c:213
static int ast_unlock_path_flock(const char *path)
Definition: main/app.c:2362
pid_t pid
Definition: main/app.c:78
int ast_safe_sleep(struct ast_channel *chan, int ms)
Wait for a specified amount of time, looking for hangups.
Definition: channel.c:1570
int ast_queue_hangup(struct ast_channel *chan)
Queue a hangup frame.
Definition: channel.c:1146
static const char type[]
Definition: chan_ooh323.c:109
int app_init(void)
Initialize the application core.
Definition: main/app.c:3145
Tone Indication Support.
char digit
int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Looks to see if adding anything to this extension might match something. (exists ^ canmatch) ...
Definition: pbx.c:4199
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:122
Main Channel structure associated with a channel.
channel group info
Definition: channel.h:2906
#define RES_EXIT
Definition: main/app.c:2524
ast_ivr_action action
struct ast_module * module
The module for the voicemail provider.
struct stasis_topic * ast_queue_topic(const char *queuename)
Get the Stasis Message Bus API topic for queue messages for a particular queue name.
Definition: main/app.c:3129
static int __ast_play_and_record(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, int *sound_duration, int beep, int silencethreshold, int maxsilence, const char *path, int prepend, const char *acceptdtmf, const char *canceldtmf, int skip_confirmation_sound, enum ast_record_if_exists if_exists)
Definition: main/app.c:1520
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Definition: file.c:1250
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
unsigned int __ast_app_separate_args(char *buf, char delim, int remove_chars, char **array, int arraylen)
Separate a string into arguments in an array.
Definition: main/app.c:2139
int ast_vm_msg_remove(const char *mailbox, const char *context, size_t num_msgs, const char *folder, const char *msgs[])
Remove/delete messages from a mailbox folder.
Definition: main/app.c:787
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: linkedlists.h:420
static const struct ast_vm_functions vm_table
static const char default_acceptdtmf[]
Definition: main/app.c:1929
static AO2_GLOBAL_OBJ_STATIC(vm_provider)
The container for the voicemail provider.
int ast_play_and_prepend(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int *duration, int *sound_duration, int beep, int silencethreshold, int maxsilence)
Record a file based on input frm a channel. Recording is performed in &#39;prepend&#39; mode which works a li...
Definition: main/app.c:1942
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
Definition: autoservice.c:200
int ast_app_inboxcount2(const char *mailboxes, int *urgentmsgs, int *newmsgs, int *oldmsgs)
Determine number of urgent/new/old messages in a mailbox.
Definition: main/app.c:709
static struct stasis_topic * queue_topic_all
Definition: main/app.c:90
static struct ast_tone_zone * ast_tone_zone_unref(struct ast_tone_zone *tz)
Release a reference to an ast_tone_zone.
Definition: indications.h:205
#define AST_RWLIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a read/write list of specified type, statically initialized...
Definition: linkedlists.h:332
int pbx_exec(struct ast_channel *c, struct ast_app *app, const char *data)
Execute an application.
Definition: pbx_app.c:471
void ast_unreplace_sigchld(void)
Restore the SIGCHLD handler.
Definition: extconf.c:815
int ast_app_getdata_full(struct ast_channel *c, const char *prompt, char *s, int maxlen, int timeout, int audiofd, int ctrlfd)
Full version with audiofd and controlfd. NOTE: returns &#39;2&#39; on ctrlfd available, not &#39;1&#39; like other fu...
Definition: main/app.c:267
int ast_vm_msg_move(const char *mailbox, const char *context, size_t num_msgs, const char *oldfolder, const char *old_msg_ids[], const char *newfolder)
Move messages from one folder to another.
Definition: main/app.c:773
int ast_app_has_voicemail(const char *mailboxes, const char *folder)
Determine if a given mailbox has any voicemail If folder is NULL, defaults to "INBOX". If folder is "INBOX", includes the number of messages in the "Urgent" folder.
Definition: main/app.c:672
static int vm_greeter_warnings
Definition: main/app.c:556
void *(* alloc)(struct ast_channel *chan, void *params)
Definition: channel.h:227
#define AST_DIGIT_ANY
Definition: file.h:48
int ast_app_inboxcount(const char *mailboxes, int *newmsgs, int *oldmsgs)
Determine number of new/old messages in a mailbox.
Definition: main/app.c:694
int ast_activate_generator(struct ast_channel *chan, struct ast_generator *gen, void *params)
Definition: channel.c:2956
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition: channel.c:4309
size_t ast_str_size(const struct ast_str *buf)
Returns the current maximum length (without reallocation) of the current buffer.
Definition: strings.h:699
AST_THREADSTORAGE_PUBLIC(ast_str_thread_global_buf)
int ast_app_parse_timelen(const char *timestr, int *result, enum ast_timelen unit)
Common routine to parse time lengths, with optional time unit specifier.
Definition: main/app.c:3053
void ast_dsp_free(struct ast_dsp *dsp)
Definition: dsp.c:1770
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
Convenient Signal Processing routines.
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:51
static const char default_canceldtmf[]
Definition: main/app.c:1930
int ast_app_group_set_channel(struct ast_channel *chan, const char *data)
Set the group for a channel, splitting the provided data into group and category, if specified...
Definition: main/app.c:1976
#define ast_set_flag(p, flag)
Definition: utils.h:70
int ast_check_hangup_locked(struct ast_channel *chan)
Definition: channel.c:455
Stasis Message Bus API. See Stasis Message Bus API for detailed documentation.
#define LOG_WARNING
Definition: logger.h:274
int ast_vm_greeter_is_registered(void)
Determine if a voicemail greeter provider is registered.
Definition: main/app.c:558
static int parse_tone_uri(char *tone_parser, const char **tone_indication, const char **tone_zone)
Definition: main/app.c:1318
static int sayname(struct ast_channel *chan, const char *mailbox, const char *context)
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
static int maxsilence
#define ast_str_make_space(buf, new_len)
Definition: strings.h:780
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
Voicemail greeter function table definition.
int ast_unlock_path(const char *path)
Unlock a path.
Definition: main/app.c:2413
static struct test_val d
static struct stasis_rest_handlers mailboxes
REST handler for /api-docs/mailboxes.json.
struct ast_dsp * ast_dsp_new(void)
Allocates a new dsp, assumes 8khz for internal sample rate.
Definition: dsp.c:1745
static int tmp()
Definition: bt_open.c:389
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
unsigned int flags
Definition: utils.h:200
struct ast_tone_zone * ast_channel_zone(const struct ast_channel *chan)
void ast_close_fds_above_n(int n)
Common routine for child processes, to close all fds prior to exec(2)
Definition: main/app.c:2982
static pthread_t shaun_of_the_dead_thread
Definition: main/app.c:75
ast_record_if_exists
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition: linkedlists.h:438
Test Framework API.
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4289
static int option_matchmore(struct ast_ivr_menu *menu, char *option)
Definition: main/app.c:2610
static int messagecount(const char *mailbox_id, const char *folder)
int ast_ignore_pattern(const char *context, const char *pattern)
Checks to see if a number should be ignored.
Definition: pbx.c:6921
unsigned int stop
Definition: app_meetme.c:1098
static enum AST_LOCK_RESULT ast_lock_path_lockfile(const char *path)
Definition: main/app.c:2203
Definition of a media format.
Definition: format.c:43
int ast_senddigit_external(struct ast_channel *chan, char digit, unsigned int duration)
Send a DTMF digit to a channel from an external thread.
Definition: channel.c:4949
#define ao2_global_obj_ref(holder)
Definition: astobj2.h:925
#define VM_GREETER_MODULE_VERSION
#define ast_set_flag64(p, flag)
Definition: utils.h:127
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:449
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:406
#define ast_assert(a)
Definition: utils.h:710
int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
Parses a string containing application options and sets flags/arguments.
Definition: main/app.c:2846
#define ast_opt_transmit_silence
Definition: options.h:124
static struct test_val c
const char * ast_format_get_name(const struct ast_format *format)
Get the name associated with a format.
Definition: format.c:334
static void app_cleanup(void)
Definition: main/app.c:3134
int ast_app_run_sub(struct ast_channel *autoservice_chan, struct ast_channel *sub_chan, const char *sub_location, const char *sub_args, int ignore_hangup)
Run a subroutine on a channel, placing an optional second channel into autoservice.
Definition: main/app.c:418
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
struct ast_vm_mailbox_snapshot * ast_vm_mailbox_snapshot_destroy(struct ast_vm_mailbox_snapshot *mailbox_snapshot)
destroy a snapshot
Definition: main/app.c:765
struct stasis_topic * stasis_topic_pool_get_topic(struct stasis_topic_pool *pool, const char *topic_name)
Find or create a topic in the pool.
Definition: stasis.c:1884
const char * str
Definition: app_jack.c:147
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
static int ast_ivr_menu_run_internal(struct ast_channel *chan, struct ast_ivr_menu *menu, void *cbdata)
Definition: main/app.c:2640
const char * args
void ast_playtones_stop(struct ast_channel *chan)
Stop playing tones on a channel.
Definition: indications.c:393
#define NULL
Definition: resample.c:96
void ast_app_options2str64(const struct ast_app_option *options, struct ast_flags64 *flags, char *buf, size_t len)
Given a list of options array, return an option string based on passed flags.
Definition: main/app.c:2856
Definitions to aid in the use of thread local storage.
char * end
Definition: eagi_proxy.c:73
int ast_senddigit(struct ast_channel *chan, char digit, unsigned int duration)
Send a DTMF digit to a channel.
Definition: channel.c:4936
int ast_filedelete(const char *filename, const char *fmt)
Deletes a file.
Definition: file.c:1098
#define AST_FRAME_DTMF
int ast_app_dtget(struct ast_channel *chan, const char *context, char *collect, size_t size, int maxlen, int timeout)
This function presents a dialtone and reads an extension into &#39;collect&#39; which must be a pointer to a ...
Definition: main/app.c:139
static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
Check the given mailbox&#39;s message count.
int ast_vm_msg_forward(const char *from_mailbox, const char *from_context, const char *from_folder, const char *to_mailbox, const char *to_context, const char *to_folder, size_t num_msgs, const char *msg_ids[], int delete_old)
forward a message from one mailbox to another.
Definition: main/app.c:799
Structure used to handle a large number of boolean flags == used only in app_dial?
Definition: utils.h:204
int ast_play_and_record_full(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, int *sound_duration, int beep, int silencethreshold, int maxsilence, const char *path, const char *acceptdtmf, const char *canceldtmf, int skip_confirmation_sound, enum ast_record_if_exists if_exists)
Record a file based on input from a channel This function will play "auth-thankyou" upon successful r...
Definition: main/app.c:1932
struct stasis_topic * ast_queue_topic_all(void)
Get the Stasis Message Bus API topic for queue messages.
Definition: main/app.c:3124
#define AST_FILE_MODE
Definition: asterisk.h:32
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:614
int ast_channel_priority(const struct ast_channel *chan)
#define ast_verb(level,...)
Definition: logger.h:463
void() ast_vm_msg_play_cb(struct ast_channel *chan, const char *playfile, int duration)
Voicemail playback callback function definition.
int ast_linear_stream(struct ast_channel *chan, const char *filename, int fd, int allowoverride)
Stream a filename (or file descriptor) as a generator.
Definition: main/app.c:1029
static void linear_release(struct ast_channel *chan, void *params)
Definition: main/app.c:948
const char * ast_vm_index_to_foldername(int id)
Return name of folder, given an id.
Definition: main/app.c:743
#define FMT
def from_mailbox(key, val, section, pjsip, nmapped)
struct ast_frame_subclass subclass
int totalsilence
Definition: dsp.c:409
ast_getdata_result
Utility functions.
#define ast_module_unref(mod)
Release a reference to the module.
Definition: module.h:469
#define VM_GREETER_API_CALL(res, api_call, api_parms)
Definition: main/app.c:658
struct stasis_topic_pool * stasis_topic_pool_create(struct stasis_topic *pooled_topic)
Create a topic pool that routes messages from dynamically generated topics to the given topic...
Definition: stasis.c:1833
struct ast_format * ast_channel_readformat(struct ast_channel *chan)
off_t ast_tellstream(struct ast_filestream *fs)
Tell where we are in a stream.
Definition: file.c:1048
void ast_frame_dtor(struct ast_frame *frame)
NULL-safe wrapper for ast_frfree, good for RAII_VAR.
Definition: main/frame.c:187
static int set_read_to_slin(struct ast_channel *chan, struct ast_format **orig_format)
Sets a channel&#39;s read format to AST_FORMAT_SLINEAR, recording its original format.
Definition: main/app.c:1486
#define ast_pthread_create_background(a, b, c, d)
Definition: utils.h:567
Number structure.
Definition: app_followme.c:154
#define ao2_bump(obj)
Definition: astobj2.h:491
static char * table
Definition: cdr_odbc.c:58
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:1065
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:77
static char mailbox[AST_MAX_MAILBOX_UNIQUEID]
Definition: chan_mgcp.c:207
int ast_app_group_get_count(const char *group, const char *category)
Get the current channel count of the specified group and category.
Definition: main/app.c:2023
static int dtmf_stream(struct ast_channel *chan, const char *digits, int between, unsigned int duration, int is_external)
Definition: main/app.c:853
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
#define VM_API_CALL(res, api_call, api_parms)
Definition: main/app.c:637
static struct stasis_topic_pool * queue_topic_pool
Definition: main/app.c:91
#define AST_MALLOCD_HDR
int ast_app_group_list_rdlock(void)
Read Lock the group count list.
Definition: main/app.c:2124
enum ast_format_cmp_res ast_format_cmp(const struct ast_format *format1, const struct ast_format *format2)
Compare two formats.
Definition: format.c:201
static int option_exists(struct ast_ivr_menu *menu, char *option)
Definition: main/app.c:2599
struct zombie::@320 list
A structure to hold the description of an application &#39;option&#39;.
static struct ast_frame * make_silence(const struct ast_frame *orig)
Construct a silence frame of the same duration as orig.
Definition: main/app.c:1434
General Asterisk PBX channel definitions.
Asterisk JSON abstraction layer.
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Definition: clicompat.c:19
Asterisk file paths, configured in asterisk.conf.
#define AST_FRIENDLY_OFFSET
Offset into a frame&#39;s data buffer.
static int quote(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
int ast_set_read_format(struct ast_channel *chan, struct ast_format *format)
Sets read format on channel chan.
Definition: channel.c:5766
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
A set of tones for a given locale.
Definition: indications.h:74
Definition: dsp.c:405
static int ast_unlock_path_lockfile(const char *path)
Definition: main/app.c:2240
#define AST_PTHREADT_NULL
Definition: lock.h:66
int ast_control_streamfile_w_cb(struct ast_channel *chan, const char *file, const char *fwd, const char *rev, const char *stop, const char *suspend, const char *restart, int skipms, long *offsetms, ast_waitstream_fr_cb cb)
Stream a file with fast forward, pause, reverse, restart.
Definition: main/app.c:1245
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
int ast_app_exec_macro(struct ast_channel *autoservice_chan, struct ast_channel *macro_chan, const char *macro_args)
Run a macro on a channel, placing an optional second channel into autoservice.
Definition: main/app.c:290
#define ast_poll(a, b, c)
Definition: poll-compat.h:88
struct ast_pbx * ast_channel_pbx(const struct ast_channel *chan)
int ast_app_group_update(struct ast_channel *old, struct ast_channel *new)
Update all group counting for a channel to a new one.
Definition: main/app.c:2083
static int silencethreshold
int ast_parseable_goto(struct ast_channel *chan, const char *goto_string)
Definition: pbx.c:8859
#define AST_MAX_EXTENSION
Definition: channel.h:135
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:493
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:556
int ast_play_and_record(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, int *sound_duration, int silencethreshold, int maxsilence, const char *path)
Record a file based on input from a channel. Use default accept and cancel DTMF. This function will p...
Definition: main/app.c:1937
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition: strings.h:85
int ast_str_get_encoded_str(struct ast_str **str, int maxlen, const char *stream)
Decode a stream of encoded control or extended ASCII characters.
Definition: main/app.c:2955
#define VM_MODULE_VERSION
long int ast_random(void)
Definition: main/utils.c:2064
union ast_frame::@250 data
#define AST_RWLIST_REMOVE_CURRENT
Definition: linkedlists.h:569
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
static struct ast_tone_zone_sound * ast_tone_zone_sound_unref(struct ast_tone_zone_sound *ts)
Release a reference to an ast_tone_zone_sound.
Definition: indications.h:227
int autoclose
Definition: main/app.c:943
A set of macros to manage forward-linked lists.
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:193
int ast_waitstream_fr(struct ast_channel *c, const char *breakon, const char *forward, const char *rewind, int ms)
Same as waitstream but allows stream to be forwarded or rewound.
Definition: file.c:1745
int ast_set_write_format(struct ast_channel *chan, struct ast_format *format)
Sets write format on channel chan.
Definition: channel.c:5807
struct stasis_topic * stasis_topic_create(const char *name)
Create a new topic.
Definition: stasis.c:618
struct path_lock::@321 le
void ast_vm_greeter_unregister(const char *module_name)
Unregister the specified voicemail greeter provider.
Definition: main/app.c:601
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
Definition: pbx.c:4179
static void * shaun_of_the_dead(void *data)
Definition: main/app.c:94
void ast_replace_sigchld(void)
Replace the SIGCHLD handler.
Definition: extconf.c:801
char * group
Definition: channel.h:2909
const char * ast_channel_exten(const struct ast_channel *chan)
Core PBX routines and definitions.
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
Definition: autoservice.c:266
#define RES_REPEAT
Definition: main/app.c:2525
struct ast_module * module
The module for the voicemail greeter provider.
#define AST_RWLIST_TRAVERSE_SAFE_BEGIN
Definition: linkedlists.h:544
const char * ast_app_expand_sub_args(struct ast_channel *chan, const char *args)
Add missing context/exten to subroutine argument string.
Definition: main/app.c:368
int ast_app_group_match_get_count(const char *groupmatch, const char *category)
Get the current channel count of all groups that match the specified pattern and category.
Definition: main/app.c:2043
static int read_newoption(struct ast_channel *chan, struct ast_ivr_menu *menu, char *exten, int maxexten)
Definition: main/app.c:2622
struct ast_channel * chan
Definition: channel.h:2907
#define AST_LIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a list of specified type, statically initialized.
Definition: linkedlists.h:290
uint64_t flags
Definition: utils.h:205
void ast_dsp_set_threshold(struct ast_dsp *dsp, int threshold)
Set the minimum average magnitude threshold to determine talking by the DSP.
Definition: dsp.c:1775
#define ast_test_suite_event_notify(s, f,...)
Definition: test.h:196
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:290
struct ast_silence_generator * ast_channel_start_silence_generator(struct ast_channel *chan)
Starts a silence generator on the given channel.
Definition: channel.c:8183
struct ast_format * origwfmt
Definition: main/app.c:945
int ast_app_messagecount(const char *mailbox_id, const char *folder)
Get the number of messages in a given mailbox folder.
Definition: main/app.c:735
control_tone_frame_response_result
Definition: main/app.c:1274
const char * ast_config_AST_DATA_DIR
Definition: options.c:158
static enum AST_LOCK_RESULT ast_lock_path_flock(const char *path)
Definition: main/app.c:2277
int __ast_vm_greeter_register(const struct ast_vm_greeter_functions *vm_table, struct ast_module *module)
Set voicemail greeter function callbacks.
Definition: main/app.c:569
static int skipms
struct ast_vm_mailbox_snapshot * ast_vm_mailbox_snapshot_create(const char *mailbox, const char *context, const char *folder, int descending, enum ast_vm_snapshot_sort_val sort_val, int combine_INBOX_and_OLD)
Create a snapshot of a mailbox which contains information about every msg.
Definition: main/app.c:751
int ast_app_sayname(struct ast_channel *chan, const char *mailbox_id)
Play a recorded user name for the mailbox to the specified channel.
Definition: main/app.c:727
#define LOG_ERROR
Definition: logger.h:285
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:730
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
void() ast_waitstream_fr_cb(struct ast_channel *chan, long ms, enum ast_waitstream_fr_cb_values val)
callback used during dtmf controlled file playback to indicate location of playback in a file after r...
Definition: file.h:65
int ast_control_streamfile(struct ast_channel *chan, const char *file, const char *fwd, const char *rev, const char *stop, const char *suspend, const char *restart, int skipms, long *offsetms)
Stream a file with fast forward, pause, reverse, restart.
Definition: main/app.c:1259
void ast_dtmf_stream_external(struct ast_channel *chan, const char *digits, int between, unsigned int duration)
Send a string of DTMF digits to a channel from an external thread.
Definition: main/app.c:936
static int array(struct ast_channel *chan, const char *cmd, char *var, const char *value)
const char * module_name
The name of the module that provides the voicemail greeter functionality.
int ast_app_group_split_group(const char *data, char *group, int group_max, char *category, int category_max)
Split a group string into group and category, returning a default category if none is provided...
Definition: main/app.c:1949
struct ast_frame * ast_readframe(struct ast_filestream *s)
Read a frame from a filestream.
Definition: file.c:899
static int maxretries
Definition: res_adsi.c:60
#define ao2_global_obj_release(holder)
Definition: astobj2.h:865
ast_lock_type
Definition: check_expr.c:35
Stack applications callback functions.
int ast_stream_rewind(struct ast_filestream *fs, off_t ms)
Rewind stream ms.
Definition: file.c:1063
struct ast_tone_zone * ast_get_indication_zone(const char *country)
locate ast_tone_zone
Definition: indications.c:433
static const struct ast_app_stack_funcs * app_stack_callbacks
Definition: main/app.c:361
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
int errno
int ast_control_tone(struct ast_channel *chan, const char *tone)
Controls playback of a tone.
Definition: main/app.c:1339
Description of a tone.
Definition: indications.h:35
struct ast_tone_zone_sound * ast_get_indication_tone(const struct ast_tone_zone *zone, const char *indication)
Locate a tone zone sound.
Definition: indications.c:455
#define comment
Definition: ael_lex.c:976
int ast_app_group_discard(struct ast_channel *chan)
Discard all group counting for a channel.
Definition: main/app.c:2102
struct ast_filestream * ast_writefile(const char *filename, const char *type, const char *comment, int flags, int check, mode_t mode)
Starts writing a file.
Definition: file.c:1361
static void * linear_alloc(struct ast_channel *chan, void *params)
Definition: main/app.c:995
static void vm_warn_no_provider(void)
Definition: main/app.c:630
static struct ast_generator linearstream
Definition: main/app.c:1022
#define LOG_NOTICE
Definition: logger.h:263
int ast_seekstream(struct ast_filestream *fs, off_t sample_offset, int whence)
Seeks into stream.
Definition: file.c:1038
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:409
int ast_app_run_macro(struct ast_channel *autoservice_chan, struct ast_channel *macro_chan, const char *macro_name, const char *macro_args)
Run a macro on a channel, placing an optional second channel into autoservice.
Definition: main/app.c:337
long int flag
Definition: f2c.h:83
void ast_set_lock_type(enum AST_LOCK_TYPE type)
Set the type of locks used by ast_lock_path()
Definition: main/app.c:2392
void ast_channel_stop_silence_generator(struct ast_channel *chan, struct ast_silence_generator *state)
Stops a previously-started silence generator on the given channel.
Definition: channel.c:8229
#define ast_free(a)
Definition: astmm.h:182
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
void ast_install_stack_functions(const struct ast_app_stack_funcs *funcs)
Set stack application function callbacks.
Definition: main/app.c:363
static enum control_tone_frame_response_result control_tone_frame_response(struct ast_channel *chan, struct ast_frame *fr, struct ast_tone_zone_sound *ts, const char *tone, int *paused)
Definition: main/app.c:1280
int ast_app_group_list_wrlock(void)
Write Lock the group count list.
Definition: main/app.c:2119
int ast_stream_and_wait(struct ast_channel *chan, const char *file, const char *digits)
stream file until digit If the file name is non-empty, try to play it.
Definition: file.c:1814
#define AST_FLAGS_ALL
Definition: utils.h:196
int ast_closestream(struct ast_filestream *f)
Closes a stream.
Definition: file.c:1068
struct ast_filestream * ast_channel_stream(const struct ast_channel *chan)
int ast_vm_msg_play(struct ast_channel *chan, const char *mailbox, const char *context, const char *folder, const char *msg_num, ast_vm_msg_play_cb *cb)
Play a voicemail msg back on a channel.
Definition: main/app.c:816
int ast_write(struct ast_channel *chan, struct ast_frame *frame)
Write a frame to a channel This function writes the given frame to the indicated channel.
Definition: channel.c:5106
int allowoverride
Definition: main/app.c:944
static void suspend(struct cc_core_instance *core_instance)
Definition: ccss.c:3193
struct ast_ivr_option * options
int ast_play_and_wait(struct ast_channel *chan, const char *fn)
Play a stream and wait for a digit, returning the digit that was pressed.
Definition: main/app.c:1410
void ast_safe_fork_cleanup(void)
Common routine to cleanup after fork&#39;ed process is complete (if reaping was stopped) ...
Definition: main/app.c:3048
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
char * category
Definition: channel.h:2908
void closefrom(int lowfd)
Definition: strcompat.c:429
struct zombie * next
Definition: main/app.c:79
static int linear_generator(struct ast_channel *chan, void *data, int len, int samples)
Definition: main/app.c:965
unsigned int arg_index
The index of the entry in the arguments array that should be used for this option&#39;s argument...
Structure used to handle boolean flags.
Definition: utils.h:199
static int vm_warnings
Definition: main/app.c:445
#define ast_clear_flag(p, flag)
Definition: utils.h:77
int(* run_sub)(struct ast_channel *chan, const char *args, int ignore_hangup)
Callback for the routine to run a subroutine on a channel.
ast_vm_snapshot_sort_val
int ast_truncstream(struct ast_filestream *fs)
Trunc stream at current location.
Definition: file.c:1043
#define RES_UPONE
Definition: main/app.c:2523
static int ivr_dispatch(struct ast_channel *chan, struct ast_ivr_option *option, char *exten, void *cbdata)
Definition: main/app.c:2530
#define ast_module_running_ref(mod)
Hold a reference to the module if it is running.
Definition: module.h:455
int ast_waitfordigit(struct ast_channel *c, int ms)
Waits for a digit.
Definition: channel.c:3180
const char * module_name
The name of the module that provides the voicemail functionality.
void ast_vm_unregister(const char *module_name)
Unregister the specified voicemail provider.
Definition: main/app.c:490
int ast_app_exec_sub(struct ast_channel *autoservice_chan, struct ast_channel *sub_chan, const char *sub_args, int ignore_hangup)
Run a subroutine on a channel, placing an optional second channel into autoservice.
Definition: main/app.c:387
#define ao2_global_obj_replace_unref(holder, obj)
Definition: astobj2.h:908
int ast_dsp_silence(struct ast_dsp *dsp, struct ast_frame *f, int *totalsilence)
Process the audio frame for silence.
Definition: dsp.c:1483
#define AST_RWLIST_INSERT_TAIL
Definition: linkedlists.h:740
struct ast_group_info * ast_app_group_list_head(void)
Get the head of the group count list.
Definition: main/app.c:2129
char * path
Definition: main/app.c:2261
static int global_silence_threshold
Definition: main/app.c:1495
char * strsep(char **str, const char *delims)
Structure used for ast_copy_recording_to_vm in order to cleanly supply data needed for making the rec...
static int parse_options(const struct ast_app_option *options, void *_flags, char **args, char *optstr, int flaglen)
Definition: main/app.c:2766
This structure is allocated by file.c in one chunk, together with buf_size and desc_size bytes of mem...
Definition: mod_format.h:101
char * ast_get_encoded_str(const char *stream, char *result, size_t result_size)
Decode a stream of encoded control or extended ASCII characters.
Definition: main/app.c:2942
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3167
int __ast_vm_register(const struct ast_vm_functions *vm_table, struct ast_module *module)
Set voicemail function callbacks.
Definition: main/app.c:458
int dtimeoutms
Definition: pbx.h:212
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
int ast_safe_fork(int stop_reaper)
Common routine to safely fork without a chance of a signal handler firing badly in the child...
Definition: main/app.c:2987
static int has_voicemail(const char *mailbox, const char *folder)
Determines if the given folder has messages.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
void ast_str_update(struct ast_str *buf)
Update the length of the buffer, after using ast_str merely as a buffer.
Definition: strings.h:663
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
int ast_vm_is_registered(void)
Determine if a voicemail provider is registered.
Definition: main/app.c:447
ast_app: A registered application
Definition: pbx_app.c:45
const char * ast_channel_name(const struct ast_channel *chan)
int ast_app_parse_options64(const struct ast_app_option *options, struct ast_flags64 *flags, char **args, char *optstr)
Parses a string containing application options and sets flags/arguments.
Definition: main/app.c:2851
int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
Writes a frame to a stream.
Definition: file.c:209
char * ast_read_textfile(const char *filename)
Read a file into asterisk.
Definition: main/app.c:2732
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
Definition: file.c:1776
int ast_readstring_full(struct ast_channel *c, char *s, int len, int timeout, int rtimeout, char *enders, int audiofd, int ctrlfd)
Definition: channel.c:6577
#define ast_frfree(fr)
static PGresult * result
Definition: cel_pgsql.c:88
int ast_control_streamfile_lang(struct ast_channel *chan, const char *file, const char *fwd, const char *rev, const char *stop, const char *suspend, const char *restart, int skipms, const char *lang, long *offsetms)
Version of ast_control_streamfile() which allows the language of the media file to be specified...
Definition: main/app.c:1267
static int global_maxsilence
Definition: main/app.c:1496
struct ast_group_info::@235 group_list
static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
Data structure associated with a single frame of data.
static int control_streamfile(struct ast_channel *chan, const char *file, const char *fwd, const char *rev, const char *stop, const char *suspend, const char *restart, int skipms, long *offsetms, const char *lang, ast_waitstream_fr_cb cb)
Definition: main/app.c:1071
int ast_app_group_list_unlock(void)
Unlock the group count list.
Definition: main/app.c:2134
struct ast_filestream * ast_readfile(const char *filename, const char *type, const char *comment, int flags, int check, mode_t mode)
Starts reading from a file.
Definition: file.c:1309
const char * ast_channel_language(const struct ast_channel *chan)
unsigned int module_version
The version of this function table.
int ast_playtones_start(struct ast_channel *chan, int vol, const char *tonelist, int interruptible)
Start playing a list of tones on a channel.
Definition: indications.c:302
int ast_filerename(const char *oldname, const char *newname, const char *fmt)
Renames a file.
Definition: file.c:1103
int ast_app_copy_recording_to_vm(struct ast_vm_recording_data *vm_rec_data)
param[in] vm_rec_data Contains data needed to make the recording. retval 0 voicemail successfully cre...
Definition: main/app.c:686
const char * ast_channel_context(const struct ast_channel *chan)
const char * data
Description of a tone.
Definition: indications.h:52
static void vm_greeter_warn_no_provider(void)
Definition: main/app.c:651
static int external_sleep(struct ast_channel *chan, int ms)
Definition: main/app.c:847
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:528
enum ast_frame_type frametype
#define PATH_MAX
Definition: asterisk.h:40
enum ast_getdata_result ast_app_getdata(struct ast_channel *c, const char *prompt, char *s, int maxlen, int timeout)
ast_app_getdata
Definition: main/app.c:198
char x
Definition: extconf.c:81
static struct test_options options
static struct ast_str * prompt
Definition: asterisk.c:2725
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:120
struct ast_flags * ast_channel_flags(struct ast_channel *chan)
int ast_readstring(struct ast_channel *c, char *s, int len, int timeout, int rtimeout, char *enders)
Reads multiple digits.
Definition: channel.c:6572
#define AST_RWLIST_FIRST
Definition: linkedlists.h:422
struct ast_format * format
struct ast_app * pbx_findapp(const char *app)
Look up an application.
Definition: ael_main.c:165
int ast_record_review(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, const char *path)
Allow to record message and have a review option.
Definition: main/app.c:2429
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
int ast_dsp_get_threshold_from_settings(enum threshold which)
Get silence threshold from dsp.conf.
Definition: dsp.c:1996
Asterisk module definitions.
struct ast_format * ast_channel_writeformat(struct ast_channel *chan)
int ast_ivr_menu_run(struct ast_channel *chan, struct ast_ivr_menu *menu, void *cbdata)
Runs an IVR menu.
Definition: main/app.c:2725
#define paren
Definition: ael_lex.c:973
Voicemail function table definition.
AST_LOCK_TYPE
Type of locking to use in ast_lock_path / ast_unlock_path.
struct ast_frame * ast_read_noaudio(struct ast_channel *chan)
Reads a frame, returning AST_FRAME_NULL frame if audio.
Definition: channel.c:4299
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
const char *(* expand_sub_args)(struct ast_channel *chan, const char *args)
Add missing context/exten to Gosub application argument string.
#define RES_RESTART
Definition: main/app.c:2526
int ast_get_encoded_char(const char *stream, char *result, size_t *consumed)
Decode an encoded control or extended ASCII character.
Definition: main/app.c:2867
#define AST_RWLIST_TRAVERSE_SAFE_END
Definition: linkedlists.h:616
int ast_stopstream(struct ast_channel *c)
Stops a stream.
Definition: file.c:187
int ast_waitstream_fr_w_cb(struct ast_channel *c, const char *breakon, const char *forward, const char *rewind, int ms, ast_waitstream_fr_cb cb)
Same as waitstream_fr but allows a callback to be alerted when a user fastforwards or rewinds the fil...
Definition: file.c:1734
jack_status_t status
Definition: app_jack.c:146
#define AST_MAX_FORMATS
Definition: main/app.c:121
Media Format Cache API.
static void path_lock_destroy(struct path_lock *obj)
Definition: main/app.c:2266
int ast_dtmf_stream(struct ast_channel *chan, struct ast_channel *peer, const char *digits, int between, unsigned int duration)
Send a string of DTMF digits to a channel.
Definition: main/app.c:921
int rtimeoutms
Definition: pbx.h:213
enum AST_LOCK_RESULT ast_lock_path(const char *path)
Lock a filesystem path.
Definition: main/app.c:2397
#define ast_test_flag64(p, flag)
Definition: utils.h:120