summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES6
-rw-r--r--funcs/func_sorcery.c221
-rw-r--r--include/asterisk/config.h29
-rw-r--r--include/asterisk/sorcery.h66
-rw-r--r--main/bucket.c8
-rw-r--r--main/config.c20
-rw-r--r--main/sorcery.c87
-rw-r--r--res/res_pjsip/config_auth.c2
-rw-r--r--res/res_pjsip/config_transport.c41
-rw-r--r--res/res_pjsip/location.c69
-rw-r--r--res/res_pjsip/pjsip_configuration.c78
-rw-r--r--res/res_pjsip_acl.c12
-rw-r--r--res/res_pjsip_endpoint_identifier_ip.c28
-rw-r--r--res/res_pjsip_outbound_registration.c23
-rw-r--r--tests/test_sorcery.c323
15 files changed, 903 insertions, 110 deletions
diff --git a/CHANGES b/CHANGES
index 91acc9e5c..81ed1bc72 100644
--- a/CHANGES
+++ b/CHANGES
@@ -98,6 +98,12 @@ ARI
* The live recording object on recording events now contains a target_uri
field which contains the URI of what is being recorded.
+Core
+------------------
+ * Exposed sorcery-based configuration files like pjsip.conf to dialplans via
+ the new AST_SORCERY diaplan function.
+
+
------------------------------------------------------------------------------
--- Functionality changes from Asterisk 12.0.0 to Asterisk 12.1.0 ------------
------------------------------------------------------------------------------
diff --git a/funcs/func_sorcery.c b/funcs/func_sorcery.c
new file mode 100644
index 000000000..1671b3f05
--- /dev/null
+++ b/funcs/func_sorcery.c
@@ -0,0 +1,221 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Fairview 5 Engineering, LLC
+ *
+ * George Joseph <george.joseph@fairview5.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Get a field from a sorcery object
+ *
+ * \author \verbatim George Joseph <george.joseph@fairview5.com> \endverbatim
+ *
+ * \ingroup functions
+ *
+ */
+
+/*** MODULEINFO
+ <support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "")
+
+#include "asterisk/app.h"
+#include "asterisk/pbx.h"
+#include "asterisk/module.h"
+#include "asterisk/sorcery.h"
+
+/*** DOCUMENTATION
+ <function name="AST_SORCERY" language="en_US">
+ <synopsis>
+ Get a field from a sorcery object
+ </synopsis>
+ <syntax>
+ <parameter name="module_name" required="true">
+ <para>The name of the module owning the sorcery instance.</para>
+ </parameter>
+ <parameter name="object_type" required="true">
+ <para>The type of object to query.</para>
+ </parameter>
+ <parameter name="object_id" required="true">
+ <para>The id of the object to query.</para>
+ </parameter>
+ <parameter name="field_name" required="true">
+ <para>The name of the field.</para>
+ </parameter>
+ <parameter name="retrieval_method" required="false">
+ <para>Fields that have multiple occurrences may be retrieved in two ways.</para>
+ <enumlist>
+ <enum name="concat"><para>Returns all matching fields concatenated
+ in a single string separated by <replaceable>separator</replaceable>
+ which defaults to <literal>,</literal>.</para></enum>
+
+ <enum name="single"><para>Returns the nth occurrence of the field
+ as specified by <replaceable>occurrence_number</replaceable> which defaults to <literal>1</literal>.
+ </para></enum>
+ </enumlist>
+ <para>The default is <literal>concat</literal> with separator <literal>,</literal>.</para>
+ </parameter>
+ <parameter name="retrieval_details" required="false">
+ <para>Specifies either the separator for <literal>concat</literal>
+ or the occurrence number for <literal>single</literal>.</para>
+ </parameter>
+ </syntax>
+ </function>
+***/
+
+static int sorcery_function_read(struct ast_channel *chan,
+ const char *cmd, char *data, struct ast_str **buf, ssize_t len)
+{
+ char *parsed_data = ast_strdupa(data);
+ RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
+ RAII_VAR(void *, sorcery_obj, NULL, ao2_cleanup);
+ struct ast_variable *change_set;
+ struct ast_variable *it_change_set;
+ int found, field_number = 1, ix, method;
+ char *separator = ",";
+
+ enum methods {
+ CONCAT,
+ SINGLE,
+ };
+
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(module_name);
+ AST_APP_ARG(object_type);
+ AST_APP_ARG(object_id);
+ AST_APP_ARG(field_name);
+ AST_APP_ARG(method);
+ AST_APP_ARG(method_arg);
+ );
+
+ /* Check for zero arguments */
+ if (ast_strlen_zero(parsed_data)) {
+ ast_log(AST_LOG_ERROR, "Cannot call %s without arguments\n", cmd);
+ return -1;
+ }
+
+ AST_STANDARD_APP_ARGS(args, parsed_data);
+
+ if (ast_strlen_zero(args.module_name)) {
+ ast_log(AST_LOG_ERROR, "Cannot call %s without a module name to query\n", cmd);
+ return -1;
+ }
+
+ if (ast_strlen_zero(args.object_type)) {
+ ast_log(AST_LOG_ERROR, "Cannot call %s with an empty object type\n", cmd);
+ return -1;
+ }
+
+ if (ast_strlen_zero(args.object_id)) {
+ ast_log(AST_LOG_ERROR, "Cannot call %s with an empty object name\n", cmd);
+ return -1;
+ }
+
+ if (ast_strlen_zero(args.field_name)) {
+ ast_log(AST_LOG_ERROR, "Cannot call %s with an empty field name\n", cmd);
+ return -1;
+ }
+
+ if (ast_strlen_zero(args.method)) {
+ method = CONCAT;
+ } else {
+ if (strcmp(args.method, "concat") == 0) {
+ method = CONCAT;
+ if (ast_strlen_zero(args.method_arg)) {
+ separator = ",";
+ } else {
+ separator = args.method_arg;
+ }
+
+ } else if (strcmp(args.method, "single") == 0) {
+ method = SINGLE;
+ if (!ast_strlen_zero(args.method_arg)) {
+ if (sscanf(args.method_arg, "%30d", &field_number) <= 0 || field_number <= 0 ) {
+ ast_log(AST_LOG_ERROR, "occurrence_number must be a positive integer\n");
+ return -1;
+ }
+ }
+ } else {
+ ast_log(AST_LOG_ERROR, "Retrieval method must be 'concat' or 'single'\n");
+ return -1;
+ }
+ }
+
+ sorcery = ast_sorcery_retrieve_by_module_name(args.module_name);
+ if (!sorcery) {
+ ast_log(AST_LOG_ERROR, "Failed to retrieve sorcery instance for module %s\n", args.module_name);
+ return -1;
+ }
+
+ sorcery_obj = ast_sorcery_retrieve_by_id(sorcery, args.object_type, args.object_id);
+ if (!sorcery_obj) {
+ return -1;
+ }
+
+ change_set = ast_sorcery_objectset_create(sorcery, sorcery_obj);
+ if (!change_set) {
+ return -1;
+ }
+
+ ix=1;
+ found = 0;
+ for (it_change_set = change_set; it_change_set; it_change_set = it_change_set->next) {
+
+ if (method == CONCAT && strcmp(it_change_set->name, args.field_name) == 0) {
+ ast_str_append(buf, 0, "%s%s", it_change_set->value, separator);
+ found = 1;
+ continue;
+ }
+
+ if (method == SINGLE && strcmp(it_change_set->name, args.field_name) == 0 && ix++ == field_number) {
+ ast_str_set(buf, len, "%s", it_change_set->value);
+ found = 1;
+ break;
+ }
+ }
+
+ ast_variables_destroy(change_set);
+
+ if (!found) {
+ return -1;
+ }
+
+ if (method == CONCAT) {
+ ast_str_truncate(*buf, -1);
+ }
+
+ return 0;
+}
+
+static struct ast_custom_function sorcery_function = {
+ .name = "AST_SORCERY",
+ .read2 = sorcery_function_read,
+};
+
+static int unload_module(void)
+{
+ return ast_custom_function_unregister(&sorcery_function);
+}
+
+static int load_module(void)
+{
+ return ast_custom_function_register(&sorcery_function);
+}
+
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Get a field from a sorcery object");
+
diff --git a/include/asterisk/config.h b/include/asterisk/config.h
index 6d341db61..1c10d176b 100644
--- a/include/asterisk/config.h
+++ b/include/asterisk/config.h
@@ -691,7 +691,34 @@ void ast_include_rename(struct ast_config *conf, const char *from_file, const ch
void ast_variable_append(struct ast_category *category, struct ast_variable *variable);
void ast_variable_insert(struct ast_category *category, struct ast_variable *variable, const char *line);
int ast_variable_delete(struct ast_category *category, const char *variable, const char *match, const char *line);
-struct ast_variable *ast_variable_list_sort(struct ast_variable *start);
+
+/*!
+ * \brief Performs an in-place sort on the variable list by ascending name
+ *
+ * \param head The variable list head
+ *
+ * \return The new list head
+ */
+struct ast_variable *ast_variable_list_sort(struct ast_variable *head);
+
+/*!
+ * \brief Appends a variable list to the end of another list
+ *
+ * \param head A pointer to an ast_variable * of the existing variable list head. May NOT be NULL
+ * but the content may be to initialize a new list. If so, upon return, this parameter will be updated
+ * with a pointer to the new list head.
+ * \param search_hint The place in the current list to start searching for the end of the list.
+ * Might help performance on longer lists. If NULL, it defaults to head.
+ * \param new_var The head of the new variable list to be appended
+ *
+ * \return The tail of the resulting list.
+ *
+ * \note If the existing *head is NULL, it will be updated to new_var. This allows you to call
+ * ast_variable_list_append in a loop or callback without initializing the list first.
+ */
+struct ast_variable *ast_variable_list_append_hint(struct ast_variable **head, struct ast_variable *search_hint,
+ struct ast_variable *new_var);
+#define ast_variable_list_append(head, new_var) ast_variable_list_append_hint(head, NULL, new_var)
/*!
* \brief Update variable value within a config
diff --git a/include/asterisk/sorcery.h b/include/asterisk/sorcery.h
index cf11528d1..d4d62bfdb 100644
--- a/include/asterisk/sorcery.h
+++ b/include/asterisk/sorcery.h
@@ -119,6 +119,24 @@ enum ast_sorcery_retrieve_flags {
AST_RETRIEVE_FLAG_ALL = (1 << 1),
};
+/*!
+ * \brief Field handler flags
+ */
+enum ast_sorcery_field_handler_flags {
+ /*! \brief Try both handlers, string first */
+ AST_HANDLER_PREFER_STRING,
+
+ /*! \brief Try both handlers, list first */
+ AST_HANDLER_PREFER_LIST,
+
+ /*! \brief Use string handler only */
+ AST_HANDLER_ONLY_STRING,
+
+ /*! \brief Use list handler only */
+ AST_HANDLER_ONLY_LIST,
+};
+
+
/*! \brief Forward declaration for the sorcery main structure */
struct ast_sorcery;
@@ -465,15 +483,19 @@ int ast_sorcery_object_fields_register(struct ast_sorcery *sorcery, const char *
* \param type Type of object
* \param name Name of the field
* \param default_val Default value of the field
+ * \param config_handler A custom handler for translating the string representation of the fields
+ * \param sorcery_handler A custom handler for translating the native representation of the fields
+ * \param multiple_handler A custom handler for translating the native representation of the fields
* \param opt_type Option type
* \param flags Option type specific flags
*
* \retval 0 success
* \retval -1 failure
*/
-int __ast_sorcery_object_field_register(struct ast_sorcery *sorcery, const char *type, const char *name, const char *default_val, enum aco_option_type opt_type,
- aco_option_handler config_handler, sorcery_field_handler sorcery_handler, unsigned int flags, unsigned int no_doc,
- size_t argc, ...);
+int __ast_sorcery_object_field_register(struct ast_sorcery *sorcery, const char *type,
+ const char *name, const char *default_val, enum aco_option_type opt_type,
+ aco_option_handler config_handler, sorcery_field_handler sorcery_handler,
+ sorcery_fields_handler multiple_handler, unsigned int flags, unsigned int no_doc, size_t argc, ...);
/*!
* \brief Register a field within an object
@@ -489,7 +511,7 @@ int __ast_sorcery_object_field_register(struct ast_sorcery *sorcery, const char
* \retval -1 failure
*/
#define ast_sorcery_object_field_register(sorcery, type, name, default_val, opt_type, flags, ...) \
- __ast_sorcery_object_field_register(sorcery, type, name, default_val, opt_type, NULL, NULL, flags, 0, VA_NARGS(__VA_ARGS__), __VA_ARGS__)
+ __ast_sorcery_object_field_register(sorcery, type, name, default_val, opt_type, NULL, NULL, NULL, flags, 0, VA_NARGS(__VA_ARGS__), __VA_ARGS__)
/*!
* \brief Register a field within an object without documentation
@@ -505,7 +527,7 @@ int __ast_sorcery_object_field_register(struct ast_sorcery *sorcery, const char
* \retval -1 failure
*/
#define ast_sorcery_object_field_register_nodoc(sorcery, type, name, default_val, opt_type, flags, ...) \
- __ast_sorcery_object_field_register(sorcery, type, name, default_val, opt_type, NULL, NULL, flags, 1, VA_NARGS(__VA_ARGS__), __VA_ARGS__)
+ __ast_sorcery_object_field_register(sorcery, type, name, default_val, opt_type, NULL, NULL, NULL, flags, 1, VA_NARGS(__VA_ARGS__), __VA_ARGS__)
/*!
* \brief Register a field within an object with custom handlers
@@ -516,13 +538,14 @@ int __ast_sorcery_object_field_register(struct ast_sorcery *sorcery, const char
* \param default_val Default value of the field
* \param config_handler Custom configuration handler
* \param sorcery_handler Custom sorcery handler
+ * \param multiple_handler Custom multiple handler
* \param flags Option type specific flags
*
* \retval 0 success
* \retval -1 failure
*/
-#define ast_sorcery_object_field_register_custom(sorcery, type, name, default_val, config_handler, sorcery_handler, flags, ...) \
- __ast_sorcery_object_field_register(sorcery, type, name, default_val, OPT_CUSTOM_T, config_handler, sorcery_handler, flags, 0, VA_NARGS(__VA_ARGS__), __VA_ARGS__);
+#define ast_sorcery_object_field_register_custom(sorcery, type, name, default_val, config_handler, sorcery_handler, multiple_handler, flags, ...) \
+ __ast_sorcery_object_field_register(sorcery, type, name, default_val, OPT_CUSTOM_T, config_handler, sorcery_handler, multiple_handler, flags, 0, VA_NARGS(__VA_ARGS__), __VA_ARGS__);
/*!
* \brief Register a field within an object with custom handlers without documentation
@@ -533,13 +556,14 @@ int __ast_sorcery_object_field_register(struct ast_sorcery *sorcery, const char
* \param default_val Default value of the field
* \param config_handler Custom configuration handler
* \param sorcery_handler Custom sorcery handler
+ * \param multiple_handler Custom multiple handler
* \param flags Option type specific flags
*
* \retval 0 success
* \retval -1 failure
*/
-#define ast_sorcery_object_field_register_custom_nodoc(sorcery, type, name, default_val, config_handler, sorcery_handler, flags, ...) \
- __ast_sorcery_object_field_register(sorcery, type, name, default_val, OPT_CUSTOM_T, config_handler, sorcery_handler, flags, 1, VA_NARGS(__VA_ARGS__), __VA_ARGS__);
+#define ast_sorcery_object_field_register_custom_nodoc(sorcery, type, name, default_val, config_handler, sorcery_handler, multiple_handler, flags, ...) \
+ __ast_sorcery_object_field_register(sorcery, type, name, default_val, OPT_CUSTOM_T, config_handler, sorcery_handler, multiple_handler, flags, 1, VA_NARGS(__VA_ARGS__), __VA_ARGS__);
/*!
* \brief Inform any wizards to load persistent objects
@@ -578,6 +602,22 @@ void ast_sorcery_reload_object(const struct ast_sorcery *sorcery, const char *ty
*/
void ast_sorcery_ref(struct ast_sorcery *sorcery);
+
+/*!
+ * \brief Create an object set (KVP list) for an object
+ *
+ * \param sorcery Pointer to a sorcery structure
+ * \param object Pointer to a sorcery object
+ * \param flags Flags indicating which handler to use and in what order.
+ *
+ * \retval non-NULL success
+ * \retval NULL if error occurred
+ *
+ * \note The returned ast_variable list must be destroyed using ast_variables_destroy
+ */
+struct ast_variable *ast_sorcery_objectset_create2(const struct ast_sorcery *sorcery,
+ const void *object, enum ast_sorcery_field_handler_flags flags);
+
/*!
* \brief Create an object set (KVP list) for an object
*
@@ -588,8 +628,14 @@ void ast_sorcery_ref(struct ast_sorcery *sorcery);
* \retval NULL if error occurred
*
* \note The returned ast_variable list must be destroyed using ast_variables_destroy
+ *
+ * \note This function attempts to use a field's sorcery_fields_handler first and if that
+ * doesn't exist or fails, a field's sorcery_field_handler is used. The difference is
+ * that the former may return multiple list entries for the same field and the latter will only
+ * return 1. It's up to the field itself to determine what the appropriate content is.
*/
-struct ast_variable *ast_sorcery_objectset_create(const struct ast_sorcery *sorcery, const void *object);
+#define ast_sorcery_objectset_create(sorcery, object) \
+ ast_sorcery_objectset_create2(sorcery, object, AST_HANDLER_PREFER_LIST)
/*!
* \brief Create an object set in JSON format for an object
diff --git a/main/bucket.c b/main/bucket.c
index b3a0d3ca9..f698c570b 100644
--- a/main/bucket.c
+++ b/main/bucket.c
@@ -944,8 +944,8 @@ int ast_bucket_init(void)
}
ast_sorcery_object_field_register(bucket_sorcery, "bucket", "scheme", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_bucket, scheme));
- ast_sorcery_object_field_register_custom(bucket_sorcery, "bucket", "created", "", timeval_str2struct, timeval_struct2str, 0, FLDSET(struct ast_bucket, created));
- ast_sorcery_object_field_register_custom(bucket_sorcery, "bucket", "modified", "", timeval_str2struct, timeval_struct2str, 0, FLDSET(struct ast_bucket, modified));
+ ast_sorcery_object_field_register_custom(bucket_sorcery, "bucket", "created", "", timeval_str2struct, timeval_struct2str, NULL, 0, FLDSET(struct ast_bucket, created));
+ ast_sorcery_object_field_register_custom(bucket_sorcery, "bucket", "modified", "", timeval_str2struct, timeval_struct2str, NULL, 0, FLDSET(struct ast_bucket, modified));
if (ast_sorcery_apply_default(bucket_sorcery, "file", "bucket_file", NULL)) {
ast_log(LOG_ERROR, "Failed to apply intermediary for 'file' object type in Bucket sorcery\n");
@@ -958,8 +958,8 @@ int ast_bucket_init(void)
}
ast_sorcery_object_field_register(bucket_sorcery, "file", "scheme", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_bucket_file, scheme));
- ast_sorcery_object_field_register_custom(bucket_sorcery, "file", "created", "", timeval_str2struct, timeval_struct2str, 0, FLDSET(struct ast_bucket_file, created));
- ast_sorcery_object_field_register_custom(bucket_sorcery, "file", "modified", "", timeval_str2struct, timeval_struct2str, 0, FLDSET(struct ast_bucket_file, modified));
+ ast_sorcery_object_field_register_custom(bucket_sorcery, "file", "created", "", timeval_str2struct, timeval_struct2str, NULL, 0, FLDSET(struct ast_bucket_file, created));
+ ast_sorcery_object_field_register_custom(bucket_sorcery, "file", "modified", "", timeval_str2struct, timeval_struct2str, NULL, 0, FLDSET(struct ast_bucket_file, modified));
return 0;
}
diff --git a/main/config.c b/main/config.c
index 70ef6a804..db9182a46 100644
--- a/main/config.c
+++ b/main/config.c
@@ -620,6 +620,26 @@ struct ast_variable *ast_variable_list_sort(struct ast_variable *start)
return top.next;
}
+struct ast_variable *ast_variable_list_append_hint(struct ast_variable **head, struct ast_variable *search_hint, struct ast_variable *newvar)
+{
+ struct ast_variable *curr;
+ ast_assert(head != NULL);
+
+ if (!*head) {
+ *head = newvar;
+ } else {
+ if (search_hint == NULL) {
+ search_hint = *head;
+ }
+ for (curr = search_hint; curr->next; curr = curr->next);
+ curr->next = newvar;
+ }
+
+ for (curr = newvar; curr->next; curr = curr->next);
+
+ return curr;
+}
+
const char *ast_config_option(struct ast_config *cfg, const char *cat, const char *var)
{
const char *tmp;
diff --git a/main/sorcery.c b/main/sorcery.c
index bbdfa8cf2..99d051ab2 100644
--- a/main/sorcery.c
+++ b/main/sorcery.c
@@ -811,7 +811,7 @@ int ast_sorcery_object_fields_register(struct ast_sorcery *sorcery, const char *
}
int __ast_sorcery_object_field_register(struct ast_sorcery *sorcery, const char *type, const char *name, const char *default_val, enum aco_option_type opt_type,
- aco_option_handler config_handler, sorcery_field_handler sorcery_handler, unsigned int flags, unsigned int no_doc, size_t argc, ...)
+ aco_option_handler config_handler, sorcery_field_handler sorcery_handler, sorcery_fields_handler multiple_handler, unsigned int flags, unsigned int no_doc, size_t argc, ...)
{
RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
RAII_VAR(struct ast_sorcery_object_field *, object_field, NULL, ao2_cleanup);
@@ -832,6 +832,7 @@ int __ast_sorcery_object_field_register(struct ast_sorcery *sorcery, const char
ast_copy_string(object_field->name, name, sizeof(object_field->name));
object_field->handler = sorcery_handler;
+ object_field->multiple_handler = multiple_handler;
va_start(args, argc);
for (pos = 0; pos < argc; pos++) {
@@ -1015,13 +1016,47 @@ void ast_sorcery_ref(struct ast_sorcery *sorcery)
ao2_ref(sorcery, +1);
}
-struct ast_variable *ast_sorcery_objectset_create(const struct ast_sorcery *sorcery, const void *object)
+static struct ast_variable *get_single_field_as_var_list(const void *object, struct ast_sorcery_object_field *object_field)
+{
+ struct ast_variable *tmp = NULL;
+ char *buf = NULL;
+
+ if (!object_field->handler) {
+ return NULL;
+ }
+
+ if (!(object_field->handler(object, object_field->args, &buf))) {
+ tmp = ast_variable_new(object_field->name, S_OR(buf, ""), "");
+ }
+ ast_free(buf);
+
+ return tmp;
+}
+
+static struct ast_variable *get_multiple_fields_as_var_list(const void *object, struct ast_sorcery_object_field *object_field)
+{
+ struct ast_variable *tmp = NULL;
+
+ if (!object_field->multiple_handler) {
+ return NULL;
+ }
+
+ if (object_field->multiple_handler(object, &tmp)) {
+ ast_variables_destroy(tmp);
+ tmp = NULL;
+ }
+
+ return tmp;
+}
+
+struct ast_variable *ast_sorcery_objectset_create2(const struct ast_sorcery *sorcery,
+ const void *object, enum ast_sorcery_field_handler_flags flags)
{
const struct ast_sorcery_object_details *details = object;
RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
struct ao2_iterator i;
struct ast_sorcery_object_field *object_field;
- struct ast_variable *fields = NULL;
+ struct ast_variable *head = NULL, *tail = NULL;
int res = 0;
if (!object_type) {
@@ -1033,38 +1068,46 @@ struct ast_variable *ast_sorcery_objectset_create(const struct ast_sorcery *sorc
for (; (object_field = ao2_iterator_next(&i)) && !res; ao2_ref(object_field, -1)) {
struct ast_variable *tmp = NULL;
- if (object_field->multiple_handler) {
- if ((res = object_field->multiple_handler(object, &tmp))) {
- ast_variables_destroy(tmp);
+ switch (flags) {
+ case AST_HANDLER_PREFER_LIST:
+ if ((tmp = get_multiple_fields_as_var_list(object, object_field)) ||
+ (tmp = get_single_field_as_var_list(object, object_field))) {
+ break;
}
- } else if (object_field->handler) {
- char *buf = NULL;
-
- if ((res = object_field->handler(object, object_field->args, &buf)) ||
- !(tmp = ast_variable_new(object_field->name, S_OR(buf, ""), ""))) {
- res = -1;
+ continue;
+ case AST_HANDLER_PREFER_STRING:
+ if ((tmp = get_single_field_as_var_list(object, object_field)) ||
+ (tmp = get_multiple_fields_as_var_list(object, object_field))) {
+ break;
}
-
- ast_free(buf);
- } else {
+ continue;
+ case AST_HANDLER_ONLY_LIST:
+ if ((tmp = get_multiple_fields_as_var_list(object, object_field))) {
+ break;
+ }
+ continue;
+ case AST_HANDLER_ONLY_STRING:
+ if ((tmp = get_single_field_as_var_list(object, object_field))) {
+ break;
+ }
+ continue;
+ default:
continue;
}
- if (!res && tmp) {
- tmp->next = fields;
- fields = tmp;
- }
+ tail = ast_variable_list_append_hint(&head, tail, tmp);
+
}
ao2_iterator_destroy(&i);
/* If any error occurs we destroy all fields handled before so a partial objectset is not returned */
if (res) {
- ast_variables_destroy(fields);
- fields = NULL;
+ ast_variables_destroy(head);
+ head = NULL;
}
- return fields;
+ return head;
}
struct ast_json *ast_sorcery_objectset_json_create(const struct ast_sorcery *sorcery, const void *object)
diff --git a/res/res_pjsip/config_auth.c b/res/res_pjsip/config_auth.c
index 056449b60..bfba26253 100644
--- a/res/res_pjsip/config_auth.c
+++ b/res/res_pjsip/config_auth.c
@@ -323,7 +323,7 @@ int ast_sip_initialize_sorcery_auth(void)
ast_sorcery_object_field_register(sorcery, SIP_SORCERY_AUTH_TYPE, "nonce_lifetime",
"32", OPT_UINT_T, 0, FLDSET(struct ast_sip_auth, nonce_lifetime));
ast_sorcery_object_field_register_custom(sorcery, SIP_SORCERY_AUTH_TYPE, "auth_type",
- "userpass", auth_type_handler, auth_type_to_str, 0, 0);
+ "userpass", auth_type_handler, auth_type_to_str, NULL, 0, 0);
ast_sip_register_endpoint_formatter(&endpoint_auth_formatter);
ast_sip_register_cli_formatter(&cli_auth_formatter);
diff --git a/res/res_pjsip/config_transport.c b/res/res_pjsip/config_transport.c
index 58d0f1577..797427b4a 100644
--- a/res/res_pjsip/config_transport.c
+++ b/res/res_pjsip/config_transport.c
@@ -440,6 +440,29 @@ static int transport_localnet_handler(const struct aco_option *opt, struct ast_v
return error;
}
+static int localnet_to_vl(const void *obj, struct ast_variable **fields)
+{
+ const struct ast_sip_transport *transport = obj;
+
+ char str[MAX_OBJECT_FIELD];
+ struct ast_variable *head = NULL;
+ struct ast_ha *ha = transport->localnet;
+
+ for (; ha; ha = ha->next) {
+ const char *addr = ast_strdupa(ast_sockaddr_stringify_addr(&ha->addr));
+ snprintf(str, MAX_OBJECT_FIELD, "%s%s/%s", ha->sense == AST_SENSE_ALLOW ? "!" : "",
+ addr, ast_sockaddr_stringify_addr(&ha->netmask));
+
+ ast_variable_list_append(&head, ast_variable_new("local_net", str, ""));
+ }
+
+ if (head) {
+ *fields = head;
+ }
+
+ return 0;
+}
+
static int localnet_to_str(const void *obj, const intptr_t *args, char **buf)
{
RAII_VAR(struct ast_str *, str, ast_str_create(MAX_OBJECT_FIELD), ast_free);
@@ -599,8 +622,8 @@ int ast_sip_initialize_sorcery_transport(void)
}
ast_sorcery_object_field_register(sorcery, "transport", "type", "", OPT_NOOP_T, 0, 0);
- ast_sorcery_object_field_register_custom(sorcery, "transport", "protocol", "udp", transport_protocol_handler, transport_protocol_to_str, 0, 0);
- ast_sorcery_object_field_register_custom(sorcery, "transport", "bind", "", transport_bind_handler, transport_bind_to_str, 0, 0);
+ ast_sorcery_object_field_register_custom(sorcery, "transport", "protocol", "udp", transport_protocol_handler, transport_protocol_to_str, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(sorcery, "transport", "bind", "", transport_bind_handler, transport_bind_to_str, NULL, 0, 0);
ast_sorcery_object_field_register(sorcery, "transport", "async_operations", "1", OPT_UINT_T, 0, FLDSET(struct ast_sip_transport, async_operations));
ast_sorcery_object_field_register(sorcery, "transport", "ca_list_file", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, ca_list_file));
ast_sorcery_object_field_register(sorcery, "transport", "cert_file", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, cert_file));
@@ -610,13 +633,13 @@ int ast_sip_initialize_sorcery_transport(void)
ast_sorcery_object_field_register(sorcery, "transport", "external_signaling_port", "0", OPT_UINT_T, PARSE_IN_RANGE, FLDSET(struct ast_sip_transport, external_signaling_port), 0, 65535);
ast_sorcery_object_field_register(sorcery, "transport", "external_media_address", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, external_media_address));
ast_sorcery_object_field_register(sorcery, "transport", "domain", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, domain));
- ast_sorcery_object_field_register_custom(sorcery, "transport", "verify_server", "", transport_tls_bool_handler, verify_server_to_str, 0, 0);
- ast_sorcery_object_field_register_custom(sorcery, "transport", "verify_client", "", transport_tls_bool_handler, verify_client_to_str, 0, 0);
- ast_sorcery_object_field_register_custom(sorcery, "transport", "require_client_cert", "", transport_tls_bool_handler, require_client_cert_to_str, 0, 0);
- ast_sorcery_object_field_register_custom(sorcery, "transport", "method", "", transport_tls_method_handler, tls_method_to_str, 0, 0);
- ast_sorcery_object_field_register_custom(sorcery, "transport", "cipher", "", transport_tls_cipher_handler, transport_tls_cipher_to_str, 0, 0);
- ast_sorcery_object_field_register_custom(sorcery, "transport", "local_net", "", transport_localnet_handler, localnet_to_str, 0, 0);
- ast_sorcery_object_field_register_custom(sorcery, "transport", "tos", "0", transport_tos_handler, tos_to_str, 0, 0);
+ ast_sorcery_object_field_register_custom(sorcery, "transport", "verify_server", "", transport_tls_bool_handler, verify_server_to_str, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(sorcery, "transport", "verify_client", "", transport_tls_bool_handler, verify_client_to_str, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(sorcery, "transport", "require_client_cert", "", transport_tls_bool_handler, require_client_cert_to_str, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(sorcery, "transport", "method", "", transport_tls_method_handler, tls_method_to_str, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(sorcery, "transport", "cipher", "", transport_tls_cipher_handler, transport_tls_cipher_to_str, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(sorcery, "transport", "local_net", "", transport_localnet_handler, localnet_to_str, localnet_to_vl, 0, 0);
+ ast_sorcery_object_field_register_custom(sorcery, "transport", "tos", "0", transport_tos_handler, tos_to_str, NULL, 0, 0);
ast_sorcery_object_field_register(sorcery, "transport", "cos", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_transport, cos));
ast_sip_register_endpoint_formatter(&endpoint_transport_formatter);
diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c
index 6c77beefe..eb12d8e74 100644
--- a/res/res_pjsip/location.c
+++ b/res/res_pjsip/location.c
@@ -279,6 +279,25 @@ static int permanent_uri_handler(const struct aco_option *opt, struct ast_variab
return 0;
}
+static int contact_to_vl(void *object, void *arg, int flags)
+{
+ struct ast_sip_contact *contact = object;
+ struct ast_variable **var = arg;
+
+ ast_variable_list_append(&*var, ast_variable_new("contact", contact->uri, ""));
+
+ return 0;
+}
+
+static int contacts_to_vl(const void *obj, struct ast_variable **fields)
+{
+ const struct ast_sip_aor *aor = obj;
+
+ ast_sip_for_each_contact(aor, contact_to_vl, fields);
+
+ return 0;
+}
+
int ast_sip_for_each_aor(const char *aors, ao2_callback_fn on_aor, void *arg)
{
char *copy, *name;
@@ -343,7 +362,46 @@ int ast_sip_contact_to_str(void *object, void *arg, int flags)
static int sip_aor_to_ami(const struct ast_sip_aor *aor, struct ast_str **buf)
{
- return ast_sip_sorcery_object_to_ami(aor, buf);
+ RAII_VAR(struct ast_variable *, objset, ast_sorcery_objectset_create2(
+ ast_sip_get_sorcery(), aor, AST_HANDLER_ONLY_STRING), ast_variables_destroy);
+ struct ast_variable *i;
+
+ if (!objset) {
+ return -1;
+ }
+
+ ast_str_append(buf, 0, "ObjectType: %s\r\n",
+ ast_sorcery_object_get_type(aor));
+ ast_str_append(buf, 0, "ObjectName: %s\r\n",
+ ast_sorcery_object_get_id(aor));
+
+ for (i = objset; i; i = i->next) {
+ char *camel = ast_to_camel_case(i->name);
+ if (strcmp(camel, "Contact") == 0) {
+ ast_free(camel);
+ camel = NULL;
+ }
+ ast_str_append(buf, 0, "%s: %s\r\n", S_OR(camel, "Contacts"), i->value);
+ ast_free(camel);
+ }
+
+ return 0;
+}
+
+static int contacts_to_str(const void *obj, const intptr_t *args, char **buf)
+{
+ const struct ast_sip_aor *aor = obj;
+ RAII_VAR(struct ast_str *, str, ast_str_create(MAX_OBJECT_FIELD), ast_free);
+
+ ast_sip_for_each_contact(aor, ast_sip_contact_to_str, &str);
+ ast_str_truncate(str, -1);
+
+ *buf = ast_strdup(ast_str_buffer(str));
+ if (!*buf) {
+ return -1;
+ }
+
+ return 0;
}
static int format_ami_aor_handler(void *obj, void *arg, int flags)
@@ -364,11 +422,6 @@ static int format_ami_aor_handler(void *obj, void *arg, int flags)
}
sip_aor_to_ami(aor, &buf);
- ast_str_append(&buf, 0, "Contacts: ");
- ast_sip_for_each_contact(aor, ast_sip_contact_to_str, &buf);
- ast_str_truncate(buf, -1);
- ast_str_append(&buf, 0, "\r\n");
-
total_contacts = ao2_container_count(contacts);
num_permanent = aor->permanent_contacts ?
ao2_container_count(aor->permanent_contacts) : 0;
@@ -670,7 +723,7 @@ int ast_sip_initialize_sorcery_location(void)
ast_sorcery_object_field_register(sorcery, "contact", "type", "", OPT_NOOP_T, 0, 0);
ast_sorcery_object_field_register(sorcery, "contact", "uri", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, uri));
ast_sorcery_object_field_register(sorcery, "contact", "path", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, path));
- ast_sorcery_object_field_register_custom(sorcery, "contact", "expiration_time", "", expiration_str2struct, expiration_struct2str, 0, 0);
+ ast_sorcery_object_field_register_custom(sorcery, "contact", "expiration_time", "", expiration_str2struct, expiration_struct2str, NULL, 0, 0);
ast_sorcery_object_field_register(sorcery, "contact", "qualify_frequency", 0, OPT_UINT_T,
PARSE_IN_RANGE, FLDSET(struct ast_sip_contact, qualify_frequency), 0, 86400);
ast_sorcery_object_field_register(sorcery, "contact", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, outbound_proxy));
@@ -684,7 +737,7 @@ int ast_sip_initialize_sorcery_location(void)
ast_sorcery_object_field_register(sorcery, "aor", "authenticate_qualify", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_aor, authenticate_qualify));
ast_sorcery_object_field_register(sorcery, "aor", "max_contacts", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_aor, max_contacts));
ast_sorcery_object_field_register(sorcery, "aor", "remove_existing", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_aor, remove_existing));
- ast_sorcery_object_field_register_custom(sorcery, "aor", "contact", "", permanent_uri_handler, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(sorcery, "aor", "contact", "", permanent_uri_handler, contacts_to_str, contacts_to_vl, 0, 0);
ast_sorcery_object_field_register(sorcery, "aor", "mailboxes", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_aor, mailboxes));
ast_sorcery_object_field_register(sorcery, "aor", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_aor, outbound_proxy));
ast_sorcery_object_field_register(sorcery, "aor", "support_path", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_aor, support_path));
diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c
index 994987b7a..110be2906 100644
--- a/res/res_pjsip/pjsip_configuration.c
+++ b/res/res_pjsip/pjsip_configuration.c
@@ -809,12 +809,12 @@ static int set_var_handler(const struct aco_option *opt,
}
*val++ = '\0';
+
if (!(new_var = ast_variable_new(name, val, ""))) {
return -1;
}
- new_var->next = endpoint->channel_vars;
- endpoint->channel_vars = new_var;
+ ast_variable_list_append(&endpoint->channel_vars, new_var);
return 0;
}
@@ -834,6 +834,16 @@ static int set_var_to_str(const void *obj, const intptr_t *args, char **buf)
return 0;
}
+static int set_var_to_vl(const void *obj, struct ast_variable **fields)
+{
+ const struct ast_sip_endpoint *endpoint = obj;
+ if (endpoint->channel_vars) {
+ *fields = ast_variables_dup(endpoint->channel_vars);
+ }
+ return 0;
+}
+
+
static void *sip_nat_hook_alloc(const char *name)
{
return ast_sorcery_generic_alloc(sizeof(struct ast_sip_nat_hook), NULL);
@@ -1021,8 +1031,8 @@ static void sip_sorcery_object_ami_set_type_name(const void *obj, struct ast_str
int ast_sip_sorcery_object_to_ami(const void *obj, struct ast_str **buf)
{
- RAII_VAR(struct ast_variable *, objset, ast_sorcery_objectset_create(
- ast_sip_get_sorcery(), obj), ast_variables_destroy);
+ RAII_VAR(struct ast_variable *, objset, ast_sorcery_objectset_create2(
+ ast_sip_get_sorcery(), obj, AST_HANDLER_ONLY_STRING), ast_variables_destroy);
struct ast_variable *i;
if (!objset) {
@@ -1569,7 +1579,7 @@ int ast_res_pjsip_initialize_configuration(const struct ast_module_info *ast_mod
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "context", "default", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, context));
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "disallow", "", OPT_CODEC_T, 0, FLDSET(struct ast_sip_endpoint, media.prefs, media.codecs));
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allow", "", OPT_CODEC_T, 1, FLDSET(struct ast_sip_endpoint, media.prefs, media.codecs));
- ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtmf_mode", "rfc4733", dtmf_handler, dtmf_to_str, 0, 0);
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtmf_mode", "rfc4733", dtmf_handler, dtmf_to_str, NULL, 0, 0);
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtp_ipv6", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.ipv6));
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtp_symmetric", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.symmetric));
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "ice_support", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.ice_support));
@@ -1579,23 +1589,23 @@ int ast_res_pjsip_initialize_configuration(const struct ast_module_info *ast_mod
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "transport", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, transport));
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, outbound_proxy));
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "moh_suggest", "default", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, mohsuggest));
- ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "100rel", "yes", prack_handler, prack_to_str, 0, 0);
- ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "timers", "yes", timers_handler, timers_to_str, 0, 0);
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "100rel", "yes", prack_handler, prack_to_str, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "timers", "yes", timers_handler, timers_to_str, NULL, 0, 0);
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "timers_min_se", "90", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, extensions.timer.min_se));
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "timers_sess_expires", "1800", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, extensions.timer.sess_expires));
- ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "auth", "", inbound_auth_handler, inbound_auths_to_str, 0, 0);
- ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "outbound_auth", "", outbound_auth_handler, outbound_auths_to_str, 0, 0);
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "auth", "", inbound_auth_handler, inbound_auths_to_str, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "outbound_auth", "", outbound_auth_handler, outbound_auths_to_str, NULL, 0, 0);
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "aors", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, aors));
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "media_address", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, media.address));
- ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "identify_by", "username", ident_handler, ident_to_str, 0, 0);
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "identify_by", "username", ident_handler, ident_to_str, NULL, 0, 0);
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "direct_media", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.direct_media.enabled));
- ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "direct_media_method", "invite", direct_media_method_handler, direct_media_method_to_str, 0, 0);
- ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "connected_line_method", "invite", connected_line_method_handler, connected_line_method_to_str, 0, 0);
- ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "direct_media_glare_mitigation", "none", direct_media_glare_mitigation_handler, direct_media_glare_mitigation_to_str, 0, 0);
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "direct_media_method", "invite", direct_media_method_handler, direct_media_method_to_str, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "connected_line_method", "invite", connected_line_method_handler, connected_line_method_to_str, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "direct_media_glare_mitigation", "none", direct_media_glare_mitigation_handler, direct_media_glare_mitigation_to_str, NULL, 0, 0);
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "disable_direct_media_on_nat", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.direct_media.disable_on_nat));
- ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "callerid", "", caller_id_handler, caller_id_to_str, 0, 0);
- ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "callerid_privacy", "", caller_id_privacy_handler, caller_id_privacy_to_str, 0, 0);
- ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "callerid_tag", "", caller_id_tag_handler, caller_id_tag_to_str, 0, 0);
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "callerid", "", caller_id_handler, caller_id_to_str, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "callerid_privacy", "", caller_id_privacy_handler, caller_id_privacy_to_str, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "callerid_tag", "", caller_id_tag_handler, caller_id_tag_to_str, NULL, 0, 0);
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "trust_id_inbound", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, id.trust_inbound));
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "trust_id_outbound", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, id.trust_outbound));
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "send_pai", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, id.send_pai));
@@ -1603,17 +1613,17 @@ int ast_res_pjsip_initialize_configuration(const struct ast_module_info *ast_mod
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "send_diversion", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, id.send_diversion));
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "mailboxes", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, subscription.mwi.mailboxes));
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "aggregate_mwi", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, subscription.mwi.aggregate));
- ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "media_encryption", "no", media_encryption_handler, media_encryption_to_str, 0, 0);
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "media_encryption", "no", media_encryption_handler, media_encryption_to_str, NULL, 0, 0);
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "use_avpf", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.use_avpf));
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "one_touch_recording", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, info.recording.enabled));
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "inband_progress", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, inband_progress));
- ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "call_group", "", group_handler, callgroup_to_str, 0, 0);
- ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "pickup_group", "", group_handler, pickupgroup_to_str, 0, 0);
- ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "named_call_group", "", named_groups_handler, named_callgroups_to_str, 0, 0);
- ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "named_pickup_group", "", named_groups_handler, named_pickupgroups_to_str, 0, 0);
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "call_group", "", group_handler, callgroup_to_str, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "pickup_group", "", group_handler, pickupgroup_to_str, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "named_call_group", "", named_groups_handler, named_callgroups_to_str, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "named_pickup_group", "", named_groups_handler, named_pickupgroups_to_str, NULL, 0, 0);
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "device_state_busy_at", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, devicestate_busy_at));
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "t38_udptl", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.t38.enabled));
- ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "t38_udptl_ec", "none", t38udptl_ec_handler, t38udptl_ec_to_str, 0, 0);
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "t38_udptl_ec", "none", t38udptl_ec_handler, t38udptl_ec_to_str, NULL, 0, 0);
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "t38_udptl_maxdatagram", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.t38.maxdatagram));
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "fax_detect", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, faxdetect));
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "t38_udptl_nat", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.t38.nat));
@@ -1625,8 +1635,8 @@ int ast_res_pjsip_initialize_configuration(const struct ast_module_info *ast_mod
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allow_transfer", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, allowtransfer));
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "sdp_owner", "-", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, media.sdpowner));
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "sdp_session", "Asterisk", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, media.sdpsession));
- ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "tos_audio", "0", tos_handler, tos_audio_to_str, 0, 0);
- ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "tos_video", "0", tos_handler, tos_video_to_str, 0, 0);
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "tos_audio", "0", tos_handler, tos_audio_to_str, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "tos_video", "0", tos_handler, tos_video_to_str, NULL, 0, 0);
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "cos_audio", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.cos_audio));
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "cos_video", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.cos_video));
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allow_subscribe", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, subscription.allow));
@@ -1635,17 +1645,17 @@ int ast_res_pjsip_initialize_configuration(const struct ast_module_info *ast_mod
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "from_domain", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, fromdomain));
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "mwi_from_user", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, subscription.mwi.fromuser));
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtp_engine", "asterisk", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, media.rtp.engine));
- ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_verify", "", dtls_handler, dtlsverify_to_str, 0, 0);
- ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_rekey", "", dtls_handler, dtlsrekey_to_str, 0, 0);
- ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_cert_file", "", dtls_handler, dtlscertfile_to_str, 0, 0);
- ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_private_key", "", dtls_handler, dtlsprivatekey_to_str, 0, 0);
- ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_cipher", "", dtls_handler, dtlscipher_to_str, 0, 0);
- ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_ca_file", "", dtls_handler, dtlscafile_to_str, 0, 0);
- ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_ca_path", "", dtls_handler, dtlscapath_to_str, 0, 0);
- ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_setup", "", dtls_handler, dtlssetup_to_str, 0, 0);
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_verify", "", dtls_handler, dtlsverify_to_str, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_rekey", "", dtls_handler, dtlsrekey_to_str, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_cert_file", "", dtls_handler, dtlscertfile_to_str, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_private_key", "", dtls_handler, dtlsprivatekey_to_str, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_cipher", "", dtls_handler, dtlscipher_to_str, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_ca_file", "", dtls_handler, dtlscafile_to_str, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_ca_path", "", dtls_handler, dtlscapath_to_str, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_setup", "", dtls_handler, dtlssetup_to_str, NULL, 0, 0);
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "srtp_tag_32", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.srtp_tag_32));
- ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "redirect_method", "user", redirect_handler, NULL, 0, 0);
- ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "set_var", "", set_var_handler, set_var_to_str, 0, 0);
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "redirect_method", "user", redirect_handler, NULL, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "set_var", "", set_var_handler, set_var_to_str, set_var_to_vl, 0, 0);
if (ast_sip_initialize_sorcery_transport()) {
ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n");
diff --git a/res/res_pjsip_acl.c b/res/res_pjsip_acl.c
index 48c2ea4b5..acb073d4b 100644
--- a/res/res_pjsip_acl.c
+++ b/res/res_pjsip_acl.c
@@ -278,12 +278,12 @@ static int load_module(void)
}
ast_sorcery_object_field_register(ast_sip_get_sorcery(), SIP_SORCERY_ACL_TYPE, "type", "", OPT_NOOP_T, 0, 0);
- ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), SIP_SORCERY_ACL_TYPE, "permit", "", acl_handler, NULL, 0, 0);
- ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), SIP_SORCERY_ACL_TYPE, "deny", "", acl_handler, NULL, 0, 0);
- ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), SIP_SORCERY_ACL_TYPE, "acl", "", acl_handler, NULL, 0, 0);
- ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), SIP_SORCERY_ACL_TYPE, "contact_permit", "", acl_handler, NULL, 0, 0);
- ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), SIP_SORCERY_ACL_TYPE, "contact_deny", "", acl_handler, NULL, 0, 0);
- ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), SIP_SORCERY_ACL_TYPE, "contact_acl", "", acl_handler, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), SIP_SORCERY_ACL_TYPE, "permit", "", acl_handler, NULL, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), SIP_SORCERY_ACL_TYPE, "deny", "", acl_handler, NULL, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), SIP_SORCERY_ACL_TYPE, "acl", "", acl_handler, NULL, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), SIP_SORCERY_ACL_TYPE, "contact_permit", "", acl_handler, NULL, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), SIP_SORCERY_ACL_TYPE, "contact_deny", "", acl_handler, NULL, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), SIP_SORCERY_ACL_TYPE, "contact_acl", "", acl_handler, NULL, NULL, 0, 0);
ast_sip_register_service(&acl_module);
return AST_MODULE_LOAD_SUCCESS;
diff --git a/res/res_pjsip_endpoint_identifier_ip.c b/res/res_pjsip_endpoint_identifier_ip.c
index d78901e66..414f430a2 100644
--- a/res/res_pjsip_endpoint_identifier_ip.c
+++ b/res/res_pjsip_endpoint_identifier_ip.c
@@ -184,7 +184,8 @@ static int ip_identify_match_handler(const struct aco_option *opt, struct ast_va
return error;
}
-static int ip_identify_match_to_str(const void *obj, const intptr_t *args, char **buf)
+
+static int match_to_str(const void *obj, const intptr_t *args, char **buf)
{
RAII_VAR(struct ast_str *, str, ast_str_create(MAX_OBJECT_FIELD), ast_free);
const struct ip_identify_match *identify = obj;
@@ -194,6 +195,29 @@ static int ip_identify_match_to_str(const void *obj, const intptr_t *args, char
return 0;
}
+static int match_to_var_list(const void *obj, struct ast_variable **fields)
+{
+ char str[MAX_OBJECT_FIELD];
+ const struct ip_identify_match *identify = obj;
+ struct ast_variable *head = NULL;
+ struct ast_ha *ha = identify->matches;
+
+ for (; ha; ha = ha->next) {
+ const char *addr = ast_strdupa(ast_sockaddr_stringify_addr(&ha->addr));
+ snprintf(str, MAX_OBJECT_FIELD, "%s%s/%s", ha->sense == AST_SENSE_ALLOW ? "!" : "",
+ addr, ast_sockaddr_stringify_addr(&ha->netmask));
+
+ ast_variable_list_append(&head, ast_variable_new("match", str, ""));
+
+ }
+
+ if (head) {
+ *fields = head;
+ }
+
+ return 0;
+}
+
static int sip_identify_to_ami(const struct ip_identify_match *identify,
struct ast_str **buf)
{
@@ -374,7 +398,7 @@ static int load_module(void)
ast_sorcery_object_field_register(ast_sip_get_sorcery(), "identify", "type", "", OPT_NOOP_T, 0, 0);
ast_sorcery_object_field_register(ast_sip_get_sorcery(), "identify", "endpoint", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ip_identify_match, endpoint_name));
- ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), "identify", "match", "", ip_identify_match_handler, ip_identify_match_to_str, 0, 0);
+ ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), "identify", "match", "", ip_identify_match_handler, match_to_str, match_to_var_list, 0, 0);
ast_sorcery_reload_object(ast_sip_get_sorcery(), "identify");
ast_sip_register_endpoint_identifier(&ip_identifier);
diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c
index 0ef950711..019ac51cd 100644
--- a/res/res_pjsip_outbound_registration.c
+++ b/res/res_pjsip_outbound_registration.c
@@ -891,9 +891,28 @@ static int outbound_auth_handler(const struct aco_option *opt, struct ast_variab
static int outbound_auths_to_str(const void *obj, const intptr_t *args, char **buf)
{
const struct sip_outbound_registration *registration = obj;
+
return ast_sip_auths_to_str(&registration->outbound_auths, buf);
}
+static int outbound_auths_to_var_list(const void *obj, struct ast_variable **fields)
+{
+ const struct sip_outbound_registration *registration = obj;
+ int i;
+ struct ast_variable *head = NULL;
+
+ for (i = 0; i < AST_VECTOR_SIZE(&registration->outbound_auths) ; i++) {
+ ast_variable_list_append(&head, ast_variable_new("outbound_auth",
+ AST_VECTOR_GET(&registration->outbound_auths, i), ""));
+ }
+
+ if (head) {
+ *fields = head;
+ }
+
+ return 0;
+}
+
static struct sip_outbound_registration *retrieve_registration(const char *registration_name)
{
return ast_sorcery_retrieve_by_id(
@@ -1083,7 +1102,7 @@ static int ami_outbound_registration_detail(void *obj, void *arg, int flags)
static int ami_show_outbound_registrations(struct mansession *s,
const struct message *m)
{
- struct ast_sip_ami ami = { s = s, m = m };
+ struct ast_sip_ami ami = { .s = s, .m = m };
struct sip_ami_outbound ami_outbound = { .ami = &ami };
RAII_VAR(struct ao2_container *, regs, ast_sorcery_retrieve_by_fields(
ast_sip_get_sorcery(), "registration", AST_RETRIEVE_FLAG_MULTIPLE |
@@ -1240,7 +1259,7 @@ static int load_module(void)
ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "forbidden_retry_interval", "0", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, forbidden_retry_interval));
ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "max_retries", "10", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, max_retries));
ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "auth_rejection_permanent", "yes", OPT_BOOL_T, 1, FLDSET(struct sip_outbound_registration, auth_rejection_permanent));
- ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), "registration", "outbound_auth", "", outbound_auth_handler, outbound_auths_to_str, 0, 0);
+ ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), "registration", "outbound_auth", "", outbound_auth_handler, outbound_auths_to_str, outbound_auths_to_var_list, 0, 0);
ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "support_path", "no", OPT_BOOL_T, 1, FLDSET(struct sip_outbound_registration, support_path));
ast_sorcery_reload_object(ast_sip_get_sorcery(), "registration");
sip_outbound_registration_perform_all();
diff --git a/tests/test_sorcery.c b/tests/test_sorcery.c
index fe1992bc0..ed4d604e6 100644
--- a/tests/test_sorcery.c
+++ b/tests/test_sorcery.c
@@ -26,6 +26,7 @@
/*** MODULEINFO
<depend>TEST_FRAMEWORK</depend>
+ <depend>func_sorcery</depend>
<support_level>core</support_level>
***/
@@ -36,6 +37,7 @@ ASTERISK_FILE_VERSION(__FILE__, "")
#include "asterisk/test.h"
#include "asterisk/module.h"
#include "asterisk/astobj2.h"
+#include "asterisk/pbx.h"
#include "asterisk/sorcery.h"
#include "asterisk/logger.h"
#include "asterisk/json.h"
@@ -45,12 +47,22 @@ struct test_sorcery_object {
SORCERY_OBJECT(details);
unsigned int bob;
unsigned int joe;
+ struct ast_variable *jim;
+ struct ast_variable *jack;
};
+/*! \brief Internal function to destroy a test object */
+static void test_sorcery_object_destroy(void *obj)
+{
+ struct test_sorcery_object *tobj = obj;
+ ast_variables_destroy(tobj->jim);
+ ast_variables_destroy(tobj->jack);
+}
+
/*! \brief Internal function to allocate a test object */
static void *test_sorcery_object_alloc(const char *id)
{
- return ast_sorcery_generic_alloc(sizeof(struct test_sorcery_object), NULL);
+ return ast_sorcery_generic_alloc(sizeof(struct test_sorcery_object), test_sorcery_object_destroy);
}
/*! \brief Internal function for object set transformation */
@@ -85,6 +97,8 @@ static int test_sorcery_copy(const void *src, void *dst)
struct test_sorcery_object *obj = dst;
obj->bob = 10;
obj->joe = 20;
+ obj->jim = ast_variable_new("jim", "444", "");
+ obj->jack = ast_variable_new("jack", "999,000", "");
return 0;
}
@@ -235,6 +249,55 @@ static const struct ast_sorcery_observer test_observer = {
.loaded = sorcery_observer_loaded,
};
+/* This handler takes a simple value and creates new list entry for it*/
+static int jim_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+ struct test_sorcery_object *tobj = obj;
+
+ ast_variable_list_append(&tobj->jim, ast_variables_dup(var));
+
+ return 0;
+}
+
+/* This handler takes a CSV string and creates new a new list entry for each value */
+static int jack_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+ struct test_sorcery_object *tobj = obj;
+
+ char *jacks = ast_strdupa(var->value);
+ char *val;
+
+ while ((val = strsep(&jacks, ","))) {
+ ast_variable_list_append(&tobj->jack, ast_variable_new("jack", val, ""));
+ }
+ return 0;
+}
+
+static int jim_vl(const void *obj, struct ast_variable **fields)
+{
+ const struct test_sorcery_object *tobj = obj;
+ if (tobj->jim) {
+ *fields = ast_variables_dup(tobj->jim);
+ }
+ return 0;
+}
+
+static int jack_str(const void *obj, const intptr_t *args, char **buf)
+{
+ const struct test_sorcery_object *tobj = obj;
+ struct ast_variable *curr = tobj->jack;
+ RAII_VAR(struct ast_str *, str, ast_str_create(128), ast_free);
+
+ while(curr) {
+ ast_str_append(&str, 0, "%s,", curr->value);
+ curr = curr->next;
+ }
+ ast_str_truncate(str, -1);
+ *buf = ast_strdup(ast_str_buffer(str));
+ str = NULL;
+ return 0;
+}
+
static struct ast_sorcery *alloc_and_initialize_sorcery(void)
{
struct ast_sorcery *sorcery;
@@ -251,6 +314,8 @@ static struct ast_sorcery *alloc_and_initialize_sorcery(void)
ast_sorcery_object_field_register_nodoc(sorcery, "test", "bob", "5", OPT_UINT_T, 0, FLDSET(struct test_sorcery_object, bob));
ast_sorcery_object_field_register_nodoc(sorcery, "test", "joe", "10", OPT_UINT_T, 0, FLDSET(struct test_sorcery_object, joe));
+ ast_sorcery_object_field_register_custom_nodoc(sorcery, "test", "jim", "444", jim_handler, NULL, jim_vl, 0, 0);
+ ast_sorcery_object_field_register_custom_nodoc(sorcery, "test", "jack", "888,999", jack_handler, jack_str, NULL, 0, 0);
return sorcery;
}
@@ -727,6 +792,8 @@ AST_TEST_DEFINE(object_copy)
obj->bob = 50;
obj->joe = 100;
+ jim_handler(NULL, ast_variable_new("jim", "444", ""), obj);
+ jim_handler(NULL, ast_variable_new("jim", "555", ""), obj);
if (!(copy = ast_sorcery_copy(sorcery, obj))) {
ast_test_status_update(test, "Failed to create a copy of a known valid object\n");
@@ -740,6 +807,22 @@ AST_TEST_DEFINE(object_copy)
} else if (copy->joe != obj->joe) {
ast_test_status_update(test, "Value of 'joe' on newly created copy is not the same as original\n");
res = AST_TEST_FAIL;
+ } else if (!copy->jim) {
+ ast_test_status_update(test, "A new ast_variable was not created for 'jim'\n");
+ res = AST_TEST_FAIL;
+ } else if (copy->jim == obj->jim) {
+ ast_test_status_update(test, "Created copy of 'jim' is actually the ogirinal 'jim'\n");
+ res = AST_TEST_FAIL;
+ } else if (strcmp(copy->jim->value, obj->jim->value)) {
+ ast_test_status_update(test, "Value of 1st 'jim' on newly created copy is not the same as original\n");
+ res = AST_TEST_FAIL;
+ } else if (!copy->jim->next) {
+ ast_test_status_update(test, "A new ast_variable was not created for 2nd 'jim'\n");
+ res = AST_TEST_FAIL;
+ } else if (strcmp(copy->jim->next->value, obj->jim->next->value)) {
+ ast_test_status_update(test, "Value of 2nd 'jim' (%s %s) on newly created copy is not the same as original (%s %s)\n",
+ copy->jim->value, copy->jim->next->value, obj->jim->value, obj->jim->next->value);
+ res = AST_TEST_FAIL;
}
return res;
@@ -791,6 +874,12 @@ AST_TEST_DEFINE(object_copy_native)
} else if (copy->joe != 20) {
ast_test_status_update(test, "Value of 'joe' on newly created copy is not the predefined native copy value\n");
res = AST_TEST_FAIL;
+ } else if (!copy->jim) {
+ ast_test_status_update(test, "A new ast_variable was not created for 'jim'\n");
+ res = AST_TEST_FAIL;
+ } else if (strcmp(copy->jim->value, "444")) {
+ ast_test_status_update(test, "Value of 'jim' on newly created copy is not the predefined native copy value\n");
+ res = AST_TEST_FAIL;
}
return res;
@@ -804,6 +893,7 @@ AST_TEST_DEFINE(object_diff)
RAII_VAR(struct ast_variable *, changes, NULL, ast_variables_destroy);
struct ast_variable *field;
int res = AST_TEST_PASS;
+ int jims = 0;
switch (cmd) {
case TEST_INIT:
@@ -829,6 +919,8 @@ AST_TEST_DEFINE(object_diff)
obj1->bob = 99;
obj1->joe = 55;
+ jim_handler(NULL, ast_variable_new("jim", "444", ""), obj1);
+ jim_handler(NULL, ast_variable_new("jim", "555", ""), obj1);
if (!(obj2 = ast_sorcery_alloc(sorcery, "test", "blah2"))) {
ast_test_status_update(test, "Failed to allocate a second known object type\n");
@@ -837,6 +929,9 @@ AST_TEST_DEFINE(object_diff)
obj2->bob = 99;
obj2->joe = 42;
+ jim_handler(NULL, ast_variable_new("jim", "444", ""), obj2);
+ jim_handler(NULL, ast_variable_new("jim", "666", ""), obj2);
+ jim_handler(NULL, ast_variable_new("jim", "777", ""), obj2);
if (ast_sorcery_diff(sorcery, obj1, obj2, &changes)) {
ast_test_status_update(test, "Failed to diff obj1 and obj2\n");
@@ -845,16 +940,30 @@ AST_TEST_DEFINE(object_diff)
return AST_TEST_FAIL;
}
- for (field = changes; field; field = field->next) {
- if (!strcmp(field->name, "joe")) {
- if (strcmp(field->value, "42")) {
- ast_test_status_update(test, "Object diff produced unexpected value '%s' for joe\n", field->value);
- res = AST_TEST_FAIL;
- }
- } else {
- ast_test_status_update(test, "Object diff produced unexpected field '%s'\n", field->name);
- res = AST_TEST_FAIL;
- }
+ for (field = changes; field; field = field->next) {
+ if (!strcmp(field->name, "joe")) {
+ if (strcmp(field->value, "42")) {
+ ast_test_status_update(test,
+ "Object diff produced unexpected value '%s' for joe\n", field->value);
+ res = AST_TEST_FAIL;
+ }
+ } else if (!strcmp(field->name, "jim")) {
+ jims++;
+ if (!strcmp(field->value, "555")) {
+ ast_test_status_update(test,
+ "Object diff produced unexpected value '%s' for jim\n", field->value);
+ res = AST_TEST_FAIL;
+ }
+ } else {
+ ast_test_status_update(test, "Object diff produced unexpected field '%s'\n",
+ field->name);
+ res = AST_TEST_FAIL;
+ }
+ }
+
+ if (jims != 2) {
+ ast_test_status_update(test, "Object diff didn't produce 2 jims\n");
+ res = AST_TEST_FAIL;
}
return res;
@@ -972,6 +1081,16 @@ AST_TEST_DEFINE(objectset_create)
ast_test_status_update(test, "Object set failed to create proper value for 'joe'\n");
res = AST_TEST_FAIL;
}
+ } else if (!strcmp(field->name, "jim")) {
+ if (strcmp(field->value, "444")) {
+ ast_test_status_update(test, "Object set failed to create proper value for 'jim'\n");
+ res = AST_TEST_FAIL;
+ }
+ } else if (!strcmp(field->name, "jack")) {
+ if (strcmp(field->value, "888,999")) {
+ ast_test_status_update(test, "Object set failed to create proper value (%s) for 'jack'\n", field->value);
+ res = AST_TEST_FAIL;
+ }
} else {
ast_test_status_update(test, "Object set created field '%s' which is unknown\n", field->name);
res = AST_TEST_FAIL;
@@ -1029,6 +1148,16 @@ AST_TEST_DEFINE(objectset_json_create)
ast_test_status_update(test, "Object set failed to create proper value for 'joe'\n");
res = AST_TEST_FAIL;
}
+ } else if (!strcmp(ast_json_object_iter_key(field), "jim")) {
+ if (strcmp(ast_json_string_get(value), "444")) {
+ ast_test_status_update(test, "Object set failed to create proper value for 'jim'\n");
+ res = AST_TEST_FAIL;
+ }
+ } else if (!strcmp(ast_json_object_iter_key(field), "jack")) {
+ if (strcmp(ast_json_string_get(value), "888,999")) {
+ ast_test_status_update(test, "Object set failed to create proper value for 'jack'\n");
+ res = AST_TEST_FAIL;
+ }
} else {
ast_test_status_update(test, "Object set created field '%s' which is unknown\n", ast_json_object_iter_key(field));
res = AST_TEST_FAIL;
@@ -2696,6 +2825,176 @@ AST_TEST_DEFINE(configuration_file_wizard_retrieve_multiple_all)
return AST_TEST_PASS;
}
+AST_TEST_DEFINE(dialplan_function)
+{
+ RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
+ RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy);
+ struct ast_str *buf;
+ char expression[256];
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "dialplan_function";
+ info->category = "/main/sorcery/";
+ info->summary = "AST_SORCERY dialplan function";
+ info->description =
+ "Test the AST_SORCERY dialplan function";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ if (!(sorcery = alloc_and_initialize_sorcery())) {
+ ast_test_status_update(test, "Failed to open sorcery structure\n");
+ return AST_TEST_FAIL;
+ }
+
+ if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
+ ast_test_status_update(test, "Failed to allocate a known object type\n");
+ return AST_TEST_FAIL;
+ }
+
+ if (ast_sorcery_create(sorcery, obj)) {
+ ast_test_status_update(test, "Failed to create a known object type\n");
+ return AST_TEST_FAIL;
+ }
+
+ if (!(buf = ast_str_create(16))) {
+ ast_test_status_update(test, "Failed to allocate return buffer\n");
+ return AST_TEST_FAIL;
+ }
+
+ ast_str_reset(buf);
+ snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s)", "notest_sorcery", "test", "blah", "bob");
+ if (!ast_func_read2(NULL, expression, &buf, 16)) {
+ ast_free(buf);
+ ast_test_status_update(test, "Retrieved a non-existent module\n");
+ return AST_TEST_FAIL;
+ }
+
+ ast_str_reset(buf);
+ snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s)", "test_sorcery", "notest", "blah", "bob");
+ if (!ast_func_read2(NULL, expression, &buf, 16)) {
+ ast_free(buf);
+ ast_test_status_update(test, "Retrieved a non-existent type\n");
+ return AST_TEST_FAIL;
+ }
+
+ ast_str_reset(buf);
+ snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s)", "test_sorcery", "test", "noid", "bob");
+ if (!ast_func_read2(NULL, expression, &buf, 16)) {
+ ast_free(buf);
+ ast_test_status_update(test, "Retrieved a non-existent id\n");
+ return AST_TEST_FAIL;
+ }
+
+ ast_str_reset(buf);
+ snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s)", "test_sorcery", "test", "blah", "nobob");
+ if (!ast_func_read2(NULL, expression, &buf, 16)) {
+ ast_free(buf);
+ ast_test_status_update(test, "Retrieved a non-existent field\n");
+ return AST_TEST_FAIL;
+ }
+
+ ast_str_reset(buf);
+ snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s)", "test_sorcery", "test", "blah", "bob");
+ if (ast_func_read2(NULL, expression, &buf, 16)) {
+ ast_free(buf);
+ ast_test_status_update(test, "Failed retrieve field 'bob'\n");
+ return AST_TEST_FAIL;
+ }
+ if (strcmp(ast_str_buffer(buf), "5")) {
+ ast_free(buf);
+ ast_test_status_update(test, "Failed retrieve field. Got '%d', should be '5'\n", obj->bob);
+ return AST_TEST_FAIL;
+ }
+
+ ast_str_reset(buf);
+ snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s,single,1)", "test_sorcery", "test", "blah", "bob");
+ if (ast_func_read2(NULL, expression, &buf, 16)) {
+ ast_free(buf);
+ ast_test_status_update(test, "Failed retrieve field 'bob'\n");
+ return AST_TEST_FAIL;
+ }
+ if (strcmp(ast_str_buffer(buf), "5")) {
+ ast_free(buf);
+ ast_test_status_update(test, "Failed retrieve field. Got '%d', should be '5'\n", obj->bob);
+ return AST_TEST_FAIL;
+ }
+
+ ast_str_reset(buf);
+ snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s,single,2)", "test_sorcery", "test", "blah", "bob");
+ if (!ast_func_read2(NULL, expression, &buf, 16)) {
+ ast_free(buf);
+ ast_test_status_update(test, "Got a second 'bob' and shouldn't have\n");
+ return AST_TEST_FAIL;
+ }
+
+ /* 444 is already the first item in the list */
+ jim_handler(NULL, ast_variable_new("jim", "555", ""), obj);
+ jim_handler(NULL, ast_variable_new("jim", "666", ""), obj);
+
+ ast_str_reset(buf);
+ snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s)", "test_sorcery", "test", "blah", "jim");
+ if (ast_func_read2(NULL, expression, &buf, 16)) {
+ ast_free(buf);
+ ast_test_status_update(test, "Couldn't retrieve 'jim'\n");
+ return AST_TEST_FAIL;
+ }
+ if (strcmp(ast_str_buffer(buf), "444,555,666")) {
+ ast_free(buf);
+ ast_test_status_update(test, "Failed retrieve jim. Got '%s', should be '444,555,666'\n", ast_str_buffer(buf));
+ return AST_TEST_FAIL;
+ }
+
+ ast_str_reset(buf);
+ snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s,single,2)", "test_sorcery", "test", "blah", "jim");
+ if (ast_func_read2(NULL, expression, &buf, 16)) {
+ ast_free(buf);
+ ast_test_status_update(test, "Couldn't retrieve 2nd jim\n");
+ return AST_TEST_FAIL;
+ }
+ if (strcmp(ast_str_buffer(buf), "555")) {
+ ast_free(buf);
+ ast_test_status_update(test, "Failed retrieve 2nd jim. Got '%s', should be '555'\n", ast_str_buffer(buf));
+ return AST_TEST_FAIL;
+ }
+
+ ast_str_reset(buf);
+ snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s,concat,|)", "test_sorcery", "test", "blah", "jim");
+ if (ast_func_read2(NULL, expression, &buf, 16)) {
+ ast_free(buf);
+ ast_test_status_update(test, "Couldn't retrieve any 'jim'\n");
+ return AST_TEST_FAIL;
+ }
+ if (strcmp(ast_str_buffer(buf), "444|555|666")) {
+ ast_free(buf);
+ ast_test_status_update(test, "Failed retrieve 'jim'. Got '%s', should be '444|555|666'\n", ast_str_buffer(buf));
+ return AST_TEST_FAIL;
+ }
+
+ ast_str_reset(buf);
+ snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s,noconcat,3)", "test_sorcery", "test", "blah", "jim");
+ if (!ast_func_read2(NULL, expression, &buf, 16)) {
+ ast_free(buf);
+ ast_test_status_update(test, "Should have failed with invalid retrieval_type\n");
+ return AST_TEST_FAIL;
+ }
+
+ ast_str_reset(buf);
+ snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s,single,|)", "test_sorcery", "test", "blah", "jim");
+ if (!ast_func_read2(NULL, expression, &buf, 16)) {
+ ast_free(buf);
+ ast_test_status_update(test, "Should have failed with invalid occurrence_number\n");
+ return AST_TEST_FAIL;
+ }
+
+ ast_free(buf);
+
+ return AST_TEST_PASS;
+}
+
static int unload_module(void)
{
AST_TEST_UNREGISTER(wizard_registration);
@@ -2741,6 +3040,7 @@ static int unload_module(void)
AST_TEST_UNREGISTER(configuration_file_wizard_retrieve_field);
AST_TEST_UNREGISTER(configuration_file_wizard_retrieve_multiple);
AST_TEST_UNREGISTER(configuration_file_wizard_retrieve_multiple_all);
+ AST_TEST_UNREGISTER(dialplan_function);
return 0;
}
@@ -2789,6 +3089,7 @@ static int load_module(void)
AST_TEST_REGISTER(configuration_file_wizard_retrieve_field);
AST_TEST_REGISTER(configuration_file_wizard_retrieve_multiple);
AST_TEST_REGISTER(configuration_file_wizard_retrieve_multiple_all);
+ AST_TEST_REGISTER(dialplan_function);
return AST_MODULE_LOAD_SUCCESS;
}