Review Board 1.7.16


Fix directed group pickup feature code *8 with pickupsounds enabled , deadlock and segfault, affects 1.8.0 and trunk

Review Request #1185 - Created April 17, 2011 and submitted

Alec Davis
trunk
18654
Reviewers
asterisk-dev
rmudgett
Asterisk
Since 1.8, the new pickupsound and pickupfailsound in features.conf cause many issues.

1). chan_sip:handle_request_invite() shouldn't be playing out the fail/success audio, as it has 'netlock' locked.
2). dialplan applications for directed_pickups shouldn't beep.
3). feature code for directed pickup should beep on success/failure if configured.

Moved app_directed:pickup_do() to features:ast_do_pickup().

Functions below, all now use the new ast_do_pickup()
app_directed_pickup.c:
   pickup_by_channel()
   pickup_by_exten()
   pickup_by_mark()
   pickup_by_part()
features.c:
   ast_pickup_call()

Created a sip_pickup() thread to handle the pickup and playout the audio, spawned from handle_request_invite.
pickup using *8 feature code, with pickup sounds enabled/disabled

exten => 71,1,Pickup()           ; any ringing extension in same pickupgroup 
exten => 72,1,Pickup(85@phones)  ; dahdi extension
exten => 73,1,Pickup(823@phones) ; sip extension

Changes between revision 7 and 14

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

  1. trunk/apps/app_directed_pickup.c: Loading...
  2. trunk/channels/chan_sip.c: Loading...
  3. trunk/include/asterisk/features.h: Loading...
  4. trunk/main/features.c: Loading...
  5. trunk/res/res_features.exports.in: Loading...
trunk/apps/app_directed_pickup.c
Diff Revision 7 Diff Revision 14
1
/*
1
/*
2
 * Asterisk -- An open source telephony toolkit.
2
 * Asterisk -- An open source telephony toolkit.
3
 *
3
 *
4
 * Copyright (C) 2005, Joshua Colp
4
 * Copyright (C) 2005, Joshua Colp
5
 *
5
 *
6
 * Joshua Colp <jcolp@digium.com>
6
 * Joshua Colp <jcolp@digium.com>
7
 *
7
 *
8
 * Portions merged from app_pickupchan, which was
8
 * Portions merged from app_pickupchan, which was
9
 * Copyright (C) 2008, Gary Cook
9
 * Copyright (C) 2008, Gary Cook
10
 *
10
 *
11
 * See http://www.asterisk.org for more information about
11
 * See http://www.asterisk.org for more information about
12
 * the Asterisk project. Please do not directly contact
12
 * the Asterisk project. Please do not directly contact
13
 * any of the maintainers of this project for assistance;
13
 * any of the maintainers of this project for assistance;
14
 * the project provides a web site, mailing lists and IRC
14
 * the project provides a web site, mailing lists and IRC
15
 * channels for your use.
15
 * channels for your use.
16
 *
16
 *
17
 * This program is free software, distributed under the terms of
17
 * This program is free software, distributed under the terms of
18
 * the GNU General Public License Version 2. See the LICENSE file
18
 * the GNU General Public License Version 2. See the LICENSE file
19
 * at the top of the source tree.
19
 * at the top of the source tree.
20
 */
20
 */
21

    
   
21

   
22
/*! \file
22
/*! \file
23
 *
23
 *
24
 * \brief Directed Call Pickup Support
24
 * \brief Directed Call Pickup Support
25
 *
25
 *
26
 * \author Joshua Colp <jcolp@digium.com>
26
 * \author Joshua Colp <jcolp@digium.com>
27
 * \author Gary Cook
27
 * \author Gary Cook
28
 *
28
 *
29
 * \ingroup applications
29
 * \ingroup applications
30
 */
30
 */
31

    
   
31

   
32
#include "asterisk.h"
32
#include "asterisk.h"
33

    
   
33

   
34
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
34
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
35

    
   
35

   
36
#include "asterisk/file.h"
36
#include "asterisk/file.h"
37
#include "asterisk/channel.h"
37
#include "asterisk/channel.h"
38
#include "asterisk/pbx.h"
38
#include "asterisk/pbx.h"
39
#include "asterisk/module.h"
39
#include "asterisk/module.h"
40
#include "asterisk/lock.h"
40
#include "asterisk/lock.h"
41
#include "asterisk/app.h"
41
#include "asterisk/app.h"
42
#include "asterisk/features.h"
42
#include "asterisk/features.h"
43
#include "asterisk/manager.h"
43
#include "asterisk/manager.h"
44
#include "asterisk/callerid.h"
44
#include "asterisk/callerid.h"
45
#include "asterisk/cel.h"
45
#include "asterisk/cel.h"
46

    
   
46

   
47
#define PICKUPMARK "PICKUPMARK"
47
#define PICKUPMARK "PICKUPMARK"
48

    
   
48

   
49
/*** DOCUMENTATION
49
/*** DOCUMENTATION
50
	<application name="Pickup" language="en_US">
50
	<application name="Pickup" language="en_US">
51
		<synopsis>
51
		<synopsis>
52
			Directed extension call pickup.
52
			Directed extension call pickup.
53
		</synopsis>
53
		</synopsis>
54
		<syntax argsep="&amp;">
54
		<syntax argsep="&amp;">
55
			<parameter name="ext" argsep="@" required="true">
55
			<parameter name="ext" argsep="@" required="true">
56
				<argument name="extension" required="true"/>
56
				<argument name="extension" required="true"/>
57
				<argument name="context" />
57
				<argument name="context" />
58
			</parameter>
58
			</parameter>
59
			<parameter name="ext2" argsep="@" multiple="true">
59
			<parameter name="ext2" argsep="@" multiple="true">
60
				<argument name="extension2" required="true"/>
60
				<argument name="extension2" required="true"/>
61
				<argument name="context2"/>
61
				<argument name="context2"/>
62
			</parameter>
62
			</parameter>
63
		</syntax>
63
		</syntax>
64
		<description>
64
		<description>
65
			<para>This application can pickup any ringing channel that is calling
65
			<para>This application can pickup any ringing channel that is calling
66
			the specified <replaceable>extension</replaceable>. If no <replaceable>context</replaceable>
66
			the specified <replaceable>extension</replaceable>. If no <replaceable>context</replaceable>
67
			is specified, the current context will be used. If you use the special string <literal>PICKUPMARK</literal>
67
			is specified, the current context will be used. If you use the special string <literal>PICKUPMARK</literal>
68
			for the context parameter, for example 10@PICKUPMARK, this application
68
			for the context parameter, for example 10@PICKUPMARK, this application
69
			tries to find a channel which has defined a <variable>PICKUPMARK</variable>
69
			tries to find a channel which has defined a <variable>PICKUPMARK</variable>
70
			channel variable with the same value as <replaceable>extension</replaceable>
70
			channel variable with the same value as <replaceable>extension</replaceable>
71
			(in this example, <literal>10</literal>). When no parameter is specified, the application
71
			(in this example, <literal>10</literal>). When no parameter is specified, the application
72
			will pickup a channel matching the pickup group of the active channel.</para>
72
			will pickup a channel matching the pickup group of the active channel.</para>
73
		</description>
73
		</description>
74
	</application>
74
	</application>
75
	<application name="PickupChan" language="en_US">
75
	<application name="PickupChan" language="en_US">
76
		<synopsis>
76
		<synopsis>
77
			Pickup a ringing channel.
77
			Pickup a ringing channel.
78
		</synopsis>
78
		</synopsis>
79
		<syntax>
79
		<syntax>
80
			<parameter name="channel" required="true" />
80
			<parameter name="channel" required="true" />
81
			<parameter name="channel2" multiple="true" />
81
			<parameter name="channel2" multiple="true" />
82
			<parameter name="options" required="false">
82
			<parameter name="options" required="false">
83
				<optionlist>
83
				<optionlist>
84
					<option name="p">
84
					<option name="p">
85
						<para>Channel name specified partial name. Used when find channel by callid.</para>
85
						<para>Channel name specified partial name. Used when find channel by callid.</para>
86
					</option>
86
					</option>
87
				</optionlist>
87
				</optionlist>
88
			</parameter>
88
			</parameter>
89
		</syntax>
89
		</syntax>
90
		<description>
90
		<description>
91
			<para>This will pickup a specified <replaceable>channel</replaceable> if ringing.</para>
91
			<para>This will pickup a specified <replaceable>channel</replaceable> if ringing.</para>
92
		</description>
92
		</description>
93
	</application>
93
	</application>
94
 ***/
94
 ***/
95

    
   
95

   
96
static const char app[] = "Pickup";
96
static const char app[] = "Pickup";
97
static const char app2[] = "PickupChan";
97
static const char app2[] = "PickupChan";
98
/*! \todo This application should return a result code, like PICKUPRESULT */
98
/*! \todo This application should return a result code, like PICKUPRESULT */
99

    
   
99

   
100
/* Helper function that determines whether a channel is capable of being picked up */
100
/* Helper function that determines whether a channel is capable of being picked up */
101
static int can_pickup(struct ast_channel *chan)
101
static int can_pickup(struct ast_channel *chan)
102
{
102
{
103
	if (!chan->pbx && !chan->masq && (chan->_state == AST_STATE_RINGING || chan->_state == AST_STATE_RING || chan->_state == AST_STATE_DOWN))
103
	if (!chan->pbx && !chan->masq &&

    
   
104
		!ast_test_flag(chan, AST_FLAG_ZOMBIE) &&

    
   
105
		(chan->_state == AST_STATE_RINGING ||

    
   
106
		 chan->_state == AST_STATE_RING ||

    
   
107
		 chan->_state == AST_STATE_DOWN)) {
104
		return 1;
108
		return 1;
105
	else
109
	}
106
		return 0;
110
	return 0;
107
}
111
}
108

    
   
112

   
109
struct pickup_by_name_args {
113
struct pickup_by_name_args {
110
	const char *name;
114
	const char *name;
111
	size_t len;
115
	size_t len;
112
};
116
};
113

    
   
117

   
114
static int pickup_by_name_cb(void *obj, void *arg, void *data, int flags)
118
static int pickup_by_name_cb(void *obj, void *arg, void *data, int flags)
115
{
119
{
116
	struct ast_channel *chan = obj;
120
	struct ast_channel *chan = obj;
117
	struct pickup_by_name_args *args = data;
121
	struct pickup_by_name_args *args = data;
118

    
   
122

   
119
	ast_channel_lock(chan);
123
	ast_channel_lock(chan);
120
	if (!strncasecmp(chan->name, args->name, args->len) && can_pickup(chan)) {
124
	if (!strncasecmp(chan->name, args->name, args->len) && can_pickup(chan)) {
121
		/* Return with the channel still locked on purpose */
125
		/* Return with the channel still locked on purpose */
122
		return CMP_MATCH | CMP_STOP;
126
		return CMP_MATCH | CMP_STOP;
123
	}
127
	}
124
	ast_channel_unlock(chan);
128
	ast_channel_unlock(chan);
125

    
   
129

   
126
	return 0;
130
	return 0;
127
}
131
}
128

    
   
132

   
129
/*! \brief Helper Function to walk through ALL channels checking NAME and STATE */
133
/*! \brief Helper Function to walk through ALL channels checking NAME and STATE */
130
static struct ast_channel *my_ast_get_channel_by_name_locked(const char *channame)
134
static struct ast_channel *my_ast_get_channel_by_name_locked(const char *channame)
131
{
135
{
132
	char *chkchan;
136
	char *chkchan;
133
	struct pickup_by_name_args pickup_args;
137
	struct pickup_by_name_args pickup_args;
134

    
   
138

   
135
	/* Check if channel name contains a '-'.
139
	/* Check if channel name contains a '-'.
136
	 * In this case the channel name will be interpreted as full channel name.
140
	 * In this case the channel name will be interpreted as full channel name.
137
	 */
141
	 */
138
	if (strchr(channame, '-')) {
142
	if (strchr(channame, '-')) {
139
		/* check full channel name */
143
		/* check full channel name */
140
		pickup_args.len = strlen(channame);
144
		pickup_args.len = strlen(channame);
141
		pickup_args.name = channame;
145
		pickup_args.name = channame;
142
	} else {
146
	} else {
143
		/* need to append a '-' for the comparison so we check full channel name,
147
		/* need to append a '-' for the comparison so we check full channel name,
144
		 * i.e SIP/hgc- , use a temporary variable so original stays the same for
148
		 * i.e SIP/hgc- , use a temporary variable so original stays the same for
145
		 * debugging.
149
		 * debugging.
146
		 */
150
		 */
147
		pickup_args.len = strlen(channame) + 1;
151
		pickup_args.len = strlen(channame) + 1;
148
		chkchan = alloca(pickup_args.len + 1);
152
		chkchan = alloca(pickup_args.len + 1);
149
		strcpy(chkchan, channame);
153
		strcpy(chkchan, channame);
150
		strcat(chkchan, "-");
154
		strcat(chkchan, "-");
151
		pickup_args.name = chkchan;
155
		pickup_args.name = chkchan;
152
	}
156
	}
153

    
   
157

   
154
	return ast_channel_callback(pickup_by_name_cb, NULL, &pickup_args, 0);
158
	return ast_channel_callback(pickup_by_name_cb, NULL, &pickup_args, 0);
155
}
159
}
156

    
   
160

   
157
/*! \brief Attempt to pick up specified channel named , does not use context */
161
/*! \brief Attempt to pick up specified channel named , does not use context */
158
static int pickup_by_channel(struct ast_channel *chan, char *pickup)
162
static int pickup_by_channel(struct ast_channel *chan, char *pickup)
159
{
163
{
160
	int res = 0;
164
	int res = 0;
161
	struct ast_channel *target;
165
	struct ast_channel *target;
162

    
   
166

   
163
	if (!(target = my_ast_get_channel_by_name_locked(pickup))) {
167
	if (!(target = my_ast_get_channel_by_name_locked(pickup))) {
164
		return -1;
168
		return -1;
165
	}
169
	}
166

    
   
170

   
167
	/* Just check that we are not picking up the SAME as target */
171
	/* Just check that we are not picking up the SAME as target */
168
	if (chan != target) {
172
	if (chan != target) {
169
		res = ast_do_pickup(chan, target);
173
		res = ast_do_pickup(chan, target);
170
	}
174
	}
171
	ast_channel_unlock(target);
175
	ast_channel_unlock(target);
172
	target = ast_channel_unref(target);
176
	target = ast_channel_unref(target);
173

    
   
177

   
174
	return res;
178
	return res;
175
}
179
}
176

    
   
180

   
177
/* Attempt to pick up specified extension with context */
181
/* Attempt to pick up specified extension with context */
178
static int pickup_by_exten(struct ast_channel *chan, const char *exten, const char *context)
182
static int pickup_by_exten(struct ast_channel *chan, const char *exten, const char *context)
179
{
183
{
180
	struct ast_channel *target = NULL;
184
	struct ast_channel *target = NULL;
181
	struct ast_channel_iterator *iter;
185
	struct ast_channel_iterator *iter;
182
	int res = -1;
186
	int res = -1;
183

    
   
187

   
184
	if (!(iter = ast_channel_iterator_by_exten_new(exten, context))) {
188
	if (!(iter = ast_channel_iterator_by_exten_new(exten, context))) {
185
		return -1;
189
		return -1;
186
	}
190
	}
187

    
   
191

   
188
	while ((target = ast_channel_iterator_next(iter))) {
192
	while ((target = ast_channel_iterator_next(iter))) {
189
		ast_channel_lock(target);
193
		ast_channel_lock(target);
190
		if ((chan != target) && can_pickup(target)) {
194
		if ((chan != target) && can_pickup(target)) {
191
			ast_log(LOG_NOTICE,"%s pickup by %s\n", target->name, chan->name);
195
			ast_log(LOG_NOTICE, "%s pickup by %s\n", target->name, chan->name);
192
			break;
196
			break;
193
		}
197
		}
194
		ast_channel_unlock(target);
198
		ast_channel_unlock(target);
195
		target = ast_channel_unref(target);
199
		target = ast_channel_unref(target);
196
	}
200
	}
197

    
   
201

   
198
	ast_channel_iterator_destroy(iter);
202
	ast_channel_iterator_destroy(iter);
199

    
   
203

   
200
	if (target) {
204
	if (target) {
201
		res = ast_do_pickup(chan, target);
205
		res = ast_do_pickup(chan, target);
202
		ast_channel_unlock(target);
206
		ast_channel_unlock(target);
203
		target = ast_channel_unref(target);
207
		target = ast_channel_unref(target);
204
	}
208
	}
205

    
   
209

   
206
	return res;
210
	return res;
207
}
211
}
208

    
   
212

   
209
static int find_by_mark(void *obj, void *arg, void *data, int flags)
213
static int find_by_mark(void *obj, void *arg, void *data, int flags)
210
{
214
{
211
	struct ast_channel *c = obj;
215
	struct ast_channel *c = obj;
212
	const char *mark = data;
216
	const char *mark = data;
213
	const char *tmp;
217
	const char *tmp;
214
	int res;
218
	int res;
215

    
   
219

   
216
	ast_channel_lock(c);
220
	ast_channel_lock(c);
217

    
   
221

   
218
	res = (tmp = pbx_builtin_getvar_helper(c, PICKUPMARK)) &&
222
	res = (tmp = pbx_builtin_getvar_helper(c, PICKUPMARK)) &&
219
		!strcasecmp(tmp, mark) &&
223
		!strcasecmp(tmp, mark) &&
220
		can_pickup(c);
224
		can_pickup(c);
221

    
   
225

   
222
	ast_channel_unlock(c);
226
	ast_channel_unlock(c);
223

    
   
227

   
224
	return res ? CMP_MATCH | CMP_STOP : 0;
228
	return res ? CMP_MATCH | CMP_STOP : 0;
225
}
229
}
226

    
   
230

   
227
/* Attempt to pick up specified mark */
231
/* Attempt to pick up specified mark */
228
static int pickup_by_mark(struct ast_channel *chan, const char *mark)
232
static int pickup_by_mark(struct ast_channel *chan, const char *mark)
229
{
233
{
230
	struct ast_channel *target;
234
	struct ast_channel *target;
231
	int res = -1;
235
	int res = -1;
232

    
   
236

   
233
	if (!(target = ast_channel_callback(find_by_mark, NULL, (char *) mark, 0))) {
237
	if (!(target = ast_channel_callback(find_by_mark, NULL, (char *) mark, 0))) {
234
		return res;
238
		return res;
235
	}
239
	}
236

    
   
240

   
237
	ast_channel_lock(target);
241
	ast_channel_lock(target);
238
	if (can_pickup(target)) {
242
	if (can_pickup(target)) {
239
		res = ast_do_pickup(chan, target);
243
		res = ast_do_pickup(chan, target);
240
	} else {
244
	} else {
241
		ast_log(LOG_WARNING, "target has gone, or not ringing anymore for %s\n", chan->name);
245
		ast_log(LOG_WARNING, "target has gone, or not ringing anymore for %s\n", chan->name);
242
	}
246
	}
243
	ast_channel_unlock(target);
247
	ast_channel_unlock(target);
244
	target = ast_channel_unref(target);
248
	target = ast_channel_unref(target);
245
	
249

   
246
	return res;
250
	return res;
247
}
251
}
248

    
   
252

   
249
static int find_channel_by_group(void *obj, void *arg, void *data, int flags)
253
static int find_channel_by_group(void *obj, void *arg, void *data, int flags)
250
{
254
{
251
	struct ast_channel *chan = obj;
255
	struct ast_channel *chan = obj;
252
	struct ast_channel *c = data;
256
	struct ast_channel *c = data;

    
   
257
	int i;
253

    
   
258

   
254
	ast_channel_lock(chan);
259
	ast_channel_lock(chan);
255
	int i = (c != chan) &&
260
	i = (c != chan) && (chan->pickupgroup & c->callgroup) &&
256
		(chan->pickupgroup & c->callgroup) &&

   
257
		can_pickup(chan);
261
		can_pickup(chan);
258

    
   
262

   
259
	ast_channel_unlock(chan);
263
	ast_channel_unlock(chan);
260
	return i ? CMP_MATCH | CMP_STOP : 0;
264
	return i ? CMP_MATCH | CMP_STOP : 0;
261
}
265
}
262

    
   
266

   
263
static int pickup_by_group(struct ast_channel *chan)
267
static int pickup_by_group(struct ast_channel *chan)
264
{
268
{
265
	struct ast_channel *target;
269
	struct ast_channel *target;
266
	int res = -1;
270
	int res = -1;
267

    
   
271

   
268
	if (!(target = ast_channel_callback(find_channel_by_group, NULL, chan, 0))) {
272
	if (!(target = ast_channel_callback(find_channel_by_group, NULL, chan, 0))) {
269
		return res;
273
		return res;
270
	}
274
	}
271
	
275

   
272
	ast_log(LOG_NOTICE, "%s, pickup attempt by %s\n", target->name, chan->name);
276
	ast_log(LOG_NOTICE, "%s, pickup attempt by %s\n", target->name, chan->name);
273
	ast_channel_lock(target);
277
	ast_channel_lock(target);
274
	if (can_pickup(target)) {
278
	if (can_pickup(target)) {
275
		res = ast_do_pickup(chan, target);
279
		res = ast_do_pickup(chan, target);
276
	} else {
280
	} else {
277
		ast_log(LOG_WARNING, "target has gone, or not ringing anymore for %s\n", chan->name);
281
		ast_log(LOG_WARNING, "target has gone, or not ringing anymore for %s\n", chan->name);
278
	}
282
	}
279
	ast_channel_unlock(target);
283
	ast_channel_unlock(target);
280
	target = ast_channel_unref(target);
284
	target = ast_channel_unref(target);
281
	
285

   
282
	return res;
286
	return res;
283
}
287
}
284

    
   
288

   
285
/* application entry point for Pickup() */
289
/* application entry point for Pickup() */
286
static int pickup_exec(struct ast_channel *chan, const char *data)
290
static int pickup_exec(struct ast_channel *chan, const char *data)
287
{
291
{
288
	int res = 0;
292
	int res = 0;
289
	char *tmp = ast_strdupa(data);
293
	char *tmp = ast_strdupa(data);
290
	char *exten = NULL, *context = NULL;
294
	char *exten = NULL, *context = NULL;
291

    
   
295

   
292
	if (ast_strlen_zero(data)) {
296
	if (ast_strlen_zero(data)) {
293
		res = pickup_by_group(chan);
297
		res = pickup_by_group(chan);
294
		return res;
298
		return res;
295
	}
299
	}
296
	
300

   
297
	/* Parse extension (and context if there) */
301
	/* Parse extension (and context if there) */
298
	while (!ast_strlen_zero(tmp) && (exten = strsep(&tmp, "&"))) {
302
	while (!ast_strlen_zero(tmp) && (exten = strsep(&tmp, "&"))) {
299
		if ((context = strchr(exten, '@')))
303
		if ((context = strchr(exten, '@')))
300
			*context++ = '\0';
304
			*context++ = '\0';
301
		if (!ast_strlen_zero(context) && !strcasecmp(context, PICKUPMARK)) {
305
		if (!ast_strlen_zero(context) && !strcasecmp(context, PICKUPMARK)) {
302
			if (!pickup_by_mark(chan, exten))
306
			if (!pickup_by_mark(chan, exten))
303
				break;
307
				break;
304
		} else {
308
		} else {
305
			if (!pickup_by_exten(chan, exten, !ast_strlen_zero(context) ? context : chan->context))
309
			if (!pickup_by_exten(chan, exten, !ast_strlen_zero(context) ? context : chan->context))
306
				break;
310
				break;
307
		}
311
		}
308
		ast_log(LOG_NOTICE, "No target channel found for %s.\n", exten);
312
		ast_log(LOG_NOTICE, "No target channel found for %s.\n", exten);
309
	}
313
	}
310

    
   
314

   
311
	return res;
315
	return res;
312
}
316
}
313

    
   
317

   
314
/* Find channel for pick up specified by partial channel name */ 
318
/* Find channel for pick up specified by partial channel name */ 
315
static int find_by_part(void *obj, void *arg, void *data, int flags)
319
static int find_by_part(void *obj, void *arg, void *data, int flags)
316
{
320
{
317
	struct ast_channel *c = obj; 
321
	struct ast_channel *c = obj; 
318
	const char *part = data;
322
	const char *part = data;
319
	int res = 0;
323
	int res = 0;
320
	int len = strlen(part);
324
	int len = strlen(part);
321

    
   
325

   
322
	ast_channel_lock(c);
326
	ast_channel_lock(c);
323
	if (len <= strlen(c->name)) {
327
	if (len <= strlen(c->name)) {
324
		res = !(strncmp(c->name, part, len)) && (can_pickup(c));
328
		res = !(strncmp(c->name, part, len)) && (can_pickup(c));
325
	}
329
	}
326
	ast_channel_unlock(c);
330
	ast_channel_unlock(c);
327

    
   
331

   
328
	return res ? CMP_MATCH | CMP_STOP : 0;
332
	return res ? CMP_MATCH | CMP_STOP : 0;
329
}
333
}
330

    
   
334

   
331
/* Attempt to pick up specified by partial channel name */ 
335
/* Attempt to pick up specified by partial channel name */ 
332
static int pickup_by_part(struct ast_channel *chan, const char *part)
336
static int pickup_by_part(struct ast_channel *chan, const char *part)
333
{
337
{
334
	struct ast_channel *target;
338
	struct ast_channel *target;
335
	int res = -1;
339
	int res = -1;
336

    
   
340

   
337
	if ((target = ast_channel_callback(find_by_part, NULL, (char *) part, 0))) {
341
	if ((target = ast_channel_callback(find_by_part, NULL, (char *) part, 0))) {
338
		ast_channel_lock(target);
342
		ast_channel_lock(target);
339
		if (can_pickup(target)) {
343
		if (can_pickup(target)) {
340
			res = ast_do_pickup(chan, target);
344
			res = ast_do_pickup(chan, target);
341
		} else {
345
		} else {
342
			ast_log(LOG_WARNING, "target has gone, or not ringing anymore for %s\n", chan->name);
346
			ast_log(LOG_WARNING, "target has gone, or not ringing anymore for %s\n", chan->name);
343
		}
347
		}
344
		ast_channel_unlock(target);
348
		ast_channel_unlock(target);
345
		target = ast_channel_unref(target);
349
		target = ast_channel_unref(target);
346
	}
350
	}
347

    
   
351

   
348
	return res;
352
	return res;
349
}
353
}
350

    
   
354

   
351
/* application entry point for PickupChan() */
355
/* application entry point for PickupChan() */
352
static int pickupchan_exec(struct ast_channel *chan, const char *data)
356
static int pickupchan_exec(struct ast_channel *chan, const char *data)
353
{
357
{
354
	int res = 0;
358
	int res = 0;
355
	int partial_pickup = 0;
359
	int partial_pickup = 0;
356
	char *pickup = NULL;
360
	char *pickup = NULL;
357
	char *parse = ast_strdupa(data);
361
	char *parse = ast_strdupa(data);
358
	AST_DECLARE_APP_ARGS(args,
362
	AST_DECLARE_APP_ARGS(args,
359
		AST_APP_ARG(channel);
363
		AST_APP_ARG(channel);
360
		AST_APP_ARG(options);
364
		AST_APP_ARG(options);
361
	);
365
	);
362
	AST_STANDARD_APP_ARGS(args, parse);
366
	AST_STANDARD_APP_ARGS(args, parse);
363

    
   
367

   
364
	if (ast_strlen_zero(args.channel)) {
368
	if (ast_strlen_zero(args.channel)) {
365
		ast_log(LOG_WARNING, "PickupChan requires an argument (channel)!\n");
369
		ast_log(LOG_WARNING, "PickupChan requires an argument (channel)!\n");
366
		return -1;
370
		return -1;
367
	}
371
	}
368

    
   
372

   
369
	if (!ast_strlen_zero(args.options) && strchr(args.options, 'p')) {
373
	if (!ast_strlen_zero(args.options) && strchr(args.options, 'p')) {
370
		partial_pickup = 1;
374
		partial_pickup = 1;
371
	}
375
	}
372

    
   
376

   
373
	/* Parse channel */
377
	/* Parse channel */
374
	while (!ast_strlen_zero(args.channel) && (pickup = strsep(&args.channel, "&"))) {
378
	while (!ast_strlen_zero(args.channel) && (pickup = strsep(&args.channel, "&"))) {
375
		if (!strncasecmp(chan->name, pickup, strlen(pickup))) {
379
		if (!strncasecmp(chan->name, pickup, strlen(pickup))) {
376
			ast_log(LOG_NOTICE, "Cannot pickup your own channel %s.\n", pickup);
380
			ast_log(LOG_NOTICE, "Cannot pickup your own channel %s.\n", pickup);
377
		} else {
381
		} else {
378
			if (partial_pickup) {
382
			if (partial_pickup) {
379
				if (!pickup_by_part(chan, pickup)) {
383
				if (!pickup_by_part(chan, pickup)) {
380
					break;
384
					break;
381
				}
385
				}
382
			} else if (!pickup_by_channel(chan, pickup)) {
386
			} else if (!pickup_by_channel(chan, pickup)) {
383
				break;
387
				break;
384
			}
388
			}
385
			ast_log(LOG_NOTICE, "No target channel found for %s.\n", pickup);
389
			ast_log(LOG_NOTICE, "No target channel found for %s.\n", pickup);
386
		}
390
		}
387
	}
391
	}
388

    
   
392

   
389
	return res;
393
	return res;
390
}
394
}
391

    
   
395

   
392
static int unload_module(void)
396
static int unload_module(void)
393
{
397
{
394
	int res;
398
	int res;
395

    
   
399

   
396
	res = ast_unregister_application(app);
400
	res = ast_unregister_application(app);
397
	res |= ast_unregister_application(app2);
401
	res |= ast_unregister_application(app2);
398

    
   
402

   
399
	return res;
403
	return res;
400
}
404
}
401

    
   
405

   
402
static int load_module(void)
406
static int load_module(void)
403
{
407
{
404
	int res;
408
	int res;
405

    
   
409

   
406
	res = ast_register_application_xml(app, pickup_exec);
410
	res = ast_register_application_xml(app, pickup_exec);
407
	res |= ast_register_application_xml(app2, pickupchan_exec);
411
	res |= ast_register_application_xml(app2, pickupchan_exec);
408

    
   
412

   
409
	return res;
413
	return res;
410
}
414
}
411

    
   
415

   
412
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Directed Call Pickup Application");
416
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Directed Call Pickup Application");
trunk/channels/chan_sip.c
Diff Revision 7 Diff Revision 14
 
trunk/include/asterisk/features.h
Diff Revision 7 Diff Revision 14
 
trunk/main/features.c
Diff Revision 7 Diff Revision 14
 
trunk/res/res_features.exports.in
Diff Revision 7 Diff Revision 14 - File Reverted
 
  1. trunk/apps/app_directed_pickup.c: Loading...
  2. trunk/channels/chan_sip.c: Loading...
  3. trunk/include/asterisk/features.h: Loading...
  4. trunk/main/features.c: Loading...
  5. trunk/res/res_features.exports.in: Loading...

https://reviewboard.asterisk.org/ runs on a server provided by Digium, Inc. and uses bandwidth donated to the open source Asterisk community by API Digital Communications in Huntsville, AL USA.
Please report problems with this site to asteriskteam@digium.com.