[svn-commits] gtjoseph: branch 13 r431643 - in /branches/13: configs/samples/ res/

SVN commits to the Digium repositories svn-commits at lists.digium.com
Tue Feb 10 17:16:43 CST 2015


Author: gtjoseph
Date: Tue Feb 10 17:16:40 2015
New Revision: 431643

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=431643
Log:
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/


Modified:
    branches/13/configs/samples/pjsip_wizard.conf.sample
    branches/13/res/res_pjsip_config_wizard.c

Modified: branches/13/configs/samples/pjsip_wizard.conf.sample
URL: http://svnview.digium.com/svn/asterisk/branches/13/configs/samples/pjsip_wizard.conf.sample?view=diff&rev=431643&r1=431642&r2=431643
==============================================================================
--- branches/13/configs/samples/pjsip_wizard.conf.sample (original)
+++ branches/13/configs/samples/pjsip_wizard.conf.sample Tue Feb 10 17:16:40 2015
@@ -24,7 +24,7 @@
 ;============EXAMPLE WIZARD CONFIGURATION FOR A PHONE=======================
 
 ; This config would create an endpoint, aor with dynamic contact, inbound
-; auth and a phoneprov object.
+; auth, a phoneprov object and a dialplan hint for extension 1000.
 
 ;[myphone]
 ;type = wizard
@@ -32,6 +32,8 @@
 ;accepts_registrations = yes
 ;has_phoneprov = yes
 ;transport = ipv4
+;has_hint = yes
+;hint_exten = 1000
 ;inbound_auth/username = testname
 ;inbound_auth/password = test password
 ;endpoint/allow = ulaw
@@ -116,6 +118,24 @@
                      ; If yes, phoneprov/MAC must be specified.
                      ; (default: "no")
 
+;has_hint=           ; Create hint and optionally a default application.
+                     ; (default: "no")
+
+;hint_context        ; Any hints created for this wizard will be placed in this
+                     ; context.
+                     ; (default: endpoint/context)
+
+;hint_exten          ; If specified, a PJSIP/<wizard_id> hint will be created
+                     ; for this extension in 'hint_context'.
+                     ; context.
+                     ; (default: none)
+
+;hint_application    ; If specified, an extension will be placed in 'hint_context'
+                     ; at priority 1 that calls this application.  Could be any
+                     ; valid dialplan expression like
+                     ; "Gosub(stdexten,${EXTEN},1(${HINT}))"
+                     ; (default: "Dial(${HINT})")
+
 ;endpoint/<param>      ; Any parameters to be passed directly to and validated
 ;aor/<param>           ; by their respective objects.
 ;inbound_auth/<param>

Modified: branches/13/res/res_pjsip_config_wizard.c
URL: http://svnview.digium.com/svn/asterisk/branches/13/res/res_pjsip_config_wizard.c?view=diff&rev=431643&r1=431642&r2=431643
==============================================================================
--- branches/13/res/res_pjsip_config_wizard.c (original)
+++ branches/13/res/res_pjsip_config_wizard.c Tue Feb 10 17:16:40 2015
@@ -64,7 +64,8 @@
 
 			<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 @@
 			<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 @@
 			<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 @@
 
 			<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 @@
 					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 => <hint_exten>,hint,PJSIP/<wizard_id></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 => <hint_exten>,1,<hint_application></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/*">
 					<synopsis>Variables to be passed directly to the endpoint.</synopsis>
 				</configOption>
@@ -205,6 +262,8 @@
 
  /*! \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 @@
 	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,11 +646,28 @@
 	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);
@@ -488,6 +692,14 @@
 		otw->wizard->create(sorcery, otw->wizard_data, obj);
 	}
 	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;
 }
@@ -600,6 +812,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);
 




More information about the svn-commits mailing list