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 4 and 6

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 4 Diff Revision 6
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
/* Perform actual pickup between two channels */

   
101
static int pickup_do(struct ast_channel *chan, struct ast_channel *target)

   
102
{

   
103
	return ast_do_pickup(chan, target);

   
104
}

   
105

    
   

   
106
/* 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 */
107
static int can_pickup(struct ast_channel *chan)
101
static int can_pickup(struct ast_channel *chan)
108
{
102
{
109
	if (!chan->pbx && (chan->_state == AST_STATE_RINGING || chan->_state == AST_STATE_RING || chan->_state == AST_STATE_DOWN))
103
	if (!chan->pbx && (chan->_state == AST_STATE_RINGING || chan->_state == AST_STATE_RING || chan->_state == AST_STATE_DOWN))
110
		return 1;
104
		return 1;
111
	else
105
	else
112
		return 0;
106
		return 0;
113
}
107
}
114

    
   
108

   
115
struct pickup_by_name_args {
109
struct pickup_by_name_args {
116
	const char *name;
110
	const char *name;
117
	size_t len;
111
	size_t len;
118
};
112
};
119

    
   
113

   
120
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)
121
{
115
{
122
	struct ast_channel *chan = obj;
116
	struct ast_channel *chan = obj;
123
	struct pickup_by_name_args *args = data;
117
	struct pickup_by_name_args *args = data;
124

    
   
118

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

    
   
125

   
132
	return 0;
126
	return 0;
133
}
127
}
134

    
   
128

   
135
/*! \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 */
136
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)
137
{
131
{
138
	char *chkchan;
132
	char *chkchan;
139
	struct pickup_by_name_args pickup_args;
133
	struct pickup_by_name_args pickup_args;
140

    
   
134

   
141
	/* Check if channel name contains a '-'.
135
	/* Check if channel name contains a '-'.
142
	 * 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.
143
	 */
137
	 */
144
	if (strchr(channame, '-')) {
138
	if (strchr(channame, '-')) {
145
		/* check full channel name */
139
		/* check full channel name */
146
		pickup_args.len = strlen(channame);
140
		pickup_args.len = strlen(channame);
147
		pickup_args.name = channame;
141
		pickup_args.name = channame;
148
	} else {
142
	} else {
149
		/* 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,
150
		 * 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
151
		 * debugging.
145
		 * debugging.
152
		 */
146
		 */
153
		pickup_args.len = strlen(channame) + 1;
147
		pickup_args.len = strlen(channame) + 1;
154
		chkchan = alloca(pickup_args.len + 1);
148
		chkchan = alloca(pickup_args.len + 1);
155
		strcpy(chkchan, channame);
149
		strcpy(chkchan, channame);
156
		strcat(chkchan, "-");
150
		strcat(chkchan, "-");
157
		pickup_args.name = chkchan;
151
		pickup_args.name = chkchan;
158
	}
152
	}
159

    
   
153

   
160
	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);
161
}
155
}
162

    
   
156

   
163
/*! \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 */
164
static int pickup_by_channel(struct ast_channel *chan, char *pickup)
158
static int pickup_by_channel(struct ast_channel *chan, char *pickup)
165
{
159
{
166
	int res = 0;
160
	int res = 0;
167
	struct ast_channel *target;
161
	struct ast_channel *target;
168

    
   
162

   
169
	if (!(target = my_ast_get_channel_by_name_locked(pickup))) {
163
	if (!(target = my_ast_get_channel_by_name_locked(pickup))) {
170
		return -1;
164
		return -1;
171
	}
165
	}
172

    
   
166

   
173
	/* 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 */
174
	if (chan != target) {
168
	if (chan != target) {
175
		res = pickup_do(chan, target);
169
		res = ast_do_pickup(chan, target);
176
	}
170
	} else {
177

    
   

   
178
	ast_channel_unlock(target);
171
		ast_channel_unlock(target);
179
	target = ast_channel_unref(target);
172
		target = ast_channel_unref(target);

    
   
173
	}
180

    
   
174

   
181
	return res;
175
	return res;
182
}
176
}
183

    
   
177

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

    
   
184

   
191
	if (!(iter = ast_channel_iterator_by_exten_new(exten, context))) {
185
	if (!(iter = ast_channel_iterator_by_exten_new(exten, context))) {
192
		return -1;
186
		return -1;
193
	}
187
	}
194

    
   
188

   
195
	while ((target = ast_channel_iterator_next(iter))) {
189
	while ((target = ast_channel_iterator_next(iter))) {
196
		ast_channel_lock(target);
190
		ast_channel_lock(target);
197
		if ((chan != target) && can_pickup(target)) {
191
		if ((chan != target) && can_pickup(target)) {
198
			break;
192
			break;
199
		}
193
		}
200
		ast_channel_unlock(target);
194
		ast_channel_unlock(target);
201
		target = ast_channel_unref(target);
195
		target = ast_channel_unref(target);
202
	}
196
	}
203

    
   
197

   
204
	ast_channel_iterator_destroy(iter);
198
	ast_channel_iterator_destroy(iter);
205

    
   
199

   
206
	if (target) {
200
	if (target) {
207
		res = pickup_do(chan, target);
201
		res = ast_do_pickup(chan, target);
208
		ast_channel_unlock(target);

   
209
		target = ast_channel_unref(target);

   
210
	}
202
	}
211

    
   
203

   
212
	return res;
204
	return res;
213
}
205
}
214

    
   
206

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

    
   
213

   
222
	ast_channel_lock(c);
214
	ast_channel_lock(c);
223

    
   
215

   
224
	res = (tmp = pbx_builtin_getvar_helper(c, PICKUPMARK)) &&
216
	res = (tmp = pbx_builtin_getvar_helper(c, PICKUPMARK)) &&
225
		!strcasecmp(tmp, mark) &&
217
		!strcasecmp(tmp, mark) &&
226
		can_pickup(c);
218
		can_pickup(c);
227

    
   
219

   
228
	ast_channel_unlock(c);
220
	ast_channel_unlock(c);
229

    
   
221

   
230
	return res ? CMP_MATCH | CMP_STOP : 0;
222
	return res ? CMP_MATCH | CMP_STOP : 0;
231
}
223
}
232

    
   
224

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

    
   
230

   
239
	if ((target = ast_channel_callback(find_by_mark, NULL, (char *) mark, 0))) {
231
	if ((target = ast_channel_callback(find_by_mark, NULL, (char *) mark, 0))) {
240
		ast_channel_lock(target);
232
		ast_channel_lock(target);
241
		res = pickup_do(chan, target);
233
		if (!target->masq && can_pickup(target)) {

    
   
234
			res = ast_do_pickup(chan, target);

    
   
235
		} else {

    
   
236
			ast_log(LOG_WARNING, "target has gone, or not ringing anymore for %s\n", chan->name);
242
		ast_channel_unlock(target);
237
			ast_channel_unlock(target);
243
		target = ast_channel_unref(target);
238
			target = ast_channel_unref(target);
244
	}
239
		}

    
   
240
	}
245

    
   
241

   
246
	return res;
242
	return res;
247
}
243
}
248

    
   
244

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

   
252
	struct ast_channel *chan = obj;
247
	struct ast_channel *chan = obj;

    
   
248
	struct ast_channel *c = data;
253

    
   
249

   
254
	ast_channel_lock(chan);
250
	ast_channel_lock(chan);
255
	int i = !chan->pbx &&
251
	int i = (c != chan) &&
256
		(c != chan) &&

   
257
		(chan->pickupgroup & c->callgroup) &&
252
		(chan->pickupgroup & c->callgroup) &&
258
		((chan->_state == AST_STATE_RINGING) || (chan->_state == AST_STATE_RING)) &&
253
		!c->masq && can_pickup(chan);
259
		!c->masq;

   
260

    
   
254

   
261
	ast_channel_unlock(chan);
255
	ast_channel_unlock(chan);
262
	return i ? CMP_MATCH | CMP_STOP : 0;
256
	return i ? CMP_MATCH | CMP_STOP : 0;
263
}
257
}
264

    
   
258

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

    
   
264
		ast_log(LOG_NOTICE, "%s, pickup attempt by %s\n", target->name, chan->name);
270
		ast_channel_lock(target);
265
		ast_channel_lock(target);

    
   
266
		if (!target->masq && can_pickup(target)) {
271
		res = ast_do_pickup(chan, target);
267
			res = ast_do_pickup(chan, target);

    
   
268
		} else {

    
   
269
			ast_log(LOG_WARNING, "target has gone, or not ringing anymore for %s\n", chan->name);
272
		ast_channel_unlock(target);
270
			ast_channel_unlock(target);
273
		target = ast_channel_unref(target);
271
			target = ast_channel_unref(target);
274
	}
272
		}

    
   
273
	}
275
	return res;
274
	return res;
276
}
275
}
277

    
   
276

   
278
/* application entry point for Pickup() */
277
/* application entry point for Pickup() */
279
static int pickup_exec(struct ast_channel *chan, const char *data)
278
static int pickup_exec(struct ast_channel *chan, const char *data)
280
{
279
{
281
	int res = 0;
280
	int res = 0;
282
	char *tmp = ast_strdupa(data);
281
	char *tmp = ast_strdupa(data);
283
	char *exten = NULL, *context = NULL;
282
	char *exten = NULL, *context = NULL;
284

    
   
283

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

    
   
302

   
304
	return res;
303
	return res;
305
}
304
}
306

    
   
305

   
307
/* Find channel for pick up specified by partial channel name */ 
306
/* Find channel for pick up specified by partial channel name */ 
308
static int find_by_part(void *obj, void *arg, void *data, int flags)
307
static int find_by_part(void *obj, void *arg, void *data, int flags)
309
{
308
{
310
	struct ast_channel *c = obj; 
309
	struct ast_channel *c = obj; 
311
	const char *part = data;
310
	const char *part = data;
312
	int res = 0;
311
	int res = 0;
313
	int len = strlen(part);
312
	int len = strlen(part);
314

    
   
313

   
315
	ast_channel_lock(c);
314
	ast_channel_lock(c);
316
	if (len <= strlen(c->name)) {
315
	if (len <= strlen(c->name)) {
317
		res = !(strncmp(c->name, part, len)) && (can_pickup(c));
316
		res = !(strncmp(c->name, part, len)) && (can_pickup(c));
318
	}
317
	}
319
	ast_channel_unlock(c);
318
	ast_channel_unlock(c);
320

    
   
319

   
321
	return res ? CMP_MATCH | CMP_STOP : 0;
320
	return res ? CMP_MATCH | CMP_STOP : 0;
322
}
321
}
323

    
   
322

   
324
/* Attempt to pick up specified by partial channel name */ 
323
/* Attempt to pick up specified by partial channel name */ 
325
static int pickup_by_part(struct ast_channel *chan, const char *part)
324
static int pickup_by_part(struct ast_channel *chan, const char *part)
326
{
325
{
327
	struct ast_channel *target;
326
	struct ast_channel *target;
328
	int res = -1;
327
	int res = -1;
329

    
   
328

   
330
	if ((target = ast_channel_callback(find_by_part, NULL, (char *) part, 0))) {
329
	if ((target = ast_channel_callback(find_by_part, NULL, (char *) part, 0))) {
331
		ast_channel_lock(target);
330
		ast_channel_lock(target);
332
		res = pickup_do(chan, target);
331
		if (!target->masq && can_pickup(target)) {

    
   
332
			res = ast_do_pickup(chan, target);

    
   
333
		} else {

    
   
334
			ast_log(LOG_WARNING, "target has gone, or not ringing anymore for %s\n", chan->name);
333
		ast_channel_unlock(target);
335
			ast_channel_unlock(target);
334
		target = ast_channel_unref(target);
336
			target = ast_channel_unref(target);
335
	}
337
		}

    
   
338
	}
336

    
   
339

   
337
	return res;
340
	return res;
338
}
341
}
339

    
   
342

   
340
/* application entry point for PickupChan() */
343
/* application entry point for PickupChan() */
341
static int pickupchan_exec(struct ast_channel *chan, const char *data)
344
static int pickupchan_exec(struct ast_channel *chan, const char *data)
342
{
345
{
343
	int res = 0;
346
	int res = 0;
344
	int partial_pickup = 0;
347
	int partial_pickup = 0;
345
	char *pickup = NULL;
348
	char *pickup = NULL;
346
	char *parse = ast_strdupa(data);
349
	char *parse = ast_strdupa(data);
347
	AST_DECLARE_APP_ARGS(args,
350
	AST_DECLARE_APP_ARGS(args,
348
		AST_APP_ARG(channel);
351
		AST_APP_ARG(channel);
349
		AST_APP_ARG(options);
352
		AST_APP_ARG(options);
350
	);
353
	);
351
	AST_STANDARD_APP_ARGS(args, parse);
354
	AST_STANDARD_APP_ARGS(args, parse);
352

    
   
355

   
353
	if (ast_strlen_zero(args.channel)) {
356
	if (ast_strlen_zero(args.channel)) {
354
		ast_log(LOG_WARNING, "PickupChan requires an argument (channel)!\n");
357
		ast_log(LOG_WARNING, "PickupChan requires an argument (channel)!\n");
355
		return -1;
358
		return -1;
356
	}
359
	}
357

    
   
360

   
358
	if (!ast_strlen_zero(args.options) && strchr(args.options, 'p')) {
361
	if (!ast_strlen_zero(args.options) && strchr(args.options, 'p')) {
359
		partial_pickup = 1;
362
		partial_pickup = 1;
360
	}
363
	}
361

    
   
364

   
362
	/* Parse channel */
365
	/* Parse channel */
363
	while (!ast_strlen_zero(args.channel) && (pickup = strsep(&args.channel, "&"))) {
366
	while (!ast_strlen_zero(args.channel) && (pickup = strsep(&args.channel, "&"))) {
364
		if (!strncasecmp(chan->name, pickup, strlen(pickup))) {
367
		if (!strncasecmp(chan->name, pickup, strlen(pickup))) {
365
			ast_log(LOG_NOTICE, "Cannot pickup your own channel %s.\n", pickup);
368
			ast_log(LOG_NOTICE, "Cannot pickup your own channel %s.\n", pickup);
366
		} else {
369
		} else {
367
			if (partial_pickup) {
370
			if (partial_pickup) {
368
				if (!pickup_by_part(chan, pickup)) {
371
				if (!pickup_by_part(chan, pickup)) {
369
					break;
372
					break;
370
				}
373
				}
371
			} else if (!pickup_by_channel(chan, pickup)) {
374
			} else if (!pickup_by_channel(chan, pickup)) {
372
				break;
375
				break;
373
			}
376
			}
374
			ast_log(LOG_NOTICE, "No target channel found for %s.\n", pickup);
377
			ast_log(LOG_NOTICE, "No target channel found for %s.\n", pickup);
375
		}
378
		}
376
	}
379
	}
377

    
   
380

   
378
	return res;
381
	return res;
379
}
382
}
380

    
   
383

   
381
static int unload_module(void)
384
static int unload_module(void)
382
{
385
{
383
	int res;
386
	int res;
384

    
   
387

   
385
	res = ast_unregister_application(app);
388
	res = ast_unregister_application(app);
386
	res |= ast_unregister_application(app2);
389
	res |= ast_unregister_application(app2);
387

    
   
390

   
388
	return res;
391
	return res;
389
}
392
}
390

    
   
393

   
391
static int load_module(void)
394
static int load_module(void)
392
{
395
{
393
	int res;
396
	int res;
394

    
   
397

   
395
	res = ast_register_application_xml(app, pickup_exec);
398
	res = ast_register_application_xml(app, pickup_exec);
396
	res |= ast_register_application_xml(app2, pickupchan_exec);
399
	res |= ast_register_application_xml(app2, pickupchan_exec);
397

    
   
400

   
398
	return res;
401
	return res;
399
}
402
}
400

    
   
403

   
401
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Directed Call Pickup Application");
404
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Directed Call Pickup Application");
trunk/channels/chan_sip.c
Diff Revision 4 Diff Revision 6
 
trunk/include/asterisk/features.h
Diff Revision 4 Diff Revision 6
 
trunk/main/features.c
Diff Revision 4 Diff Revision 6
 
trunk/res/res_features.exports.in
Diff Revision 4 Diff Revision 6
 
  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.