[asterisk-commits] murf: trunk r172890 - in /trunk: ./ apps/ include/asterisk/ main/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon Feb 2 11:37:16 CST 2009


Author: murf
Date: Mon Feb  2 11:37:15 2009
New Revision: 172890

URL: http://svn.digium.com/svn-view/asterisk?view=rev&rev=172890
Log:
This change allows the disconnect feature (as in "one-touch" in features.c)
to be used within the dial app, before a call is bridged.

Many thanks to sobomax for submitting this patch. 

Quoting from bug 11582:

  "So the goal of the patch was to use the user configured feature code during the 
   call setup phase. The original ast_feature_interpret() function is not well suited 
   for this purpose as it uses much call bridge specific data and doesn't separate a 
   detection of feature from a feature handler call. So a new function ast_feature_detect() 
   has been extracted off the ast_feature_interpret() function but keeping the original 
   logic intact except some insignificant changes to locking.

  "Having created the ast_feature_detect() function the possibility to use feature detection 
   in almost any place of the asterisk code. So a call to this function has been added to 
   wait_for_answer() function of app_dial.so module. This code doesn't call the feature handler 
   however and uses old call leg disconnect logic to make the changes as small and simple as 
   possible to prevent unexpected problems. A disconnect feature currently is the only one 
   supported during call setup as other features as call parking and call transfer don't make much 
   sense during call setup. However if need in some of the features would arise it is much easier to 
   implement as the infrastructure changes are already in place with this patch."

I have cleaned up the patch somewhat, and verified that the existing functionality is not
harmed, and that the new functionality works. Terry has committed his stuff, and there were
no conflicts (see 14274).

(closes issue #11583)
Reported by: sobomax
Patches:
      patch-apps__app_dial.c uploaded by sobomax (license 359)
      patch-include__asterisk__features.h uploaded by sobomax (license 359)
      patch-res__res_features.c uploaded by sobomax (license 359)
      enable-features-during-call-setup.diff uploaded by sobomax (license 359)
      11583.newdiff uploaded by murf (license 17)
      enable-features-during-call-setup-1.diff uploaded by sobomax (license 359)
      11583.latest-patch uploaded by murf (license 17)
Tested by: sobomax, murf



Modified:
    trunk/CHANGES
    trunk/apps/app_dial.c
    trunk/include/asterisk/features.h
    trunk/main/features.c

Modified: trunk/CHANGES
URL: http://svn.digium.com/svn-view/asterisk/trunk/CHANGES?view=diff&rev=172890&r1=172889&r2=172890
==============================================================================
--- trunk/CHANGES (original)
+++ trunk/CHANGES Mon Feb  2 11:37:15 2009
@@ -128,6 +128,8 @@
  * The contrib/scripts/ directory now has a script called sip_nat_settings that will
    give you the correct output for an asterisk box behind nat. It will give you the
    externhost and localnet settings.
+ * The 'one-touch' disconnect feature is now available during Dial,
+   instead of just when a call is connected.
 
 Asterisk Manager Interface
 --------------------------

Modified: trunk/apps/app_dial.c
URL: http://svn.digium.com/svn-view/asterisk/trunk/apps/app_dial.c?view=diff&rev=172890&r1=172889&r2=172890
==============================================================================
--- trunk/apps/app_dial.c (original)
+++ trunk/apps/app_dial.c Mon Feb  2 11:37:15 2009
@@ -560,6 +560,7 @@
 	uint64_t flags;
 };
 
+static int detect_disconnect(struct ast_channel *chan, char code);
 
 static void hanguptree(struct chanlist *outgoing, struct ast_channel *exception, int answered_elsewhere)
 {
@@ -1054,8 +1055,8 @@
 				}
 
 				if (ast_test_flag64(peerflags, OPT_CALLER_HANGUP) &&
-						(f->subclass == '*')) { /* hmm it it not guaranteed to be '*' anymore. */
-					ast_verb(3, "User hit %c to disconnect call.\n", f->subclass);
+						detect_disconnect(in, f->subclass)) {
+					ast_verb(3, "User requested call disconnect.\n");
 					*to = 0;
 					strcpy(pa->status, "CANCEL");
 					ast_cdr_noanswer(in->cdr);
@@ -1098,6 +1099,58 @@
 
 	return peer;
 }
+
+static char featurecode[FEATURE_MAX_LEN + 1] = "";
+
+static int detect_disconnect(struct ast_channel *chan, char code)
+{
+	struct feature_interpret_result result;
+	int x;
+	struct ast_flags features;
+	int res = FEATURE_RETURN_PASSDIGITS;
+	struct ast_call_feature *feature;
+	char *cptr;
+	const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
+	int len;
+
+	len = strlen(featurecode);
+	if (len >= FEATURE_MAX_LEN) {
+		featurecode[0] = '\0';
+	}
+	cptr = &featurecode[strlen(featurecode)];
+	cptr[0] = code;
+	cptr[1] = '\0';
+
+	memset(&features, 0, sizeof(struct ast_flags));
+	ast_set_flag(&features, AST_FEATURE_DISCONNECT);
+
+	ast_features_lock();
+
+	res = ast_feature_detect(chan, &features, featurecode, &result, dynamic_features);
+
+	if (res != FEATURE_RETURN_STOREDIGITS)
+		featurecode[0] = '\0';
+
+
+	if (result.builtin_feature && result.builtin_feature->feature_mask & AST_FEATURE_DISCONNECT) {
+		ast_features_unlock();
+		return 1;
+	}
+		
+	for (x = 0; x < result.num_dyn_features; ++x) {
+		feature = result.dynamic_features[x];
+		if (feature->feature_mask & AST_FEATURE_DISCONNECT) {
+			ast_features_unlock();
+			return 1;
+		}
+	}
+
+	ast_features_unlock();
+
+	return 0;
+}
+
+
 
 static void replace_macro_delimiter(char *s)
 {

Modified: trunk/include/asterisk/features.h
URL: http://svn.digium.com/svn-view/asterisk/trunk/include/asterisk/features.h?view=diff&rev=172890&r1=172889&r2=172890
==============================================================================
--- trunk/include/asterisk/features.h (original)
+++ trunk/include/asterisk/features.h Mon Feb  2 11:37:15 2009
@@ -36,6 +36,15 @@
 
 #define PARK_APP_NAME "Park"
 
+#define FEATURE_RETURN_HANGUP		-1
+#define FEATURE_RETURN_SUCCESSBREAK	 0
+#define FEATURE_RETURN_PASSDIGITS	 21
+#define FEATURE_RETURN_STOREDIGITS	 22
+#define FEATURE_RETURN_SUCCESS	 	 23
+#define FEATURE_RETURN_KEEPTRYING    24
+
+typedef int (*feature_operation)(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data);
+
 /*! \brief main call feature structure */
 
 enum {
@@ -53,7 +62,7 @@
 	char sname[FEATURE_SNAME_LEN];
 	char exten[FEATURE_MAX_LEN];
 	char default_exten[FEATURE_MAX_LEN];
-	int (*operation)(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data);
+	feature_operation operation;
 	unsigned int flags;
 	char app[FEATURE_APP_LEN];		
 	char app_args[FEATURE_APP_ARGS_LEN];
@@ -61,12 +70,20 @@
 	AST_LIST_ENTRY(ast_call_feature) feature_entry;
 };
 
-#define AST_FEATURE_RETURN_HANGUP                   -1
-#define AST_FEATURE_RETURN_SUCCESSBREAK             0
-#define AST_FEATURE_RETURN_PASSDIGITS               21
-#define AST_FEATURE_RETURN_STOREDIGITS              22
-#define AST_FEATURE_RETURN_SUCCESS                  23
-#define AST_FEATURE_RETURN_KEEPTRYING               24
+#define AST_FEATURE_RETURN_HANGUP                   FEATURE_RETURN_HANGUP
+#define AST_FEATURE_RETURN_SUCCESSBREAK             FEATURE_RETURN_SUCCESSBREAK
+#define AST_FEATURE_RETURN_PASSDIGITS               FEATURE_RETURN_PASSDIGITS
+#define AST_FEATURE_RETURN_STOREDIGITS              FEATURE_RETURN_STOREDIGITS
+#define AST_FEATURE_RETURN_SUCCESS                  FEATURE_RETURN_SUCCESS
+#define AST_FEATURE_RETURN_KEEPTRYING               FEATURE_RETURN_KEEPTRYING
+
+struct feature_interpret_result {
+    struct ast_call_feature *builtin_feature;
+    struct ast_call_feature *dynamic_features[20];
+    struct ast_call_feature *group_features[20];
+    int num_dyn_features;
+    int num_grp_features;
+};
 
 /*!
  * \brief Park a call and read back parked location 
@@ -122,6 +139,12 @@
     \param feature the ast_call_feature object which was registered before*/
 void ast_unregister_feature(struct ast_call_feature *feature);
 
+int ast_feature_detect(struct ast_channel *chan, const struct ast_flags *features, char *code, struct feature_interpret_result *result, const char *dynamic_features);
+
+void ast_features_lock(void);
+void ast_features_unlock(void);
+
+
 /*! \brief look for a call feature entry by its sname
 	\param name a string ptr, should match "automon", "blindxfer", "atxfer", etc. */
 struct ast_call_feature *ast_find_call_feature(const char *name);

Modified: trunk/main/features.c
URL: http://svn.digium.com/svn-view/asterisk/trunk/main/features.c?view=diff&rev=172890&r1=172889&r2=172890
==============================================================================
--- trunk/main/features.c (original)
+++ trunk/main/features.c Mon Feb  2 11:37:15 2009
@@ -856,8 +856,8 @@
 	return masq_park_call(rchan, peer, timeout, extout, 1, NULL);
 }
 
-#define FEATURE_SENSE_CHAN	(1 << 0)
-#define FEATURE_SENSE_PEER	(1 << 1)
+#define FEATURE_SENSE_CHAN     (1 << 0)
+#define FEATURE_SENSE_PEER     (1 << 1)
 
 /*! 
  * \brief set caller and callee according to the direction 
@@ -1935,44 +1935,40 @@
 	return res;
 }
 
-/*!
- * \brief Check the dynamic features
- * \param chan,peer,config,code,sense
- *
- * Lock features list, browse for code, unlock list
- * \retval res on success.
- * \retval -1 on failure.
-*/
-static int ast_feature_interpret(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
+void ast_features_lock(void)
+{
+	ast_rwlock_rdlock(&features_lock);
+	AST_RWLIST_WRLOCK(&feature_list);
+	AST_RWLIST_RDLOCK(&feature_groups);
+}
+
+void ast_features_unlock(void)
+{
+	AST_RWLIST_UNLOCK(&feature_groups);
+	AST_RWLIST_UNLOCK(&feature_list);
+	ast_rwlock_unlock(&features_lock);
+}
+
+int ast_feature_detect(struct ast_channel *chan, const struct ast_flags *features, char *code, struct feature_interpret_result *result, const char *dynamic_features)
 {
 	int x;
-	struct ast_flags features;
+	int res = FEATURE_RETURN_PASSDIGITS;
 	struct ast_call_feature *feature;
 	struct feature_group *fg = NULL;
 	struct feature_group_exten *fge;
-	const char *dynamic_features;
 	char *tmp, *tok;
-	int res = AST_FEATURE_RETURN_PASSDIGITS;
-	int feature_detected = 0;
-
-	if (sense == FEATURE_SENSE_CHAN) {
-		ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
-		dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
-	}
-	else {
-		ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);
-		dynamic_features = pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES");
-	}
-	ast_debug(3, "Feature interpret: chan=%s, peer=%s, code=%s, sense=%d, features=%d, dynamic=%s\n", chan->name, peer->name, code, sense, features.flags, dynamic_features);
-
-	ast_rwlock_rdlock(&features_lock);
+	
+	result->builtin_feature = NULL;
+	result->num_dyn_features = 0;
+	result->num_grp_features = 0;
+	
+	
 	for (x = 0; x < FEATURES_COUNT; x++) {
-		if ((ast_test_flag(&features, builtin_features[x].feature_mask)) &&
+		if ((ast_test_flag(features, builtin_features[x].feature_mask)) &&
 		    !ast_strlen_zero(builtin_features[x].exten)) {
 			/* Feature is up for consideration */
 			if (!strcmp(builtin_features[x].exten, code)) {
-				res = builtin_features[x].operation(chan, peer, config, code, sense, NULL);
-				feature_detected = 1;
+				result->builtin_feature = &builtin_features[x];
 				break;
 			} else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
 				if (res == AST_FEATURE_RETURN_PASSDIGITS)
@@ -1980,15 +1976,13 @@
 			}
 		}
 	}
-	ast_rwlock_unlock(&features_lock);
-
-	if (ast_strlen_zero(dynamic_features) || feature_detected)
+
+	if (ast_strlen_zero(dynamic_features))
 		return res;
 
 	tmp = ast_strdupa(dynamic_features);
 
 	while ((tok = strsep(&tmp, "#"))) {
-		AST_RWLIST_RDLOCK(&feature_groups);
 
 		fg = find_group(tok);
 
@@ -1996,10 +1990,9 @@
 			AST_LIST_TRAVERSE(&fg->features, fge, entry) {
 				if (strcasecmp(fge->exten, code))
 					continue;
-
-				res = fge->feature->operation(chan, peer, config, code, sense, fge->feature);
-				if (res != AST_FEATURE_RETURN_KEEPTRYING) {
-					AST_RWLIST_UNLOCK(&feature_groups);
+				
+				result->group_features[result->num_grp_features++] = fge->feature;
+				if (result->num_grp_features >= (sizeof(result->group_features) / sizeof(result->group_features[0]))) {
 					break;
 				}
 				res = AST_FEATURE_RETURN_PASSDIGITS;
@@ -2008,29 +2001,74 @@
 				break;
 		}
 
-		AST_RWLIST_UNLOCK(&feature_groups);
-
-		AST_RWLIST_RDLOCK(&feature_list);
-
 		if (!(feature = find_dynamic_feature(tok))) {
-			AST_RWLIST_UNLOCK(&feature_list);
 			continue;
 		}
 			
 		/* Feature is up for consideration */
 		if (!strcmp(feature->exten, code)) {
 			ast_verb(3, " Feature Found: %s exten: %s\n",feature->sname, tok);
-			res = feature->operation(chan, peer, config, code, sense, feature);
-			if (res != AST_FEATURE_RETURN_KEEPTRYING) {
-				AST_RWLIST_UNLOCK(&feature_list);
+			result->dynamic_features[result->num_dyn_features++] = feature;
+			if (result->num_dyn_features >= (sizeof(result->dynamic_features) / sizeof(result->dynamic_features[0]))) {
 				break;
 			}
 			res = AST_FEATURE_RETURN_PASSDIGITS;
 		} else if (!strncmp(feature->exten, code, strlen(code)))
 			res = AST_FEATURE_RETURN_STOREDIGITS;
-
-		AST_RWLIST_UNLOCK(&feature_list);
-	}
+	}
+	return res;
+}
+
+ /*!
+  * \brief Check the dynamic features
+  * \param chan,peer,config,code,sense
+  *
+  * Lock features list, browse for code, unlock list
+  * \retval res on success.
+  * \retval -1 on failure.
+ */
+static int ast_feature_interpret(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
+{
+	struct feature_interpret_result result;
+	int x;
+	struct ast_flags features;
+	int res = AST_FEATURE_RETURN_PASSDIGITS;
+	struct ast_call_feature *feature;
+	const char *dynamic_features;
+	
+	if (sense == FEATURE_SENSE_CHAN) {
+		ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
+		dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
+	} else {
+		ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);
+		dynamic_features = pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES");
+	}
+	ast_debug(3, "Feature interpret: chan=%s, peer=%s, code=%s, sense=%d, features=%d, dynamic=%s\n", chan->name, peer->name, code, sense, features.flags, dynamic_features);
+	
+	ast_features_lock();
+	res = ast_feature_detect(chan, &features, code, &result, dynamic_features);
+	
+	if (result.builtin_feature) {
+		res = result.builtin_feature->operation(chan, peer, config, code, sense, NULL);
+	}
+
+	for (x = 0; x < result.num_grp_features; ++x) {
+		feature = result.group_features[x];
+		res = feature->operation(chan, peer, config, code, sense, feature);
+		if (res != FEATURE_RETURN_KEEPTRYING) {
+			break;
+		}
+		res = FEATURE_RETURN_PASSDIGITS;
+	}
+	for (x = 0; x < result.num_dyn_features; ++x) {
+		feature = result.dynamic_features[x];
+		res = feature->operation(chan, peer, config, code, sense, feature);
+		if (res != FEATURE_RETURN_KEEPTRYING) {
+			break;
+		}
+		res = FEATURE_RETURN_PASSDIGITS;
+	}
+	ast_features_unlock();
 	
 	return res;
 }




More information about the asterisk-commits mailing list