[asterisk-commits] gtjoseph: trunk r424965 - in /trunk: ./ configs/samples/ include/asterisk/ ma...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Thu Oct 9 12:46:27 CDT 2014
Author: gtjoseph
Date: Thu Oct 9 12:46:23 2014
New Revision: 424965
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=424965
Log:
res_phoneprov: Refactor phoneprov to allow pluggable config providers
This patch makes res_phoneprov more modular so other modules (like pjsip)
can provide configuration information instead of res_phoneprov relying solely
on users.conf and sip.conf. To accomplish this a new ast_phoneprov public API
is now exposed which allows config providers to register themselves, set
defaults (server profile, etc) and add user extensions.
* ast_phoneprov_provider_register registers the provider and provides callbacks
for loading default settings and loading users.
* ast_phoneprov_provider_unregister clears the defaults and users.
* ast_phoneprov_add_extension should be called once for each user/extension
by the provider's load_users callback to add them.
* ast_phoneprov_delete_extension deletes one extension.
* ast_phoneprov_delete_extensions deletes all extensions for the provider.
Tested-by: George Joseph
Review: https://reviewboard.asterisk.org/r/3970/
........
Merged revisions 424963 from http://svn.asterisk.org/svn/asterisk/branches/12
........
Merged revisions 424964 from http://svn.asterisk.org/svn/asterisk/branches/13
Added:
trunk/include/asterisk/phoneprov.h
- copied unchanged from r424964, branches/13/include/asterisk/phoneprov.h
trunk/res/res_phoneprov.exports.in
- copied unchanged from r424964, branches/13/res/res_phoneprov.exports.in
Modified:
trunk/ (props changed)
trunk/configs/samples/phoneprov.conf.sample
trunk/include/asterisk/chanvars.h
trunk/main/chanvars.c
trunk/res/res_phoneprov.c
Propchange: trunk/
------------------------------------------------------------------------------
Binary property 'branch-13-merged' - no diff available.
Modified: trunk/configs/samples/phoneprov.conf.sample
URL: http://svnview.digium.com/svn/asterisk/trunk/configs/samples/phoneprov.conf.sample?view=diff&rev=424965&r1=424964&r2=424965
==============================================================================
--- trunk/configs/samples/phoneprov.conf.sample (original)
+++ trunk/configs/samples/phoneprov.conf.sample Thu Oct 9 12:46:23 2014
@@ -1,4 +1,7 @@
[general]
+; This section applies only to the default sip.conf/users.conf config provider
+; embedded in res_phoneprov. Other providers may provide their own default settings.
+
; The default behavior of res_phoneprov will be to set the SERVER template variable to
; the IP address that the phone uses to contact the provisioning server and the
; SERVER_PORT variable to the bindport setting in sip.conf. Unless you have a very
@@ -15,7 +18,8 @@
; with the provisioning server. You can define either static files, or dynamically
; generated files that can have dynamic names and point to templates that variables
; can be substituted into. You can also set arbitrary variables for the profiles
-; templates to have access to. Example:
+; templates to have access to. Profiles are shared across all config providers.
+; Example:
;[example]
;mime_type => application/octet-stream
@@ -25,7 +29,9 @@
;setvar => DB_CIDNAME=${ODBC_CID_NAME_LOOKUP(${USERNAME})}
; Dynamically generated files have a filename registered with variable substitution
-; with variables obtained while reading users.conf.
+; with variables obtained from various config providers. The default provider
+; embedded in res_phoneprov reads users.conf. Other providers will have their own
+; sources for the variables and may provide additional variables not listed here.
; Built in variables and the options in users.conf that they come from
; MAC (macaddress)
Modified: trunk/include/asterisk/chanvars.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/chanvars.h?view=diff&rev=424965&r1=424964&r2=424965
==============================================================================
--- trunk/include/asterisk/chanvars.h (original)
+++ trunk/include/asterisk/chanvars.h Thu Oct 9 12:46:23 2014
@@ -33,6 +33,8 @@
AST_LIST_HEAD_NOLOCK(varshead, ast_var_t);
+struct varshead *ast_var_list_create(void);
+void ast_var_list_destroy(struct varshead *head);
#ifdef MALLOC_DEBUG
struct ast_var_t *_ast_var_assign(const char *name, const char *value, const char *file, int lineno, const char *function);
#define ast_var_assign(a,b) _ast_var_assign(a,b,__FILE__,__LINE__,__PRETTY_FUNCTION__)
@@ -43,5 +45,21 @@
const char *ast_var_name(const struct ast_var_t *var);
const char *ast_var_full_name(const struct ast_var_t *var);
const char *ast_var_value(const struct ast_var_t *var);
+char *ast_var_find(const struct varshead *head, const char *name);
+struct varshead *ast_var_list_clone(struct varshead *head);
+
+#define AST_VAR_LIST_TRAVERSE(head, var) AST_LIST_TRAVERSE(head, var, entries)
+
+static inline void AST_VAR_LIST_INSERT_TAIL(struct varshead *head, struct ast_var_t *var) {
+ if (var) {
+ AST_LIST_INSERT_TAIL(head, var, entries);
+ }
+}
+
+static inline void AST_VAR_LIST_INSERT_HEAD(struct varshead *head, struct ast_var_t *var) {
+ if (var) {
+ AST_LIST_INSERT_HEAD(head, var, entries);
+ }
+}
#endif /* _ASTERISK_CHANVARS_H */
Modified: trunk/main/chanvars.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/chanvars.c?view=diff&rev=424965&r1=424964&r2=424965
==============================================================================
--- trunk/main/chanvars.c (original)
+++ trunk/main/chanvars.c Thu Oct 9 12:46:23 2014
@@ -90,4 +90,67 @@
return (var ? var->value : NULL);
}
+char *ast_var_find(const struct varshead *head, const char *name)
+{
+ struct ast_var_t *var;
+ AST_LIST_TRAVERSE(head, var, entries) {
+ if (!strcmp(name, var->name)) {
+ return var->value;
+ }
+ }
+ return NULL;
+}
+
+struct varshead *ast_var_list_create(void)
+{
+ struct varshead *head;
+
+ head = ast_calloc(1, sizeof(*head));
+ if (!head) {
+ return NULL;
+ }
+ AST_LIST_HEAD_INIT_NOLOCK(head);
+ return head;
+}
+
+void ast_var_list_destroy(struct varshead *head)
+{
+ struct ast_var_t *var;
+
+ if (!head) {
+ return;
+ }
+
+ while ((var = AST_LIST_REMOVE_HEAD(head, entries))) {
+ ast_var_delete(var);
+ }
+
+ ast_free(head);
+}
+
+struct varshead *ast_var_list_clone(struct varshead *head)
+{
+ struct varshead *clone;
+ struct ast_var_t *var, *newvar;
+
+ if (!head) {
+ return NULL;
+ }
+
+ clone = ast_var_list_create();
+ if (!clone) {
+ return NULL;
+ }
+
+ AST_VAR_LIST_TRAVERSE(head, var) {
+ newvar = ast_var_assign(var->name, var->value);
+ if (!newvar) {
+ ast_var_list_destroy(clone);
+ return NULL;
+ }
+ AST_VAR_LIST_INSERT_TAIL(clone, newvar);
+ }
+
+ return clone;
+}
Modified: trunk/res/res_phoneprov.c
URL: http://svnview.digium.com/svn/asterisk/trunk/res/res_phoneprov.c?view=diff&rev=424965&r1=424964&r2=424965
==============================================================================
--- trunk/res/res_phoneprov.c (original)
+++ trunk/res/res_phoneprov.c Thu Oct 9 12:46:23 2014
@@ -2,10 +2,12 @@
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 1999 - 2008, Digium, Inc.
+ * Copyright (C) 2014, Fairview 5 Engineering, LLC
*
* Mark Spencer <markster at digium.com>
* Matthew Brooks <mbrooks at digium.com>
* Terry Wilson <twilson at digium.com>
+ * George Joseph <george.joseph at fairview5.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
@@ -24,7 +26,8 @@
*
* \author Matthew Brooks <mbrooks at digium.com>
* \author Terry Wilson <twilson at digium.com>
- */
+ * \author George Joseph <george.joseph at fairview5.com>
+ */
/*! \li \ref res_phoneprov.c uses the configuration file \ref phoneprov.conf and \ref users.conf and \ref sip.conf
* \addtogroup configuration_file Configuration Files
@@ -38,6 +41,8 @@
/*** MODULEINFO
<support_level>extended</support_level>
***/
+
+#define AST_API_MODULE
#include "asterisk.h"
@@ -65,12 +70,15 @@
#include "asterisk/acl.h"
#include "asterisk/astobj2.h"
#include "asterisk/ast_version.h"
+#include "asterisk/phoneprov.h"
#ifdef LOW_MEMORY
+#define MAX_PROVIDER_BUCKETS 1
#define MAX_PROFILE_BUCKETS 1
#define MAX_ROUTE_BUCKETS 1
#define MAX_USER_BUCKETS 1
#else
+#define MAX_PROVIDER_BUCKETS 17
#define MAX_PROFILE_BUCKETS 17
#define MAX_ROUTE_BUCKETS 563
#define MAX_USER_BUCKETS 563
@@ -85,7 +93,7 @@
</synopsis>
<syntax>
<parameter name="mac" required="true" />
- <parameter name="template" required="true" />
+ <parameter name="template_file" required="true" />
</syntax>
<description>
<para>Output the specified template for each extension associated with the specified MAC address.</para>
@@ -109,41 +117,162 @@
</function>
***/
+/*!
+ * \brief Creates a hash function for a structure string field.
+ * \param fname The name to use for the function
+ * \param stype The structure type
+ * \param field The field in the structure to hash
+ *
+ * SIMPLE_HASH_FN(mystruct, myfield) will produce a function
+ * named mystruct_hash_fn which hashes mystruct->myfield.
+ */
+#define SIMPLE_HASH_FN(fname, stype, field) \
+static int fname(const void *obj, const int flags) \
+{ \
+ const struct stype *provider = obj; \
+ const char *key; \
+ switch (flags & OBJ_SEARCH_MASK) { \
+ case OBJ_SEARCH_KEY: \
+ key = obj; \
+ break; \
+ case OBJ_SEARCH_OBJECT: \
+ provider = obj; \
+ key = provider->field; \
+ break; \
+ default: \
+ ast_assert(0); \
+ return 0; \
+ } \
+ return ast_str_hash(key); \
+}
+
+/*!
+ * \brief Creates a compare function for a structure string field.
+ * \param fname The name to use for the function
+ * \param stype The structure type
+ * \param field The field in the structure to compare
+ *
+ * SIMPLE_CMP_FN(mystruct, myfield) will produce a function
+ * named mystruct_cmp_fn which compares mystruct->myfield.
+ */
+#define SIMPLE_CMP_FN(fname, stype, field) \
+static int fname(void *obj, void *arg, int flags) \
+{ \
+ const struct stype *object_left = obj, *object_right = arg; \
+ const char *right_key = arg; \
+ int cmp; \
+ switch (flags & OBJ_SEARCH_MASK) { \
+ case OBJ_SEARCH_OBJECT: \
+ right_key = object_right->field; \
+ case OBJ_SEARCH_KEY: \
+ cmp = strcmp(object_left->field, right_key); \
+ break; \
+ case OBJ_SEARCH_PARTIAL_KEY: \
+ cmp = strncmp(object_left->field, right_key, strlen(right_key)); \
+ break; \
+ default: \
+ cmp = 0; \
+ break; \
+ } \
+ if (cmp) { \
+ return 0; \
+ } \
+ return CMP_MATCH; \
+}
+
+const char *ast_phoneprov_std_variable_lookup[] = {
+ [AST_PHONEPROV_STD_MAC] = "MAC",
+ [AST_PHONEPROV_STD_PROFILE] = "PROFILE",
+ [AST_PHONEPROV_STD_USERNAME] = "USERNAME",
+ [AST_PHONEPROV_STD_DISPLAY_NAME] = "DISPLAY_NAME",
+ [AST_PHONEPROV_STD_SECRET] = "SECRET",
+ [AST_PHONEPROV_STD_LABEL] = "LABEL",
+ [AST_PHONEPROV_STD_CALLERID] = "CALLERID",
+ [AST_PHONEPROV_STD_TIMEZONE] = "TIMEZONE",
+ [AST_PHONEPROV_STD_LINENUMBER] = "LINE",
+ [AST_PHONEPROV_STD_LINEKEYS] = "LINEKEYS",
+ [AST_PHONEPROV_STD_SERVER] = "SERVER",
+ [AST_PHONEPROV_STD_SERVER_PORT] = "SERVER_PORT",
+ [AST_PHONEPROV_STD_SERVER_IFACE] = "SERVER_IFACE",
+ [AST_PHONEPROV_STD_VOICEMAIL_EXTEN] = "VOICEMAIL_EXTEN",
+ [AST_PHONEPROV_STD_EXTENSION_LENGTH] = "EXTENSION_LENGTH",
+ [AST_PHONEPROV_STD_TZOFFSET] = "TZOFFSET",
+ [AST_PHONEPROV_STD_DST_ENABLE] = "DST_ENABLE",
+ [AST_PHONEPROV_STD_DST_START_MONTH] = "DST_START_MONTH",
+ [AST_PHONEPROV_STD_DST_START_MDAY] = "DST_START_MDAY",
+ [AST_PHONEPROV_STD_DST_START_HOUR] = "DST_START_HOUR",
+ [AST_PHONEPROV_STD_DST_END_MONTH] = "DST_END_MONTH",
+ [AST_PHONEPROV_STD_DST_END_MDAY] = "DST_END_MDAY",
+ [AST_PHONEPROV_STD_DST_END_HOUR] = "DST_END_HOUR",
+};
+
+/* Translate the standard variables to their users.conf equivalents. */
+const char *pp_user_lookup[] = {
+ [AST_PHONEPROV_STD_MAC] = "macaddress",
+ [AST_PHONEPROV_STD_PROFILE] = "profile",
+ [AST_PHONEPROV_STD_USERNAME] = "username",
+ [AST_PHONEPROV_STD_DISPLAY_NAME] = "fullname",
+ [AST_PHONEPROV_STD_SECRET] = "secret",
+ [AST_PHONEPROV_STD_LABEL] = "label",
+ [AST_PHONEPROV_STD_CALLERID] = "cid_number",
+ [AST_PHONEPROV_STD_TIMEZONE] = "timezone",
+ [AST_PHONEPROV_STD_LINENUMBER] = "linenumber",
+ [AST_PHONEPROV_STD_LINEKEYS] = "linekeys",
+ [AST_PHONEPROV_STD_SERVER] = NULL,
+ [AST_PHONEPROV_STD_SERVER_PORT] = NULL,
+ [AST_PHONEPROV_STD_SERVER_IFACE] = NULL,
+ [AST_PHONEPROV_STD_VOICEMAIL_EXTEN] = "vmexten",
+ [AST_PHONEPROV_STD_EXTENSION_LENGTH] = "localextenlength",
+ [AST_PHONEPROV_STD_TZOFFSET] = NULL,
+ [AST_PHONEPROV_STD_DST_ENABLE] = NULL,
+ [AST_PHONEPROV_STD_DST_START_MONTH] = NULL,
+ [AST_PHONEPROV_STD_DST_START_MDAY] = NULL,
+ [AST_PHONEPROV_STD_DST_START_HOUR] = NULL,
+ [AST_PHONEPROV_STD_DST_END_MONTH] = NULL,
+ [AST_PHONEPROV_STD_DST_END_MDAY] = NULL,
+ [AST_PHONEPROV_STD_DST_END_HOUR] = NULL,
+};
+
+/* Translate the standard variables to their phoneprov.conf [general] equivalents. */
+const char *pp_general_lookup[] = {
+ [AST_PHONEPROV_STD_MAC] = NULL,
+ [AST_PHONEPROV_STD_PROFILE] = "default_profile",
+ [AST_PHONEPROV_STD_USERNAME] = NULL,
+ [AST_PHONEPROV_STD_DISPLAY_NAME] = NULL,
+ [AST_PHONEPROV_STD_SECRET] = NULL,
+ [AST_PHONEPROV_STD_LABEL] = NULL,
+ [AST_PHONEPROV_STD_CALLERID] = NULL,
+ [AST_PHONEPROV_STD_TIMEZONE] = NULL,
+ [AST_PHONEPROV_STD_LINENUMBER] = NULL,
+ [AST_PHONEPROV_STD_LINEKEYS] = NULL,
+ [AST_PHONEPROV_STD_SERVER] = "serveraddr",
+ [AST_PHONEPROV_STD_SERVER_PORT] = "serverport",
+ [AST_PHONEPROV_STD_SERVER_IFACE] = "serveriface",
+ [AST_PHONEPROV_STD_VOICEMAIL_EXTEN] = NULL,
+ [AST_PHONEPROV_STD_EXTENSION_LENGTH] = NULL,
+ [AST_PHONEPROV_STD_TZOFFSET] = NULL,
+ [AST_PHONEPROV_STD_DST_ENABLE] = NULL,
+ [AST_PHONEPROV_STD_DST_START_MONTH] = NULL,
+ [AST_PHONEPROV_STD_DST_START_MDAY] = NULL,
+ [AST_PHONEPROV_STD_DST_START_HOUR] = NULL,
+ [AST_PHONEPROV_STD_DST_END_MONTH] = NULL,
+ [AST_PHONEPROV_STD_DST_END_MDAY] = NULL,
+ [AST_PHONEPROV_STD_DST_END_HOUR] = NULL,
+};
+
/*! \brief for use in lookup_iface */
static struct in_addr __ourip = { .s_addr = 0x00000000, };
-/* \note This enum and the pp_variable_list must be in the same order or
- * bad things happen! */
-enum pp_variables {
- PP_MACADDRESS,
- PP_USERNAME,
- PP_FULLNAME,
- PP_SECRET,
- PP_LABEL,
- PP_CALLERID,
- PP_TIMEZONE,
- PP_LINENUMBER,
- PP_LINEKEYS,
- PP_VAR_LIST_LENGTH, /* This entry must always be the last in the list */
+/*! \brief structure to hold config providers */
+struct phoneprov_provider {
+ AST_DECLARE_STRING_FIELDS(
+ AST_STRING_FIELD(provider_name);
+ );
+ ast_phoneprov_load_users_cb load_users;
};
-
-/*! \brief Lookup table to translate between users.conf property names and
- * variables for use in phoneprov templates */
-static const struct pp_variable_lookup {
- enum pp_variables id;
- const char * const user_var;
- const char * const template_var;
-} pp_variable_list[] = {
- { PP_MACADDRESS, "macaddress", "MAC" },
- { PP_USERNAME, "username", "USERNAME" },
- { PP_FULLNAME, "fullname", "DISPLAY_NAME" },
- { PP_SECRET, "secret", "SECRET" },
- { PP_LABEL, "label", "LABEL" },
- { PP_CALLERID, "cid_number", "CALLERID" },
- { PP_TIMEZONE, "timezone", "TIMEZONE" },
- { PP_LINENUMBER, "linenumber", "LINE" },
- { PP_LINEKEYS, "linekeys", "LINEKEYS" },
-};
+struct ao2_container *providers;
+SIMPLE_HASH_FN(phoneprov_provider_hash_fn, phoneprov_provider, provider_name)
+SIMPLE_CMP_FN(phoneprov_provider_cmp_fn, phoneprov_provider, provider_name)
/*! \brief structure to hold file data */
struct phoneprov_file {
@@ -153,6 +282,16 @@
AST_STRING_FIELD(mime_type);/*!< Mime-type of the file */
);
AST_LIST_ENTRY(phoneprov_file) entry;
+};
+
+/*! \brief structure to hold extensions */
+struct extension {
+ AST_DECLARE_STRING_FIELDS(
+ AST_STRING_FIELD(name);
+ );
+ int index;
+ struct varshead *headp; /*!< List of variables to substitute into templates */
+ AST_LIST_ENTRY(extension) entry;
};
/*! \brief structure to hold phone profiles read from phoneprov.conf */
@@ -166,24 +305,22 @@
AST_LIST_HEAD_NOLOCK(, phoneprov_file) static_files; /*!< List of static files */
AST_LIST_HEAD_NOLOCK(, phoneprov_file) dynamic_files; /*!< List of dynamic files */
};
-
-struct extension {
- AST_DECLARE_STRING_FIELDS(
- AST_STRING_FIELD(name);
- );
- int index;
- struct varshead *headp; /*!< List of variables to substitute into templates */
- AST_LIST_ENTRY(extension) entry;
-};
+struct ao2_container *profiles;
+SIMPLE_HASH_FN(phone_profile_hash_fn, phone_profile, name)
+SIMPLE_CMP_FN(phone_profile_cmp_fn, phone_profile, name)
/*! \brief structure to hold users read from users.conf */
struct user {
AST_DECLARE_STRING_FIELDS(
AST_STRING_FIELD(macaddress); /*!< Mac address of user's phone */
+ AST_STRING_FIELD(provider_name); /*!< Name of the provider who registered this mac */
);
struct phone_profile *profile; /*!< Profile the phone belongs to */
AST_LIST_HEAD_NOLOCK(, extension) extensions;
};
+struct ao2_container *users;
+SIMPLE_HASH_FN(user_hash_fn, user, macaddress)
+SIMPLE_CMP_FN(user_cmp_fn, user, macaddress)
/*! \brief structure to hold http routes (valid URIs, and the files they link to) */
struct http_route {
@@ -193,19 +330,13 @@
struct phoneprov_file *file; /*!< The file that links to the URI */
struct user *user; /*!< The user that has variables to substitute into the file
* NULL in the case of a static route */
+ struct phone_profile *profile;
};
-
-static struct ao2_container *profiles;
-static struct ao2_container *http_routes;
-static struct ao2_container *users;
-
-static char global_server[80] = ""; /*!< Server to substitute into templates */
-static char global_serverport[6] = ""; /*!< Server port to substitute into templates */
-static char global_default_profile[80] = ""; /*!< Default profile to use if one isn't specified */
-
-/*! \brief List of global variables currently available: VOICEMAIL_EXTEN, EXTENSION_LENGTH */
-static struct varshead global_variables;
-static ast_mutex_t globals_lock;
+struct ao2_container *http_routes;
+SIMPLE_HASH_FN(http_route_hash_fn, http_route, uri)
+SIMPLE_CMP_FN(http_route_cmp_fn, http_route, uri)
+
+#define SIPUSERS_PROVIDER_NAME "sipusers"
/* iface is the interface (e.g. eth0); address is the return value */
static int lookup_iface(const char *iface, struct in_addr *address)
@@ -238,88 +369,31 @@
}
}
-static struct phone_profile *unref_profile(struct phone_profile *prof)
-{
- ao2_ref(prof, -1);
-
- return NULL;
-}
-
-/*! \brief Return a phone profile looked up by name */
-static struct phone_profile *find_profile(const char *name)
-{
- struct phone_profile tmp = {
- .name = name,
- };
-
- return ao2_find(profiles, &tmp, OBJ_POINTER);
-}
-
-static int profile_hash_fn(const void *obj, const int flags)
-{
- const struct phone_profile *profile = obj;
-
- return ast_str_case_hash(profile->name);
-}
-
-static int profile_cmp_fn(void *obj, void *arg, int flags)
-{
- const struct phone_profile *profile1 = obj, *profile2 = arg;
-
- return !strcasecmp(profile1->name, profile2->name) ? CMP_MATCH | CMP_STOP : 0;
+static struct phoneprov_provider *find_provider(char *name)
+{
+ return ao2_find(providers, name, OBJ_SEARCH_KEY);
+}
+
+/*! \brief Delete all providers */
+static void delete_providers(void)
+{
+ if (!providers) {
+ return;
+ }
+
+ ao2_callback(providers, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
+}
+
+static void provider_destructor(void *obj)
+{
+ struct phoneprov_provider *provider = obj;
+ ast_string_field_free_memory(provider);
}
static void delete_file(struct phoneprov_file *file)
{
ast_string_field_free_memory(file);
ast_free(file);
-}
-
-static void profile_destructor(void *obj)
-{
- struct phone_profile *profile = obj;
- struct phoneprov_file *file;
- struct ast_var_t *var;
-
- while ((file = AST_LIST_REMOVE_HEAD(&profile->static_files, entry)))
- delete_file(file);
-
- while ((file = AST_LIST_REMOVE_HEAD(&profile->dynamic_files, entry)))
- delete_file(file);
-
- while ((var = AST_LIST_REMOVE_HEAD(profile->headp, entries)))
- ast_var_delete(var);
-
- ast_free(profile->headp);
- ast_string_field_free_memory(profile);
-}
-
-static struct http_route *unref_route(struct http_route *route)
-{
- ao2_ref(route, -1);
-
- return NULL;
-}
-
-static int routes_hash_fn(const void *obj, const int flags)
-{
- const struct http_route *route = obj;
-
- return ast_str_case_hash(route->uri);
-}
-
-static int routes_cmp_fn(void *obj, void *arg, int flags)
-{
- const struct http_route *route1 = obj, *route2 = arg;
-
- return !strcasecmp(route1->uri, route2->uri) ? CMP_MATCH | CMP_STOP : 0;
-}
-
-static void route_destructor(void *obj)
-{
- struct http_route *route = obj;
-
- ast_string_field_free_memory(route);
}
/*! \brief Read a TEXT file into a string and return the length */
@@ -365,189 +439,66 @@
struct ast_tm tm_info;
int tzoffset;
char buffer[21];
- struct ast_var_t *var;
struct timeval when;
time(&utc_time);
ast_get_dst_info(&utc_time, &dstenable, &dststart, &dstend, &tzoffset, zone);
snprintf(buffer, sizeof(buffer), "%d", tzoffset);
- var = ast_var_assign("TZOFFSET", buffer);
- if (var)
- AST_LIST_INSERT_TAIL(headp, var, entries);
-
- if (!dstenable)
+ AST_VAR_LIST_INSERT_TAIL(headp, ast_var_assign("TZOFFSET", buffer));
+
+ if (!dstenable) {
return;
-
- if ((var = ast_var_assign("DST_ENABLE", "1")))
- AST_LIST_INSERT_TAIL(headp, var, entries);
+ }
+
+ AST_VAR_LIST_INSERT_TAIL(headp, ast_var_assign("DST_ENABLE", "1"));
when.tv_sec = dststart;
ast_localtime(&when, &tm_info, zone);
snprintf(buffer, sizeof(buffer), "%d", tm_info.tm_mon+1);
- if ((var = ast_var_assign("DST_START_MONTH", buffer)))
- AST_LIST_INSERT_TAIL(headp, var, entries);
+ AST_VAR_LIST_INSERT_TAIL(headp, ast_var_assign("DST_START_MONTH", buffer));
snprintf(buffer, sizeof(buffer), "%d", tm_info.tm_mday);
- if ((var = ast_var_assign("DST_START_MDAY", buffer)))
- AST_LIST_INSERT_TAIL(headp, var, entries);
+ AST_VAR_LIST_INSERT_TAIL(headp, ast_var_assign("DST_START_MDAY", buffer));
snprintf(buffer, sizeof(buffer), "%d", tm_info.tm_hour);
- if ((var = ast_var_assign("DST_START_HOUR", buffer)))
- AST_LIST_INSERT_TAIL(headp, var, entries);
+ AST_VAR_LIST_INSERT_TAIL(headp, ast_var_assign("DST_START_HOUR", buffer));
when.tv_sec = dstend;
ast_localtime(&when, &tm_info, zone);
snprintf(buffer, sizeof(buffer), "%d", tm_info.tm_mon + 1);
- if ((var = ast_var_assign("DST_END_MONTH", buffer)))
- AST_LIST_INSERT_TAIL(headp, var, entries);
+ AST_VAR_LIST_INSERT_TAIL(headp, ast_var_assign("DST_END_MONTH", buffer));
snprintf(buffer, sizeof(buffer), "%d", tm_info.tm_mday);
- if ((var = ast_var_assign("DST_END_MDAY", buffer)))
- AST_LIST_INSERT_TAIL(headp, var, entries);
+ AST_VAR_LIST_INSERT_TAIL(headp, ast_var_assign("DST_END_MDAY", buffer));
snprintf(buffer, sizeof(buffer), "%d", tm_info.tm_hour);
- if ((var = ast_var_assign("DST_END_HOUR", buffer)))
- AST_LIST_INSERT_TAIL(headp, var, entries);
-}
-
-/*! \brief Callback that is executed everytime an http request is received by this module */
-static int phoneprov_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_vars, struct ast_variable *headers)
-{
- struct http_route *route;
- struct http_route search_route = {
- .uri = uri,
- };
- struct ast_str *result;
- char path[PATH_MAX];
- char *file = NULL;
- int len;
- int fd;
- struct ast_str *http_header;
-
- if (method != AST_HTTP_GET && method != AST_HTTP_HEAD) {
- ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
- return 0;
- }
-
- if (!(route = ao2_find(http_routes, &search_route, OBJ_POINTER))) {
- goto out404;
- }
-
- snprintf(path, sizeof(path), "%s/phoneprov/%s", ast_config_AST_DATA_DIR, route->file->template);
-
- if (!route->user) { /* Static file */
-
- fd = open(path, O_RDONLY);
- if (fd < 0) {
- goto out500;
- }
-
- len = lseek(fd, 0, SEEK_END);
- lseek(fd, 0, SEEK_SET);
- if (len < 0) {
- ast_log(LOG_WARNING, "Could not load file: %s (%d)\n", path, len);
- close(fd);
- goto out500;
- }
-
- http_header = ast_str_create(80);
- ast_str_set(&http_header, 0, "Content-type: %s\r\n",
- route->file->mime_type);
-
- ast_http_send(ser, method, 200, NULL, http_header, NULL, fd, 0);
-
- close(fd);
- route = unref_route(route);
- return 0;
- } else { /* Dynamic file */
- struct ast_str *tmp;
-
- len = load_file(path, &file);
- if (len < 0) {
- ast_log(LOG_WARNING, "Could not load file: %s (%d)\n", path, len);
- if (file) {
- ast_free(file);
- }
-
- goto out500;
- }
-
- if (!file) {
- goto out500;
- }
-
- if (!(tmp = ast_str_create(len))) {
- if (file) {
- ast_free(file);
- }
-
- goto out500;
- }
-
- /* Unless we are overridden by serveriface or serveraddr, we set the SERVER variable to
- * the IP address we are listening on that the phone contacted for this config file */
- if (ast_strlen_zero(global_server)) {
- union {
- struct sockaddr sa;
- struct sockaddr_in sa_in;
- } name;
- socklen_t namelen = sizeof(name.sa);
- int res;
-
- if ((res = getsockname(ser->fd, &name.sa, &namelen))) {
- ast_log(LOG_WARNING, "Could not get server IP, breakage likely.\n");
- } else {
- struct ast_var_t *var;
- struct extension *exten_iter;
-
- if ((var = ast_var_assign("SERVER", ast_inet_ntoa(name.sa_in.sin_addr)))) {
- AST_LIST_TRAVERSE(&route->user->extensions, exten_iter, entry) {
- AST_LIST_INSERT_TAIL(exten_iter->headp, var, entries);
- }
- }
- }
- }
-
- ast_str_substitute_variables_varshead(&tmp, 0, AST_LIST_FIRST(&route->user->extensions)->headp, file);
-
- if (file) {
- ast_free(file);
- }
-
- http_header = ast_str_create(80);
- ast_str_set(&http_header, 0, "Content-type: %s\r\n",
- route->file->mime_type);
-
- if (!(result = ast_str_create(512))) {
- ast_log(LOG_ERROR, "Could not create result string!\n");
- if (tmp) {
- ast_free(tmp);
- }
- ast_free(http_header);
- goto out500;
- }
- ast_str_append(&result, 0, "%s", ast_str_buffer(tmp));
-
- ast_http_send(ser, method, 200, NULL, http_header, result, 0, 0);
- if (tmp) {
- ast_free(tmp);
- }
-
- route = unref_route(route);
-
- return 0;
- }
-
-out404:
- ast_http_error(ser, 404, "Not Found", "Nothing to see here. Move along.");
- return 0;
-
-out500:
- route = unref_route(route);
- ast_http_error(ser, 500, "Internal Error", "An internal error has occured.");
- return 0;
+ AST_VAR_LIST_INSERT_TAIL(headp, ast_var_assign("DST_END_HOUR", buffer));
+}
+
+static struct http_route *unref_route(struct http_route *route)
+{
+ ao2_cleanup(route);
+
+ return NULL;
+}
+
+static void route_destructor(void *obj)
+{
+ struct http_route *route = obj;
+
+ ast_string_field_free_memory(route);
+}
+
+/*! \brief Delete all http routes, freeing their memory */
+static void delete_routes(void)
+{
+ if (!http_routes) {
+ return;
+ }
+
+ ao2_callback(http_routes, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
}
/*! \brief Build a route structure and add it to the list of available http routes
@@ -555,7 +506,7 @@
\param user User to link to the route (NULL means static route)
\param uri URI of the route
*/
-static void build_route(struct phoneprov_file *pp_file, struct user *user, char *uri)
+static void build_route(struct phoneprov_file *pp_file, struct phone_profile *profile, struct user *user, char *uri)
{
struct http_route *route;
@@ -572,10 +523,56 @@
ast_string_field_set(route, uri, S_OR(uri, pp_file->format));
route->user = user;
route->file = pp_file;
+ route->profile = profile;
ao2_link(http_routes, route);
route = unref_route(route);
+}
+
+static struct phone_profile *unref_profile(struct phone_profile *prof)
+{
+ ao2_cleanup(prof);
+
+ return NULL;
+}
+
+/*! \brief Return a phone profile looked up by name */
+static struct phone_profile *find_profile(const char *name)
+{
+ return ao2_find(profiles, name, OBJ_SEARCH_KEY);
+}
+
+static void profile_destructor(void *obj)
+{
+ struct phone_profile *profile = obj;
+ struct phoneprov_file *file;
+ struct ast_var_t *var;
+
+ while ((file = AST_LIST_REMOVE_HEAD(&profile->static_files, entry))) {
+ delete_file(file);
+ }
+
+ while ((file = AST_LIST_REMOVE_HEAD(&profile->dynamic_files, entry))) {
+ delete_file(file);
+ }
+
+ while ((var = AST_LIST_REMOVE_HEAD(profile->headp, entries))) {
+ ast_var_delete(var);
+ }
+
+ ast_free(profile->headp);
+ ast_string_field_free_memory(profile);
+}
+
+/*! \brief Delete all phone profiles, freeing their memory */
+static void delete_profiles(void)
+{
+ if (!profiles) {
+ return;
+ }
+
+ ao2_callback(profiles, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
}
/*! \brief Build a phone profile and add it to the list of phone profiles
@@ -585,7 +582,6 @@
static void build_profile(const char *name, struct ast_variable *v)
{
struct phone_profile *profile;
- struct ast_var_t *var;
if (!(profile = ao2_alloc(sizeof(*profile), profile_destructor))) {
return;
@@ -596,7 +592,7 @@
return;
}
- if (!(profile->headp = ast_calloc(1, sizeof(*profile->headp)))) {
+ if (!(profile->headp = ast_var_list_create())) {
profile = unref_profile(profile);
return;
}
@@ -609,7 +605,6 @@
if (!strcasecmp(v->name, "mime_type")) {
ast_string_field_set(profile, default_mime_type, v->value);
} else if (!strcasecmp(v->name, "setvar")) {
- struct ast_var_t *variable;
char *value_copy = ast_strdupa(v->value);
AST_DECLARE_APP_ARGS(args,
@@ -625,8 +620,7 @@
args.varval = ast_strip(args.varval);
if (ast_strlen_zero(args.varname) || ast_strlen_zero(args.varval))
break;
- if ((variable = ast_var_assign(args.varname, args.varval)))
- AST_LIST_INSERT_TAIL(profile->headp, variable, entries);
+ AST_VAR_LIST_INSERT_TAIL(profile->headp, ast_var_assign(args.varname, args.varval));
} while (0);
} else if (!strcasecmp(v->name, "staticdir")) {
ast_string_field_set(profile, staticdir, v->value);
@@ -664,7 +658,7 @@
ast_string_field_build(pp_file, template, "%s%s", profile->staticdir, args.filename);
AST_LIST_INSERT_TAIL(&profile->static_files, pp_file, entry);
/* Add a route for the static files, as their filenames won't change per-user */
- build_route(pp_file, NULL, NULL);
+ build_route(pp_file, profile, NULL, NULL);
} else {
ast_string_field_set(pp_file, format, v->name);
ast_string_field_set(pp_file, template, args.filename);
@@ -673,18 +667,6 @@
}
}
- /* Append the global variables to the variables list for this profile.
- * This is for convenience later, when we need to provide a single
- * variable list for use in substitution. */
- ast_mutex_lock(&globals_lock);
- AST_LIST_TRAVERSE(&global_variables, var, entries) {
- struct ast_var_t *new_var;
- if ((new_var = ast_var_assign(var->name, var->value))) {
- AST_LIST_INSERT_TAIL(profile->headp, new_var, entries);
- }
- }
- ast_mutex_unlock(&globals_lock);
-
ao2_link(profiles, profile);
profile = unref_profile(profile);
@@ -692,24 +674,17 @@
static struct extension *delete_extension(struct extension *exten)
{
- struct ast_var_t *var;
- while ((var = AST_LIST_REMOVE_HEAD(exten->headp, entries))) {
- ast_var_delete(var);
- }
- ast_free(exten->headp);
+ ast_var_list_destroy(exten->headp);
ast_string_field_free_memory(exten);
-
ast_free(exten);
return NULL;
}
-static struct extension *build_extension(struct ast_config *cfg, const char *name)
+static struct extension *build_extension(const char *name, struct varshead *vars)
{
struct extension *exten;
- struct ast_var_t *var;
const char *tmp;
- int i;
if (!(exten = ast_calloc_with_stringfields(1, struct extension, 32))) {
return NULL;
@@ -717,56 +692,36 @@
ast_string_field_set(exten, name, name);
- if (!(exten->headp = ast_calloc(1, sizeof(*exten->headp)))) {
- ast_free(exten);
- exten = NULL;
+ exten->headp = ast_var_list_clone(vars);
+ if (!exten->headp) {
+ ast_log(LOG_ERROR, "Unable to clone variables for extension '%s'\n", name);
+ delete_extension(exten);
return NULL;
}
- for (i = 0; i < PP_VAR_LIST_LENGTH; i++) {
- tmp = ast_variable_retrieve(cfg, name, pp_variable_list[i].user_var);
-
- /* If we didn't get a USERNAME variable, set it to the user->name */
- if (i == PP_USERNAME && !tmp) {
- if ((var = ast_var_assign(pp_variable_list[PP_USERNAME].template_var, exten->name))) {
- AST_LIST_INSERT_TAIL(exten->headp, var, entries);
- }
- continue;
- } else if (i == PP_TIMEZONE) {
- /* perfectly ok if tmp is NULL, will set variables based on server's time zone */
- set_timezone_variables(exten->headp, tmp);
- } else if (i == PP_LINENUMBER) {
- if (!tmp) {
- tmp = "1";
- }
- exten->index = atoi(tmp);
- } else if (i == PP_LINEKEYS) {
- if (!tmp) {
- tmp = "1";
- }
- }
-
- if (tmp && (var = ast_var_assign(pp_variable_list[i].template_var, tmp))) {
- AST_LIST_INSERT_TAIL(exten->headp, var, entries);
- }
- }
-
- if (!ast_strlen_zero(global_server)) {
- if ((var = ast_var_assign("SERVER", global_server)))
- AST_LIST_INSERT_TAIL(exten->headp, var, entries);
- }
-
- if (!ast_strlen_zero(global_serverport)) {
- if ((var = ast_var_assign("SERVER_PORT", global_serverport)))
- AST_LIST_INSERT_TAIL(exten->headp, var, entries);
- }
+ tmp = ast_var_find(exten->headp, ast_phoneprov_std_variable_lookup[AST_PHONEPROV_STD_LINENUMBER]);
+ if (!tmp) {
+ AST_VAR_LIST_INSERT_TAIL(exten->headp,
+ ast_var_assign(ast_phoneprov_std_variable_lookup[AST_PHONEPROV_STD_LINENUMBER], "1"));
+ exten->index = 1;
+ } else {
+ sscanf(tmp, "%d", &exten->index);
+ }
+
+ if (!ast_var_find(exten->headp, ast_phoneprov_std_variable_lookup[AST_PHONEPROV_STD_LINEKEYS])) {
+ AST_VAR_LIST_INSERT_TAIL(exten->headp,
+ ast_var_assign(ast_phoneprov_std_variable_lookup[AST_PHONEPROV_STD_LINEKEYS], "1"));
+ }
+
+ set_timezone_variables(exten->headp,
+ ast_var_find(vars, ast_phoneprov_std_variable_lookup[AST_PHONEPROV_STD_TIMEZONE]));
return exten;
}
static struct user *unref_user(struct user *user)
{
- ao2_ref(user, -1);
+ ao2_cleanup(user);
return NULL;
}
@@ -774,25 +729,19 @@
/*! \brief Return a user looked up by name */
static struct user *find_user(const char *macaddress)
{
- struct user tmp = {
- .macaddress = macaddress,
- };
-
- return ao2_find(users, &tmp, OBJ_POINTER);
-}
-
-static int users_hash_fn(const void *obj, const int flags)
-{
- const struct user *user = obj;
-
- return ast_str_case_hash(user->macaddress);
-}
-
-static int users_cmp_fn(void *obj, void *arg, int flags)
-{
- const struct user *user1 = obj, *user2 = arg;
-
- return !strcasecmp(user1->macaddress, user2->macaddress) ? CMP_MATCH | CMP_STOP : 0;
+ return ao2_find(users, macaddress, OBJ_SEARCH_KEY);
+}
+
+static int routes_delete_cb(void *obj, void *arg, int flags)
+{
+ struct http_route *route = obj;
+ struct user *user = route->user;
+ char *macaddress = arg;
+
+ if (user && !strcmp(user->macaddress, macaddress)) {
+ return CMP_MATCH;
+ }
+ return 0;
}
/*! \brief Free all memory associated with a user */
@@ -809,41 +758,39 @@
user->profile = unref_profile(user->profile);
}
+ ao2_callback(http_routes, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, routes_delete_cb, (void *)user->macaddress);
+
ast_string_field_free_memory(user);
}
/*! \brief Delete all users */
static void delete_users(void)
{
- struct ao2_iterator i;
+ if (!users) {
+ return;
+ }
+
+ ao2_callback(users, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
+}
+
+/*! \brief Build and return a user structure based on gathered config data */
+static struct user *build_user(const char *mac, struct phone_profile *profile, char *provider_name)
+{
struct user *user;
- i = ao2_iterator_init(users, 0);
- while ((user = ao2_iterator_next(&i))) {
- ao2_unlink(users, user);
- user = unref_user(user);
- }
- ao2_iterator_destroy(&i);
-}
-
-/*! \brief Build and return a user structure based on gathered config data */
-static struct user *build_user(const char *mac, struct phone_profile *profile)
-{
- struct user *user;
-
if (!(user = ao2_alloc(sizeof(*user), user_destructor))) {
- profile = unref_profile(profile);
return NULL;
}
- if (ast_string_field_init(user, 32)) {
- profile = unref_profile(profile);
+ if (ast_string_field_init(user, 64)) {
user = unref_user(user);
return NULL;
}
ast_string_field_set(user, macaddress, mac);
- user->profile = profile; /* already ref counted by find_profile */
+ ast_string_field_set(user, provider_name, provider_name);
+ user->profile = profile;
+ ao2_ref(profile, 1);
return user;
}
@@ -851,7 +798,7 @@
/*! \brief Add an extension to a user ordered by index/linenumber */
static int add_user_extension(struct user *user, struct extension *exten)
{
- struct ast_var_t *var;
+ struct ast_var_t *pvar, *var2;
struct ast_str *str = ast_str_create(16);
if (!str) {
@@ -860,15 +807,16 @@
/* Append profile variables here, and substitute variables on profile
* setvars, so that we can use user specific variables in them */
- AST_LIST_TRAVERSE(user->profile->headp, var, entries) {
- struct ast_var_t *var2;
-
- ast_str_substitute_variables_varshead(&str, 0, exten->headp, var->value);
- if ((var2 = ast_var_assign(var->name, ast_str_buffer(str)))) {
- AST_LIST_INSERT_TAIL(exten->headp, var2, entries);
- }
- }
-
+ AST_VAR_LIST_TRAVERSE(user->profile->headp, pvar) {
+ if (ast_var_find(exten->headp, pvar->name)) {
+ continue;
+ }
+
+ ast_str_substitute_variables_varshead(&str, 0, exten->headp, pvar->value);
+ if ((var2 = ast_var_assign(pvar->name, ast_str_buffer(str)))) {
+ AST_VAR_LIST_INSERT_TAIL(exten->headp, var2);
+ }
+ }
ast_free(str);
if (AST_LIST_EMPTY(&user->extensions)) {
@@ -904,187 +852,146 @@
AST_LIST_TRAVERSE(&user->profile->dynamic_files, pp_file, entry) {
ast_str_substitute_variables_varshead(&str, 0, AST_LIST_FIRST(&user->extensions)->headp, pp_file->format);
- build_route(pp_file, user, ast_str_buffer(str));
+ build_route(pp_file, user->profile, user, ast_str_buffer(str));
}
ast_free(str);
return 0;
}
-/* \brief Parse config files and create appropriate structures */
-static int set_config(void)
-{
- struct ast_config *cfg, *phoneprov_cfg;
- char *cat;
- struct ast_variable *v;
- struct ast_flags config_flags = { 0 };
- struct ast_var_t *var;
-
- /* Try to grab the port from sip.conf. If we don't get it here, we'll set it
- * to whatever is set in phoneprov.conf or default to 5060 */
- if ((cfg = ast_config_load("sip.conf", config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) {
- ast_copy_string(global_serverport, S_OR(ast_variable_retrieve(cfg, "general", "bindport"), "5060"), sizeof(global_serverport));
- ast_config_destroy(cfg);
- }
-
- if (!(cfg = ast_config_load("users.conf", config_flags)) || cfg == CONFIG_STATUS_FILEINVALID) {
- ast_log(LOG_WARNING, "Unable to load users.conf\n");
+/*! \brief Callback that is executed everytime an http request is received by this module */
+static int phoneprov_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_vars, struct ast_variable *headers)
+{
+ struct http_route *route;
+ struct ast_str *result;
+ char path[PATH_MAX];
+ char *file = NULL;
+ char *server;
+ int len;
+ int fd;
+ struct ast_str *http_header;
+
+ if (method != AST_HTTP_GET && method != AST_HTTP_HEAD) {
+ ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
return 0;
}
- /* Go ahead and load global variables from users.conf so we can append to profiles */
- for (v = ast_variable_browse(cfg, "general"); v; v = v->next) {
- if (!strcasecmp(v->name, "vmexten")) {
- if ((var = ast_var_assign("VOICEMAIL_EXTEN", v->value))) {
- ast_mutex_lock(&globals_lock);
[... 859 lines stripped ...]
More information about the asterisk-commits
mailing list