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

Diff revision 1

This is not the most recent revision of the diff. The latest diff is revision 16. See what's changed.

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/include/asterisk/features.h: Loading...
  3. trunk/main/features.c: Loading...
  4. trunk/res/res_features.exports.in: Loading...
trunk/apps/app_directed_pickup.c
Revision 313856 New Change
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 */
100
/* Perform actual pickup between two channels */
101
static int pickup_do(struct ast_channel *chan, struct ast_channel *target)
101
static int pickup_do(struct ast_channel *chan, struct ast_channel *target)
102
{
102
{
103
	int res = 0;
103
	return ast_do_pickup(chan, target);
104
	struct ast_party_connected_line connected_caller;

   
105
	struct ast_channel *chans[2] = { chan, target };

   
106

    
   

   
107
	ast_debug(1, "Call pickup on '%s' by '%s'\n", target->name, chan->name);

   
108
	ast_cel_report_event(target, AST_CEL_PICKUP, NULL, NULL, chan);

   
109

    
   

   
110
	ast_party_connected_line_init(&connected_caller);

   
111
	ast_party_connected_line_copy(&connected_caller, &target->connected);

   
112
	connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;

   
113
	if (ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) {

   
114
		ast_channel_update_connected_line(chan, &connected_caller, NULL);

   
115
	}

   
116
	ast_party_connected_line_free(&connected_caller);

   
117

    
   

   
118
	ast_channel_lock(chan);

   
119
	ast_connected_line_copy_from_caller(&connected_caller, &chan->caller);

   
120
	ast_channel_unlock(chan);

   
121
	connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;

   
122
	ast_channel_queue_connected_line_update(chan, &connected_caller, NULL);

   
123
	ast_party_connected_line_free(&connected_caller);

   
124

    
   

   
125
	if ((res = ast_answer(chan))) {

   
126
		ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);

   
127
		return -1;

   
128
	}

   
129

    
   

   
130
	if ((res = ast_queue_control(chan, AST_CONTROL_ANSWER))) {

   
131
		ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);

   
132
		return -1;

   
133
	}

   
134

    
   

   
135
	if ((res = ast_channel_masquerade(target, chan))) {

   
136
		ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, target->name);

   
137
		return -1;

   
138
	}

   
139

    
   

   
140
	/* If you want UniqueIDs, set channelvars in manager.conf to CHANNEL(uniqueid) */

   
141
	ast_manager_event_multichan(EVENT_FLAG_CALL, "Pickup", 2, chans,

   
142
		"Channel: %s\r\nTargetChannel: %s\r\n", chan->name, target->name);

   
143

    
   

   
144
	return res;

   
145
}
104
}
146

    
   
105

   
147
/* Helper function that determines whether a channel is capable of being picked up */
106
/* Helper function that determines whether a channel is capable of being picked up */
148
static int can_pickup(struct ast_channel *chan)
107
static int can_pickup(struct ast_channel *chan)
149
{
108
{
150
	if (!chan->pbx && (chan->_state == AST_STATE_RINGING || chan->_state == AST_STATE_RING || chan->_state == AST_STATE_DOWN))
109
	if (!chan->pbx && (chan->_state == AST_STATE_RINGING || chan->_state == AST_STATE_RING || chan->_state == AST_STATE_DOWN))
151
		return 1;
110
		return 1;
152
	else
111
	else
153
		return 0;
112
		return 0;
154
}
113
}
155

    
   
114

   
156
struct pickup_by_name_args {
115
struct pickup_by_name_args {
157
	const char *name;
116
	const char *name;
158
	size_t len;
117
	size_t len;
159
};
118
};
160

    
   
119

   
161
static int pickup_by_name_cb(void *obj, void *arg, void *data, int flags)
120
static int pickup_by_name_cb(void *obj, void *arg, void *data, int flags)
162
{
121
{
163
	struct ast_channel *chan = obj;
122
	struct ast_channel *chan = obj;
164
	struct pickup_by_name_args *args = data;
123
	struct pickup_by_name_args *args = data;
165

    
   
124

   
166
	ast_channel_lock(chan);
125
	ast_channel_lock(chan);
167
	if (!strncasecmp(chan->name, args->name, args->len) && can_pickup(chan)) {
126
	if (!strncasecmp(chan->name, args->name, args->len) && can_pickup(chan)) {
168
		/* Return with the channel still locked on purpose */
127
		/* Return with the channel still locked on purpose */
169
		return CMP_MATCH | CMP_STOP;
128
		return CMP_MATCH | CMP_STOP;
170
	}
129
	}
171
	ast_channel_unlock(chan);
130
	ast_channel_unlock(chan);
172

    
   
131

   
173
	return 0;
132
	return 0;
174
}
133
}
175

    
   
134

   
176
/*! \brief Helper Function to walk through ALL channels checking NAME and STATE */
135
/*! \brief Helper Function to walk through ALL channels checking NAME and STATE */
177
static struct ast_channel *my_ast_get_channel_by_name_locked(const char *channame)
136
static struct ast_channel *my_ast_get_channel_by_name_locked(const char *channame)
178
{
137
{
179
	char *chkchan;
138
	char *chkchan;
180
	struct pickup_by_name_args pickup_args;
139
	struct pickup_by_name_args pickup_args;
181

    
   
140

   
182
	/* Check if channel name contains a '-'.
141
	/* Check if channel name contains a '-'.
183
	 * In this case the channel name will be interpreted as full channel name.
142
	 * In this case the channel name will be interpreted as full channel name.
184
	 */
143
	 */
185
	if (strchr(channame, '-')) {
144
	if (strchr(channame, '-')) {
186
		/* check full channel name */
145
		/* check full channel name */
187
		pickup_args.len = strlen(channame);
146
		pickup_args.len = strlen(channame);
188
		pickup_args.name = channame;
147
		pickup_args.name = channame;
189
	} else {
148
	} else {
190
		/* need to append a '-' for the comparison so we check full channel name,
149
		/* need to append a '-' for the comparison so we check full channel name,
191
		 * i.e SIP/hgc- , use a temporary variable so original stays the same for
150
		 * i.e SIP/hgc- , use a temporary variable so original stays the same for
192
		 * debugging.
151
		 * debugging.
193
		 */
152
		 */
194
		pickup_args.len = strlen(channame) + 1;
153
		pickup_args.len = strlen(channame) + 1;
195
		chkchan = alloca(pickup_args.len + 1);
154
		chkchan = alloca(pickup_args.len + 1);
196
		strcpy(chkchan, channame);
155
		strcpy(chkchan, channame);
197
		strcat(chkchan, "-");
156
		strcat(chkchan, "-");
198
		pickup_args.name = chkchan;
157
		pickup_args.name = chkchan;
199
	}
158
	}
200

    
   
159

   
201
	return ast_channel_callback(pickup_by_name_cb, NULL, &pickup_args, 0);
160
	return ast_channel_callback(pickup_by_name_cb, NULL, &pickup_args, 0);
202
}
161
}
203

    
   
162

   
204
/*! \brief Attempt to pick up specified channel named , does not use context */
163
/*! \brief Attempt to pick up specified channel named , does not use context */
205
static int pickup_by_channel(struct ast_channel *chan, char *pickup)
164
static int pickup_by_channel(struct ast_channel *chan, char *pickup)
206
{
165
{
207
	int res = 0;
166
	int res = 0;
208
	struct ast_channel *target;
167
	struct ast_channel *target;
209

    
   
168

   
210
	if (!(target = my_ast_get_channel_by_name_locked(pickup))) {
169
	if (!(target = my_ast_get_channel_by_name_locked(pickup))) {
211
		return -1;
170
		return -1;
212
	}
171
	}
213

    
   
172

   
214
	/* Just check that we are not picking up the SAME as target */
173
	/* Just check that we are not picking up the SAME as target */
215
	if (chan != target) {
174
	if (chan != target) {
216
		res = pickup_do(chan, target);
175
		res = pickup_do(chan, target);
217
	}
176
	}
218

    
   
177

   
219
	ast_channel_unlock(target);
178
	ast_channel_unlock(target);
220
	target = ast_channel_unref(target);
179
	target = ast_channel_unref(target);
221

    
   
180

   
222
	return res;
181
	return res;
223
}
182
}
224

    
   
183

   
225
/* Attempt to pick up specified extension with context */
184
/* Attempt to pick up specified extension with context */
226
static int pickup_by_exten(struct ast_channel *chan, const char *exten, const char *context)
185
static int pickup_by_exten(struct ast_channel *chan, const char *exten, const char *context)
227
{
186
{
228
	struct ast_channel *target = NULL;
187
	struct ast_channel *target = NULL;
229
	struct ast_channel_iterator *iter;
188
	struct ast_channel_iterator *iter;
230
	int res = -1;
189
	int res = -1;
231

    
   
190

   
232
	if (!(iter = ast_channel_iterator_by_exten_new(exten, context))) {
191
	if (!(iter = ast_channel_iterator_by_exten_new(exten, context))) {
233
		return -1;
192
		return -1;
234
	}
193
	}
235

    
   
194

   
236
	while ((target = ast_channel_iterator_next(iter))) {
195
	while ((target = ast_channel_iterator_next(iter))) {
237
		ast_channel_lock(target);
196
		ast_channel_lock(target);
238
		if ((chan != target) && can_pickup(target)) {
197
		if ((chan != target) && can_pickup(target)) {
239
			break;
198
			break;
240
		}
199
		}
241
		ast_channel_unlock(target);
200
		ast_channel_unlock(target);
242
		target = ast_channel_unref(target);
201
		target = ast_channel_unref(target);
243
	}
202
	}
244

    
   
203

   
245
	ast_channel_iterator_destroy(iter);
204
	ast_channel_iterator_destroy(iter);
246

    
   
205

   
247
	if (target) {
206
	if (target) {
248
		res = pickup_do(chan, target);
207
		res = pickup_do(chan, target);
249
		ast_channel_unlock(target);
208
		ast_channel_unlock(target);
250
		target = ast_channel_unref(target);
209
		target = ast_channel_unref(target);
251
	}
210
	}
252

    
   
211

   
253
	return res;
212
	return res;
254
}
213
}
255

    
   
214

   
256
static int find_by_mark(void *obj, void *arg, void *data, int flags)
215
static int find_by_mark(void *obj, void *arg, void *data, int flags)
257
{
216
{
258
	struct ast_channel *c = obj;
217
	struct ast_channel *c = obj;
259
	const char *mark = data;
218
	const char *mark = data;
260
	const char *tmp;
219
	const char *tmp;
261
	int res;
220
	int res;
262

    
   
221

   
263
	ast_channel_lock(c);
222
	ast_channel_lock(c);
264

    
   
223

   
265
	res = (tmp = pbx_builtin_getvar_helper(c, PICKUPMARK)) &&
224
	res = (tmp = pbx_builtin_getvar_helper(c, PICKUPMARK)) &&
266
		!strcasecmp(tmp, mark) &&
225
		!strcasecmp(tmp, mark) &&
267
		can_pickup(c);
226
		can_pickup(c);
268

    
   
227

   
269
	ast_channel_unlock(c);
228
	ast_channel_unlock(c);
270

    
   
229

   
271
	return res ? CMP_MATCH | CMP_STOP : 0;
230
	return res ? CMP_MATCH | CMP_STOP : 0;
272
}
231
}
273

    
   
232

   
274
/* Attempt to pick up specified mark */
233
/* Attempt to pick up specified mark */
275
static int pickup_by_mark(struct ast_channel *chan, const char *mark)
234
static int pickup_by_mark(struct ast_channel *chan, const char *mark)
276
{
235
{
277
	struct ast_channel *target;
236
	struct ast_channel *target;
278
	int res = -1;
237
	int res = -1;
279

    
   
238

   
280
	if ((target = ast_channel_callback(find_by_mark, NULL, (char *) mark, 0))) {
239
	if ((target = ast_channel_callback(find_by_mark, NULL, (char *) mark, 0))) {
281
		ast_channel_lock(target);
240
		ast_channel_lock(target);
282
		res = pickup_do(chan, target);
241
		res = pickup_do(chan, target);
283
		ast_channel_unlock(target);
242
		ast_channel_unlock(target);
284
		target = ast_channel_unref(target);
243
		target = ast_channel_unref(target);
285
	}
244
	}
286

    
   
245

   
287
	return res;
246
	return res;
288
}
247
}
289

    
   
248

   
290
/* application entry point for Pickup() */
249
/* application entry point for Pickup() */
291
static int pickup_exec(struct ast_channel *chan, const char *data)
250
static int pickup_exec(struct ast_channel *chan, const char *data)
292
{
251
{
293
	int res = 0;
252
	int res = 0;
294
	char *tmp = ast_strdupa(data);
253
	char *tmp = ast_strdupa(data);
295
	char *exten = NULL, *context = NULL;
254
	char *exten = NULL, *context = NULL;
296

    
   
255

   
297
	if (ast_strlen_zero(data)) {
256
	if (ast_strlen_zero(data)) {
298
		res = ast_pickup_call(chan);
257
		res = ast_pickup_call(chan);
299
		return res;
258
		return res;
300
	}
259
	}
301
	
260
	
302
	/* Parse extension (and context if there) */
261
	/* Parse extension (and context if there) */
303
	while (!ast_strlen_zero(tmp) && (exten = strsep(&tmp, "&"))) {
262
	while (!ast_strlen_zero(tmp) && (exten = strsep(&tmp, "&"))) {
304
		if ((context = strchr(exten, '@')))
263
		if ((context = strchr(exten, '@')))
305
			*context++ = '\0';
264
			*context++ = '\0';
306
		if (!ast_strlen_zero(context) && !strcasecmp(context, PICKUPMARK)) {
265
		if (!ast_strlen_zero(context) && !strcasecmp(context, PICKUPMARK)) {
307
			if (!pickup_by_mark(chan, exten))
266
			if (!pickup_by_mark(chan, exten))
308
				break;
267
				break;
309
		} else {
268
		} else {
310
			if (!pickup_by_exten(chan, exten, !ast_strlen_zero(context) ? context : chan->context))
269
			if (!pickup_by_exten(chan, exten, !ast_strlen_zero(context) ? context : chan->context))
311
				break;
270
				break;
312
		}
271
		}
313
		ast_log(LOG_NOTICE, "No target channel found for %s.\n", exten);
272
		ast_log(LOG_NOTICE, "No target channel found for %s.\n", exten);
314
	}
273
	}
315

    
   
274

   
316
	return res;
275
	return res;
317
}
276
}
318

    
   
277

   
319
/* Find channel for pick up specified by partial channel name */ 
278
/* Find channel for pick up specified by partial channel name */ 
320
static int find_by_part(void *obj, void *arg, void *data, int flags)
279
static int find_by_part(void *obj, void *arg, void *data, int flags)
321
{
280
{
322
	struct ast_channel *c = obj; 
281
	struct ast_channel *c = obj; 
323
	const char *part = data;
282
	const char *part = data;
324
	int res = 0;
283
	int res = 0;
325
	int len = strlen(part);
284
	int len = strlen(part);
326

    
   
285

   
327
	ast_channel_lock(c);
286
	ast_channel_lock(c);
328
	if (len <= strlen(c->name)) {
287
	if (len <= strlen(c->name)) {
329
		res = !(strncmp(c->name, part, len)) && (can_pickup(c));
288
		res = !(strncmp(c->name, part, len)) && (can_pickup(c));
330
	}
289
	}
331
	ast_channel_unlock(c);
290
	ast_channel_unlock(c);
332

    
   
291

   
333
	return res ? CMP_MATCH | CMP_STOP : 0;
292
	return res ? CMP_MATCH | CMP_STOP : 0;
334
}
293
}
335

    
   
294

   
336
/* Attempt to pick up specified by partial channel name */ 
295
/* Attempt to pick up specified by partial channel name */ 
337
static int pickup_by_part(struct ast_channel *chan, const char *part)
296
static int pickup_by_part(struct ast_channel *chan, const char *part)
338
{
297
{
339
	struct ast_channel *target;
298
	struct ast_channel *target;
340
	int res = -1;
299
	int res = -1;
341

    
   
300

   
342
	if ((target = ast_channel_callback(find_by_part, NULL, (char *) part, 0))) {
301
	if ((target = ast_channel_callback(find_by_part, NULL, (char *) part, 0))) {
343
		ast_channel_lock(target);
302
		ast_channel_lock(target);
344
		res = pickup_do(chan, target);
303
		res = pickup_do(chan, target);
345
		ast_channel_unlock(target);
304
		ast_channel_unlock(target);
346
		target = ast_channel_unref(target);
305
		target = ast_channel_unref(target);
347
	}
306
	}
348

    
   
307

   
349
	return res;
308
	return res;
350
}
309
}
351

    
   
310

   
352
/* application entry point for PickupChan() */
311
/* application entry point for PickupChan() */
353
static int pickupchan_exec(struct ast_channel *chan, const char *data)
312
static int pickupchan_exec(struct ast_channel *chan, const char *data)
354
{
313
{
355
	int res = 0;
314
	int res = 0;
356
	int partial_pickup = 0;
315
	int partial_pickup = 0;
357
	char *pickup = NULL;
316
	char *pickup = NULL;
358
	char *parse = ast_strdupa(data);
317
	char *parse = ast_strdupa(data);
359
	AST_DECLARE_APP_ARGS(args,
318
	AST_DECLARE_APP_ARGS(args,
360
		AST_APP_ARG(channel);
319
		AST_APP_ARG(channel);
361
		AST_APP_ARG(options);
320
		AST_APP_ARG(options);
362
	);
321
	);
363
	AST_STANDARD_APP_ARGS(args, parse);
322
	AST_STANDARD_APP_ARGS(args, parse);
364

    
   
323

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

    
   
328

   
370
	if (!ast_strlen_zero(args.options) && strchr(args.options, 'p')) {
329
	if (!ast_strlen_zero(args.options) && strchr(args.options, 'p')) {
371
		partial_pickup = 1;
330
		partial_pickup = 1;
372
	}
331
	}
373

    
   
332

   
374
	/* Parse channel */
333
	/* Parse channel */
375
	while (!ast_strlen_zero(args.channel) && (pickup = strsep(&args.channel, "&"))) {
334
	while (!ast_strlen_zero(args.channel) && (pickup = strsep(&args.channel, "&"))) {
376
		if (!strncasecmp(chan->name, pickup, strlen(pickup))) {
335
		if (!strncasecmp(chan->name, pickup, strlen(pickup))) {
377
			ast_log(LOG_NOTICE, "Cannot pickup your own channel %s.\n", pickup);
336
			ast_log(LOG_NOTICE, "Cannot pickup your own channel %s.\n", pickup);
378
		} else {
337
		} else {
379
			if (partial_pickup) {
338
			if (partial_pickup) {
380
				if (!pickup_by_part(chan, pickup)) {
339
				if (!pickup_by_part(chan, pickup)) {
381
					break;
340
					break;
382
				}
341
				}
383
			} else if (!pickup_by_channel(chan, pickup)) {
342
			} else if (!pickup_by_channel(chan, pickup)) {
384
				break;
343
				break;
385
			}
344
			}
386
			ast_log(LOG_NOTICE, "No target channel found for %s.\n", pickup);
345
			ast_log(LOG_NOTICE, "No target channel found for %s.\n", pickup);
387
		}
346
		}
388
	}
347
	}
389

    
   
348

   
390
	return res;
349
	return res;
391
}
350
}
392

    
   
351

   
393
static int unload_module(void)
352
static int unload_module(void)
394
{
353
{
395
	int res;
354
	int res;
396

    
   
355

   
397
	res = ast_unregister_application(app);
356
	res = ast_unregister_application(app);
398
	res |= ast_unregister_application(app2);
357
	res |= ast_unregister_application(app2);
399

    
   
358

   
400
	return res;
359
	return res;
401
}
360
}
402

    
   
361

   
403
static int load_module(void)
362
static int load_module(void)
404
{
363
{
405
	int res;
364
	int res;
406

    
   
365

   
407
	res = ast_register_application_xml(app, pickup_exec);
366
	res = ast_register_application_xml(app, pickup_exec);
408
	res |= ast_register_application_xml(app2, pickupchan_exec);
367
	res |= ast_register_application_xml(app2, pickupchan_exec);
409

    
   
368

   
410
	return res;
369
	return res;
411
}
370
}
412

    
   
371

   
413
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Directed Call Pickup Application");
372
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Directed Call Pickup Application");
trunk/include/asterisk/features.h
Revision 313856 New Change
 
trunk/main/features.c
Revision 313856 New Change
 
trunk/res/res_features.exports.in
Revision 313856 New Change
 
  1. trunk/apps/app_directed_pickup.c: Loading...
  2. trunk/include/asterisk/features.h: Loading...
  3. trunk/main/features.c: Loading...
  4. 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.