summaryrefslogtreecommitdiff
path: root/res/res_pjsip_config_wizard.c
diff options
context:
space:
mode:
authorGeorge Joseph <george.joseph@fairview5.com>2015-02-10 23:16:40 +0000
committerGeorge Joseph <george.joseph@fairview5.com>2015-02-10 23:16:40 +0000
commit4d8ab20a8abac76c680a40605bb6e6e8e675afde (patch)
tree325f79c5659ab360a2732dc084f60844bb580474 /res/res_pjsip_config_wizard.c
parent32e42e50cc3316fee9343fed3323a8f771bffb53 (diff)
res_pjsip_config_wizard: Add ability to auto-create hints.
Looking at the Super Awesome Company sample reminded me that creating hints is just plain gruntwork. So you can now have the pjsip conifg wizard auto-create them for you. Specifying 'hint_exten' in the wizard will create 'exten => <hint_exten>,hint/PJSIP/<wizard_id>' in whatever is specified for 'hint_context'. Specifying 'hint_application' in the wizard will create 'exten => <hint_exten>,1,<hint_application>' in whatever is specified for 'hint_context'. The default for 'hint_context' is the endpoint's context. There's no default for 'hint_application'. If not specified, no app is added. There's no default for 'hint_exten'. If not specified, neither the hint itself nor the application will be created. Some may think this is the slippery slope to users.conf but hints are a basic necessity for phones unlike voicemail, manager, etc that users.conf creates. Tested-by: George Joseph Review: https://reviewboard.asterisk.org/r/4383/ git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/13@431643 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'res/res_pjsip_config_wizard.c')
-rw-r--r--res/res_pjsip_config_wizard.c224
1 files changed, 222 insertions, 2 deletions
diff --git a/res/res_pjsip_config_wizard.c b/res/res_pjsip_config_wizard.c
index d88d84e54..2d7e15c33 100644
--- a/res/res_pjsip_config_wizard.c
+++ b/res/res_pjsip_config_wizard.c
@@ -64,7 +64,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<para>For example, the following configuration snippet would create the
endpoint, aor, contact, auth and phoneprov objects necessary for a phone to
- get phone provisioning information, register, and make and receive calls.</para>
+ get phone provisioning information, register, and make and receive calls.
+ A hint is also created in the default context for extension 1000.</para>
<para> </para>
<para>[myphone]</para>
@@ -75,6 +76,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<para>accepts_registrations = yes</para>
<para>has_phoneprov = yes</para>
<para>transport = ipv4</para>
+ <para>has_hint = yes</para>
+ <para>hint_exten = 1000</para>
<para>inbound_auth/username = testname</para>
<para>inbound_auth/password = test password</para>
<para>endpoint/allow = ulaw</para>
@@ -83,7 +86,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<para>phoneprov/PROFILE = profile1</para>
<para> </para>
- <para>The first 7 items are specific to the wizard. The rest of the items
+ <para>The first 8 items are specific to the wizard. The rest of the items
are passed verbatim to the underlying objects.</para>
<para> </para>
@@ -108,11 +111,19 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<para>Of course, any of the items in either example could be placed into
templates and shared among wizard objects.</para>
+
+ <para> </para>
+ <para>For more information, visit:</para>
+ <para><literal>https://wiki.asterisk.org/wiki/display/AST/PJSIP+Configuration+Wizard</literal></para>
</description>
<configFile name="pjsip_wizard.conf">
<configObject name="wizard">
<synopsis>Provides config wizard.</synopsis>
+ <description>
+ <para>For more information, visit:</para>
+ <para><literal>https://wiki.asterisk.org/wiki/display/AST/PJSIP+Configuration+Wizard</literal></para>
+ </description>
<configOption name="type">
<synopsis>Must be 'wizard'.</synopsis>
</configOption>
@@ -171,6 +182,52 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
The literal <literal>${REMOTE_HOST}</literal> will be substituted with the
appropriate remote_host for each contact.</para></description>
</configOption>
+ <configOption name="has_hint" default="no">
+ <synopsis>Create hint and optionally a default application.</synopsis>
+ <description><para>Create hint and optionally a default application.</para></description>
+ </configOption>
+ <configOption name="hint_context" default="endpoint/context or 'default'">
+ <synopsis>The context in which to place hints.</synopsis>
+ <description>
+ <para>Ignored if <literal>hint_exten</literal> is not specified otherwise specifies the
+ context into which the dialplan hints will be placed. If not specified,
+ defaults to the endpoint's context or <literal>default</literal> if that isn't
+ found.
+ </para></description>
+ </configOption>
+ <configOption name="hint_exten">
+ <synopsis>Extension to map a PJSIP hint to.</synopsis>
+ <description>
+ <para>Will create the following entry in <literal>hint_context</literal>:</para>
+ <para> <literal>exten =&gt; &lt;hint_exten&gt;,hint,PJSIP/&lt;wizard_id&gt;</literal></para>
+ <para> </para>
+ <para>Normal dialplan precedence rules apply so if there's already a hint for
+ this extension in <literal>hint_context</literal>, this one will be ignored.
+ For more information, visit: </para>
+ <para><literal>https://wiki.asterisk.org/wiki/display/AST/PJSIP+Configuration+Wizard</literal></para>
+ </description>
+ </configOption>
+ <configOption name="hint_application">
+ <synopsis>Application to call when 'hint_exten' is dialed.</synopsis>
+ <description>
+ <para>Ignored if <literal>hint_exten</literal> isn't specified otherwise
+ will create the following priority 1 extension in <literal>hint_context</literal>:</para>
+ <para> <literal>exten =&gt; &lt;hint_exten&gt;,1,&lt;hint_application&gt;</literal></para>
+ <para> </para>
+ <para>You can specify any valid extensions.conf application expression.</para>
+ <para>Examples: </para>
+ <para> <literal>Dial(${HINT})</literal></para>
+ <para> <literal>Gosub(stdexten,${EXTEN},1(${HINT}))</literal></para>
+ <para> </para>
+ <para>Any extensions.conf style variables specified are passed directly to the
+ dialplan.</para>
+ <para> </para>
+ <para>Normal dialplan precedence rules apply so if there's already a priority 1
+ application for this specific extension in <literal>hint_context</literal>,
+ this one will be ignored. For more information, visit: </para>
+ <para><literal>https://wiki.asterisk.org/wiki/display/AST/PJSIP+Configuration+Wizard</literal></para>
+ </description>
+ </configOption>
<configOption name="endpoint&#47;*">
<synopsis>Variables to be passed directly to the endpoint.</synopsis>
</configOption>
@@ -206,6 +263,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
/*! \brief Defines the maximum number of characters that can be added to a wizard id. */
#define MAX_ID_SUFFIX 20
+#define BASE_REGISTRAR "res_pjsip_config_wizard"
+
/*! \brief A generic char * vector definition. */
AST_VECTOR(string_vector, char *);
@@ -329,6 +388,134 @@ static struct ast_variable *get_object_variables(struct ast_variable *vars, char
return return_vars;
}
+/* Don't call while holding context locks. */
+static int delete_extens(const char *context, const char *exten)
+{
+ struct pbx_find_info find_info = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
+
+ if (pbx_find_extension(NULL, NULL, &find_info, context, exten, PRIORITY_HINT, NULL, NULL, E_MATCH)) {
+ ast_context_remove_extension(context, exten, PRIORITY_HINT, BASE_REGISTRAR);
+ }
+
+ if (pbx_find_extension(NULL, NULL, &find_info, context, exten, 1, NULL, NULL, E_MATCH)) {
+ ast_context_remove_extension(context, exten, 1, BASE_REGISTRAR);
+ }
+
+ return 0;
+}
+
+static int add_extension(struct ast_context *context, const char *exten,
+ int priority, const char *application)
+{
+ struct pbx_find_info find_info = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
+ struct ast_exten *existing_exten;
+ char *data = NULL;
+ char *app = NULL;
+ void *free_ptr = NULL;
+ char *paren;
+ const char *context_name;
+
+ if (!context || ast_strlen_zero(exten) || ast_strlen_zero(application)) {
+ return -1;
+ }
+
+ /* The incoming application has to be split into the app name and the
+ * arguments (data). The app name can be any storage type as add_extension
+ * copies it into its own buffer. Data however, needs to be dynamically
+ * allocated and a free function provided.
+ */
+
+ paren = strchr(application, '(');
+ if (!paren) {
+ app = (char *)application;
+ } else {
+ app = ast_strdupa(application);
+ app[paren - application] = '\0';
+ data = ast_strdup(paren + 1);
+ if (!data) {
+ return -1;
+ }
+ data[strlen(data) - 1] = '\0';
+ free_ptr = ast_free_ptr;
+ if (ast_strlen_zero(app) || ast_strlen_zero(data)) {
+ ast_free(data);
+ return -1;
+ }
+ }
+
+ /* Don't disturb existing, exact-match, entries. */
+ context_name = ast_get_context_name(context);
+ if ((existing_exten = pbx_find_extension(NULL, NULL, &find_info, context_name, exten,
+ priority, NULL, NULL, E_MATCH))) {
+ const char *existing_app = ast_get_extension_app(existing_exten);
+ const char *existing_data = ast_get_extension_app_data(existing_exten);
+ if (!strcmp(existing_app, app)
+ && !strcmp(existing_data ? existing_data : "", data ? data : "")) {
+ ast_free(data);
+ return 0;
+ }
+
+ ast_context_remove_extension2(context, exten, priority, BASE_REGISTRAR, 1);
+ }
+
+ if (ast_add_extension2_nolock(context, 0, exten, priority, NULL, NULL,
+ app, data, free_ptr, BASE_REGISTRAR)) {
+ ast_free(data);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int add_hints(const char *context, const char *exten, const char *application, const char *id)
+{
+ struct ast_context *hint_context;
+ char *hint_device;
+
+ hint_device = ast_alloca(strlen("PJSIP/") + strlen(id) + 1);
+ sprintf(hint_device, "PJSIP/%s", id);
+
+ /* We need the contexts list locked to safely be able to both read and lock the specific context within */
+ if (ast_wrlock_contexts()) {
+ ast_log(LOG_ERROR, "Failed to lock the contexts list.\n");
+ return -1;
+ }
+
+ if (!(hint_context = ast_context_find_or_create(NULL, NULL, context, BASE_REGISTRAR))) {
+ ast_log(LOG_ERROR, "Unable to find or create hint context '%s'\n", context);
+ if (ast_unlock_contexts()) {
+ ast_assert(0);
+ }
+ return -1;
+ }
+
+ /* Transfer the all-contexts lock to the specific context */
+ if (ast_wrlock_context(hint_context)) {
+ ast_unlock_contexts();
+ ast_log(LOG_ERROR, "failed to obtain write lock on context\n");
+ return -1;
+ }
+ ast_unlock_contexts();
+
+ if (add_extension(hint_context, exten, PRIORITY_HINT, hint_device)) {
+ ast_log(LOG_ERROR, "Failed to add hint '%s@%s' to the PBX.\n",
+ exten, context);
+ }
+
+ if (!ast_strlen_zero(application)) {
+ if (add_extension(hint_context, exten, 1, application)) {
+ ast_log(LOG_ERROR, "Failed to add hint '%s@%s' to the PBX.\n",
+ exten, context);
+ }
+ } else {
+ ast_context_remove_extension2(hint_context, exten, 1, BASE_REGISTRAR, 1);
+ }
+
+ ast_unlock_context(hint_context);
+
+ return 0;
+}
+
static int handle_auth(const struct ast_sorcery *sorcery, struct object_type_wizard *otw,
struct ast_category *wiz, char *direction)
{
@@ -459,12 +646,29 @@ static int handle_endpoint(const struct ast_sorcery *sorcery, struct object_type
struct ast_sorcery_object *obj = NULL;
const char *id = ast_category_get_name(wiz);
const char *transport = ast_variable_find_in_list(wizvars, "transport");
+ const char *hint_context = hint_context = ast_variable_find_in_list(wizvars, "hint_context");
+ const char *hint_exten = ast_variable_find_in_list(wizvars, "hint_exten");
+ const char *hint_application= ast_variable_find_in_list(wizvars, "hint_application");
char new_id[strlen(id) + MAX_ID_SUFFIX];
RAII_VAR(struct ast_variable *, vars, get_object_variables(wizvars, "endpoint/"), ast_variables_destroy);
variable_list_append_return(&vars, "@pjsip_wizard", id);
variable_list_append_return(&vars, "aors", id);
+ if (ast_strlen_zero(hint_context)) {
+ hint_context = ast_variable_find_in_list(vars, "context");
+ }
+
+ if (ast_strlen_zero(hint_context)) {
+ hint_context = "default";
+ }
+
+ if (!ast_strlen_zero(hint_exten)) {
+ /* These are added so we can find and delete the hints when the endpoint gets deleted */
+ variable_list_append_return(&vars, "@hint_context", hint_context);
+ variable_list_append_return(&vars, "@hint_exten", hint_exten);
+ }
+
if (!ast_strlen_zero(transport)) {
variable_list_append_return(&vars, "transport", transport);
}
@@ -489,6 +693,14 @@ static int handle_endpoint(const struct ast_sorcery *sorcery, struct object_type
}
ao2_ref(obj, -1);
+ if (!ast_strlen_zero(hint_exten)) {
+ if (is_variable_true(wizvars, "has_hint")) {
+ add_hints(hint_context, hint_exten, hint_application, id);
+ } else {
+ delete_extens(hint_context, hint_exten);
+ }
+ }
+
return 0;
}
@@ -601,6 +813,14 @@ static int delete_existing_cb(void *obj, void *arg, int flags)
{
struct object_type_wizard *otw = arg;
+ if (!strcmp(otw->object_type, "endpoint")) {
+ const char *context = ast_sorcery_object_get_extended(obj, "hint_context");
+ const char *exten = ast_sorcery_object_get_extended(obj, "hint_exten");
+ if (!ast_strlen_zero(context) && !ast_strlen_zero(exten)) {
+ delete_extens(context, exten);
+ }
+ }
+
otw->wizard->delete(otw->sorcery, otw->wizard_data, obj);
return CMP_MATCH;