47 #include "asterisk/res_pjsip.h"
274 #define MAX_ID_SUFFIX 20
276 #define BASE_REGISTRAR "res_pjsip_config_wizard"
292 #define NOT_EQUALS(a, b) (a != b)
293 #define OTW_DELETE_CB(otw) ({ \
294 ast_config_destroy(otw->last_config); \
298 const static char *object_types[] = {
"phoneprov",
"registration",
"identify",
"endpoint",
"aor",
"auth", NULL};
300 static int is_one_of(
const char *needle,
const char *haystack[])
303 for (i = 0; haystack[i]; i++) {
304 if (!strcmp(needle, haystack[i])) {
320 if (!strcmp(otw->object_type, object_type)) {
332 const char *
id,
const char *type,
struct ast_variable *vars)
337 ast_log(LOG_ERROR,
"Unable to allocate an object of type '%s' with id '%s'.\n", type,
id);
342 ast_log(LOG_ERROR,
"Unable to apply object type '%s' with id '%s'. Check preceeding errors.\n", type,
id);
359 struct ast_variable *
new = ast_variable_new(name, value,
"");
362 ast_log(LOG_ERROR,
"Unable to allocate memory for new variable '%s'.\n", name);
366 ast_variable_list_append(existing,
new);
373 #define variable_list_append_return(existing, name, value) ({ \
374 struct ast_variable *new = ast_variable_new(name, value, ""); \
376 ast_log(LOG_ERROR, "Unable to allocate memory for new variable '%s'.\n", name); \
379 ast_variable_list_append(existing, new); \
390 int plen = strlen(prefix);
392 for(; v; v = v->
next) {
405 static int delete_extens(
const char *context,
const char *exten)
409 if (pbx_find_extension(NULL, NULL, &find_info, context, exten,
PRIORITY_HINT, NULL, NULL, E_MATCH)) {
413 if (pbx_find_extension(NULL, NULL, &find_info, context, exten, 1, NULL, NULL, E_MATCH)) {
420 static int add_extension(
struct ast_context *context,
const char *exten,
421 int priority,
const char *application)
427 void *free_ptr = NULL;
429 const char *context_name;
431 if (!context || ast_strlen_zero(exten) || ast_strlen_zero(application)) {
441 paren = strchr(application,
'(');
443 app = (
char *)application;
446 app[paren - application] =
'\0';
451 data[strlen(data) - 1] =
'\0';
453 if (ast_strlen_zero(app) || ast_strlen_zero(data)) {
460 context_name = ast_get_context_name(context);
461 if ((existing_exten = pbx_find_extension(NULL, NULL, &find_info, context_name, exten,
462 priority, NULL, NULL, E_MATCH))) {
463 const char *existing_app = ast_get_extension_app(existing_exten);
464 const char *existing_data = ast_get_extension_app_data(existing_exten);
465 if (!strcmp(existing_app, app)
466 && !strcmp(existing_data ? existing_data :
"", data ? data :
"")) {
475 app, data, free_ptr, BASE_REGISTRAR, NULL, 0)) {
482 static int add_hints(
const char *context,
const char *exten,
const char *application,
const char *
id)
487 hint_device =
ast_alloca(strlen(
"PJSIP/") + strlen(
id) + 1);
488 sprintf(hint_device,
"PJSIP/%s",
id);
492 ast_log(LOG_ERROR,
"Failed to lock the contexts list.\n");
497 ast_log(LOG_ERROR,
"Unable to find or create hint context '%s'\n", context);
507 ast_log(LOG_ERROR,
"failed to obtain write lock on context\n");
512 if (add_extension(hint_context, exten,
PRIORITY_HINT, hint_device)) {
513 ast_log(LOG_ERROR,
"Failed to add hint '%s@%s' to the PBX.\n",
517 if (!ast_strlen_zero(application)) {
518 if (add_extension(hint_context, exten, 1, application)) {
519 ast_log(LOG_ERROR,
"Failed to add hint '%s@%s' to the PBX.\n",
538 char prefix[strlen(direction) + strlen(
"_auth/") + 1];
539 char *test_variable = NULL;
542 snprintf(prefix,
sizeof(prefix),
"%s_auth/", direction);
545 if (!strcmp(direction,
"outbound")) {
546 snprintf(new_id,
sizeof(new_id),
"%s-oauth",
id);
547 test_variable =
"sends_auth";
549 snprintf(new_id,
sizeof(new_id),
"%s-iauth",
id);
550 test_variable =
"accepts_auth";
556 "Wizard '%s' must have '%s_auth/username' if it %s.\n",
id, direction, test_variable);
561 obj = otw->wizard->
retrieve_id(sorcery, otw->wizard_data,
"auth", new_id);
563 otw->wizard->
delete(sorcery, otw->wizard_data, obj);
581 if (otw->wizard->
update(sorcery, otw->wizard_data, obj)) {
582 otw->wizard->
create(sorcery, otw->wizard_data, obj);
594 if ((rc = handle_auth(sorcery, otw, wiz,
"outbound"))) {
598 return handle_auth(sorcery, otw, wiz,
"inbound");
607 const char *contact_pattern;
614 if (!ast_strlen_zero(outbound_proxy)) {
621 contact_pattern =
"sip:${REMOTE_HOST}";
624 if (host_count > 0 && !ast_strlen_zero(contact_pattern)) {
631 for (host_counter = 0; host_counter < host_count; host_counter++) {
633 RAII_VAR(
struct varshead *, subst_vars, ast_var_list_create(), ast_var_list_destroy);
634 struct ast_var_t *var = ast_var_assign(
"REMOTE_HOST",
637 AST_VAR_LIST_INSERT_TAIL(subst_vars, var);
651 if (otw->wizard->
update(sorcery, otw->wizard_data, obj)) {
652 otw->wizard->
create(sorcery, otw->wizard_data, obj);
676 if (!ast_strlen_zero(outbound_proxy)) {
680 if (ast_strlen_zero(hint_context)) {
684 if (ast_strlen_zero(hint_context)) {
685 hint_context =
"default";
688 if (!ast_strlen_zero(hint_exten)) {
694 if (!ast_strlen_zero(transport)) {
699 snprintf(new_id,
sizeof(new_id),
"%s-oauth",
id);
704 snprintf(new_id,
sizeof(new_id),
"%s-iauth",
id);
713 if (otw->wizard->
update(sorcery, otw->wizard_data, obj)) {
714 otw->wizard->
create(sorcery, otw->wizard_data, obj);
718 if (!ast_strlen_zero(hint_exten)) {
720 add_hints(hint_context, hint_exten, hint_application,
id);
722 delete_extens(hint_context, hint_exten);
740 snprintf(new_id,
sizeof(new_id),
"%s-identify",
id);
746 obj = otw->wizard->
retrieve_id(sorcery, otw->wizard_data,
"identify", new_id);
748 otw->wizard->
delete(sorcery, otw->wizard_data, obj);
756 "Wizard '%s' must have 'remote_hosts' if it doesn't accept registrations.\n",
id);
764 for (host_counter = 0; host_counter < host_count; host_counter++) {
775 if (otw->wizard->
update(sorcery, otw->wizard_data, obj)) {
776 otw->wizard->
create(sorcery, otw->wizard_data, obj);
792 snprintf(new_id,
sizeof(new_id),
"%s-phoneprov",
id);
795 obj = otw->wizard->
retrieve_id(sorcery, otw->wizard_data,
"phoneprov", new_id);
797 otw->wizard->
delete(sorcery, otw->wizard_data, obj);
805 "Wizard '%s' must have 'phoneprov/MAC' if it has_phoneprov.\n",
id);
817 if (otw->wizard->
update(sorcery, otw->wizard_data, obj)) {
818 otw->wizard->
create(sorcery, otw->wizard_data, obj);
825 static int delete_existing_cb(
void *obj,
void *arg,
int flags)
829 if (!strcmp(otw->object_type,
"endpoint")) {
832 if (!ast_strlen_zero(context) && !ast_strlen_zero(exten)) {
833 delete_extens(context, exten);
837 otw->wizard->
delete(otw->sorcery, otw->wizard_data, obj);
848 const char *server_uri_pattern;
849 const char *client_uri_pattern;
852 const char *username;
865 search = ast_variable_new(
"@pjsip_wizard",
id,
"");
870 if (!ast_strlen_zero(outbound_proxy)) {
874 otw->wizard->
retrieve_multiple(sorcery, otw->wizard_data,
"registration", existing, search);
886 ast_log(LOG_ERROR,
"Wizard '%s' must have 'remote_hosts' if it sends registrations.\n",
id);
893 server_uri_pattern =
"sip:${REMOTE_HOST}";
897 client_uri_pattern =
"sip:${USERNAME}@${REMOTE_HOST}";
902 ast_log(LOG_ERROR,
"Wizard '%s' must have 'outbound_auth/username' if it sends"
903 " authentication.\n",
id);
914 for (host_counter = 0; host_counter < host_count; host_counter++) {
915 struct ast_var_t *rh = ast_var_assign(
"REMOTE_HOST",
917 struct ast_var_t *un = ast_var_assign(
"USERNAME", username);
920 RAII_VAR(
struct varshead *, subst_vars, ast_var_list_create(), ast_var_list_destroy);
923 AST_VAR_LIST_INSERT_TAIL(subst_vars, rh);
924 AST_VAR_LIST_INSERT_TAIL(subst_vars, un);
926 if (!ast_strlen_zero(server_uri_pattern)) {
932 if (!ast_strlen_zero(client_uri_pattern)) {
940 snprintf(new_id,
sizeof(new_id),
"%s-oauth",
id);
944 if (!ast_strlen_zero(transport)) {
953 snprintf(new_id,
sizeof(new_id),
"%s-reg-%d",
id, host_counter);
955 obj =
create_object(sorcery, new_id,
"registration", registration_vars);
960 if (otw->wizard->
update(sorcery, otw->wizard_data, obj)) {
961 otw->wizard->
create(sorcery, otw->wizard_data, obj);
984 const char *remote_hosts;
990 if (!ast_strlen_zero(remote_hosts)) {
1002 ast_debug(4,
"%s handler starting.\n", otw->object_type);
1004 if (!strcmp(otw->object_type,
"auth")) {
1005 rc = handle_auths(sorcery, otw, wiz);
1006 }
else if (!strcmp(otw->object_type,
"aor")) {
1007 rc = handle_aor(sorcery, otw, wiz, &remote_hosts_vector);
1008 }
else if (!strcmp(otw->object_type,
"endpoint")) {
1009 rc = handle_endpoint(sorcery, otw, wiz);
1010 }
else if (!strcmp(otw->object_type,
"identify")) {
1011 rc = handle_identify(sorcery, otw, wiz, &remote_hosts_vector);
1012 }
else if (!strcmp(otw->object_type,
"phoneprov")) {
1013 rc = handle_phoneprov(sorcery, otw, wiz);
1014 }
else if (!strcmp(otw->object_type,
"registration")) {
1015 rc = handle_registrations(sorcery, otw, wiz, &remote_hosts_vector);
1021 ast_debug(4,
"%s handler complete. rc: %d\n", otw->object_type, rc);
1032 const struct ast_sorcery *sorcery,
const char *object_type,
int reloaded);
1035 const char *wizard_args,
void *wizard_data);
1037 struct ast_sorcery *sorcery,
const char *object_type);
1052 const struct ast_sorcery *sorcery,
const char *object_type,
int reloaded)
1056 char *filename =
"pjsip_wizard.conf";
1060 if (!strstr(
"auth aor endpoint identify registration phoneprov", object_type)) {
1067 ast_log(LOG_ERROR,
"There was no wizard for object type '%s'\n", object_type);
1071 if (reloaded && otw->last_config) {
1078 ast_log(LOG_ERROR,
"Unable to load config file '%s'\n", filename);
1080 }
else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
1081 ast_debug(2,
"Config file '%s' was unchanged for '%s'.\n", filename, object_type);
1083 }
else if (cfg == CONFIG_STATUS_FILEINVALID) {
1084 ast_log(LOG_ERROR,
"Contents of config file '%s' are invalid and cannot be parsed\n", filename);
1093 if (otw->last_config) {
1101 if (!last_cat || changes) {
1102 ast_debug(3,
"%s: %s(s) for wizard '%s'\n", reloaded ?
"Reload" :
"Load", object_type,
id);
1103 if (wizard_apply_handler(sorcery, otw, category)) {
1104 ast_log(LOG_ERROR,
"Unable to create objects for wizard '%s'\n",
id);
1109 if (!otw->last_config) {
1110 otw->last_config = cfg;
1125 ast_log(LOG_ERROR,
"Unable to allocate temporary container.\n");
1129 search = ast_variable_new(
"@pjsip_wizard",
id,
"");
1131 ast_log(LOG_ERROR,
"Unable to allocate memory for vaiable '@pjsip_wizard'.\n");
1134 otw->wizard->
retrieve_multiple(sorcery, otw->wizard_data, object_type, existing, search);
1138 ast_debug(3,
"Delete on %s: %d %s(s) for wizard: %s\n",
1141 delete_existing_cb, otw);
1146 otw->last_config = cfg;
1152 const char *wizard_args,
void *wizard_data)
1156 if (!is_one_of(object_type, object_types)) {
1162 if (wizard_args && !strcmp(wizard_args,
"pjsip_wizard")) {
1163 otw =
ast_malloc(
sizeof(*otw) + strlen(object_type) + 1);
1168 otw->sorcery = sorcery;
1169 otw->wizard = wizard;
1170 otw->wizard_data = wizard_data;
1171 otw->last_config = NULL;
1172 strcpy(otw->object_type, object_type);
1177 ast_debug(1,
"Wizard mapped for object_type '%s'\n", object_type);
1185 struct ast_sorcery *sorcery,
const char *object_type)
1187 if (is_one_of(object_type, object_types)) {
1198 if (strcmp(name,
"res_pjsip")) {
1210 if (strcmp(name,
"res_pjsip")) {
1223 const char *fn = NULL;
1227 e->
command =
"pjsip export config_wizard primitives [to]";
1229 "Usage: pjsip export config_wizard primitives [ to <filename ]\n"
1230 " Export the config_wizard objects as pjsip primitives to\n"
1231 " the console or to <filename>\n";
1246 ast_log(LOG_ERROR,
"Unable to write %s (%s)\n", fn, strerror(errno));
1251 fprintf(f,
";! Automatically generated configuration file\n");
1252 fprintf(f,
";! Filename: %s\n", fn);
1253 fprintf(f,
";! Generator: %s\n",
"'pjsip export config_wizard primitives'");
1254 fprintf(f,
";! Creation Date: %s", date);
1258 sorcery = ast_sip_get_sorcery();
1273 while ((o = ao2_iterator_next(&i))) {
1284 for (v = vars; v; v = v->
next) {
1285 if (!ast_strlen_zero(v->
value)) {
1287 fprintf(f,
"%s = %s\n", v->
name, v->
value);
1289 ast_cli(a->fd,
"%s = %s\n", v->
name, v->
value);
1298 ao2_cleanup(container);
1304 ast_cli(a->fd,
"Wrote configuration to %s\n", fn);
1312 AST_CLI_DEFINE(handle_export_primitives,
"Export config wizard primitives"),
1315 static int load_module(
void)
1324 static int unload_module(
void)
1334 AST_MODULE_INFO(
ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER,
"PJSIP Config Wizard",
1335 .support_level = AST_MODULE_SUPPORT_CORE,
1336 .load = load_module,
1337 .unload = unload_module,
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
struct ast_variable * next
#define AST_VECTOR_RW_INIT(vec, size)
Initialize a vector with a read/write lock.
static void wizard_mapped_observer(const char *name, struct ast_sorcery *sorcery, const char *object_type, struct ast_sorcery_wizard *wizard, const char *wizard_args, void *wizard_data)
When each wizard is mapped, save it off to the vector.
int ast_unlock_context(struct ast_context *con)
Asterisk main include file. File version handling, generic pbx functions.
ast_exten: An extension The dialplan is saved as a linked list with each context having it's own link...
int(* update)(const struct ast_sorcery *sorcery, void *data, void *object)
Callback for updating an object.
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define MAX_ID_SUFFIX
Defines the maximum number of characters that can be added to a wizard id.
Keeps track of the sorcery wizard and last config for each object type.
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
#define ast_sorcery_apply_wizard_mapping(sorcery, type, name, data, caching)
Apply additional object wizard mappings.
#define variable_list_append_return(existing, name, value)
Appends a variable to the end of an existing list. On failure, cause the calling function to return -...
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
int ast_sorcery_instance_observer_add(struct ast_sorcery *sorcery, const struct ast_sorcery_instance_observer *callbacks)
Add an observer to a sorcery instance.
static void object_type_loaded_observer(const char *name, const struct ast_sorcery *sorcery, const char *object_type, int reloaded)
Called after an object type is loaded/reloaded.
The arg parameter is a search key, but is not an object.
void(* instance_created)(const char *name, struct ast_sorcery *sorcery)
Callback after an instance is created.
static void * create_object(const struct ast_sorcery *sorcery, const char *id, const char *type, struct ast_variable *vars)
Creates a sorcery object and applies a variable list.
Interface for the global sorcery observer.
static void instance_destroying_observer(const char *name, struct ast_sorcery *sorcery)
When the res_pjsip instance is destroyed, remove the observer and unref the module. This should then allow this module to unload cleanly.
#define AST_VECTOR_RW_UNLOCK(vec)
Unlock vector.
descriptor for a cli entry.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container, as described below.
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
struct ast_config * ast_config_load2(const char *filename, const char *who_asked, struct ast_flags flags)
Load a config file.
Structure for variables, used for configurations and for channel variables.
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
struct ast_category * ast_category_delete(struct ast_config *cfg, struct ast_category *cat)
Delete a category.
int ast_sorcery_object_id_compare(void *obj, void *arg, int flags)
ao2 object comparator based on sorcery id.
Full structure for sorcery.
#define AST_VECTOR_RW_RDLOCK(vec)
Obtain read lock on vector.
static void instance_created_observer(const char *name, struct ast_sorcery *sorcery)
When the res_pjsip instance is created, add an observer to it and initialize the wizard vector...
#define ast_cli_register_multiple(e, len)
Register multiple commands.
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
int ast_sorcery_objectset_apply(const struct ast_sorcery *sorcery, void *object, struct ast_variable *objectset)
Apply an object set (KVP list) to an object.
Return all matching objects.
int ast_wrlock_contexts(void)
Write locks the context list.
#define ast_strdup(str)
A wrapper for strdup()
int ast_sorcery_global_observer_add(const struct ast_sorcery_global_observer *callbacks)
Add a global observer to sorcery.
int(* create)(const struct ast_sorcery *sorcery, void *data, void *object)
Callback for creating an object.
const char * ast_variable_find_last_in_list(const struct ast_variable *list, const char *variable)
Gets the value of the LAST occurrence of a variable from a variable list.
void ast_free_ptr(void *ptr)
free() wrapper
struct ast_category * ast_category_browse_filtered(struct ast_config *config, const char *category_name, struct ast_category *prev, const char *filter)
Browse categories with filters.
int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
Simply remove extension from context.
int(* delete)(const struct ast_sorcery *sorcery, void *data, void *object)
Callback for deleting an object.
void ast_sorcery_global_observer_remove(const struct ast_sorcery_global_observer *callbacks)
Remove a global observer from sorcery.
const char * ast_sorcery_object_get_extended(const void *object, const char *name)
Get an extended field value from a sorcery object.
A generic char * vector definition.
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
#define AST_VECTOR_RW_FREE(vec)
Deallocates this locked vector.
#define ast_strdupa(s)
duplicate a string in memory from the stack
Interface for the sorcery instance observer.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
struct ast_variable * ast_category_first(struct ast_category *cat)
given a pointer to a category, return the root variable.
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
const char * ast_variable_find_in_list(const struct ast_variable *list, const char *variable)
Gets the value of a variable from a variable list by name.
Structure for internal sorcery object information.
char * ast_strsep(char **s, const char sep, uint32_t flags)
Act like strsep but ignore separators inside quotes.
#define ast_malloc(len)
A wrapper for malloc()
struct ao2_container * container
#define ast_debug(level,...)
Log a DEBUG message.
#define AST_VECTOR(name, type)
Define a vector structure.
Core PBX routines and definitions.
void ast_sorcery_instance_observer_remove(struct ast_sorcery *sorcery, const struct ast_sorcery_instance_observer *callbacks)
Remove an observer from a sorcery instance.
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
static struct object_type_wizard * find_wizard(const char *object_type)
Finds the otw for the object type.
void(* retrieve_multiple)(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const struct ast_variable *fields)
Optional callback for retrieving multiple objects using some optional field criteria.
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Support for dynamic strings.
void ast_str_substitute_variables_varshead(struct ast_str **buf, ssize_t maxlen, struct varshead *headp, const char *templ)
int ast_unlock_contexts(void)
Unlocks contexts.
static struct sorcery_test_observer observer
Global scope observer structure for testing.
#define ast_module_ref(mod)
Hold a reference to the module.
int ast_wrlock_context(struct ast_context *con)
Write locks a given context.
void * ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, const char *id)
Allocate an object.
static struct ast_variable * get_object_variables(struct ast_variable *vars, char *prefix)
We need to strip off the prefix from the name of each variable so they're suitable for objectset_appl...
#define ast_sorcery_objectset_create(sorcery, object)
Create an object set (KVP list) for an object.
AST_VECTOR_RW(ast_sorcery_object_wizards, struct ast_sorcery_object_wizard *)
Interface for a sorcery object type wizards.
#define AST_VECTOR_RW_WRLOCK(vec)
Obtain write lock on vector.
Vector container support.
static void object_type_registered_observer(const char *name, struct ast_sorcery *sorcery, const char *object_type)
When each object type is registered, map a memory wizard to it.
Structure used to handle boolean flags.
void * ast_sorcery_retrieve_by_fields(const struct ast_sorcery *sorcery, const char *type, unsigned int flags, struct ast_variable *fields)
Retrieve an object or multiple objects using specific fields.
#define ast_module_unref(mod)
Release a reference to the module.
Interface for a sorcery wizard.
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
int ast_variable_lists_match(const struct ast_variable *left, const struct ast_variable *right, int exact_match)
Tests 2 variable lists to see if they match.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
void *(* retrieve_id)(const struct ast_sorcery *sorcery, void *data, const char *type, const char *id)
Callback for retrieving an object using an id.
Standard Command Line Interface.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar, int already_locked)
This functionc locks given context, search for the right extension and fires out all peer in this ext...
static int force_inline attribute_pure ast_begins_with(const char *str, const char *prefix)
Checks whether a string begins with another.
#define AST_VECTOR_REMOVE_ALL_CMP_UNORDERED(vec, value, cmp, cleanup)
Remove all elements from a vector that matches the given comparison.
static int variable_list_append(struct ast_variable **existing, const char *name, const char *value)
Appends a variable to the end of an existing list.
struct ast_category * ast_category_get(const struct ast_config *config, const char *category_name, const char *filter)
Retrieve a category if it exists.
struct ast_context * ast_context_find_or_create(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar)
Register a new context or find an existing one.
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
static int is_variable_true(struct ast_variable *vars, const char *name)
Finds the last variable in a list and tests it.
#define ASTERISK_GPL_KEY
The text the key() function should return.
Asterisk module definitions.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
ast_context: An extension context
struct ast_variable * ast_variables_dup(struct ast_variable *var)
Duplicate variable list.
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
int ast_add_extension2_nolock(struct ast_context *con, int replace, const char *extension, int priority, const char *label, const char *callerid, const char *application, void *data, void(*datad)(void *), const char *registrar, const char *registrar_file, int registrar_line)
Same as ast_add_extension2, but assumes you have already locked context.
const char * ast_category_get_name(const struct ast_category *category)
Return the name of the category.
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Sorcery Data Access Layer API.