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 5 and 7

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/main/features.c: Loading...
trunk/apps/app_directed_pickup.c
Diff Revision 5 Diff Revision 7
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->_state == AST_STATE_RINGING || chan->_state == AST_STATE_RING || chan->_state == AST_STATE_DOWN))
103
	if (!chan->pbx && !chan->masq && (chan->_state == AST_STATE_RINGING || chan->_state == AST_STATE_RING || chan->_state == AST_STATE_DOWN))
104
		return 1;
104
		return 1;
105
	else
105
	else
106
		return 0;
106
		return 0;
107
}
107
}
108

    
   
108

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

    
   
113

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

    
   
118

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

    
   
125

   
126
	return 0;
126
	return 0;
127
}
127
}
128

    
   
128

   
129
/*! \brief Helper Function to walk through ALL channels checking NAME and STATE */
129
/*! \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)
130
static struct ast_channel *my_ast_get_channel_by_name_locked(const char *channame)
131
{
131
{
132
	char *chkchan;
132
	char *chkchan;
133
	struct pickup_by_name_args pickup_args;
133
	struct pickup_by_name_args pickup_args;
134

    
   
134

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

    
   
153

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

    
   
156

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

    
   
162

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

    
   
166

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

    
   

   
172
	ast_channel_unlock(target);
171
	ast_channel_unlock(target);
173
	target = ast_channel_unref(target);
172
	target = ast_channel_unref(target);
174

    
   
173

   
175
	return res;
174
	return res;
176
}
175
}
177

    
   
176

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

    
   
183

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

    
   
187

   
189
	while ((target = ast_channel_iterator_next(iter))) {
188
	while ((target = ast_channel_iterator_next(iter))) {
190
		ast_channel_lock(target);
189
		ast_channel_lock(target);
191
		if ((chan != target) && can_pickup(target)) {
190
		if ((chan != target) && can_pickup(target)) {

    
   
191
			ast_log(LOG_NOTICE,"%s pickup by %s\n", target->name, chan->name);
192
			break;
192
			break;
193
		}
193
		}
194
		ast_channel_unlock(target);
194
		ast_channel_unlock(target);
195
		target = ast_channel_unref(target);
195
		target = ast_channel_unref(target);
196
	}
196
	}
197

    
   
197

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

    
   
199

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

    
   
205

   
206
	return res;
206
	return res;
207
}
207
}
208

    
   
208

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

    
   
215

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

    
   
217

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

    
   
221

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

    
   
223

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

    
   
226

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

    
   
232

   
233
	if ((target = ast_channel_callback(find_by_mark, NULL, (char *) mark, 0))) {
233
	if (!(target = ast_channel_callback(find_by_mark, NULL, (char *) mark, 0))) {

    
   
234
		return res;

    
   
235
	}

    
   
236

   
234
		ast_channel_lock(target);
237
	ast_channel_lock(target);

    
   
238
	if (can_pickup(target)) {
235
		res = ast_do_pickup(chan, target);
239
		res = ast_do_pickup(chan, target);

    
   
240
	} else {

    
   
241
		ast_log(LOG_WARNING, "target has gone, or not ringing anymore for %s\n", chan->name);

    
   
242
	}
236
		ast_channel_unlock(target);
243
	ast_channel_unlock(target);
237
		target = ast_channel_unref(target);
244
	target = ast_channel_unref(target);
238
	}
245
	
239

    
   

   
240
	return res;
246
	return res;
241
}
247
}
242

    
   
248

   
243
static int find_channel_by_group(void *obj, void *arg, void *data, int flags)
249
static int find_channel_by_group(void *obj, void *arg, void *data, int flags)
244
{
250
{
245
	struct ast_channel *chan = obj;
251
	struct ast_channel *chan = obj;
246
	struct ast_channel *c = data;
252
	struct ast_channel *c = data;
247

    
   
253

   
248
	ast_channel_lock(chan);
254
	ast_channel_lock(chan);
249
	int i = (c != chan) &&
255
	int i = (c != chan) &&
250
		(chan->pickupgroup & c->callgroup) &&
256
		(chan->pickupgroup & c->callgroup) &&
251
		!c->masq && can_pickup(chan);
257
		can_pickup(chan);
252

    
   
258

   
253
	ast_channel_unlock(chan);
259
	ast_channel_unlock(chan);
254
	return i ? CMP_MATCH | CMP_STOP : 0;
260
	return i ? CMP_MATCH | CMP_STOP : 0;
255
}
261
}
256

    
   
262

   
257
static int pickup_by_group(struct ast_channel *chan)
263
static int pickup_by_group(struct ast_channel *chan)
258
{
264
{
259
	struct ast_channel *target;
265
	struct ast_channel *target;
260
	int res = -1;
266
	int res = -1;
261
	if ((target = ast_channel_callback(find_channel_by_group, NULL, chan, 0))) {
267

   

    
   
268
	if (!(target = ast_channel_callback(find_channel_by_group, NULL, chan, 0))) {

    
   
269
		return res;

    
   
270
	}

    
   
271
	

    
   
272
	ast_log(LOG_NOTICE, "%s, pickup attempt by %s\n", target->name, chan->name);
262
		ast_channel_lock(target);
273
	ast_channel_lock(target);

    
   
274
	if (can_pickup(target)) {
263
		res = ast_do_pickup(chan, target);
275
		res = ast_do_pickup(chan, target);

    
   
276
	} else {

    
   
277
		ast_log(LOG_WARNING, "target has gone, or not ringing anymore for %s\n", chan->name);

    
   
278
	}
264
		ast_channel_unlock(target);
279
	ast_channel_unlock(target);
265
		target = ast_channel_unref(target);
280
	target = ast_channel_unref(target);
266
	}
281
	
267
	return res;
282
	return res;
268
}
283
}
269

    
   
284

   
270
/* application entry point for Pickup() */
285
/* application entry point for Pickup() */
271
static int pickup_exec(struct ast_channel *chan, const char *data)
286
static int pickup_exec(struct ast_channel *chan, const char *data)
272
{
287
{
273
	int res = 0;
288
	int res = 0;
274
	char *tmp = ast_strdupa(data);
289
	char *tmp = ast_strdupa(data);
275
	char *exten = NULL, *context = NULL;
290
	char *exten = NULL, *context = NULL;
276

    
   
291

   
277
	if (ast_strlen_zero(data)) {
292
	if (ast_strlen_zero(data)) {
278
		res = pickup_by_group(chan);
293
		res = pickup_by_group(chan);
279
		return res;
294
		return res;
280
	}
295
	}
281
	
296
	
282
	/* Parse extension (and context if there) */
297
	/* Parse extension (and context if there) */
283
	while (!ast_strlen_zero(tmp) && (exten = strsep(&tmp, "&"))) {
298
	while (!ast_strlen_zero(tmp) && (exten = strsep(&tmp, "&"))) {
284
		if ((context = strchr(exten, '@')))
299
		if ((context = strchr(exten, '@')))
285
			*context++ = '\0';
300
			*context++ = '\0';
286
		if (!ast_strlen_zero(context) && !strcasecmp(context, PICKUPMARK)) {
301
		if (!ast_strlen_zero(context) && !strcasecmp(context, PICKUPMARK)) {
287
			if (!pickup_by_mark(chan, exten))
302
			if (!pickup_by_mark(chan, exten))
288
				break;
303
				break;
289
		} else {
304
		} else {
290
			if (!pickup_by_exten(chan, exten, !ast_strlen_zero(context) ? context : chan->context))
305
			if (!pickup_by_exten(chan, exten, !ast_strlen_zero(context) ? context : chan->context))
291
				break;
306
				break;
292
		}
307
		}
293
		ast_log(LOG_NOTICE, "No target channel found for %s.\n", exten);
308
		ast_log(LOG_NOTICE, "No target channel found for %s.\n", exten);
294
	}
309
	}
295

    
   
310

   
296
	return res;
311
	return res;
297
}
312
}
298

    
   
313

   
299
/* Find channel for pick up specified by partial channel name */ 
314
/* Find channel for pick up specified by partial channel name */ 
300
static int find_by_part(void *obj, void *arg, void *data, int flags)
315
static int find_by_part(void *obj, void *arg, void *data, int flags)
301
{
316
{
302
	struct ast_channel *c = obj; 
317
	struct ast_channel *c = obj; 
303
	const char *part = data;
318
	const char *part = data;
304
	int res = 0;
319
	int res = 0;
305
	int len = strlen(part);
320
	int len = strlen(part);
306

    
   
321

   
307
	ast_channel_lock(c);
322
	ast_channel_lock(c);
308
	if (len <= strlen(c->name)) {
323
	if (len <= strlen(c->name)) {
309
		res = !(strncmp(c->name, part, len)) && (can_pickup(c));
324
		res = !(strncmp(c->name, part, len)) && (can_pickup(c));
310
	}
325
	}
311
	ast_channel_unlock(c);
326
	ast_channel_unlock(c);
312

    
   
327

   
313
	return res ? CMP_MATCH | CMP_STOP : 0;
328
	return res ? CMP_MATCH | CMP_STOP : 0;
314
}
329
}
315

    
   
330

   
316
/* Attempt to pick up specified by partial channel name */ 
331
/* Attempt to pick up specified by partial channel name */ 
317
static int pickup_by_part(struct ast_channel *chan, const char *part)
332
static int pickup_by_part(struct ast_channel *chan, const char *part)
318
{
333
{
319
	struct ast_channel *target;
334
	struct ast_channel *target;
320
	int res = -1;
335
	int res = -1;
321

    
   
336

   
322
	if ((target = ast_channel_callback(find_by_part, NULL, (char *) part, 0))) {
337
	if ((target = ast_channel_callback(find_by_part, NULL, (char *) part, 0))) {
323
		ast_channel_lock(target);
338
		ast_channel_lock(target);

    
   
339
		if (can_pickup(target)) {
324
		res = ast_do_pickup(chan, target);
340
			res = ast_do_pickup(chan, target);

    
   
341
		} else {

    
   
342
			ast_log(LOG_WARNING, "target has gone, or not ringing anymore for %s\n", chan->name);

    
   
343
		}
325
		ast_channel_unlock(target);
344
		ast_channel_unlock(target);
326
		target = ast_channel_unref(target);
345
		target = ast_channel_unref(target);
327
	}
346
	}
328

    
   
347

   
329
	return res;
348
	return res;
330
}
349
}
331

    
   
350

   
332
/* application entry point for PickupChan() */
351
/* application entry point for PickupChan() */
333
static int pickupchan_exec(struct ast_channel *chan, const char *data)
352
static int pickupchan_exec(struct ast_channel *chan, const char *data)
334
{
353
{
335
	int res = 0;
354
	int res = 0;
336
	int partial_pickup = 0;
355
	int partial_pickup = 0;
337
	char *pickup = NULL;
356
	char *pickup = NULL;
338
	char *parse = ast_strdupa(data);
357
	char *parse = ast_strdupa(data);
339
	AST_DECLARE_APP_ARGS(args,
358
	AST_DECLARE_APP_ARGS(args,
340
		AST_APP_ARG(channel);
359
		AST_APP_ARG(channel);
341
		AST_APP_ARG(options);
360
		AST_APP_ARG(options);
342
	);
361
	);
343
	AST_STANDARD_APP_ARGS(args, parse);
362
	AST_STANDARD_APP_ARGS(args, parse);
344

    
   
363

   
345
	if (ast_strlen_zero(args.channel)) {
364
	if (ast_strlen_zero(args.channel)) {
346
		ast_log(LOG_WARNING, "PickupChan requires an argument (channel)!\n");
365
		ast_log(LOG_WARNING, "PickupChan requires an argument (channel)!\n");
347
		return -1;
366
		return -1;
348
	}
367
	}
349

    
   
368

   
350
	if (!ast_strlen_zero(args.options) && strchr(args.options, 'p')) {
369
	if (!ast_strlen_zero(args.options) && strchr(args.options, 'p')) {
351
		partial_pickup = 1;
370
		partial_pickup = 1;
352
	}
371
	}
353

    
   
372

   
354
	/* Parse channel */
373
	/* Parse channel */
355
	while (!ast_strlen_zero(args.channel) && (pickup = strsep(&args.channel, "&"))) {
374
	while (!ast_strlen_zero(args.channel) && (pickup = strsep(&args.channel, "&"))) {
356
		if (!strncasecmp(chan->name, pickup, strlen(pickup))) {
375
		if (!strncasecmp(chan->name, pickup, strlen(pickup))) {
357
			ast_log(LOG_NOTICE, "Cannot pickup your own channel %s.\n", pickup);
376
			ast_log(LOG_NOTICE, "Cannot pickup your own channel %s.\n", pickup);
358
		} else {
377
		} else {
359
			if (partial_pickup) {
378
			if (partial_pickup) {
360
				if (!pickup_by_part(chan, pickup)) {
379
				if (!pickup_by_part(chan, pickup)) {
361
					break;
380
					break;
362
				}
381
				}
363
			} else if (!pickup_by_channel(chan, pickup)) {
382
			} else if (!pickup_by_channel(chan, pickup)) {
364
				break;
383
				break;
365
			}
384
			}
366
			ast_log(LOG_NOTICE, "No target channel found for %s.\n", pickup);
385
			ast_log(LOG_NOTICE, "No target channel found for %s.\n", pickup);
367
		}
386
		}
368
	}
387
	}
369

    
   
388

   
370
	return res;
389
	return res;
371
}
390
}
372

    
   
391

   
373
static int unload_module(void)
392
static int unload_module(void)
374
{
393
{
375
	int res;
394
	int res;
376

    
   
395

   
377
	res = ast_unregister_application(app);
396
	res = ast_unregister_application(app);
378
	res |= ast_unregister_application(app2);
397
	res |= ast_unregister_application(app2);
379

    
   
398

   
380
	return res;
399
	return res;
381
}
400
}
382

    
   
401

   
383
static int load_module(void)
402
static int load_module(void)
384
{
403
{
385
	int res;
404
	int res;
386

    
   
405

   
387
	res = ast_register_application_xml(app, pickup_exec);
406
	res = ast_register_application_xml(app, pickup_exec);
388
	res |= ast_register_application_xml(app2, pickupchan_exec);
407
	res |= ast_register_application_xml(app2, pickupchan_exec);
389

    
   
408

   
390
	return res;
409
	return res;
391
}
410
}
392

    
   
411

   
393
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Directed Call Pickup Application");
412
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Directed Call Pickup Application");
trunk/main/features.c
Diff Revision 5 Diff Revision 7
 
  1. trunk/apps/app_directed_pickup.c: Loading...
  2. trunk/main/features.c: 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.