2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2006, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
21 * \brief Routines implementing call features as call pickup, parking and transfer
23 * \author Mark Spencer <markster@digium.com>
28 ASTERISK_FILE_VERSION(__FILE__
, "$Revision$")
38 #include <sys/signal.h>
39 #include <netinet/in.h>
41 #include "asterisk/lock.h"
42 #include "asterisk/file.h"
43 #include "asterisk/logger.h"
44 #include "asterisk/channel.h"
45 #include "asterisk/pbx.h"
46 #include "asterisk/options.h"
47 #include "asterisk/causes.h"
48 #include "asterisk/module.h"
49 #include "asterisk/translate.h"
50 #include "asterisk/app.h"
51 #include "asterisk/say.h"
52 #include "asterisk/features.h"
53 #include "asterisk/musiconhold.h"
54 #include "asterisk/config.h"
55 #include "asterisk/cli.h"
56 #include "asterisk/manager.h"
57 #include "asterisk/utils.h"
58 #include "asterisk/adsi.h"
59 #include "asterisk/devicestate.h"
60 #include "asterisk/monitor.h"
62 #define DEFAULT_PARK_TIME 45000
63 #define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000
64 #define DEFAULT_FEATURE_DIGIT_TIMEOUT 500
65 #define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000
67 #define AST_MAX_WATCHERS 256
70 AST_FEATURE_FLAG_NEEDSDTMF
= (1 << 0),
71 AST_FEATURE_FLAG_ONPEER
= (1 << 1),
72 AST_FEATURE_FLAG_ONSELF
= (1 << 2),
73 AST_FEATURE_FLAG_BYCALLEE
= (1 << 3),
74 AST_FEATURE_FLAG_BYCALLER
= (1 << 4),
75 AST_FEATURE_FLAG_BYBOTH
= (3 << 3),
78 static char *parkedcall
= "ParkedCall";
80 static int parkaddhints
= 0; /*!< Add parking hints automatically */
81 static int parkingtime
= DEFAULT_PARK_TIME
; /*!< No more than 45 seconds parked before you do something with them */
82 static char parking_con
[AST_MAX_EXTENSION
]; /*!< Context for which parking is made accessible */
83 static char parking_con_dial
[AST_MAX_EXTENSION
]; /*!< Context for dialback for parking (KLUDGE) */
84 static char parking_ext
[AST_MAX_EXTENSION
]; /*!< Extension you type to park the call */
85 static char pickup_ext
[AST_MAX_EXTENSION
]; /*!< Call pickup extension */
86 static char parkmohclass
[MAX_MUSICCLASS
]; /*!< Music class used for parking */
87 static int parking_start
; /*!< First available extension for parking */
88 static int parking_stop
; /*!< Last available extension for parking */
90 static char courtesytone
[256]; /*!< Courtesy tone */
91 static int parkedplay
= 0; /*!< Who to play the courtesy tone to */
92 static char xfersound
[256]; /*!< Call transfer sound */
93 static char xferfailsound
[256]; /*!< Call transfer failure sound */
95 static int parking_offset
;
96 static int parkfindnext
;
100 static int transferdigittimeout
;
101 static int featuredigittimeout
;
103 static int atxfernoanswertimeout
;
105 static char *registrar
= "res_features"; /*!< Registrar for operations */
107 /* module and CLI command definitions */
108 static char *synopsis
= "Answer a parked call";
110 static char *descrip
= "ParkedCall(exten):"
111 "Used to connect to a parked call. This application is always\n"
112 "registered internally and does not need to be explicitly added\n"
113 "into the dialplan, although you should include the 'parkedcalls'\n"
116 static char *parkcall
= "Park";
118 static char *synopsis2
= "Park yourself";
120 static char *descrip2
= "Park():"
121 "Used to park yourself (typically in combination with a supervised\n"
122 "transfer to know the parking space). This application is always\n"
123 "registered internally and does not need to be explicitly added\n"
124 "into the dialplan, although you should include the 'parkedcalls'\n"
125 "context (or the context specified in features.conf).\n\n"
126 "If you set the PARKINGEXTEN variable to an extension in your\n"
127 "parking context, park() will park the call on that extension, unless\n"
128 "it already exists. In that case, execution will continue at next\n"
131 static struct ast_app
*monitor_app
= NULL
;
132 static int monitor_ok
= 1;
135 struct ast_channel
*chan
; /*!< Parking channel */
136 struct timeval start
; /*!< Time the parking started */
137 int parkingnum
; /*!< Parking lot */
138 char parkingexten
[AST_MAX_EXTENSION
]; /*!< If set beforehand, parking extension used for this call */
139 char context
[AST_MAX_CONTEXT
]; /*!< Where to go if our parking time expires */
140 char exten
[AST_MAX_EXTENSION
];
142 int parkingtime
; /*!< Maximum length in parking lot before return */
145 unsigned char moh_trys
;
146 struct parkeduser
*next
;
149 static struct parkeduser
*parkinglot
;
151 AST_MUTEX_DEFINE_STATIC(parking_lock
); /*!< protects all static variables above */
153 static pthread_t parking_thread
;
155 char *ast_parking_ext(void)
160 char *ast_pickup_ext(void)
165 struct ast_bridge_thread_obj
167 struct ast_bridge_config bconfig
;
168 struct ast_channel
*chan
;
169 struct ast_channel
*peer
;
174 /*! \brief store context, priority and extension */
175 static void set_c_e_p(struct ast_channel
*chan
, const char *context
, const char *ext
, int pri
)
177 ast_copy_string(chan
->context
, context
, sizeof(chan
->context
));
178 ast_copy_string(chan
->exten
, ext
, sizeof(chan
->exten
));
179 chan
->priority
= pri
;
182 static void check_goto_on_transfer(struct ast_channel
*chan
)
184 struct ast_channel
*xferchan
;
185 const char *val
= pbx_builtin_getvar_helper(chan
, "GOTO_ON_BLINDXFR");
186 char *x
, *goto_on_transfer
;
189 if (ast_strlen_zero(val
))
192 goto_on_transfer
= ast_strdupa(val
);
194 if (!(xferchan
= ast_channel_alloc(0, AST_STATE_DOWN
, 0, 0, "", "", "", 0, chan
->name
)))
197 for (x
= goto_on_transfer
; x
&& *x
; x
++) {
201 /* Make formats okay */
202 xferchan
->readformat
= chan
->readformat
;
203 xferchan
->writeformat
= chan
->writeformat
;
204 ast_channel_masquerade(xferchan
, chan
);
205 ast_parseable_goto(xferchan
, goto_on_transfer
);
206 xferchan
->_state
= AST_STATE_UP
;
207 ast_clear_flag(xferchan
, AST_FLAGS_ALL
);
208 xferchan
->_softhangup
= 0;
209 if ((f
= ast_read(xferchan
))) {
212 ast_pbx_start(xferchan
);
214 ast_hangup(xferchan
);
218 static struct ast_channel
*ast_feature_request_and_dial(struct ast_channel
*caller
, const char *type
, int format
, void *data
, int timeout
, int *outstate
, const char *cid_num
, const char *cid_name
);
221 static void *ast_bridge_call_thread(void *data
)
223 struct ast_bridge_thread_obj
*tobj
= data
;
225 tobj
->chan
->appl
= "Transferred Call";
226 tobj
->chan
->data
= tobj
->peer
->name
;
227 tobj
->peer
->appl
= "Transferred Call";
228 tobj
->peer
->data
= tobj
->chan
->name
;
229 if (tobj
->chan
->cdr
) {
230 ast_cdr_reset(tobj
->chan
->cdr
, NULL
);
231 ast_cdr_setdestchan(tobj
->chan
->cdr
, tobj
->peer
->name
);
233 if (tobj
->peer
->cdr
) {
234 ast_cdr_reset(tobj
->peer
->cdr
, NULL
);
235 ast_cdr_setdestchan(tobj
->peer
->cdr
, tobj
->chan
->name
);
238 ast_bridge_call(tobj
->peer
, tobj
->chan
, &tobj
->bconfig
);
239 ast_hangup(tobj
->chan
);
240 ast_hangup(tobj
->peer
);
241 bzero(tobj
, sizeof(*tobj
)); /*! \todo XXX for safety */
246 static void ast_bridge_call_thread_launch(void *data
)
250 struct sched_param sched
;
252 pthread_attr_init(&attr
);
253 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
254 ast_pthread_create(&thread
, &attr
,ast_bridge_call_thread
, data
);
255 pthread_attr_destroy(&attr
);
256 memset(&sched
, 0, sizeof(sched
));
257 pthread_setschedparam(thread
, SCHED_RR
, &sched
);
260 static int adsi_announce_park(struct ast_channel
*chan
, char *parkingexten
)
263 int justify
[5] = {ADSI_JUST_CENT
, ADSI_JUST_CENT
, ADSI_JUST_CENT
, ADSI_JUST_CENT
};
265 char *message
[5] = {NULL
, NULL
, NULL
, NULL
, NULL
};
267 snprintf(tmp
, sizeof(tmp
), "Parked on %s", parkingexten
);
269 res
= ast_adsi_load_session(chan
, NULL
, 0, 1);
272 return ast_adsi_print(chan
, message
, justify
, 1);
275 /*! \brief Notify metermaids that we've changed an extension */
276 static void notify_metermaids(char *exten
, char *context
)
278 if (option_debug
> 3)
279 ast_log(LOG_DEBUG
, "Notification of state change to metermaids %s@%s\n", exten
, context
);
281 /* Send notification to devicestate subsystem */
282 ast_device_state_changed("park:%s@%s", exten
, context
);
286 /*! \brief metermaids callback from devicestate.c */
287 static int metermaidstate(const char *data
)
289 int res
= AST_DEVICE_INVALID
;
290 char *context
= ast_strdupa(data
);
293 exten
= strsep(&context
, "@");
297 if (option_debug
> 3)
298 ast_log(LOG_DEBUG
, "Checking state of exten %s in context %s\n", exten
, context
);
300 res
= ast_exists_extension(NULL
, context
, exten
, 1, NULL
);
303 return AST_DEVICE_NOT_INUSE
;
305 return AST_DEVICE_INUSE
;
308 /*! \brief Park a call
309 \note We put the user in the parking list, then wake up the parking thread to be sure it looks
310 after these channels too */
311 int ast_park_call(struct ast_channel
*chan
, struct ast_channel
*peer
, int timeout
, int *extout
)
313 struct parkeduser
*pu
, *cur
;
314 int i
, x
= -1, parking_range
;
315 struct ast_context
*con
;
316 const char *parkingexten
;
318 /* Allocate memory for parking data */
319 if (!(pu
= ast_calloc(1, sizeof(*pu
))))
322 /* Lock parking lot */
323 ast_mutex_lock(&parking_lock
);
324 /* Check for channel variable PARKINGEXTEN */
325 parkingexten
= pbx_builtin_getvar_helper(chan
, "PARKINGEXTEN");
326 if (!ast_strlen_zero(parkingexten
)) {
327 if (ast_exists_extension(NULL
, parking_con
, parkingexten
, 1, NULL
)) {
328 ast_mutex_unlock(&parking_lock
);
330 ast_log(LOG_WARNING
, "Requested parking extension already exists: %s@%s\n", parkingexten
, parking_con
);
331 return -1; /* We failed to park this call, plain and simple so we need to error out */
333 ast_copy_string(pu
->parkingexten
, parkingexten
, sizeof(pu
->parkingexten
));
334 x
= atoi(parkingexten
);
336 /* Select parking space within range */
337 parking_range
= parking_stop
- parking_start
+1;
338 for (i
= 0; i
< parking_range
; i
++) {
339 x
= (i
+ parking_offset
) % parking_range
+ parking_start
;
342 if (cur
->parkingnum
== x
)
350 if (!(i
< parking_range
)) {
351 ast_log(LOG_WARNING
, "No more parking spaces\n");
353 ast_mutex_unlock(&parking_lock
);
356 /* Set pointer for next parking */
358 parking_offset
= x
- parking_start
+ 1;
361 chan
->appl
= "Parked Call";
366 /* Put the parked channel on hold if we have two different channels */
368 ast_indicate_data(pu
->chan
, AST_CONTROL_HOLD
,
369 S_OR(parkmohclass
, NULL
),
370 !ast_strlen_zero(parkmohclass
) ? strlen(parkmohclass
) + 1 : 0);
373 pu
->start
= ast_tvnow();
375 pu
->parkingtime
= (timeout
> 0) ? timeout
: parkingtime
;
380 ast_copy_string(pu
->peername
, peer
->name
, sizeof(pu
->peername
));
382 /* Remember what had been dialed, so that if the parking
383 expires, we try to come back to the same place */
384 ast_copy_string(pu
->context
, S_OR(chan
->macrocontext
, chan
->context
), sizeof(pu
->context
));
385 ast_copy_string(pu
->exten
, S_OR(chan
->macroexten
, chan
->exten
), sizeof(pu
->exten
));
386 pu
->priority
= chan
->macropriority
? chan
->macropriority
: chan
->priority
;
387 pu
->next
= parkinglot
;
390 /* If parking a channel directly, don't quiet yet get parking running on it */
393 ast_mutex_unlock(&parking_lock
);
394 /* Wake up the (presumably select()ing) thread */
395 pthread_kill(parking_thread
, SIGURG
);
396 if (option_verbose
> 1)
397 ast_verbose(VERBOSE_PREFIX_2
"Parked %s on %d@%s. Will timeout back to extension [%s] %s, %d in %d seconds\n", pu
->chan
->name
, pu
->parkingnum
, parking_con
, pu
->context
, pu
->exten
, pu
->priority
, (pu
->parkingtime
/1000));
399 if (pu
->parkingnum
!= -1)
400 snprintf(pu
->parkingexten
, sizeof(pu
->parkingexten
), "%d", x
);
401 manager_event(EVENT_FLAG_CALL
, "ParkedCall",
407 "CallerIDName: %s\r\n",
408 pu
->parkingexten
, pu
->chan
->name
, peer
? peer
->name
: "",
409 (long)pu
->start
.tv_sec
+ (long)(pu
->parkingtime
/1000) - (long)time(NULL
),
410 S_OR(pu
->chan
->cid
.cid_num
, "<unknown>"),
411 S_OR(pu
->chan
->cid
.cid_name
, "<unknown>")
414 if (peer
&& adsipark
&& ast_adsi_available(peer
)) {
415 adsi_announce_park(peer
, pu
->parkingexten
); /* Only supports parking numbers */
416 ast_adsi_unload_session(peer
);
419 con
= ast_context_find(parking_con
);
421 con
= ast_context_create(NULL
, parking_con
, registrar
);
422 if (!con
) /* Still no context? Bad */
423 ast_log(LOG_ERROR
, "Parking context '%s' does not exist and unable to create\n", parking_con
);
424 /* Tell the peer channel the number of the parking space */
425 if (peer
&& pu
->parkingnum
!= -1) { /* Only say number if it's a number */
426 /* Make sure we don't start saying digits to the channel being parked */
427 ast_set_flag(peer
, AST_FLAG_MASQ_NOSTREAM
);
428 ast_say_digits(peer
, pu
->parkingnum
, "", peer
->language
);
429 ast_clear_flag(peer
, AST_FLAG_MASQ_NOSTREAM
);
432 if (!ast_add_extension2(con
, 1, pu
->parkingexten
, 1, NULL
, NULL
, parkedcall
, strdup(pu
->parkingexten
), ast_free
, registrar
))
433 notify_metermaids(pu
->parkingexten
, parking_con
);
435 if (pu
->notquiteyet
) {
436 /* Wake up parking thread if we're really done */
437 ast_indicate_data(pu
->chan
, AST_CONTROL_HOLD
,
438 S_OR(parkmohclass
, NULL
),
439 !ast_strlen_zero(parkmohclass
) ? strlen(parkmohclass
) + 1 : 0);
441 pthread_kill(parking_thread
, SIGURG
);
446 int ast_masq_park_call(struct ast_channel
*rchan
, struct ast_channel
*peer
, int timeout
, int *extout
)
448 struct ast_channel
*chan
;
451 /* Make a new, fake channel that we'll use to masquerade in the real one */
452 if (!(chan
= ast_channel_alloc(0, AST_STATE_DOWN
, 0, 0, rchan
->accountcode
, rchan
->exten
, rchan
->context
, rchan
->amaflags
, "Parked/%s",rchan
->name
))) {
453 ast_log(LOG_WARNING
, "Unable to create parked channel\n");
457 /* Make formats okay */
458 chan
->readformat
= rchan
->readformat
;
459 chan
->writeformat
= rchan
->writeformat
;
460 ast_channel_masquerade(chan
, rchan
);
462 /* Setup the extensions and such */
463 set_c_e_p(chan
, rchan
->context
, rchan
->exten
, rchan
->priority
);
465 /* Make the masq execute */
470 ast_park_call(chan
, peer
, timeout
, extout
);
475 #define FEATURE_RETURN_HANGUP -1
476 #define FEATURE_RETURN_SUCCESSBREAK 0
477 #define FEATURE_RETURN_PBX_KEEPALIVE AST_PBX_KEEPALIVE
478 #define FEATURE_RETURN_NO_HANGUP_PEER AST_PBX_NO_HANGUP_PEER
479 #define FEATURE_RETURN_PASSDIGITS 21
480 #define FEATURE_RETURN_STOREDIGITS 22
481 #define FEATURE_RETURN_SUCCESS 23
482 #define FEATURE_RETURN_KEEPTRYING 24
484 #define FEATURE_SENSE_CHAN (1 << 0)
485 #define FEATURE_SENSE_PEER (1 << 1)
488 * set caller and callee according to the direction
490 static void set_peers(struct ast_channel
**caller
, struct ast_channel
**callee
,
491 struct ast_channel
*peer
, struct ast_channel
*chan
, int sense
)
493 if (sense
== FEATURE_SENSE_PEER
) {
502 /*! \brief support routing for one touch call parking */
503 static int builtin_parkcall(struct ast_channel
*chan
, struct ast_channel
*peer
, struct ast_bridge_config
*config
, char *code
, int sense
, void *data
)
505 struct ast_channel
*parker
;
506 struct ast_channel
*parkee
;
508 struct ast_module_user
*u
;
510 u
= ast_module_user_add(chan
);
512 set_peers(&parker
, &parkee
, peer
, chan
, sense
);
513 /* Setup the exten/priority to be s/1 since we don't know
514 where this call should return */
515 strcpy(chan
->exten
, "s");
517 if (chan
->_state
!= AST_STATE_UP
)
518 res
= ast_answer(chan
);
520 res
= ast_safe_sleep(chan
, 1000);
522 res
= ast_park_call(parkee
, parker
, 0, NULL
);
524 ast_module_user_remove(u
);
527 if (sense
== FEATURE_SENSE_CHAN
)
528 res
= AST_PBX_NO_HANGUP_PEER
;
530 res
= AST_PBX_KEEPALIVE
;
536 static int builtin_automonitor(struct ast_channel
*chan
, struct ast_channel
*peer
, struct ast_bridge_config
*config
, char *code
, int sense
, void *data
)
538 char *caller_chan_id
= NULL
, *callee_chan_id
= NULL
, *args
= NULL
, *touch_filename
= NULL
;
541 struct ast_channel
*caller_chan
, *callee_chan
;
544 ast_log(LOG_ERROR
,"Cannot record the call. The monitor application is disabled.\n");
548 if (!monitor_app
&& !(monitor_app
= pbx_findapp("Monitor"))) {
550 ast_log(LOG_ERROR
,"Cannot record the call. The monitor application is disabled.\n");
554 set_peers(&caller_chan
, &callee_chan
, peer
, chan
, sense
);
556 if (!ast_strlen_zero(courtesytone
)) {
557 if (ast_autoservice_start(callee_chan
))
559 if (ast_stream_and_wait(caller_chan
, courtesytone
, caller_chan
->language
, "")) {
560 ast_log(LOG_WARNING
, "Failed to play courtesy tone!\n");
561 ast_autoservice_stop(callee_chan
);
564 if (ast_autoservice_stop(callee_chan
))
568 if (callee_chan
->monitor
) {
569 if (option_verbose
> 3)
570 ast_verbose(VERBOSE_PREFIX_3
"User hit '%s' to stop recording call.\n", code
);
571 ast_monitor_stop(callee_chan
, 1);
572 return FEATURE_RETURN_SUCCESS
;
575 if (caller_chan
&& callee_chan
) {
576 const char *touch_format
= pbx_builtin_getvar_helper(caller_chan
, "TOUCH_MONITOR_FORMAT");
577 const char *touch_monitor
= pbx_builtin_getvar_helper(caller_chan
, "TOUCH_MONITOR");
580 touch_format
= pbx_builtin_getvar_helper(callee_chan
, "TOUCH_MONITOR_FORMAT");
583 touch_monitor
= pbx_builtin_getvar_helper(callee_chan
, "TOUCH_MONITOR");
586 len
= strlen(touch_monitor
) + 50;
588 touch_filename
= alloca(len
);
589 snprintf(touch_filename
, len
, "auto-%ld-%s", (long)time(NULL
), touch_monitor
);
590 snprintf(args
, len
, "%s|%s|m", (touch_format
) ? touch_format
: "wav", touch_filename
);
592 caller_chan_id
= ast_strdupa(S_OR(caller_chan
->cid
.cid_num
, caller_chan
->name
));
593 callee_chan_id
= ast_strdupa(S_OR(callee_chan
->cid
.cid_num
, callee_chan
->name
));
594 len
= strlen(caller_chan_id
) + strlen(callee_chan_id
) + 50;
596 touch_filename
= alloca(len
);
597 snprintf(touch_filename
, len
, "auto-%ld-%s-%s", (long)time(NULL
), caller_chan_id
, callee_chan_id
);
598 snprintf(args
, len
, "%s|%s|m", S_OR(touch_format
, "wav"), touch_filename
);
601 for( x
= 0; x
< strlen(args
); x
++) {
606 if (option_verbose
> 3)
607 ast_verbose(VERBOSE_PREFIX_3
"User hit '%s' to record call. filename: %s\n", code
, args
);
609 pbx_exec(callee_chan
, monitor_app
, args
);
610 pbx_builtin_setvar_helper(callee_chan
, "TOUCH_MONITOR_OUTPUT", touch_filename
);
611 pbx_builtin_setvar_helper(caller_chan
, "TOUCH_MONITOR_OUTPUT", touch_filename
);
613 return FEATURE_RETURN_SUCCESS
;
616 ast_log(LOG_NOTICE
,"Cannot record the call. One or both channels have gone away.\n");
620 static int builtin_disconnect(struct ast_channel
*chan
, struct ast_channel
*peer
, struct ast_bridge_config
*config
, char *code
, int sense
, void *data
)
622 if (option_verbose
> 3)
623 ast_verbose(VERBOSE_PREFIX_3
"User hit '%s' to disconnect call.\n", code
);
624 return FEATURE_RETURN_HANGUP
;
627 static int finishup(struct ast_channel
*chan
)
629 ast_indicate(chan
, AST_CONTROL_UNHOLD
);
631 return ast_autoservice_stop(chan
);
634 /*! \brief Find the context for the transfer */
635 static const char *real_ctx(struct ast_channel
*transferer
, struct ast_channel
*transferee
)
637 const char *s
= pbx_builtin_getvar_helper(transferer
, "TRANSFER_CONTEXT");
638 if (ast_strlen_zero(s
))
639 s
= pbx_builtin_getvar_helper(transferee
, "TRANSFER_CONTEXT");
640 if (ast_strlen_zero(s
)) /* Use the non-macro context to transfer the call XXX ? */
641 s
= transferer
->macrocontext
;
642 if (ast_strlen_zero(s
))
643 s
= transferer
->context
;
647 static int builtin_blindtransfer(struct ast_channel
*chan
, struct ast_channel
*peer
, struct ast_bridge_config
*config
, char *code
, int sense
, void *data
)
649 struct ast_channel
*transferer
;
650 struct ast_channel
*transferee
;
651 const char *transferer_real_context
;
655 set_peers(&transferer
, &transferee
, peer
, chan
, sense
);
656 transferer_real_context
= real_ctx(transferer
, transferee
);
657 /* Start autoservice on chan while we talk to the originator */
658 ast_autoservice_start(transferee
);
659 ast_indicate(transferee
, AST_CONTROL_HOLD
);
661 memset(xferto
, 0, sizeof(xferto
));
664 res
= ast_stream_and_wait(transferer
, "pbx-transfer", transferer
->language
, AST_DIGIT_ANY
);
666 finishup(transferee
);
667 return -1; /* error ? */
669 if (res
> 0) /* If they've typed a digit already, handle it */
670 xferto
[0] = (char) res
;
672 ast_stopstream(transferer
);
673 res
= ast_app_dtget(transferer
, transferer_real_context
, xferto
, sizeof(xferto
), 100, transferdigittimeout
);
674 if (res
< 0) { /* hangup, would be 0 for invalid and 1 for valid */
675 finishup(transferee
);
678 if (!strcmp(xferto
, ast_parking_ext())) {
679 res
= finishup(transferee
);
682 else if (!ast_park_call(transferee
, transferer
, 0, NULL
)) { /* success */
683 /* We return non-zero, but tell the PBX not to hang the channel when
684 the thread dies -- We have to be careful now though. We are responsible for
685 hanging up the channel, else it will never be hung up! */
687 return (transferer
== peer
) ? AST_PBX_KEEPALIVE
: AST_PBX_NO_HANGUP_PEER
;
689 ast_log(LOG_WARNING
, "Unable to park call %s\n", transferee
->name
);
691 /*! \todo XXX Maybe we should have another message here instead of invalid extension XXX */
692 } else if (ast_exists_extension(transferee
, transferer_real_context
, xferto
, 1, transferer
->cid
.cid_num
)) {
693 pbx_builtin_setvar_helper(peer
, "BLINDTRANSFER", transferee
->name
);
694 pbx_builtin_setvar_helper(chan
, "BLINDTRANSFER", peer
->name
);
695 res
=finishup(transferee
);
696 if (!transferer
->cdr
) {
697 transferer
->cdr
=ast_cdr_alloc();
699 ast_cdr_init(transferer
->cdr
, transferer
); /* initilize our channel's cdr */
700 ast_cdr_start(transferer
->cdr
);
703 if (transferer
->cdr
) {
704 ast_cdr_setdestchan(transferer
->cdr
, transferee
->name
);
705 ast_cdr_setapp(transferer
->cdr
, "BLINDTRANSFER","");
707 if (!transferee
->pbx
) {
708 /* Doh! Use our handy async_goto functions */
709 if (option_verbose
> 2)
710 ast_verbose(VERBOSE_PREFIX_3
"Transferring %s to '%s' (context %s) priority 1\n"
711 ,transferee
->name
, xferto
, transferer_real_context
);
712 if (ast_async_goto(transferee
, transferer_real_context
, xferto
, 1))
713 ast_log(LOG_WARNING
, "Async goto failed :-(\n");
716 /* Set the channel's new extension, since it exists, using transferer context */
717 set_c_e_p(transferee
, transferer_real_context
, xferto
, 0);
719 check_goto_on_transfer(transferer
);
722 if (option_verbose
> 2)
723 ast_verbose(VERBOSE_PREFIX_3
"Unable to find extension '%s' in context '%s'\n", xferto
, transferer_real_context
);
725 if (ast_stream_and_wait(transferer
, xferfailsound
, transferer
->language
, AST_DIGIT_ANY
) < 0 ) {
726 finishup(transferee
);
729 ast_stopstream(transferer
);
730 res
= finishup(transferee
);
732 if (option_verbose
> 1)
733 ast_verbose(VERBOSE_PREFIX_2
"Hungup during autoservice stop on '%s'\n", transferee
->name
);
736 return FEATURE_RETURN_SUCCESS
;
739 static int check_compat(struct ast_channel
*c
, struct ast_channel
*newchan
)
741 if (ast_channel_make_compatible(c
, newchan
) < 0) {
742 ast_log(LOG_WARNING
, "Had to drop call because I couldn't make %s compatible with %s\n",
743 c
->name
, newchan
->name
);
750 static int builtin_atxfer(struct ast_channel
*chan
, struct ast_channel
*peer
, struct ast_bridge_config
*config
, char *code
, int sense
, void *data
)
752 struct ast_channel
*transferer
;
753 struct ast_channel
*transferee
;
754 const char *transferer_real_context
;
755 char xferto
[256] = "";
758 struct ast_channel
*newchan
;
759 struct ast_channel
*xferchan
;
760 struct ast_bridge_thread_obj
*tobj
;
761 struct ast_bridge_config bconfig
;
766 ast_log(LOG_DEBUG
, "Executing Attended Transfer %s, %s (sense=%d) \n", chan
->name
, peer
->name
, sense
);
767 set_peers(&transferer
, &transferee
, peer
, chan
, sense
);
768 transferer_real_context
= real_ctx(transferer
, transferee
);
769 /* Start autoservice on chan while we talk to the originator */
770 ast_autoservice_start(transferee
);
771 ast_indicate(transferee
, AST_CONTROL_HOLD
);
774 res
= ast_stream_and_wait(transferer
, "pbx-transfer", transferer
->language
, AST_DIGIT_ANY
);
776 finishup(transferee
);
779 if (res
> 0) /* If they've typed a digit already, handle it */
780 xferto
[0] = (char) res
;
782 /* this is specific of atxfer */
783 res
= ast_app_dtget(transferer
, transferer_real_context
, xferto
, sizeof(xferto
), 100, transferdigittimeout
);
784 if (res
< 0) { /* hangup, would be 0 for invalid and 1 for valid */
785 finishup(transferee
);
789 ast_log(LOG_WARNING
, "Did not read data.\n");
790 finishup(transferee
);
791 if (ast_stream_and_wait(transferer
, "beeperr", transferer
->language
, ""))
793 return FEATURE_RETURN_SUCCESS
;
796 /* valid extension, res == 1 */
797 if (!ast_exists_extension(transferer
, transferer_real_context
, xferto
, 1, transferer
->cid
.cid_num
)) {
798 ast_log(LOG_WARNING
, "Extension %s does not exist in context %s\n",xferto
,transferer_real_context
);
799 finishup(transferee
);
800 if (ast_stream_and_wait(transferer
, "beeperr", transferer
->language
, ""))
802 return FEATURE_RETURN_SUCCESS
;
806 snprintf(xferto
+ l
, sizeof(xferto
) - l
, "@%s/n", transferer_real_context
); /* append context */
807 newchan
= ast_feature_request_and_dial(transferer
, "Local", ast_best_codec(transferer
->nativeformats
),
808 xferto
, atxfernoanswertimeout
, &outstate
, transferer
->cid
.cid_num
, transferer
->cid
.cid_name
);
809 ast_indicate(transferer
, -1);
811 finishup(transferee
);
812 /* any reason besides user requested cancel and busy triggers the failed sound */
813 if (outstate
!= AST_CONTROL_UNHOLD
&& outstate
!= AST_CONTROL_BUSY
&&
814 ast_stream_and_wait(transferer
, xferfailsound
, transferer
->language
, ""))
816 return FEATURE_RETURN_SUCCESS
;
819 if (check_compat(transferer
, newchan
)) {
820 /* we do mean transferee here, NOT transferer */
821 finishup(transferee
);
824 memset(&bconfig
,0,sizeof(struct ast_bridge_config
));
825 ast_set_flag(&(bconfig
.features_caller
), AST_FEATURE_DISCONNECT
);
826 ast_set_flag(&(bconfig
.features_callee
), AST_FEATURE_DISCONNECT
);
827 res
= ast_bridge_call(transferer
, newchan
, &bconfig
);
828 if (newchan
->_softhangup
|| !transferer
->_softhangup
) {
830 if (ast_stream_and_wait(transferer
, xfersound
, transferer
->language
, ""))
831 ast_log(LOG_WARNING
, "Failed to play transfer sound!\n");
832 finishup(transferee
);
833 transferer
->_softhangup
= 0;
834 return FEATURE_RETURN_SUCCESS
;
837 if (check_compat(transferee
, newchan
)) {
838 finishup(transferee
);
842 ast_indicate(transferee
, AST_CONTROL_UNHOLD
);
844 if ((ast_autoservice_stop(transferee
) < 0)
845 || (ast_waitfordigit(transferee
, 100) < 0)
846 || (ast_waitfordigit(newchan
, 100) < 0)
847 || ast_check_hangup(transferee
)
848 || ast_check_hangup(newchan
)) {
853 xferchan
= ast_channel_alloc(0, AST_STATE_DOWN
, 0, 0, "", "", "", 0, "Transfered/%s", transferee
->name
);
858 /* Make formats okay */
859 xferchan
->readformat
= transferee
->readformat
;
860 xferchan
->writeformat
= transferee
->writeformat
;
861 ast_channel_masquerade(xferchan
, transferee
);
862 ast_explicit_goto(xferchan
, transferee
->context
, transferee
->exten
, transferee
->priority
);
863 xferchan
->_state
= AST_STATE_UP
;
864 ast_clear_flag(xferchan
, AST_FLAGS_ALL
);
865 xferchan
->_softhangup
= 0;
867 if ((f
= ast_read(xferchan
)))
870 newchan
->_state
= AST_STATE_UP
;
871 ast_clear_flag(newchan
, AST_FLAGS_ALL
);
872 newchan
->_softhangup
= 0;
874 tobj
= ast_calloc(1, sizeof(struct ast_bridge_thread_obj
));
876 ast_hangup(xferchan
);
880 tobj
->chan
= xferchan
;
881 tobj
->peer
= newchan
;
882 tobj
->bconfig
= *config
;
884 if (ast_stream_and_wait(newchan
, xfersound
, newchan
->language
, ""))
885 ast_log(LOG_WARNING
, "Failed to play transfer sound!\n");
886 ast_bridge_call_thread_launch(tobj
);
887 return -1; /* XXX meaning the channel is bridged ? */
891 /* add atxfer and automon as undefined so you can only use em if you configure them */
892 #define FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0]))
894 AST_RWLOCK_DEFINE_STATIC(features_lock
);
896 static struct ast_call_feature builtin_features
[] =
898 { AST_FEATURE_REDIRECT
, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer
, AST_FEATURE_FLAG_NEEDSDTMF
, "" },
899 { AST_FEATURE_REDIRECT
, "Attended Transfer", "atxfer", "", "", builtin_atxfer
, AST_FEATURE_FLAG_NEEDSDTMF
, "" },
900 { AST_FEATURE_AUTOMON
, "One Touch Monitor", "automon", "", "", builtin_automonitor
, AST_FEATURE_FLAG_NEEDSDTMF
, "" },
901 { AST_FEATURE_DISCONNECT
, "Disconnect Call", "disconnect", "*", "*", builtin_disconnect
, AST_FEATURE_FLAG_NEEDSDTMF
, "" },
902 { AST_FEATURE_PARKCALL
, "Park Call", "parkcall", "", "", builtin_parkcall
, AST_FEATURE_FLAG_NEEDSDTMF
, "" },
906 static AST_LIST_HEAD_STATIC(feature_list
,ast_call_feature
);
908 /*! \brief register new feature into feature_list*/
909 void ast_register_feature(struct ast_call_feature
*feature
)
912 ast_log(LOG_NOTICE
,"You didn't pass a feature!\n");
916 AST_LIST_LOCK(&feature_list
);
917 AST_LIST_INSERT_HEAD(&feature_list
,feature
,feature_entry
);
918 AST_LIST_UNLOCK(&feature_list
);
920 if (option_verbose
>= 2)
921 ast_verbose(VERBOSE_PREFIX_2
"Registered Feature '%s'\n",feature
->sname
);
924 /*! \brief unregister feature from feature_list */
925 void ast_unregister_feature(struct ast_call_feature
*feature
)
930 AST_LIST_LOCK(&feature_list
);
931 AST_LIST_REMOVE(&feature_list
,feature
,feature_entry
);
932 AST_LIST_UNLOCK(&feature_list
);
936 /*! \brief Remove all features in the list */
937 static void ast_unregister_features(void)
939 struct ast_call_feature
*feature
;
941 AST_LIST_LOCK(&feature_list
);
942 while ((feature
= AST_LIST_REMOVE_HEAD(&feature_list
,feature_entry
)))
944 AST_LIST_UNLOCK(&feature_list
);
947 /*! \brief find a feature by name */
948 static struct ast_call_feature
*find_dynamic_feature(const char *name
)
950 struct ast_call_feature
*tmp
;
952 AST_LIST_TRAVERSE(&feature_list
, tmp
, feature_entry
) {
953 if (!strcasecmp(tmp
->sname
, name
))
960 /*! \brief exec an app by feature */
961 static int feature_exec_app(struct ast_channel
*chan
, struct ast_channel
*peer
, struct ast_bridge_config
*config
, char *code
, int sense
, void *data
)
964 struct ast_call_feature
*feature
= data
;
965 struct ast_channel
*work
, *idle
;
968 if (!feature
) { /* shouldn't ever happen! */
969 ast_log(LOG_NOTICE
, "Found feature before, but at execing we've lost it??\n");
973 if (sense
== FEATURE_SENSE_CHAN
) {
974 if (!ast_test_flag(feature
, AST_FEATURE_FLAG_BYCALLER
))
975 return FEATURE_RETURN_KEEPTRYING
;
976 if (ast_test_flag(feature
, AST_FEATURE_FLAG_ONSELF
)) {
984 if (!ast_test_flag(feature
, AST_FEATURE_FLAG_BYCALLEE
))
985 return FEATURE_RETURN_KEEPTRYING
;
986 if (ast_test_flag(feature
, AST_FEATURE_FLAG_ONSELF
)) {
995 if (!(app
= pbx_findapp(feature
->app
))) {
996 ast_log(LOG_WARNING
, "Could not find application (%s)\n", feature
->app
);
1000 ast_autoservice_start(idle
);
1002 if (!ast_strlen_zero(feature
->moh_class
))
1003 ast_moh_start(idle
, feature
->moh_class
, NULL
);
1005 res
= pbx_exec(work
, app
, feature
->app_args
);
1007 if (!ast_strlen_zero(feature
->moh_class
))
1010 ast_autoservice_stop(idle
);
1012 if (res
== AST_PBX_KEEPALIVE
)
1013 return FEATURE_RETURN_PBX_KEEPALIVE
;
1014 else if (res
== AST_PBX_NO_HANGUP_PEER
)
1015 return FEATURE_RETURN_NO_HANGUP_PEER
;
1017 return FEATURE_RETURN_SUCCESSBREAK
;
1019 return FEATURE_RETURN_SUCCESS
; /*! \todo XXX should probably return res */
1022 static void unmap_features(void)
1026 ast_rwlock_wrlock(&features_lock
);
1027 for (x
= 0; x
< FEATURES_COUNT
; x
++)
1028 strcpy(builtin_features
[x
].exten
, builtin_features
[x
].default_exten
);
1029 ast_rwlock_unlock(&features_lock
);
1032 static int remap_feature(const char *name
, const char *value
)
1036 ast_rwlock_wrlock(&features_lock
);
1037 for (x
= 0; x
< FEATURES_COUNT
; x
++) {
1038 if (strcasecmp(builtin_features
[x
].sname
, name
))
1041 ast_copy_string(builtin_features
[x
].exten
, value
, sizeof(builtin_features
[x
].exten
));
1045 ast_rwlock_unlock(&features_lock
);
1050 static int ast_feature_interpret(struct ast_channel
*chan
, struct ast_channel
*peer
, struct ast_bridge_config
*config
, char *code
, int sense
)
1053 struct ast_flags features
;
1054 int res
= FEATURE_RETURN_PASSDIGITS
;
1055 struct ast_call_feature
*feature
;
1056 const char *dynamic_features
=pbx_builtin_getvar_helper(chan
,"DYNAMIC_FEATURES");
1059 if (sense
== FEATURE_SENSE_CHAN
)
1060 ast_copy_flags(&features
, &(config
->features_caller
), AST_FLAGS_ALL
);
1062 ast_copy_flags(&features
, &(config
->features_callee
), AST_FLAGS_ALL
);
1063 if (option_debug
> 2)
1064 ast_log(LOG_DEBUG
, "Feature interpret: chan=%s, peer=%s, sense=%d, features=%d\n", chan
->name
, peer
->name
, sense
, features
.flags
);
1066 ast_rwlock_rdlock(&features_lock
);
1067 for (x
= 0; x
< FEATURES_COUNT
; x
++) {
1068 if ((ast_test_flag(&features
, builtin_features
[x
].feature_mask
)) &&
1069 !ast_strlen_zero(builtin_features
[x
].exten
)) {
1070 /* Feature is up for consideration */
1071 if (!strcmp(builtin_features
[x
].exten
, code
)) {
1072 res
= builtin_features
[x
].operation(chan
, peer
, config
, code
, sense
, NULL
);
1074 } else if (!strncmp(builtin_features
[x
].exten
, code
, strlen(code
))) {
1075 if (res
== FEATURE_RETURN_PASSDIGITS
)
1076 res
= FEATURE_RETURN_STOREDIGITS
;
1080 ast_rwlock_unlock(&features_lock
);
1082 if (ast_strlen_zero(dynamic_features
))
1085 tmp
= ast_strdupa(dynamic_features
);
1087 while ((tok
= strsep(&tmp
, "#"))) {
1088 AST_LIST_LOCK(&feature_list
);
1089 if (!(feature
= find_dynamic_feature(tok
))) {
1090 AST_LIST_UNLOCK(&feature_list
);
1094 /* Feature is up for consideration */
1095 if (!strcmp(feature
->exten
, code
)) {
1096 if (option_verbose
> 2)
1097 ast_verbose(VERBOSE_PREFIX_3
" Feature Found: %s exten: %s\n",feature
->sname
, tok
);
1098 res
= feature
->operation(chan
, peer
, config
, code
, sense
, feature
);
1099 if (res
!= FEATURE_RETURN_KEEPTRYING
) {
1100 AST_LIST_UNLOCK(&feature_list
);
1103 res
= FEATURE_RETURN_PASSDIGITS
;
1104 } else if (!strncmp(feature
->exten
, code
, strlen(code
)))
1105 res
= FEATURE_RETURN_STOREDIGITS
;
1107 AST_LIST_UNLOCK(&feature_list
);
1113 static void set_config_flags(struct ast_channel
*chan
, struct ast_channel
*peer
, struct ast_bridge_config
*config
)
1117 ast_clear_flag(config
, AST_FLAGS_ALL
);
1119 ast_rwlock_rdlock(&features_lock
);
1120 for (x
= 0; x
< FEATURES_COUNT
; x
++) {
1121 if (!ast_test_flag(builtin_features
+ x
, AST_FEATURE_FLAG_NEEDSDTMF
))
1124 if (ast_test_flag(&(config
->features_caller
), builtin_features
[x
].feature_mask
))
1125 ast_set_flag(config
, AST_BRIDGE_DTMF_CHANNEL_0
);
1127 if (ast_test_flag(&(config
->features_callee
), builtin_features
[x
].feature_mask
))
1128 ast_set_flag(config
, AST_BRIDGE_DTMF_CHANNEL_1
);
1130 ast_rwlock_unlock(&features_lock
);
1132 if (chan
&& peer
&& !(ast_test_flag(config
, AST_BRIDGE_DTMF_CHANNEL_0
) && ast_test_flag(config
, AST_BRIDGE_DTMF_CHANNEL_1
))) {
1133 const char *dynamic_features
= pbx_builtin_getvar_helper(chan
, "DYNAMIC_FEATURES");
1135 if (dynamic_features
) {
1136 char *tmp
= ast_strdupa(dynamic_features
);
1138 struct ast_call_feature
*feature
;
1140 /* while we have a feature */
1141 while ((tok
= strsep(&tmp
, "#"))) {
1142 AST_LIST_LOCK(&feature_list
);
1143 if ((feature
= find_dynamic_feature(tok
)) && ast_test_flag(feature
, AST_FEATURE_FLAG_NEEDSDTMF
)) {
1144 if (ast_test_flag(feature
, AST_FEATURE_FLAG_BYCALLER
))
1145 ast_set_flag(config
, AST_BRIDGE_DTMF_CHANNEL_0
);
1146 if (ast_test_flag(feature
, AST_FEATURE_FLAG_BYCALLEE
))
1147 ast_set_flag(config
, AST_BRIDGE_DTMF_CHANNEL_1
);
1149 AST_LIST_UNLOCK(&feature_list
);
1155 /*! \todo XXX Check - this is very similar to the code in channel.c */
1156 static struct ast_channel
*ast_feature_request_and_dial(struct ast_channel
*caller
, const char *type
, int format
, void *data
, int timeout
, int *outstate
, const char *cid_num
, const char *cid_name
)
1161 struct ast_channel
*chan
;
1162 struct ast_channel
*monitor_chans
[2];
1163 struct ast_channel
*active_channel
;
1164 int res
= 0, ready
= 0;
1166 if ((chan
= ast_request(type
, format
, data
, &cause
))) {
1167 ast_set_callerid(chan
, cid_num
, cid_name
, cid_num
);
1168 ast_channel_inherit_variables(caller
, chan
);
1169 pbx_builtin_setvar_helper(chan
, "TRANSFERERNAME", caller
->name
);
1171 chan
->cdr
=ast_cdr_alloc();
1173 ast_cdr_init(chan
->cdr
, chan
); /* initilize our channel's cdr */
1174 ast_cdr_start(chan
->cdr
);
1178 if (!ast_call(chan
, data
, timeout
)) {
1179 struct timeval started
;
1181 char *disconnect_code
= NULL
, *dialed_code
= NULL
;
1183 ast_indicate(caller
, AST_CONTROL_RINGING
);
1184 /* support dialing of the featuremap disconnect code while performing an attended tranfer */
1185 ast_rwlock_rdlock(&features_lock
);
1186 for (x
= 0; x
< FEATURES_COUNT
; x
++) {
1187 if (strcasecmp(builtin_features
[x
].sname
, "disconnect"))
1190 disconnect_code
= builtin_features
[x
].exten
;
1191 len
= strlen(disconnect_code
) + 1;
1192 dialed_code
= alloca(len
);
1193 memset(dialed_code
, 0, len
);
1196 ast_rwlock_unlock(&features_lock
);
1198 started
= ast_tvnow();
1200 while (!ast_check_hangup(caller
) && timeout
&& (chan
->_state
!= AST_STATE_UP
)) {
1201 struct ast_frame
*f
= NULL
;
1203 monitor_chans
[0] = caller
;
1204 monitor_chans
[1] = chan
;
1205 active_channel
= ast_waitfor_n(monitor_chans
, 2, &to
);
1207 /* see if the timeout has been violated */
1208 if(ast_tvdiff_ms(ast_tvnow(), started
) > timeout
) {
1209 state
= AST_CONTROL_UNHOLD
;
1210 ast_log(LOG_NOTICE
, "We exceeded our AT-timeout\n");
1211 break; /*doh! timeout*/
1214 if (!active_channel
)
1217 if (chan
&& (chan
== active_channel
)){
1219 if (f
== NULL
) { /*doh! where'd he go?*/
1220 state
= AST_CONTROL_HANGUP
;
1225 if (f
->frametype
== AST_FRAME_CONTROL
|| f
->frametype
== AST_FRAME_DTMF
|| f
->frametype
== AST_FRAME_TEXT
) {
1226 if (f
->subclass
== AST_CONTROL_RINGING
) {
1227 state
= f
->subclass
;
1228 if (option_verbose
> 2)
1229 ast_verbose( VERBOSE_PREFIX_3
"%s is ringing\n", chan
->name
);
1230 ast_indicate(caller
, AST_CONTROL_RINGING
);
1231 } else if ((f
->subclass
== AST_CONTROL_BUSY
) || (f
->subclass
== AST_CONTROL_CONGESTION
)) {
1232 state
= f
->subclass
;
1233 if (option_verbose
> 2)
1234 ast_verbose( VERBOSE_PREFIX_3
"%s is busy\n", chan
->name
);
1235 ast_indicate(caller
, AST_CONTROL_BUSY
);
1239 } else if (f
->subclass
== AST_CONTROL_ANSWER
) {
1240 /* This is what we are hoping for */
1241 state
= f
->subclass
;
1246 } else if (f
->subclass
!= -1) {
1247 ast_log(LOG_NOTICE
, "Don't know what to do about control frame: %d\n", f
->subclass
);
1249 /* else who cares */
1252 } else if (caller
&& (active_channel
== caller
)) {
1253 f
= ast_read(caller
);
1254 if (f
== NULL
) { /*doh! where'd he go?*/
1255 if (caller
->_softhangup
&& !chan
->_softhangup
) {
1256 /* make this a blind transfer */
1260 state
= AST_CONTROL_HANGUP
;
1265 if (f
->frametype
== AST_FRAME_DTMF
) {
1266 dialed_code
[x
++] = f
->subclass
;
1267 dialed_code
[x
] = '\0';
1268 if (strlen(dialed_code
) == len
) {
1270 } else if (x
&& strncmp(dialed_code
, disconnect_code
, x
)) {
1272 dialed_code
[x
] = '\0';
1274 if (*dialed_code
&& !strcmp(dialed_code
, disconnect_code
)) {
1275 /* Caller Canceled the call */
1276 state
= AST_CONTROL_UNHOLD
;
1287 ast_log(LOG_NOTICE
, "Unable to call channel %s/%s\n", type
, (char *)data
);
1289 ast_log(LOG_NOTICE
, "Unable to request channel %s/%s\n", type
, (char *)data
);
1291 case AST_CAUSE_BUSY
:
1292 state
= AST_CONTROL_BUSY
;
1294 case AST_CAUSE_CONGESTION
:
1295 state
= AST_CONTROL_CONGESTION
;
1300 ast_indicate(caller
, -1);
1301 if (chan
&& ready
) {
1302 if (chan
->_state
== AST_STATE_UP
)
1303 state
= AST_CONTROL_ANSWER
;
1316 if (chan
&& res
<= 0) {
1317 if (chan
->cdr
|| (chan
->cdr
= ast_cdr_alloc())) {
1319 ast_cdr_init(chan
->cdr
, chan
);
1320 snprintf(tmp
, 256, "%s/%s", type
, (char *)data
);
1321 ast_cdr_setapp(chan
->cdr
,"Dial",tmp
);
1322 ast_cdr_update(chan
);
1323 ast_cdr_start(chan
->cdr
);
1324 ast_cdr_end(chan
->cdr
);
1325 /* If the cause wasn't handled properly */
1326 if (ast_cdr_disposition(chan
->cdr
,chan
->hangupcause
))
1327 ast_cdr_failed(chan
->cdr
);
1329 ast_log(LOG_WARNING
, "Unable to create Call Detail Record\n");
1336 int ast_bridge_call(struct ast_channel
*chan
,struct ast_channel
*peer
,struct ast_bridge_config
*config
)
1338 /* Copy voice back and forth between the two channels. Give the peer
1339 the ability to transfer calls with '#<extension' syntax. */
1340 struct ast_frame
*f
;
1341 struct ast_channel
*who
;
1342 char chan_featurecode
[FEATURE_MAX_LEN
+ 1]="";
1343 char peer_featurecode
[FEATURE_MAX_LEN
+ 1]="";
1348 struct ast_option_header
*aoh
;
1349 struct ast_bridge_config backup_config
;
1350 struct ast_cdr
*bridge_cdr
;
1352 memset(&backup_config
, 0, sizeof(backup_config
));
1354 config
->start_time
= ast_tvnow();
1357 pbx_builtin_setvar_helper(chan
, "BRIDGEPEER", peer
->name
);
1358 pbx_builtin_setvar_helper(peer
, "BRIDGEPEER", chan
->name
);
1360 pbx_builtin_setvar_helper(chan
, "BLINDTRANSFER", NULL
);
1363 const char *monitor_exec
;
1364 struct ast_channel
*src
= NULL
;
1366 if (!(monitor_app
= pbx_findapp("Monitor")))
1369 if ((monitor_exec
= pbx_builtin_getvar_helper(chan
, "AUTO_MONITOR")))
1371 else if ((monitor_exec
= pbx_builtin_getvar_helper(peer
, "AUTO_MONITOR")))
1373 if (monitor_app
&& src
) {
1374 char *tmp
= ast_strdupa(monitor_exec
);
1375 pbx_exec(src
, monitor_app
, tmp
);
1379 set_config_flags(chan
, peer
, config
);
1380 config
->firstpass
= 1;
1382 /* Answer if need be */
1383 if (ast_answer(chan
))
1385 peer
->appl
= "Bridged Call";
1386 peer
->data
= chan
->name
;
1388 /* copy the userfield from the B-leg to A-leg if applicable */
1389 if (chan
->cdr
&& peer
->cdr
&& !ast_strlen_zero(peer
->cdr
->userfield
)) {
1391 if (!ast_strlen_zero(chan
->cdr
->userfield
)) {
1392 snprintf(tmp
, sizeof(tmp
), "%s;%s", chan
->cdr
->userfield
, peer
->cdr
->userfield
);
1393 ast_cdr_appenduserfield(chan
, tmp
);
1395 ast_cdr_setuserfield(chan
, peer
->cdr
->userfield
);
1396 /* free the peer's cdr without ast_cdr_free complaining */
1402 struct ast_channel
*other
; /* used later */
1404 res
= ast_channel_bridge(chan
, peer
, config
, &f
, &who
);
1406 if (config
->feature_timer
) {
1407 /* Update time limit for next pass */
1408 diff
= ast_tvdiff_ms(ast_tvnow(), config
->start_time
);
1409 config
->feature_timer
-= diff
;
1411 /* Running on backup config, meaning a feature might be being
1412 activated, but that's no excuse to keep things going
1414 if (backup_config
.feature_timer
&& ((backup_config
.feature_timer
-= diff
) <= 0)) {
1416 ast_log(LOG_DEBUG
, "Timed out, realtime this time!\n");
1417 config
->feature_timer
= 0;
1423 } else if (config
->feature_timer
<= 0) {
1424 /* Not *really* out of time, just out of time for
1425 digits to come in for features. */
1427 ast_log(LOG_DEBUG
, "Timed out for feature!\n");
1428 if (!ast_strlen_zero(peer_featurecode
)) {
1429 ast_dtmf_stream(chan
, peer
, peer_featurecode
, 0);
1430 memset(peer_featurecode
, 0, sizeof(peer_featurecode
));
1432 if (!ast_strlen_zero(chan_featurecode
)) {
1433 ast_dtmf_stream(peer
, chan
, chan_featurecode
, 0);
1434 memset(chan_featurecode
, 0, sizeof(chan_featurecode
));
1438 hasfeatures
= !ast_strlen_zero(chan_featurecode
) || !ast_strlen_zero(peer_featurecode
);
1440 /* Restore original (possibly time modified) bridge config */
1441 memcpy(config
, &backup_config
, sizeof(struct ast_bridge_config
));
1442 memset(&backup_config
, 0, sizeof(backup_config
));
1444 hadfeatures
= hasfeatures
;
1445 /* Continue as we were */
1448 /* The bridge returned without a frame and there is a feature in progress.
1449 * However, we don't think the feature has quite yet timed out, so just
1450 * go back into the bridge. */
1454 if (config
->feature_timer
<=0) {
1455 /* We ran out of time */
1456 config
->feature_timer
= 0;
1466 if (!ast_test_flag(chan
, AST_FLAG_ZOMBIE
) && !ast_test_flag(peer
, AST_FLAG_ZOMBIE
))
1467 ast_log(LOG_WARNING
, "Bridge failed on channels %s and %s, res = %d\n", chan
->name
, peer
->name
, res
);
1471 if (!f
|| (f
->frametype
== AST_FRAME_CONTROL
&&
1472 (f
->subclass
== AST_CONTROL_HANGUP
|| f
->subclass
== AST_CONTROL_BUSY
||
1473 f
->subclass
== AST_CONTROL_CONGESTION
) ) ) {
1477 /* many things should be sent to the 'other' channel */
1478 other
= (who
== chan
) ? peer
: chan
;
1479 if (f
->frametype
== AST_FRAME_CONTROL
) {
1480 switch (f
->subclass
) {
1481 case AST_CONTROL_RINGING
:
1482 case AST_CONTROL_FLASH
:
1484 ast_indicate(other
, f
->subclass
);
1486 case AST_CONTROL_HOLD
:
1487 case AST_CONTROL_UNHOLD
:
1488 ast_indicate_data(other
, f
->subclass
, f
->data
, f
->datalen
);
1490 case AST_CONTROL_OPTION
:
1492 /* Forward option Requests */
1493 if (aoh
&& aoh
->flag
== AST_OPTION_FLAG_REQUEST
) {
1494 ast_channel_setoption(other
, ntohs(aoh
->option
), aoh
->data
,
1495 f
->datalen
- sizeof(struct ast_option_header
), 0);
1499 } else if (f
->frametype
== AST_FRAME_DTMF_BEGIN
) {
1501 } else if (f
->frametype
== AST_FRAME_DTMF
) {
1505 hadfeatures
= hasfeatures
;
1506 /* This cannot overrun because the longest feature is one shorter than our buffer */
1508 sense
= FEATURE_SENSE_CHAN
;
1509 featurecode
= chan_featurecode
;
1511 sense
= FEATURE_SENSE_PEER
;
1512 featurecode
= peer_featurecode
;
1514 /*! append the event to featurecode. we rely on the string being zero-filled, and
1515 * not overflowing it.
1516 * \todo XXX how do we guarantee the latter ?
1518 featurecode
[strlen(featurecode
)] = f
->subclass
;
1519 /* Get rid of the frame before we start doing "stuff" with the channels */
1522 config
->feature_timer
= backup_config
.feature_timer
;
1523 res
= ast_feature_interpret(chan
, peer
, config
, featurecode
, sense
);
1525 case FEATURE_RETURN_PASSDIGITS
:
1526 ast_dtmf_stream(other
, who
, featurecode
, 0);
1528 case FEATURE_RETURN_SUCCESS
:
1529 memset(featurecode
, 0, sizeof(chan_featurecode
));
1532 if (res
>= FEATURE_RETURN_PASSDIGITS
) {
1536 hasfeatures
= !ast_strlen_zero(chan_featurecode
) || !ast_strlen_zero(peer_featurecode
);
1537 if (hadfeatures
&& !hasfeatures
) {
1538 /* Restore backup */
1539 memcpy(config
, &backup_config
, sizeof(struct ast_bridge_config
));
1540 memset(&backup_config
, 0, sizeof(struct ast_bridge_config
));
1541 } else if (hasfeatures
) {
1543 /* Backup configuration */
1544 memcpy(&backup_config
, config
, sizeof(struct ast_bridge_config
));
1545 /* Setup temporary config options */
1546 config
->play_warning
= 0;
1547 ast_clear_flag(&(config
->features_caller
), AST_FEATURE_PLAY_WARNING
);
1548 ast_clear_flag(&(config
->features_callee
), AST_FEATURE_PLAY_WARNING
);
1549 config
->warning_freq
= 0;
1550 config
->warning_sound
= NULL
;
1551 config
->end_sound
= NULL
;
1552 config
->start_sound
= NULL
;
1553 config
->firstpass
= 0;
1555 config
->start_time
= ast_tvnow();
1556 config
->feature_timer
= featuredigittimeout
;
1558 ast_log(LOG_DEBUG
, "Set time limit to %ld\n", config
->feature_timer
);
1566 /* arrange the cdrs */
1567 bridge_cdr
= ast_cdr_alloc();
1569 if (chan
->cdr
&& peer
->cdr
) { /* both of them? merge */
1570 ast_cdr_init(bridge_cdr
,chan
); /* seems more logicaller to use the destination as a base, but, really, it's random */
1571 ast_cdr_start(bridge_cdr
); /* now is the time to start */
1573 /* absorb the channel cdr */
1574 ast_cdr_merge(bridge_cdr
, chan
->cdr
);
1575 if (!ast_test_flag(chan
->cdr
, AST_CDR_FLAG_LOCKED
))
1576 ast_cdr_discard(chan
->cdr
); /* if locked cdrs are in chan, they are taken over in the merge */
1578 /* absorb the peer cdr */
1579 ast_cdr_merge(bridge_cdr
, peer
->cdr
);
1580 if (!ast_test_flag(peer
->cdr
, AST_CDR_FLAG_LOCKED
))
1581 ast_cdr_discard(peer
->cdr
); /* if locked cdrs are in peer, they are taken over in the merge */
1584 chan
->cdr
= bridge_cdr
; /* make this available to the rest of the world via the chan while the call is in progress */
1585 } else if (chan
->cdr
) {
1586 /* take the cdr from the channel - literally */
1587 ast_cdr_init(bridge_cdr
,chan
);
1588 /* absorb this data */
1589 ast_cdr_merge(bridge_cdr
, chan
->cdr
);
1590 if (!ast_test_flag(chan
->cdr
, AST_CDR_FLAG_LOCKED
))
1591 ast_cdr_discard(chan
->cdr
); /* if locked cdrs are in chan, they are taken over in the merge */
1592 chan
->cdr
= bridge_cdr
; /* make this available to the rest of the world via the chan while the call is in progress */
1593 } else if (peer
->cdr
) {
1594 /* take the cdr from the peer - literally */
1595 ast_cdr_init(bridge_cdr
,peer
);
1596 /* absorb this data */
1597 ast_cdr_merge(bridge_cdr
, peer
->cdr
);
1598 if (!ast_test_flag(peer
->cdr
, AST_CDR_FLAG_LOCKED
))
1599 ast_cdr_discard(peer
->cdr
); /* if locked cdrs are in chan, they are taken over in the merge */
1601 peer
->cdr
= bridge_cdr
; /* make this available to the rest of the world via the chan while the call is in progress */
1603 /* make up a new cdr */
1604 ast_cdr_init(bridge_cdr
,chan
); /* eh, just pick one of them */
1605 chan
->cdr
= bridge_cdr
; /* */
1607 if (ast_strlen_zero(bridge_cdr
->dstchannel
)) {
1608 if (strcmp(bridge_cdr
->channel
, peer
->name
) != 0)
1609 ast_cdr_setdestchan(bridge_cdr
, peer
->name
);
1611 ast_cdr_setdestchan(bridge_cdr
, chan
->name
);
1617 static void post_manager_event(const char *s
, char *parkingexten
, struct ast_channel
*chan
)
1619 manager_event(EVENT_FLAG_CALL
, s
,
1623 "CallerIDName: %s\r\n\r\n",
1626 S_OR(chan
->cid
.cid_num
, "<unknown>"),
1627 S_OR(chan
->cid
.cid_name
, "<unknown>")
1631 /*! \brief Take care of parked calls and unpark them if needed */
1632 static void *do_parking_thread(void *ignore
)
1634 fd_set rfds
, efds
; /* results from previous select, to be preserved across loops. */
1639 struct parkeduser
*pu
, *pl
, *pt
= NULL
;
1640 int ms
= -1; /* select timeout, uninitialized */
1641 int max
= -1; /* max fd, none there yet */
1642 fd_set nrfds
, nefds
; /* args for the next select */
1646 ast_mutex_lock(&parking_lock
);
1649 /* navigate the list with prev-cur pointers to support removals */
1651 struct ast_channel
*chan
= pu
->chan
; /* shorthand */
1652 int tms
; /* timeout for this item */
1653 int x
; /* fd index in channel */
1654 struct ast_context
*con
;
1656 if (pu
->notquiteyet
) { /* Pretend this one isn't here yet */
1661 tms
= ast_tvdiff_ms(ast_tvnow(), pu
->start
);
1662 if (tms
> pu
->parkingtime
) {
1663 ast_indicate(chan
, AST_CONTROL_UNHOLD
);
1664 /* Get chan, exten from derived kludge */
1665 if (pu
->peername
[0]) {
1666 char *peername
= ast_strdupa(pu
->peername
);
1667 char *cp
= strrchr(peername
, '-');
1670 con
= ast_context_find(parking_con_dial
);
1672 con
= ast_context_create(NULL
, parking_con_dial
, registrar
);
1674 ast_log(LOG_ERROR
, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial
);
1677 char returnexten
[AST_MAX_EXTENSION
];
1678 snprintf(returnexten
, sizeof(returnexten
), "%s||t", peername
);
1679 ast_add_extension2(con
, 1, peername
, 1, NULL
, NULL
, "Dial", strdup(returnexten
), ast_free
, registrar
);
1681 set_c_e_p(chan
, parking_con_dial
, peername
, 1);
1683 /* They've been waiting too long, send them back to where they came. Theoretically they
1684 should have their original extensions and such, but we copy to be on the safe side */
1685 set_c_e_p(chan
, pu
->context
, pu
->exten
, pu
->priority
);
1688 post_manager_event("ParkedCallTimeOut", pu
->parkingexten
, chan
);
1690 if (option_verbose
> 1)
1691 ast_verbose(VERBOSE_PREFIX_2
"Timeout for %s parked on %d. Returning to %s,%s,%d\n", chan
->name
, pu
->parkingnum
, chan
->context
, chan
->exten
, chan
->priority
);
1692 /* Start up the PBX, or hang them up */
1693 if (ast_pbx_start(chan
)) {
1694 ast_log(LOG_WARNING
, "Unable to restart the PBX for user on '%s', hanging them up...\n", chan
->name
);
1697 /* And take them out of the parking lot */
1699 pl
->next
= pu
->next
;
1701 parkinglot
= pu
->next
;
1704 con
= ast_context_find(parking_con
);
1706 if (ast_context_remove_extension2(con
, pt
->parkingexten
, 1, NULL
))
1707 ast_log(LOG_WARNING
, "Whoa, failed to remove the extension!\n");
1709 notify_metermaids(pt
->parkingexten
, parking_con
);
1711 ast_log(LOG_WARNING
, "Whoa, no parking context?\n");
1713 } else { /* still within parking time, process descriptors */
1714 for (x
= 0; x
< AST_MAX_FDS
; x
++) {
1715 struct ast_frame
*f
;
1717 if (chan
->fds
[x
] == -1 || (!FD_ISSET(chan
->fds
[x
], &rfds
) && !FD_ISSET(chan
->fds
[x
], &efds
)))
1718 continue; /* nothing on this descriptor */
1720 if (FD_ISSET(chan
->fds
[x
], &efds
))
1721 ast_set_flag(chan
, AST_FLAG_EXCEPTION
);
1723 ast_clear_flag(chan
, AST_FLAG_EXCEPTION
);
1726 /* See if they need servicing */
1728 if (!f
|| (f
->frametype
== AST_FRAME_CONTROL
&& f
->subclass
== AST_CONTROL_HANGUP
)) {
1731 post_manager_event("ParkedCallGiveUp", pu
->parkingexten
, chan
);
1733 /* There's a problem, hang them up*/
1734 if (option_verbose
> 1)
1735 ast_verbose(VERBOSE_PREFIX_2
"%s got tired of being parked\n", chan
->name
);
1737 /* And take them out of the parking lot */
1739 pl
->next
= pu
->next
;
1741 parkinglot
= pu
->next
;
1744 con
= ast_context_find(parking_con
);
1746 if (ast_context_remove_extension2(con
, pt
->parkingexten
, 1, NULL
))
1747 ast_log(LOG_WARNING
, "Whoa, failed to remove the extension!\n");
1749 notify_metermaids(pt
->parkingexten
, parking_con
);
1751 ast_log(LOG_WARNING
, "Whoa, no parking context?\n");
1755 /*! \todo XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
1757 if (pu
->moh_trys
< 3 && !chan
->generatordata
) {
1759 ast_log(LOG_DEBUG
, "MOH on parked call stopped by outside source. Restarting.\n");
1760 ast_indicate_data(pu
->chan
, AST_CONTROL_HOLD
,
1761 S_OR(parkmohclass
, NULL
),
1762 !ast_strlen_zero(parkmohclass
) ? strlen(parkmohclass
) + 1 : 0);
1765 goto std
; /*! \todo XXX Ick: jumping into an else statement??? XXX */
1769 if (x
>= AST_MAX_FDS
) {
1770 std
: for (x
=0; x
<AST_MAX_FDS
; x
++) { /* mark fds for next round */
1771 if (chan
->fds
[x
] > -1) {
1772 FD_SET(chan
->fds
[x
], &nrfds
);
1773 FD_SET(chan
->fds
[x
], &nefds
);
1774 if (chan
->fds
[x
] > max
)
1778 /* Keep track of our shortest wait */
1779 if (tms
< ms
|| ms
< 0)
1786 ast_mutex_unlock(&parking_lock
);
1790 struct timeval tv
= ast_samp2tv(ms
, 1000);
1791 /* Wait for something to happen */
1792 ast_select(max
+ 1, &rfds
, NULL
, &efds
, (ms
> -1) ? &tv
: NULL
);
1794 pthread_testcancel();
1796 return NULL
; /* Never reached */
1799 /*! \brief Park a call */
1800 static int park_call_exec(struct ast_channel
*chan
, void *data
)
1802 /* Data is unused at the moment but could contain a parking
1803 lot context eventually */
1805 struct ast_module_user
*u
;
1807 u
= ast_module_user_add(chan
);
1809 /* Setup the exten/priority to be s/1 since we don't know
1810 where this call should return */
1811 strcpy(chan
->exten
, "s");
1813 /* Answer if call is not up */
1814 if (chan
->_state
!= AST_STATE_UP
)
1815 res
= ast_answer(chan
);
1816 /* Sleep to allow VoIP streams to settle down */
1818 res
= ast_safe_sleep(chan
, 1000);
1821 res
= ast_park_call(chan
, chan
, 0, NULL
);
1823 ast_module_user_remove(u
);
1825 return !res
? AST_PBX_KEEPALIVE
: res
;
1828 /*! \brief Pickup parked call */
1829 static int park_exec(struct ast_channel
*chan
, void *data
)
1832 struct ast_module_user
*u
;
1833 struct ast_channel
*peer
=NULL
;
1834 struct parkeduser
*pu
, *pl
=NULL
;
1835 struct ast_context
*con
;
1838 struct ast_bridge_config config
;
1841 ast_log(LOG_WARNING
, "Parkedcall requires an argument (extension number)\n");
1845 u
= ast_module_user_add(chan
);
1847 park
= atoi((char *)data
);
1848 ast_mutex_lock(&parking_lock
);
1851 if (pu
->parkingnum
== park
) {
1853 pl
->next
= pu
->next
;
1855 parkinglot
= pu
->next
;
1861 ast_mutex_unlock(&parking_lock
);
1864 con
= ast_context_find(parking_con
);
1866 if (ast_context_remove_extension2(con
, pu
->parkingexten
, 1, NULL
))
1867 ast_log(LOG_WARNING
, "Whoa, failed to remove the extension!\n");
1869 notify_metermaids(pu
->parkingexten
, parking_con
);
1871 ast_log(LOG_WARNING
, "Whoa, no parking context?\n");
1873 manager_event(EVENT_FLAG_CALL
, "UnParkedCall",
1878 "CallerIDName: %s\r\n",
1879 pu
->parkingexten
, pu
->chan
->name
, chan
->name
,
1880 S_OR(pu
->chan
->cid
.cid_num
, "<unknown>"),
1881 S_OR(pu
->chan
->cid
.cid_name
, "<unknown>")
1886 /* JK02: it helps to answer the channel if not already up */
1887 if (chan
->_state
!= AST_STATE_UP
)
1891 /* Play a courtesy to the source(s) configured to prefix the bridge connecting */
1893 if (!ast_strlen_zero(courtesytone
)) {
1895 ast_indicate(peer
, AST_CONTROL_UNHOLD
);
1896 if (parkedplay
== 0) {
1897 error
= ast_stream_and_wait(chan
, courtesytone
, chan
->language
, "");
1898 } else if (parkedplay
== 1) {
1899 error
= ast_stream_and_wait(peer
, courtesytone
, chan
->language
, "");
1900 } else if (parkedplay
== 2) {
1901 if (!ast_streamfile(chan
, courtesytone
, chan
->language
) &&
1902 !ast_streamfile(peer
, courtesytone
, chan
->language
)) {
1903 /*! \todo XXX we would like to wait on both! */
1904 res
= ast_waitstream(chan
, "");
1906 res
= ast_waitstream(peer
, "");
1912 ast_log(LOG_WARNING
, "Failed to play courtesy tone!\n");
1917 ast_indicate(peer
, AST_CONTROL_UNHOLD
);
1919 res
= ast_channel_make_compatible(chan
, peer
);
1921 ast_log(LOG_WARNING
, "Could not make channels %s and %s compatible for bridge\n", chan
->name
, peer
->name
);
1925 /* This runs sorta backwards, since we give the incoming channel control, as if it
1926 were the person called. */
1927 if (option_verbose
> 2)
1928 ast_verbose(VERBOSE_PREFIX_3
"Channel %s connected to parked call %d\n", chan
->name
, park
);
1930 pbx_builtin_setvar_helper(chan
, "PARKEDCHANNEL", peer
->name
);
1931 ast_cdr_setdestchan(chan
->cdr
, peer
->name
);
1932 memset(&config
, 0, sizeof(struct ast_bridge_config
));
1933 ast_set_flag(&(config
.features_callee
), AST_FEATURE_REDIRECT
);
1934 ast_set_flag(&(config
.features_caller
), AST_FEATURE_REDIRECT
);
1935 res
= ast_bridge_call(chan
, peer
, &config
);
1937 pbx_builtin_setvar_helper(chan
, "PARKEDCHANNEL", peer
->name
);
1938 ast_cdr_setdestchan(chan
->cdr
, peer
->name
);
1940 /* Simulate the PBX hanging up */
1941 if (res
!= AST_PBX_NO_HANGUP_PEER
)
1945 /*! \todo XXX Play a message XXX */
1946 if (ast_stream_and_wait(chan
, "pbx-invalidpark", chan
->language
, ""))
1947 ast_log(LOG_WARNING
, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan
->name
);
1948 if (option_verbose
> 2)
1949 ast_verbose(VERBOSE_PREFIX_3
"Channel %s tried to talk to nonexistent parked call %d\n", chan
->name
, park
);
1953 ast_module_user_remove(u
);
1958 static int handle_showfeatures(int fd
, int argc
, char *argv
[])
1961 struct ast_call_feature
*feature
;
1962 char format
[] = "%-25s %-7s %-7s\n";
1964 ast_cli(fd
, format
, "Builtin Feature", "Default", "Current");
1965 ast_cli(fd
, format
, "---------------", "-------", "-------");
1967 ast_cli(fd
, format
, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */
1969 ast_rwlock_rdlock(&features_lock
);
1970 for (i
= 0; i
< FEATURES_COUNT
; i
++)
1971 ast_cli(fd
, format
, builtin_features
[i
].fname
, builtin_features
[i
].default_exten
, builtin_features
[i
].exten
);
1972 ast_rwlock_unlock(&features_lock
);
1975 ast_cli(fd
, format
, "Dynamic Feature", "Default", "Current");
1976 ast_cli(fd
, format
, "---------------", "-------", "-------");
1977 if (AST_LIST_EMPTY(&feature_list
))
1978 ast_cli(fd
, "(none)\n");
1980 AST_LIST_LOCK(&feature_list
);
1981 AST_LIST_TRAVERSE(&feature_list
, feature
, feature_entry
)
1982 ast_cli(fd
, format
, feature
->sname
, "no def", feature
->exten
);
1983 AST_LIST_UNLOCK(&feature_list
);
1985 ast_cli(fd
, "\nCall parking\n");
1986 ast_cli(fd
, "------------\n");
1987 ast_cli(fd
,"%-20s: %s\n", "Parking extension", parking_ext
);
1988 ast_cli(fd
,"%-20s: %s\n", "Parking context", parking_con
);
1989 ast_cli(fd
,"%-20s: %d-%d\n", "Parked call extensions", parking_start
, parking_stop
);
1992 return RESULT_SUCCESS
;
1995 static char showfeatures_help
[] =
1996 "Usage: feature list\n"
1997 " Lists currently configured features.\n";
1999 static int handle_parkedcalls(int fd
, int argc
, char *argv
[])
2001 struct parkeduser
*cur
;
2004 ast_cli(fd
, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
2005 , "Context", "Extension", "Pri", "Timeout");
2007 ast_mutex_lock(&parking_lock
);
2009 for (cur
= parkinglot
; cur
; cur
= cur
->next
) {
2010 ast_cli(fd
, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n"
2011 ,cur
->parkingexten
, cur
->chan
->name
, cur
->context
, cur
->exten
2012 ,cur
->priority
, cur
->start
.tv_sec
+ (cur
->parkingtime
/1000) - time(NULL
));
2016 ast_mutex_unlock(&parking_lock
);
2017 ast_cli(fd
, "%d parked call%s.\n", numparked
, (numparked
!= 1) ? "s" : "");
2020 return RESULT_SUCCESS
;
2023 static char showparked_help
[] =
2024 "Usage: show parkedcalls\n"
2025 " Lists currently parked calls.\n";
2027 static struct ast_cli_entry cli_show_features_deprecated
= {
2028 { "show", "features", NULL
},
2029 handle_showfeatures
, NULL
,
2032 static struct ast_cli_entry cli_features
[] = {
2033 { { "feature", "show", NULL
},
2034 handle_showfeatures
, "Lists configured features",
2035 showfeatures_help
, NULL
, &cli_show_features_deprecated
},
2037 { { "show", "parkedcalls", NULL
},
2038 handle_parkedcalls
, "Lists parked calls",
2042 /*! \brief Dump lot status */
2043 static int manager_parking_status( struct mansession
*s
, const struct message
*m
)
2045 struct parkeduser
*cur
;
2046 const char *id
= astman_get_header(m
, "ActionID");
2047 char idText
[256] = "";
2049 if (!ast_strlen_zero(id
))
2050 snprintf(idText
, sizeof(idText
), "ActionID: %s\r\n", id
);
2052 astman_send_ack(s
, m
, "Parked calls will follow");
2054 ast_mutex_lock(&parking_lock
);
2056 for (cur
= parkinglot
; cur
; cur
= cur
->next
) {
2057 astman_append(s
, "Event: ParkedCall\r\n"
2063 "CallerIDName: %s\r\n"
2066 cur
->parkingnum
, cur
->chan
->name
, cur
->peername
,
2067 (long) cur
->start
.tv_sec
+ (long) (cur
->parkingtime
/ 1000) - (long) time(NULL
),
2068 S_OR(cur
->chan
->cid
.cid_num
, ""), /* XXX in other places it is <unknown> */
2069 S_OR(cur
->chan
->cid
.cid_name
, ""),
2074 "Event: ParkedCallsComplete\r\n"
2078 ast_mutex_unlock(&parking_lock
);
2080 return RESULT_SUCCESS
;
2083 static char mandescr_park
[] =
2084 "Description: Park a channel.\n"
2085 "Variables: (Names marked with * are required)\n"
2086 " *Channel: Channel name to park\n"
2087 " *Channel2: Channel to announce park info to (and return to if timeout)\n"
2088 " Timeout: Number of milliseconds to wait before callback.\n";
2090 static int manager_park(struct mansession
*s
, const struct message
*m
)
2092 const char *channel
= astman_get_header(m
, "Channel");
2093 const char *channel2
= astman_get_header(m
, "Channel2");
2094 const char *timeout
= astman_get_header(m
, "Timeout");
2099 struct ast_channel
*ch1
, *ch2
;
2101 if (ast_strlen_zero(channel
)) {
2102 astman_send_error(s
, m
, "Channel not specified");
2106 if (ast_strlen_zero(channel2
)) {
2107 astman_send_error(s
, m
, "Channel2 not specified");
2111 ch1
= ast_get_channel_by_name_locked(channel
);
2113 snprintf(buf
, sizeof(buf
), "Channel does not exist: %s", channel
);
2114 astman_send_error(s
, m
, buf
);
2118 ch2
= ast_get_channel_by_name_locked(channel2
);
2120 snprintf(buf
, sizeof(buf
), "Channel does not exist: %s", channel2
);
2121 astman_send_error(s
, m
, buf
);
2122 ast_channel_unlock(ch1
);
2126 if (!ast_strlen_zero(timeout
)) {
2127 sscanf(timeout
, "%d", &to
);
2130 res
= ast_masq_park_call(ch1
, ch2
, to
, &parkExt
);
2132 ast_softhangup(ch2
, AST_SOFTHANGUP_EXPLICIT
);
2133 astman_send_ack(s
, m
, "Park successful");
2135 astman_send_error(s
, m
, "Park failure");
2138 ast_channel_unlock(ch1
);
2139 ast_channel_unlock(ch2
);
2145 int ast_pickup_call(struct ast_channel
*chan
)
2147 struct ast_channel
*cur
= NULL
;
2150 while ( (cur
= ast_channel_walk_locked(cur
)) != NULL
) {
2153 (chan
->pickupgroup
& cur
->callgroup
) &&
2154 ((cur
->_state
== AST_STATE_RINGING
) ||
2155 (cur
->_state
== AST_STATE_RING
))) {
2158 ast_channel_unlock(cur
);
2162 ast_log(LOG_DEBUG
, "Call pickup on chan '%s' by '%s'\n",cur
->name
, chan
->name
);
2163 res
= ast_answer(chan
);
2165 ast_log(LOG_WARNING
, "Unable to answer '%s'\n", chan
->name
);
2166 res
= ast_queue_control(chan
, AST_CONTROL_ANSWER
);
2168 ast_log(LOG_WARNING
, "Unable to queue answer on '%s'\n", chan
->name
);
2169 res
= ast_channel_masquerade(cur
, chan
);
2171 ast_log(LOG_WARNING
, "Unable to masquerade '%s' into '%s'\n", chan
->name
, cur
->name
); /* Done */
2172 ast_channel_unlock(cur
);
2175 ast_log(LOG_DEBUG
, "No call pickup possible...\n");
2180 /*! \brief Add parking hints for all defined parking lots */
2181 static void park_add_hints(char *context
, int start
, int stop
)
2184 char device
[AST_MAX_EXTENSION
];
2187 for (numext
= start
; numext
<= stop
; numext
++) {
2188 snprintf(exten
, sizeof(exten
), "%d", numext
);
2189 snprintf(device
, sizeof(device
), "park:%s@%s", exten
, context
);
2190 ast_add_extension(context
, 1, exten
, PRIORITY_HINT
, NULL
, NULL
, device
, NULL
, NULL
, registrar
);
2195 static int load_config(void)
2197 int start
= 0, end
= 0;
2199 struct ast_context
*con
= NULL
;
2200 struct ast_config
*cfg
= NULL
;
2201 struct ast_variable
*var
= NULL
;
2202 char old_parking_ext
[AST_MAX_EXTENSION
];
2203 char old_parking_con
[AST_MAX_EXTENSION
] = "";
2205 if (!ast_strlen_zero(parking_con
)) {
2206 strcpy(old_parking_ext
, parking_ext
);
2207 strcpy(old_parking_con
, parking_con
);
2210 /* Reset to defaults */
2211 strcpy(parking_con
, "parkedcalls");
2212 strcpy(parking_con_dial
, "park-dial");
2213 strcpy(parking_ext
, "700");
2214 strcpy(pickup_ext
, "*8");
2215 strcpy(parkmohclass
, "default");
2216 courtesytone
[0] = '\0';
2217 strcpy(xfersound
, "beep");
2218 strcpy(xferfailsound
, "pbx-invalid");
2219 parking_start
= 701;
2225 transferdigittimeout
= DEFAULT_TRANSFER_DIGIT_TIMEOUT
;
2226 featuredigittimeout
= DEFAULT_FEATURE_DIGIT_TIMEOUT
;
2227 atxfernoanswertimeout
= DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER
;
2229 cfg
= ast_config_load("features.conf");
2231 ast_log(LOG_WARNING
,"Could not load features.conf\n");
2232 return AST_MODULE_LOAD_DECLINE
;
2234 for (var
= ast_variable_browse(cfg
, "general"); var
; var
= var
->next
) {
2235 if (!strcasecmp(var
->name
, "parkext")) {
2236 ast_copy_string(parking_ext
, var
->value
, sizeof(parking_ext
));
2237 } else if (!strcasecmp(var
->name
, "context")) {
2238 ast_copy_string(parking_con
, var
->value
, sizeof(parking_con
));
2239 } else if (!strcasecmp(var
->name
, "parkingtime")) {
2240 if ((sscanf(var
->value
, "%d", &parkingtime
) != 1) || (parkingtime
< 1)) {
2241 ast_log(LOG_WARNING
, "%s is not a valid parkingtime\n", var
->value
);
2242 parkingtime
= DEFAULT_PARK_TIME
;
2244 parkingtime
= parkingtime
* 1000;
2245 } else if (!strcasecmp(var
->name
, "parkpos")) {
2246 if (sscanf(var
->value
, "%d-%d", &start
, &end
) != 2) {
2247 ast_log(LOG_WARNING
, "Format for parking positions is a-b, where a and b are numbers at line %d of parking.conf\n", var
->lineno
);
2249 parking_start
= start
;
2252 } else if (!strcasecmp(var
->name
, "findslot")) {
2253 parkfindnext
= (!strcasecmp(var
->value
, "next"));
2254 } else if (!strcasecmp(var
->name
, "parkinghints")) {
2255 parkaddhints
= ast_true(var
->value
);
2256 } else if (!strcasecmp(var
->name
, "adsipark")) {
2257 adsipark
= ast_true(var
->value
);
2258 } else if (!strcasecmp(var
->name
, "transferdigittimeout")) {
2259 if ((sscanf(var
->value
, "%d", &transferdigittimeout
) != 1) || (transferdigittimeout
< 1)) {
2260 ast_log(LOG_WARNING
, "%s is not a valid transferdigittimeout\n", var
->value
);
2261 transferdigittimeout
= DEFAULT_TRANSFER_DIGIT_TIMEOUT
;
2263 transferdigittimeout
= transferdigittimeout
* 1000;
2264 } else if (!strcasecmp(var
->name
, "featuredigittimeout")) {
2265 if ((sscanf(var
->value
, "%d", &featuredigittimeout
) != 1) || (featuredigittimeout
< 1)) {
2266 ast_log(LOG_WARNING
, "%s is not a valid featuredigittimeout\n", var
->value
);
2267 featuredigittimeout
= DEFAULT_FEATURE_DIGIT_TIMEOUT
;
2269 } else if (!strcasecmp(var
->name
, "atxfernoanswertimeout")) {
2270 if ((sscanf(var
->value
, "%d", &atxfernoanswertimeout
) != 1) || (atxfernoanswertimeout
< 1)) {
2271 ast_log(LOG_WARNING
, "%s is not a valid atxfernoanswertimeout\n", var
->value
);
2272 atxfernoanswertimeout
= DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER
;
2274 atxfernoanswertimeout
= atxfernoanswertimeout
* 1000;
2275 } else if (!strcasecmp(var
->name
, "courtesytone")) {
2276 ast_copy_string(courtesytone
, var
->value
, sizeof(courtesytone
));
2277 } else if (!strcasecmp(var
->name
, "parkedplay")) {
2278 if (!strcasecmp(var
->value
, "both"))
2280 else if (!strcasecmp(var
->value
, "parked"))
2284 } else if (!strcasecmp(var
->name
, "xfersound")) {
2285 ast_copy_string(xfersound
, var
->value
, sizeof(xfersound
));
2286 } else if (!strcasecmp(var
->name
, "xferfailsound")) {
2287 ast_copy_string(xferfailsound
, var
->value
, sizeof(xferfailsound
));
2288 } else if (!strcasecmp(var
->name
, "pickupexten")) {
2289 ast_copy_string(pickup_ext
, var
->value
, sizeof(pickup_ext
));
2290 } else if (!strcasecmp(var
->name
, "parkedmusicclass")) {
2291 ast_copy_string(parkmohclass
, var
->value
, sizeof(parkmohclass
));
2296 for (var
= ast_variable_browse(cfg
, "featuremap"); var
; var
= var
->next
) {
2297 if (remap_feature(var
->name
, var
->value
))
2298 ast_log(LOG_NOTICE
, "Unknown feature '%s'\n", var
->name
);
2301 /* Map a key combination to an application*/
2302 ast_unregister_features();
2303 for (var
= ast_variable_browse(cfg
, "applicationmap"); var
; var
= var
->next
) {
2304 char *tmp_val
= ast_strdupa(var
->value
);
2305 char *exten
, *activateon
, *activatedby
, *app
, *app_args
, *moh_class
;
2306 struct ast_call_feature
*feature
;
2308 /* strsep() sets the argument to NULL if match not found, and it
2309 * is safe to use it with a NULL argument, so we don't check
2312 exten
= strsep(&tmp_val
,",");
2313 activatedby
= strsep(&tmp_val
,",");
2314 app
= strsep(&tmp_val
,",");
2315 app_args
= strsep(&tmp_val
,",");
2316 moh_class
= strsep(&tmp_val
,",");
2318 activateon
= strsep(&activatedby
, "/");
2320 /*! \todo XXX var_name or app_args ? */
2321 if (ast_strlen_zero(app
) || ast_strlen_zero(exten
) || ast_strlen_zero(activateon
) || ast_strlen_zero(var
->name
)) {
2322 ast_log(LOG_NOTICE
, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",
2323 app
, exten
, activateon
, var
->name
);
2327 AST_LIST_LOCK(&feature_list
);
2328 if ((feature
= find_dynamic_feature(var
->name
))) {
2329 AST_LIST_UNLOCK(&feature_list
);
2330 ast_log(LOG_WARNING
, "Dynamic Feature '%s' specified more than once!\n", var
->name
);
2333 AST_LIST_UNLOCK(&feature_list
);
2335 if (!(feature
= ast_calloc(1, sizeof(*feature
))))
2338 ast_copy_string(feature
->sname
, var
->name
, FEATURE_SNAME_LEN
);
2339 ast_copy_string(feature
->app
, app
, FEATURE_APP_LEN
);
2340 ast_copy_string(feature
->exten
, exten
, FEATURE_EXTEN_LEN
);
2343 ast_copy_string(feature
->app_args
, app_args
, FEATURE_APP_ARGS_LEN
);
2346 ast_copy_string(feature
->moh_class
, moh_class
, FEATURE_MOH_LEN
);
2348 ast_copy_string(feature
->exten
, exten
, sizeof(feature
->exten
));
2349 feature
->operation
= feature_exec_app
;
2350 ast_set_flag(feature
, AST_FEATURE_FLAG_NEEDSDTMF
);
2352 /* Allow caller and calle to be specified for backwards compatability */
2353 if (!strcasecmp(activateon
, "self") || !strcasecmp(activateon
, "caller"))
2354 ast_set_flag(feature
, AST_FEATURE_FLAG_ONSELF
);
2355 else if (!strcasecmp(activateon
, "peer") || !strcasecmp(activateon
, "callee"))
2356 ast_set_flag(feature
, AST_FEATURE_FLAG_ONPEER
);
2358 ast_log(LOG_NOTICE
, "Invalid 'ActivateOn' specification for feature '%s',"
2359 " must be 'self', or 'peer'\n", var
->name
);
2363 if (ast_strlen_zero(activatedby
))
2364 ast_set_flag(feature
, AST_FEATURE_FLAG_BYBOTH
);
2365 else if (!strcasecmp(activatedby
, "caller"))
2366 ast_set_flag(feature
, AST_FEATURE_FLAG_BYCALLER
);
2367 else if (!strcasecmp(activatedby
, "callee"))
2368 ast_set_flag(feature
, AST_FEATURE_FLAG_BYCALLEE
);
2369 else if (!strcasecmp(activatedby
, "both"))
2370 ast_set_flag(feature
, AST_FEATURE_FLAG_BYBOTH
);
2372 ast_log(LOG_NOTICE
, "Invalid 'ActivatedBy' specification for feature '%s',"
2373 " must be 'caller', or 'callee', or 'both'\n", var
->name
);
2377 ast_register_feature(feature
);
2379 if (option_verbose
>= 1)
2380 ast_verbose(VERBOSE_PREFIX_2
"Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var
->name
, app
, app_args
, exten
);
2382 ast_config_destroy(cfg
);
2384 /* Remove the old parking extension */
2385 if (!ast_strlen_zero(old_parking_con
) && (con
= ast_context_find(old_parking_con
))) {
2386 if(ast_context_remove_extension2(con
, old_parking_ext
, 1, registrar
))
2387 notify_metermaids(old_parking_ext
, old_parking_con
);
2389 ast_log(LOG_DEBUG
, "Removed old parking extension %s@%s\n", old_parking_ext
, old_parking_con
);
2392 if (!(con
= ast_context_find(parking_con
)) && !(con
= ast_context_create(NULL
, parking_con
, registrar
))) {
2393 ast_log(LOG_ERROR
, "Parking context '%s' does not exist and unable to create\n", parking_con
);
2396 res
= ast_add_extension2(con
, 1, ast_parking_ext(), 1, NULL
, NULL
, parkcall
, NULL
, NULL
, registrar
);
2398 park_add_hints(parking_con
, parking_start
, parking_stop
);
2400 notify_metermaids(ast_parking_ext(), parking_con
);
2405 static int reload(void)
2407 return load_config();
2410 static int load_module(void)
2414 memset(parking_ext
, 0, sizeof(parking_ext
));
2415 memset(parking_con
, 0, sizeof(parking_con
));
2417 if ((res
= load_config()))
2419 ast_cli_register_multiple(cli_features
, sizeof(cli_features
) / sizeof(struct ast_cli_entry
));
2420 ast_pthread_create(&parking_thread
, NULL
, do_parking_thread
, NULL
);
2421 res
= ast_register_application(parkedcall
, park_exec
, synopsis
, descrip
);
2423 res
= ast_register_application(parkcall
, park_call_exec
, synopsis2
, descrip2
);
2425 ast_manager_register("ParkedCalls", 0, manager_parking_status
, "List parked calls" );
2426 ast_manager_register2("Park", EVENT_FLAG_CALL
, manager_park
,
2427 "Park a channel", mandescr_park
);
2430 res
|= ast_devstate_prov_add("Park", metermaidstate
);
2436 static int unload_module(void)
2438 ast_module_user_hangup_all();
2440 ast_manager_unregister("ParkedCalls");
2441 ast_manager_unregister("Park");
2442 ast_cli_unregister_multiple(cli_features
, sizeof(cli_features
) / sizeof(struct ast_cli_entry
));
2443 ast_unregister_application(parkcall
);
2444 ast_devstate_prov_del("Park");
2445 return ast_unregister_application(parkedcall
);
2448 AST_MODULE_INFO(ASTERISK_GPL_KEY
, AST_MODFLAG_GLOBAL_SYMBOLS
, "Call Features Resource",
2449 .load
= load_module
,
2450 .unload
= unload_module
,