aboutsummaryrefslogtreecommitdiff
path: root/net/asterisk14/files/feature_disconnect.diff
blob: 5be713b0da133d02f83d34308c146833362eb6a3 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
--- apps/app_dial.c.orig	Wed Feb  6 18:45:30 2008
+++ apps/app_dial.c	Wed Feb  6 18:51:59 2008
@@ -297,6 +297,8 @@ AST_APP_OPTIONS(dial_exec_options, {
 	OPT_CALLER_HANGUP | OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER | \
 	OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR | OPT_CALLEE_PARK | OPT_CALLER_PARK))
 
+static int detect_disconnect(struct ast_channel *chan, char code);
+
 /* We define a custom "local user" structure because we
    use it not only for keeping track of what is in use but
    also for keeping track of who we're dialing. */
@@ -402,6 +404,7 @@ static struct ast_channel *wait_for_answ
 	struct ast_channel *peer = NULL;
 	/* single is set if only one destination is enabled */
 	int single = outgoing && !outgoing->next && !ast_test_flag(outgoing, OPT_MUSICBACK | OPT_RINGBACK);
+
 	
 	if (single) {
 		/* Turn off hold music, etc */
@@ -716,9 +719,9 @@ static struct ast_channel *wait_for_answ
 				}
 
 				if (ast_test_flag(peerflags, OPT_CALLER_HANGUP) && 
-						  (f->subclass == '*')) { /* hmm it it not guaranteed to be '*' anymore. */
+						  detect_disconnect(in, f->subclass)) { /* hmm it it not guaranteed to be '*' anymore. */
 					if (option_verbose > 2)
-						ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
+						ast_verbose(VERBOSE_PREFIX_3 "User requested call disconnect.\n");
 					*to=0;
 					ast_cdr_noanswer(in->cdr);
 					strcpy(status, "CANCEL");
@@ -776,6 +779,56 @@ static struct ast_channel *wait_for_answ
 	
 	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;
+	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);
+
+	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)
 {
--- include/asterisk/features.h.orig	Thu Aug 23 23:16:41 2007
+++ include/asterisk/features.h	Tue Dec 11 17:13:52 2007
@@ -31,6 +31,20 @@
 #define FEATURE_EXTEN_LEN	32
 #define FEATURE_MOH_LEN		80  /* same as MAX_MUSICCLASS from channel.h */
 
+#define FEATURE_RETURN_HANGUP		-1
+#define FEATURE_RETURN_SUCCESSBREAK	 0
+#define FEATURE_RETURN_PBX_KEEPALIVE	AST_PBX_KEEPALIVE
+#define FEATURE_RETURN_NO_HANGUP_PEER	AST_PBX_NO_HANGUP_PEER
+#define FEATURE_RETURN_PASSDIGITS	 21
+#define FEATURE_RETURN_STOREDIGITS	 22
+#define FEATURE_RETURN_SUCCESS	 	 23
+#define FEATURE_RETURN_KEEPTRYING    24
+
+#define FEATURE_SENSE_CHAN	(1 << 0)
+#define FEATURE_SENSE_PEER	(1 << 1)
+
+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 */
 struct ast_call_feature {
 	int feature_mask;
@@ -38,7 +52,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];
@@ -47,6 +61,12 @@
 };
 
 
+struct feature_interpret_result {
+    struct ast_call_feature *builtin_feature;
+    struct ast_call_feature *dynamic_features[20];
+    int num_dyn_features;
+};
+
 
 /*! \brief Park a call and read back parked location 
  *  \param chan the channel to actually be parked
@@ -93,5 +113,11 @@
 /*! \brief unregister feature from feature_set
     \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);
+
+void ast_features_lock(void);
+void ast_features_unlock(void);
+
 
 #endif /* _AST_FEATURES_H */
--- res/res_features.c.orig	2008-04-08 14:55:25.000000000 +0300
+++ res/res_features.c	2008-04-08 14:59:59.000000000 +0300
@@ -485,18 +485,6 @@
 }
 
 
-#define FEATURE_RETURN_HANGUP		-1
-#define FEATURE_RETURN_SUCCESSBREAK	 0
-#define FEATURE_RETURN_PBX_KEEPALIVE	AST_PBX_KEEPALIVE
-#define FEATURE_RETURN_NO_HANGUP_PEER	AST_PBX_NO_HANGUP_PEER
-#define FEATURE_RETURN_PASSDIGITS	 21
-#define FEATURE_RETURN_STOREDIGITS	 22
-#define FEATURE_RETURN_SUCCESS	 	 23
-#define FEATURE_RETURN_KEEPTRYING    24
-
-#define FEATURE_SENSE_CHAN	(1 << 0)
-#define FEATURE_SENSE_PEER	(1 << 1)
-
 /*! \brief
  * set caller and callee according to the direction
  */
@@ -1061,32 +1049,35 @@
 	return res;
 }
 
-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_LIST_LOCK(&feature_list);
+}
+
+void ast_features_unlock(void)
+{
+	AST_LIST_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)
 {
 	int x;
-	struct ast_flags features;
 	int res = FEATURE_RETURN_PASSDIGITS;
 	struct ast_call_feature *feature;
-	const char *dynamic_features;
+	const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
 	char *tmp, *tok;
 
-	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");
-	}
-	if (option_debug > 2)
-		ast_log(LOG_DEBUG, "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);
+	result->builtin_feature = NULL;
+	result->num_dyn_features = 0;
 
-	ast_rwlock_rdlock(&features_lock);
 	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);
+				result->builtin_feature = &builtin_features[x];
 				break;
 			} else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
 				if (res == FEATURE_RETURN_PASSDIGITS)
@@ -1094,7 +1085,6 @@
 			}
 		}
 	}
-	ast_rwlock_unlock(&features_lock);
 
 	if (ast_strlen_zero(dynamic_features))
 		return res;
@@ -1102,9 +1092,7 @@
 	tmp = ast_strdupa(dynamic_features);
 
 	while ((tok = strsep(&tmp, "#"))) {
-		AST_LIST_LOCK(&feature_list);	
 		if (!(feature = find_dynamic_feature(tok))) {
-			AST_LIST_UNLOCK(&feature_list);
 			continue;
 		}
 			
@@ -1112,21 +1100,52 @@
 		if (!strcmp(feature->exten, code)) {
 			if (option_verbose > 2)
 				ast_verbose(VERBOSE_PREFIX_3 " Feature Found: %s exten: %s\n",feature->sname, tok);
-			res = feature->operation(chan, peer, config, code, sense, feature);
-			if (res != FEATURE_RETURN_KEEPTRYING) {
-				AST_LIST_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 = FEATURE_RETURN_PASSDIGITS;
 		} else if (!strncmp(feature->exten, code, strlen(code)))
 			res = FEATURE_RETURN_STOREDIGITS;
 
-		AST_LIST_UNLOCK(&feature_list);
 	}
 	
 	return res;
 }
 
+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 = FEATURE_RETURN_PASSDIGITS;
+	struct ast_call_feature *feature;
+
+	if (sense == FEATURE_SENSE_CHAN)
+		ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);	
+	else
+		ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);	
+	if (option_debug > 2)
+		ast_log(LOG_DEBUG, "Feature interpret: chan=%s, peer=%s, sense=%d, features=%d\n", chan->name, peer->name, sense, features.flags);
+
+	ast_features_lock();
+	res = ast_feature_detect(chan, &features, code, &result);
+
+	if (result.builtin_feature)
+		res = result.builtin_feature->operation(chan, peer, config, code, sense, NULL);
+
+	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;
+}
+
 static void set_config_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
 {
 	int x;