359#define get_volfactor(x) x ? ((x > 0) ? (1 << x) : ((1 << abs(x)) * -1)) : 0
361static const char *
const app =
"MixMonitor";
363static const char *
const stop_app =
"StopMixMonitor";
485 unsigned char quitting = 0;
491 ast_verb(2,
"MixMonitor close filestream (mixed)\n");
498 ast_verb(2,
"MixMonitor close filestream (read)\n");
505 ast_verb(2,
"MixMonitor close filestream (write)\n");
527 .
type =
"mixmonitor",
567 int elements_processed = 0;
570 ast_debug(3,
"attempting to add next element %d from %s\n", elements_processed, cur_mailbox);
571 if ((next = strchr(cur_mailbox,
',')) || (next = strchr(cur_mailbox,
'&'))) {
575 if ((cur_folder = strchr(cur_mailbox,
'/'))) {
576 *(cur_folder++) =
'\0';
578 cur_folder =
"INBOX";
581 if ((cur_context = strchr(cur_mailbox,
'@'))) {
582 *(cur_context++) =
'\0';
584 cur_context =
"default";
589 if (!(recipient =
ast_malloc(
sizeof(*recipient)))) {
601 ast_log(
LOG_ERROR,
"Failed to properly parse extension and/or context from element %d of recipient string: %s\n", elements_processed, vm_recipients);
605 elements_processed++;
618#define SAMPLES_PER_FRAME 160
657 ast_log(
LOG_ERROR,
"Failed to string_field_init, skipping copy_to_voicemail\n");
677 ast_verb(4,
"MixMonitor attempting to send voicemail copy to %s@%s\n", recording_data.
mailbox,
689 char *last_slash =
NULL;
692 *oflags = O_CREAT | O_WRONLY;
695 last_slash = strrchr(filename,
'/');
697 if ((*
ext = strrchr(filename,
'.')) && (*
ext > last_slash)) {
729 char *fs_read_ext =
"";
730 char *fs_write_ext =
"";
768 &fr_read, &fr_write))) {
786 if ((*fs_read) && (fr_read)) {
794 if ((*fs_write) && (fr_write)) {
810 .datalen =
sizeof(stereo_buf),
820 memcpy(read_buf, fr_read->
data.
ptr,
sizeof(read_buf));
822 memset(read_buf, 0,
sizeof(read_buf));
832 stereo_buf[i * 2] = read_buf[i];
836 stereo_frame.
data.
ptr = stereo_buf;
900 ast_log(
LOG_ERROR,
"No file extension set for Mixmonitor %s. Skipping copy to voicemail.\n",
915 ast_debug(3,
"No recipients to forward monitor to, moving on.\n");
919 ast_debug(3,
"Deleting our copies of recording files\n");
1003 unsigned int flags,
int readvol,
int writevol,
1004 const char *post_process,
const char *filename_write,
1005 char *filename_read,
const char *uid_channel_var,
1006 const char *recipients,
const char *beep_id)
1010 char postprocess2[1024] =
"";
1011 char *datastore_id =
NULL;
1013 postprocess2[0] = 0;
1019 for (p2 = p1; *p2; p2++) {
1020 if (*p2 ==
'^' && *(p2+1) ==
'{') {
1174 if (*filename !=
'/') {
1185 ext = strrchr(buffer,
'.');
1186 if (
ext && !strcmp(
ext,
".wav49")) {
1189 memcpy(
ext,
".WAV",
sizeof(
".WAV"));
1192 if ((slash = strrchr(filename,
'/'))) {
1202 int x, readvol = 0, writevol = 0;
1203 char *filename_read =
NULL;
1204 char *filename_write =
NULL;
1205 char filename_buffer[1024] =
"";
1206 char *uid_channel_var =
NULL;
1207 char beep_id[64] =
"";
1210 char *recipients =
NULL;
1220 ast_log(
LOG_WARNING,
"MixMonitor requires an argument (filename or ,t(filename) and/or r(filename)\n");
1234 ast_log(
LOG_NOTICE,
"The synchronization behavior enabled by the 'S' option is now the default"
1235 " and does not need to be specified.\n");
1240 ast_log(
LOG_WARNING,
"No volume level was provided for the heard volume ('v') option.\n");
1241 }
else if ((sscanf(opts[
OPT_ARG_READVOLUME],
"%2d", &x) != 1) || (x < -4) || (x > 4)) {
1250 ast_log(
LOG_WARNING,
"No volume level was provided for the spoken volume ('V') option.\n");
1260 ast_log(
LOG_WARNING,
"No volume level was provided for the combined volume ('W') option.\n");
1261 }
else if ((sscanf(opts[
OPT_ARG_VOLUME],
"%2d", &x) != 1) || (x < -4) || (x > 4)) {
1270 ast_log(
LOG_WARNING,
"No voicemail recipients were specified for the vm copy ('m') option.\n");
1290 unsigned int interval = 15;
1292 if (sscanf(interval_str,
"%30u", &interval) != 1) {
1293 ast_log(
LOG_WARNING,
"Invalid interval '%s' for periodic beep. Using default of %u\n",
1294 interval_str, interval);
1298 ast_log(
LOG_WARNING,
"Unable to enable periodic beep, please ensure func_periodic_hook is loaded.\n");
1430 e->
command =
"mixmonitor {start|stop|list}";
1432 "Usage: mixmonitor start <chan_name> [args]\n"
1433 " The optional arguments are passed to the MixMonitor application.\n"
1434 " mixmonitor stop <chan_name> [args]\n"
1435 " The optional arguments are passed to the StopMixMonitor application.\n"
1436 " mixmonitor list <chan_name>\n";
1447 ast_cli(
a->fd,
"No channel matching '%s' found.\n",
a->argv[2]);
1452 if (!strcasecmp(
a->argv[1],
"start")) {
1454 }
else if (!strcasecmp(
a->argv[1],
"stop")){
1456 }
else if (!strcasecmp(
a->argv[1],
"list")) {
1457 ast_cli(
a->fd,
"MixMonitor ID\tFile\tReceive File\tTransmit File\n");
1458 ast_cli(
a->fd,
"=========================================================================\n");
1463 char *filename_read =
"";
1464 char *filename_write =
"";
1543 int clearmute = 1, mutedcount = 0;
1555 }
else if (!strcasecmp(
direction,
"write")) {
1557 }
else if (!strcasecmp(
direction,
"both")) {
1560 astman_send_error(s, m,
"Invalid direction specified. Must be read, write or both");
1584 if (mutedcount < 0) {
1599 stasis_message_blob =
ast_json_pack(
"{s: s, s: b, s: s, s: i}",
1602 "mixmonitorid", mixmonitor_id,
1603 "count", mutedcount);
1630 snprintf(
args,
sizeof(
args),
"%s", filename);
1653 char *uid_channel_var =
NULL;
1654 const char *mixmonitor_id =
NULL;
1761 "An ID and key must be provided\n", cmd);
1774 ds_data = datastore->
data;
1776 if (!strcasecmp(
args.key,
"filename")) {
1786 .
name =
"MIXMONITOR",
1845 .optional_modules =
"func_periodic_hook",
static int mixmonitor_exec(struct ast_channel *chan, const char *data)
static int manager_stop_mixmonitor(struct mansession *s, const struct message *m)
static char * filename_parse(char *filename, char *buffer, size_t len)
static struct ast_cli_entry cli_mixmonitor[]
static struct ast_custom_function mixmonitor_function
static void destroy_monitor_audiohook(struct mixmonitor *mixmonitor)
static const struct ast_datastore_info mixmonitor_ds_info
@ OPT_ARG_DEPRECATED_RWSYNC
static int set_mixmonitor_methods(void)
static const struct ast_app_option mixmonitor_opts[128]
static const char *const app
static void mixmonitor_save_prep(struct mixmonitor *mixmonitor, char *filename, struct ast_filestream **fs, unsigned int *oflags, int *errflag, char **ext)
static int mixmonitor_autochan_is_bridged(struct ast_autochan *autochan)
static int launch_monitor_thread(struct ast_channel *chan, const char *filename, unsigned int flags, int readvol, int writevol, const char *post_process, const char *filename_write, char *filename_read, const char *uid_channel_var, const char *recipients, const char *beep_id)
static int manager_mute_mixmonitor(struct mansession *s, const struct message *m)
Mute / unmute a MixMonitor channel.
static int clear_mixmonitor_methods(void)
static int mute_mixmonitor_instance(struct ast_channel *chan, const char *data, enum ast_audiohook_flags flag, int clearmute)
Mute / unmute an individual MixMonitor by id.
static void copy_to_voicemail(struct mixmonitor *mixmonitor, const char *ext, const char *filename)
static char * handle_cli_mixmonitor(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int start_mixmonitor_callback(struct ast_channel *chan, const char *filename, const char *options)
#define SAMPLES_PER_FRAME
static void mixmonitor_free(struct mixmonitor *mixmonitor)
static int stop_mixmonitor_exec(struct ast_channel *chan, const char *data)
static int func_mixmonitor_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static const char *const stop_app
static void mixmonitor_ds_close_fs(struct mixmonitor_ds *mixmonitor_ds)
static void * mixmonitor_thread(void *obj)
static int load_module(void)
static void mixmonitor_ds_remove_and_free(struct ast_channel *chan, const char *datastore_id)
static int manager_mixmonitor(struct mansession *s, const struct message *m)
static int setup_mixmonitor_ds(struct mixmonitor *mixmonitor, struct ast_channel *chan, char **datastore_id, const char *beep_id)
static int unload_module(void)
static int stop_mixmonitor_full(struct ast_channel *chan, const char *data)
@ MUXFLAG_DEPRECATED_RWSYNC
static int startmon(struct ast_channel *chan, struct ast_audiohook *audiohook)
static const char *const mixmonitor_spy_type
static void mixmonitor_ds_destroy(void *data)
static int stop_mixmonitor_callback(struct ast_channel *chan, const char *mixmonitor_id)
static void add_vm_recipients_from_string(struct mixmonitor *mixmonitor, const char *vm_recipients)
static void clear_mixmonitor_recipient_list(struct mixmonitor *mixmonitor)
Asterisk main include file. File version handling, generic pbx functions.
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
#define ast_strdup(str)
A wrapper for strdup()
#define ast_strdupa(s)
duplicate a string in memory from the stack
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
#define ast_calloc(num, len)
A wrapper for calloc()
#define ast_malloc(len)
A wrapper for malloc()
struct ast_frame * ast_audiohook_read_frame_all(struct ast_audiohook *audiohook, size_t samples, struct ast_format *format, struct ast_frame **read_frame, struct ast_frame **write_frame)
Reads a frame in from the audiohook structure in mixed audio mode and copies read and write frame dat...
int ast_audiohook_init(struct ast_audiohook *audiohook, enum ast_audiohook_type type, const char *source, enum ast_audiohook_init_flags flags)
Initialize an audiohook structure.
void ast_audiohook_trigger_wait(struct ast_audiohook *audiohook)
Wait for audiohook trigger to be triggered.
void ast_audiohook_update_status(struct ast_audiohook *audiohook, enum ast_audiohook_status status)
Update audiohook's status.
#define ast_audiohook_lock(ah)
Lock an audiohook.
int ast_audiohook_set_mute_all(struct ast_channel *chan, const char *source, enum ast_audiohook_flags flag, int clear)
Mute frames read from or written for all audiohooks on a channel.
@ AST_AUDIOHOOK_MUTE_READ
@ AST_AUDIOHOOK_MUTE_WRITE
@ AST_AUDIOHOOK_SUBSTITUTE_SILENCE
@ AST_AUDIOHOOK_TRIGGER_SYNC
int ast_audiohook_detach(struct ast_audiohook *audiohook)
Detach audiohook from channel.
int ast_audiohook_attach(struct ast_channel *chan, struct ast_audiohook *audiohook)
Attach audiohook to channel.
int ast_audiohook_destroy(struct ast_audiohook *audiohook)
Destroys an audiohook structure.
#define ast_audiohook_unlock(ah)
Unlock an audiohook.
@ AST_AUDIOHOOK_STATUS_DONE
@ AST_AUDIOHOOK_STATUS_RUNNING
@ AST_AUDIOHOOK_STATUS_SHUTDOWN
"smart" channels that update automatically if a channel is masqueraded
struct ast_autochan * ast_autochan_setup(struct ast_channel *chan)
set up a new ast_autochan structure
void ast_autochan_destroy(struct ast_autochan *autochan)
destroy an ast_autochan structure
#define ast_autochan_channel_lock(autochan)
Lock the autochan's channel lock.
#define ast_autochan_channel_unlock(autochan)
Periodic beeps into the audio of a call.
CallerID (and other GR30) management and generation Includes code and algorithms from the Zapata libr...
char * ast_callerid_merge(char *buf, int bufsiz, const char *name, const char *num, const char *unknown)
General Asterisk PBX channel definitions.
const char * ast_channel_name(const struct ast_channel *chan)
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
struct stasis_topic * ast_channel_topic(struct ast_channel *chan)
A topic which publishes the events for a particular channel.
#define ast_channel_lock(chan)
int ast_channel_priority(const struct ast_channel *chan)
struct ast_party_connected_line * ast_channel_connected(struct ast_channel *chan)
const char * ast_channel_uniqueid(const struct ast_channel *chan)
const char * ast_channel_context(const struct ast_channel *chan)
struct ast_channel * ast_channel_get_by_name_prefix(const char *name, size_t name_len)
Find a channel by a name prefix.
int ast_channel_is_bridged(const struct ast_channel *chan)
Determine if a channel is in a bridge.
#define ast_channel_unref(c)
Decrease channel reference count.
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
const char * ast_channel_exten(const struct ast_channel *chan)
struct ast_datastore_list * ast_channel_datastores(struct ast_channel *chan)
#define ast_channel_unlock(chan)
#define AST_MAX_EXTENSION
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Standard Command Line Interface.
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
#define AST_CLI_DEFINE(fn, txt,...)
void ast_cli(int fd, const char *fmt,...)
char * ast_complete_channels(const char *line, const char *word, int pos, int state, int rpos)
Command completion for the list of active channels.
#define ast_cli_register_multiple(e, len)
Register multiple commands.
#define ast_datastore_alloc(info, uid)
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
void write_buf(int file, char *buffer, int num)
Generic File Format Support. Should be included by clients of the file handling routines....
int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
Writes a frame to a stream.
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.
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.
int ast_closestream(struct ast_filestream *f)
Closes a stream.
int ast_filedelete(const char *filename, const char *fmt)
Deletes a file.
int AST_OPTIONAL_API_NAME() ast_beep_start(struct ast_channel *chan, unsigned int interval, char *beep_id, size_t len)
int AST_OPTIONAL_API_NAME() ast_beep_stop(struct ast_channel *chan, const char *beep_id)
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
void astman_append(struct mansession *s, const char *fmt,...)
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
struct stasis_message_type * ast_channel_mixmonitor_mute_type(void)
Message type for muting or unmuting mixmonitor on a channel.
struct stasis_message_type * ast_channel_mixmonitor_stop_type(void)
Message type for stopping mixmonitor on a channel.
struct stasis_message * ast_channel_blob_create_from_cache(const char *uniqueid, struct stasis_message_type *type, struct ast_json *blob)
Create a ast_channel_blob message, pulling channel state from the cache.
struct stasis_message_type * ast_channel_mixmonitor_start_type(void)
Message type for starting mixmonitor on a channel.
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
#define AST_APP_ARG(name)
Define an application argument.
#define AST_APP_OPTIONS(holder, options...)
Declares an array of options for an application.
#define AST_APP_OPTION_ARG(option, flagno, argno)
Declares an application option that accepts an argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
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...
int ast_safe_system(const char *s)
Safely spawn an OS shell command while closing file descriptors.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
#define AST_APP_OPTION(option, flagno)
Declares an application option that does not accept an argument.
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.
void ast_frame_free(struct ast_frame *frame, int cache)
Frees a frame or list of frames.
#define ast_frdup(fr)
Copies a frame.
#define ast_debug(level,...)
Log a DEBUG message.
ast_callid ast_read_threadstorage_callid(void)
extracts the callerid from the thread
int ast_callid_threadassoc_add(ast_callid callid)
Adds a known callid to thread storage of the calling thread.
#define ast_verb(level,...)
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
A set of macros to manage forward-linked lists.
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
#define ast_cond_destroy(cond)
#define ast_cond_wait(cond, mutex)
#define ast_cond_init(cond, attr)
#define ast_mutex_init(pmutex)
#define ast_mutex_unlock(a)
pthread_cond_t ast_cond_t
#define ast_mutex_destroy(a)
#define ast_mutex_lock(a)
#define ast_cond_signal(cond)
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
#define EVENT_FLAG_SYSTEM
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
static struct ast_mixmonitor_methods mixmonitor_methods
loadable MixMonitor functionality
int ast_set_mixmonitor_methods(struct ast_mixmonitor_methods *vmethod_table)
Setup MixMonitor virtual methods table. Use this to provide the MixMonitor functionality from a loada...
int ast_clear_mixmonitor_methods(void)
Clear the MixMonitor virtual methods table. Use this to cleanup function pointers provided by a modul...
Asterisk module definitions.
#define ast_module_unref(mod)
Release a reference to the module.
#define ast_module_ref(mod)
Hold a reference to the module.
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
@ AST_MODULE_SUPPORT_CORE
#define ASTERISK_GPL_KEY
The text the key() function should return.
int ast_unregister_application(const char *app)
Unregister an application.
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Asterisk file paths, configured in asterisk.conf.
const char * ast_config_AST_MONITOR_DIR
Core PBX routines and definitions.
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name.
#define ast_custom_function_register(acf)
Register a custom function.
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
Stasis Message Bus API. See Stasis Message Bus API for detailed documentation.
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic's subscribers.
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
#define AST_STRING_FIELD(name)
Declare a string field.
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
static force_inline int attribute_pure ast_strlen_zero(const char *s)
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"....
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
struct ast_audiohook_options options
enum ast_audiohook_status status
struct ast_channel * chan
Main Channel structure associated with a channel.
descriptor for a cli entry.
Data structure associated with a custom dialplan function.
Structure for a data store type.
Structure for a data store object.
const struct ast_datastore_info * info
This structure is allocated by file.c in one chunk, together with buf_size and desc_size bytes of mem...
Structure used to handle boolean flags.
struct ast_format * format
Data structure associated with a single frame of data.
struct ast_frame_subclass subclass
union ast_frame::@226 data
enum ast_frame_type frametype
Abstract JSON element (object, array, string, int, ...).
MixMonitor virtual methods table definition.
ast_mixmonitor_start_fn start
Structure for mutex and tracking information.
Caller Party information.
struct ast_party_id id
Caller party ID.
Connected Line/Party information.
struct ast_party_name name
Subscriber name.
struct ast_party_number number
Subscriber phone number.
unsigned char valid
TRUE if the name information is valid/present.
char * str
Subscriber name (Malloced)
unsigned char valid
TRUE if the number information is valid/present.
char * str
Subscriber phone number (Malloced)
Structure used for ast_copy_recording_to_vm in order to cleanly supply data needed for making the rec...
const ast_string_field recording_file
const ast_string_field call_callerchan
const ast_string_field context
const ast_string_field folder
const ast_string_field call_callerid
const ast_string_field call_context
const ast_string_field recording_ext
const ast_string_field call_extension
const ast_string_field mailbox
In case you didn't read that giant block of text above the mansession_session struct,...
unsigned int destruction_ok
struct ast_audiohook * audiohook
struct ast_filestream * fs_read
struct ast_filestream * fs_write
struct ast_filestream * fs
ast_cond_t destruction_condition
const ast_string_field call_callerchan
const ast_string_field call_callerid
struct ast_autochan * autochan
struct ast_audiohook audiohook
const ast_string_field call_context
const ast_string_field call_extension
struct mixmonitor::@42 recipient_list
struct mixmonitor_ds * mixmonitor_ds
char mailbox[AST_MAX_CONTEXT]
char context[AST_MAX_EXTENSION]
struct vm_recipient * next
struct vm_recipient::@41 list
#define ast_test_suite_event_notify(s, f,...)
#define ast_test_flag(p, flag)
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
#define ast_clear_flag(p, flag)
int ast_mkdir(const char *path, int mode)
Recursively create directory path.
#define ast_pthread_create_detached_background(a, b, c, d)
#define ast_set_flag(p, flag)