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>
27 <depend>chan_local</depend>
32 ASTERISK_FILE_VERSION(__FILE__
, "$Revision$")
42 #include <sys/signal.h>
43 #include <netinet/in.h>
45 #include "asterisk/lock.h"
46 #include "asterisk/file.h"
47 #include "asterisk/logger.h"
48 #include "asterisk/channel.h"
49 #include "asterisk/pbx.h"
50 #include "asterisk/options.h"
51 #include "asterisk/causes.h"
52 #include "asterisk/module.h"
53 #include "asterisk/translate.h"
54 #include "asterisk/app.h"
55 #include "asterisk/say.h"
56 #include "asterisk/features.h"
57 #include "asterisk/musiconhold.h"
58 #include "asterisk/config.h"
59 #include "asterisk/cli.h"
60 #include "asterisk/manager.h"
61 #include "asterisk/utils.h"
62 #include "asterisk/adsi.h"
63 #include "asterisk/devicestate.h"
64 #include "asterisk/monitor.h"
65 #include "asterisk/global_datastores.h"
67 #define DEFAULT_PARK_TIME 45000
68 #define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000
69 #define DEFAULT_FEATURE_DIGIT_TIMEOUT 500
70 #define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000
72 /*! size of the uniqueid field
74 * \todo Originally bristuff defines this one in channel.h but only uses it here.
76 #define AST_MAX_UNIQUEID 64
78 #define AST_MAX_WATCHERS 256
81 AST_FEATURE_FLAG_NEEDSDTMF
= (1 << 0),
82 AST_FEATURE_FLAG_ONPEER
= (1 << 1),
83 AST_FEATURE_FLAG_ONSELF
= (1 << 2),
84 AST_FEATURE_FLAG_BYCALLEE
= (1 << 3),
85 AST_FEATURE_FLAG_BYCALLER
= (1 << 4),
86 AST_FEATURE_FLAG_BYBOTH
= (3 << 3),
89 static char *parkedcall
= "ParkedCall";
90 static char *holdedcall
= "HoldedCall";
92 static int parkaddhints
= 0; /*!< Add parking hints automatically */
93 static int parkingtime
= DEFAULT_PARK_TIME
; /*!< No more than 45 seconds parked before you do something with them */
94 static char parking_con
[AST_MAX_EXTENSION
]; /*!< Context for which parking is made accessible */
95 static char parking_con_dial
[AST_MAX_EXTENSION
]; /*!< Context for dialback for parking (KLUDGE) */
96 static char parking_ext
[AST_MAX_EXTENSION
]; /*!< Extension you type to park the call */
97 static char pickup_ext
[AST_MAX_EXTENSION
]; /*!< Call pickup extension */
98 static char parkmohclass
[MAX_MUSICCLASS
]; /*!< Music class used for parking */
99 static int parking_start
; /*!< First available extension for parking */
100 static int parking_stop
; /*!< Last available extension for parking */
102 static char courtesytone
[256]; /*!< Courtesy tone */
103 static int parkedplay
= 0; /*!< Who to play the courtesy tone to */
104 static char xfersound
[256]; /*!< Call transfer sound */
105 static char xferfailsound
[256]; /*!< Call transfer failure sound */
107 static int parking_offset
;
108 static int parkfindnext
;
112 static int transferdigittimeout
;
113 static int featuredigittimeout
;
115 static int atxfernoanswertimeout
;
117 static char *registrar
= "res_features"; /*!< Registrar for operations */
119 /* module and CLI command definitions */
120 static char *synopsis
= "Answer a parked call";
122 static char *descrip
= "ParkedCall(exten):"
123 "Used to connect to a parked call. This application is always\n"
124 "registered internally and does not need to be explicitly added\n"
125 "into the dialplan, although you should include the 'parkedcalls'\n"
128 static char *parkcall
= "Park";
130 static char *synopsis2
= "Park yourself";
132 static char *descrip2
= "Park():"
133 "Used to park yourself (typically in combination with a supervised\n"
134 "transfer to know the parking space). This application is always\n"
135 "registered internally and does not need to be explicitly added\n"
136 "into the dialplan, although you should include the 'parkedcalls'\n"
137 "context (or the context specified in features.conf).\n\n"
138 "If you set the PARKINGEXTEN variable to an extension in your\n"
139 "parking context, park() will park the call on that extension, unless\n"
140 "it already exists. In that case, execution will continue at next\n"
143 static struct ast_app
*monitor_app
= NULL
;
144 static int monitor_ok
= 1;
147 struct ast_channel
*chan
; /*!< Parking channel */
148 struct timeval start
; /*!< Time the parking started */
149 int parkingnum
; /*!< Parking lot */
150 char parkingexten
[AST_MAX_EXTENSION
]; /*!< If set beforehand, parking extension used for this call */
151 char context
[AST_MAX_CONTEXT
]; /*!< Where to go if our parking time expires */
152 char exten
[AST_MAX_EXTENSION
];
154 int parkingtime
; /*!< Maximum length in parking lot before return */
157 unsigned char moh_trys
;
158 struct parkeduser
*next
;
162 struct ast_channel
*chan
;
163 struct timeval start
;
167 /* Where to go if our parking time expires */
168 char context
[AST_MAX_EXTENSION
];
169 char exten
[AST_MAX_EXTENSION
];
172 char uniqueid
[AST_MAX_UNIQUEID
];
173 char uniqueidpeer
[AST_MAX_UNIQUEID
];
174 struct holdeduser
*next
;
177 static struct parkeduser
*parkinglot
;
179 static struct holdeduser
*holdlist
;
181 AST_MUTEX_DEFINE_STATIC(parking_lock
); /*!< protects all static variables above */
183 AST_MUTEX_DEFINE_STATIC(holding_lock
);
185 static pthread_t parking_thread
;
187 static pthread_t holding_thread
;
189 char *ast_parking_ext(void)
194 char *ast_pickup_ext(void)
199 struct ast_bridge_thread_obj
201 struct ast_bridge_config bconfig
;
202 struct ast_channel
*chan
;
203 struct ast_channel
*peer
;
208 /*! \brief store context, priority and extension */
209 static void set_c_e_p(struct ast_channel
*chan
, const char *context
, const char *ext
, int pri
)
211 ast_copy_string(chan
->context
, context
, sizeof(chan
->context
));
212 ast_copy_string(chan
->exten
, ext
, sizeof(chan
->exten
));
213 chan
->priority
= pri
;
216 static void check_goto_on_transfer(struct ast_channel
*chan
)
218 struct ast_channel
*xferchan
;
219 const char *val
= pbx_builtin_getvar_helper(chan
, "GOTO_ON_BLINDXFR");
220 char *x
, *goto_on_transfer
;
223 if (ast_strlen_zero(val
))
226 goto_on_transfer
= ast_strdupa(val
);
228 if (!(xferchan
= ast_channel_alloc(0, AST_STATE_DOWN
, 0, 0, "", "", "", 0, chan
->name
)))
231 for (x
= goto_on_transfer
; x
&& *x
; x
++) {
235 /* Make formats okay */
236 xferchan
->readformat
= chan
->readformat
;
237 xferchan
->writeformat
= chan
->writeformat
;
238 ast_channel_masquerade(xferchan
, chan
);
239 ast_parseable_goto(xferchan
, goto_on_transfer
);
240 xferchan
->_state
= AST_STATE_UP
;
241 ast_clear_flag(xferchan
, AST_FLAGS_ALL
);
242 xferchan
->_softhangup
= 0;
243 if ((f
= ast_read(xferchan
))) {
246 ast_pbx_start(xferchan
);
248 ast_hangup(xferchan
);
252 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
, const char *language
);
255 static void *ast_bridge_call_thread(void *data
)
257 struct ast_bridge_thread_obj
*tobj
= data
;
259 tobj
->chan
->appl
= "Transferred Call";
260 tobj
->chan
->data
= tobj
->peer
->name
;
261 tobj
->peer
->appl
= "Transferred Call";
262 tobj
->peer
->data
= tobj
->chan
->name
;
264 ast_bridge_call(tobj
->peer
, tobj
->chan
, &tobj
->bconfig
);
265 ast_hangup(tobj
->chan
);
266 ast_hangup(tobj
->peer
);
267 bzero(tobj
, sizeof(*tobj
)); /*! \todo XXX for safety */
272 static void ast_bridge_call_thread_launch(void *data
)
276 struct sched_param sched
;
278 pthread_attr_init(&attr
);
279 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
280 ast_pthread_create(&thread
, &attr
,ast_bridge_call_thread
, data
);
281 pthread_attr_destroy(&attr
);
282 memset(&sched
, 0, sizeof(sched
));
283 pthread_setschedparam(thread
, SCHED_RR
, &sched
);
286 static int adsi_announce_park(struct ast_channel
*chan
, char *parkingexten
)
289 int justify
[5] = {ADSI_JUST_CENT
, ADSI_JUST_CENT
, ADSI_JUST_CENT
, ADSI_JUST_CENT
};
291 char *message
[5] = {NULL
, NULL
, NULL
, NULL
, NULL
};
293 snprintf(tmp
, sizeof(tmp
), "Parked on %s", parkingexten
);
295 res
= ast_adsi_load_session(chan
, NULL
, 0, 1);
298 return ast_adsi_print(chan
, message
, justify
, 1);
301 /*! \brief Notify metermaids that we've changed an extension */
302 static void notify_metermaids(char *exten
, char *context
)
304 if (option_debug
> 3)
305 ast_log(LOG_DEBUG
, "Notification of state change to metermaids %s@%s\n", exten
, context
);
307 /* Send notification to devicestate subsystem */
308 ast_device_state_changed("park:%s@%s", exten
, context
);
312 /*! \brief metermaids callback from devicestate.c */
313 static int metermaidstate(const char *data
)
315 int res
= AST_DEVICE_INVALID
;
316 char *context
= ast_strdupa(data
);
319 exten
= strsep(&context
, "@");
323 if (option_debug
> 3)
324 ast_log(LOG_DEBUG
, "Checking state of exten %s in context %s\n", exten
, context
);
326 res
= ast_exists_extension(NULL
, context
, exten
, 1, NULL
);
329 return AST_DEVICE_NOT_INUSE
;
331 return AST_DEVICE_INUSE
;
334 static int park_call_full(struct ast_channel
*chan
, struct ast_channel
*peer
, int timeout
, int *extout
, char *orig_chan_name
)
336 struct parkeduser
*pu
, *cur
;
337 int i
, x
= -1, parking_range
;
338 struct ast_context
*con
;
339 const char *parkingexten
;
341 /* Allocate memory for parking data */
342 if (!(pu
= ast_calloc(1, sizeof(*pu
))))
345 /* Lock parking lot */
346 ast_mutex_lock(&parking_lock
);
347 /* Check for channel variable PARKINGEXTEN */
348 parkingexten
= pbx_builtin_getvar_helper(chan
, "PARKINGEXTEN");
349 if (!ast_strlen_zero(parkingexten
)) {
350 /*!\note The API forces us to specify a numeric parking slot, even
351 * though the architecture would tend to support non-numeric extensions
352 * (as are possible with SIP, for example). Hence, we enforce that
353 * limitation here. If extout was not numeric, we could permit
354 * arbitrary non-numeric extensions.
356 if (sscanf(parkingexten
, "%d", &x
) != 1 || x
< 0) {
357 ast_log(LOG_WARNING
, "PARKINGEXTEN does not indicate a valid parking slot: '%s'.\n", parkingexten
);
358 ast_mutex_unlock(&parking_lock
);
360 return 1; /* Continue execution if possible */
362 snprintf(pu
->parkingexten
, sizeof(pu
->parkingexten
), "%d", x
);
364 if (ast_exists_extension(NULL
, parking_con
, pu
->parkingexten
, 1, NULL
)) {
365 ast_mutex_unlock(&parking_lock
);
367 ast_log(LOG_WARNING
, "Requested parking extension already exists: %s@%s\n", parkingexten
, parking_con
);
368 return 1; /* Continue execution if possible */
371 /* Select parking space within range */
372 parking_range
= parking_stop
- parking_start
+1;
373 for (i
= 0; i
< parking_range
; i
++) {
374 x
= (i
+ parking_offset
) % parking_range
+ parking_start
;
377 if (cur
->parkingnum
== x
)
385 if (!(i
< parking_range
)) {
386 ast_log(LOG_WARNING
, "No more parking spaces\n");
388 ast_mutex_unlock(&parking_lock
);
391 /* Set pointer for next parking */
393 parking_offset
= x
- parking_start
+ 1;
394 snprintf(pu
->parkingexten
, sizeof(pu
->parkingexten
), "%d", x
);
397 chan
->appl
= "Parked Call";
402 /* Put the parked channel on hold if we have two different channels */
404 ast_indicate_data(pu
->chan
, AST_CONTROL_HOLD
,
405 S_OR(parkmohclass
, NULL
),
406 !ast_strlen_zero(parkmohclass
) ? strlen(parkmohclass
) + 1 : 0);
409 pu
->start
= ast_tvnow();
411 pu
->parkingtime
= (timeout
> 0) ? timeout
: parkingtime
;
416 /* This is so ugly that it hurts, but implementing get_base_channel() on local channels
417 could have ugly side effects. We could have transferer<->local,1<->local,2<->parking
418 and we need the callback name to be that of transferer. Since local,1/2 have the same
419 name we can be tricky and just grab the bridged channel from the other side of the local
421 if (!strcasecmp(peer
->tech
->type
, "Local")) {
422 struct ast_channel
*tmpchan
, *base_peer
;
423 char other_side
[AST_CHANNEL_NAME
];
425 ast_copy_string(other_side
, peer
->name
, sizeof(other_side
));
426 if ((c
= strrchr(other_side
, ','))) {
429 if ((tmpchan
= ast_get_channel_by_name_locked(other_side
))) {
430 if ((base_peer
= ast_bridged_channel(tmpchan
))) {
431 ast_copy_string(pu
->peername
, base_peer
->name
, sizeof(pu
->peername
));
433 ast_channel_unlock(tmpchan
);
436 ast_copy_string(pu
->peername
, peer
->name
, sizeof(pu
->peername
));
440 /* Remember what had been dialed, so that if the parking
441 expires, we try to come back to the same place */
442 ast_copy_string(pu
->context
, S_OR(chan
->macrocontext
, chan
->context
), sizeof(pu
->context
));
443 ast_copy_string(pu
->exten
, S_OR(chan
->macroexten
, chan
->exten
), sizeof(pu
->exten
));
444 pu
->priority
= chan
->macropriority
? chan
->macropriority
: chan
->priority
;
445 pu
->next
= parkinglot
;
448 /* If parking a channel directly, don't quiet yet get parking running on it */
451 ast_mutex_unlock(&parking_lock
);
452 /* Wake up the (presumably select()ing) thread */
453 pthread_kill(parking_thread
, SIGURG
);
454 if (option_verbose
> 1)
455 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));
457 manager_event(EVENT_FLAG_CALL
, "ParkedCall",
463 "CallerIDName: %s\r\n",
464 pu
->parkingexten
, pu
->chan
->name
, peer
? peer
->name
: "",
465 (long)pu
->start
.tv_sec
+ (long)(pu
->parkingtime
/1000) - (long)time(NULL
),
466 S_OR(pu
->chan
->cid
.cid_num
, "<unknown>"),
467 S_OR(pu
->chan
->cid
.cid_name
, "<unknown>")
470 if (peer
&& adsipark
&& ast_adsi_available(peer
)) {
471 adsi_announce_park(peer
, pu
->parkingexten
); /* Only supports parking numbers */
472 ast_adsi_unload_session(peer
);
475 con
= ast_context_find(parking_con
);
477 con
= ast_context_create(NULL
, parking_con
, registrar
);
478 if (!con
) /* Still no context? Bad */
479 ast_log(LOG_ERROR
, "Parking context '%s' does not exist and unable to create\n", parking_con
);
480 /* Tell the peer channel the number of the parking space */
481 if (peer
&& (ast_strlen_zero(orig_chan_name
) || !strcasecmp(peer
->name
, orig_chan_name
))) { /* Only say number if it's a number and the channel hasn't been masqueraded away */
482 /* Make sure we don't start saying digits to the channel being parked */
483 ast_set_flag(peer
, AST_FLAG_MASQ_NOSTREAM
);
484 ast_say_digits(peer
, pu
->parkingnum
, "", peer
->language
);
485 ast_clear_flag(peer
, AST_FLAG_MASQ_NOSTREAM
);
488 if (!ast_add_extension2(con
, 1, pu
->parkingexten
, 1, NULL
, NULL
, parkedcall
, strdup(pu
->parkingexten
), ast_free
, registrar
))
489 notify_metermaids(pu
->parkingexten
, parking_con
);
491 if (pu
->notquiteyet
) {
492 /* Wake up parking thread if we're really done */
493 ast_indicate_data(pu
->chan
, AST_CONTROL_HOLD
,
494 S_OR(parkmohclass
, NULL
),
495 !ast_strlen_zero(parkmohclass
) ? strlen(parkmohclass
) + 1 : 0);
497 pthread_kill(parking_thread
, SIGURG
);
502 /*! \brief Park a call
503 \note We put the user in the parking list, then wake up the parking thread to be sure it looks
504 after these channels too */
505 int ast_park_call(struct ast_channel
*chan
, struct ast_channel
*peer
, int timeout
, int *extout
)
507 return park_call_full(chan
, peer
, timeout
, extout
, NULL
);
510 int ast_masq_park_call(struct ast_channel
*rchan
, struct ast_channel
*peer
, int timeout
, int *extout
)
512 struct ast_channel
*chan
;
514 char *orig_chan_name
= NULL
;
517 /* Make a new, fake channel that we'll use to masquerade in the real one */
518 if (!(chan
= ast_channel_alloc(0, AST_STATE_DOWN
, 0, 0, rchan
->accountcode
, rchan
->exten
, rchan
->context
, rchan
->amaflags
, "Parked/%s",rchan
->name
))) {
519 ast_log(LOG_WARNING
, "Unable to create parked channel\n");
523 /* Make formats okay */
524 chan
->readformat
= rchan
->readformat
;
525 chan
->writeformat
= rchan
->writeformat
;
526 ast_channel_masquerade(chan
, rchan
);
528 /* Setup the extensions and such */
529 set_c_e_p(chan
, rchan
->context
, rchan
->exten
, rchan
->priority
);
531 /* Make the masq execute */
536 orig_chan_name
= ast_strdupa(chan
->name
);
538 park_status
= park_call_full(chan
, peer
, timeout
, extout
, orig_chan_name
);
539 if (park_status
== 1) {
540 /* would be nice to play: "invalid parking extension" */
549 #define FEATURE_RETURN_HANGUP -1
550 #define FEATURE_RETURN_SUCCESSBREAK 0
551 #define FEATURE_RETURN_PBX_KEEPALIVE AST_PBX_KEEPALIVE
552 #define FEATURE_RETURN_NO_HANGUP_PEER AST_PBX_NO_HANGUP_PEER
553 #define FEATURE_RETURN_PASSDIGITS 21
554 #define FEATURE_RETURN_STOREDIGITS 22
555 #define FEATURE_RETURN_SUCCESS 23
556 #define FEATURE_RETURN_KEEPTRYING 24
558 #define FEATURE_SENSE_CHAN (1 << 0)
559 #define FEATURE_SENSE_PEER (1 << 1)
562 * set caller and callee according to the direction
564 static void set_peers(struct ast_channel
**caller
, struct ast_channel
**callee
,
565 struct ast_channel
*peer
, struct ast_channel
*chan
, int sense
)
567 if (sense
== FEATURE_SENSE_PEER
) {
576 /*! \brief support routing for one touch call parking */
577 static int builtin_parkcall(struct ast_channel
*chan
, struct ast_channel
*peer
, struct ast_bridge_config
*config
, char *code
, int sense
, void *data
)
579 struct ast_channel
*parker
;
580 struct ast_channel
*parkee
;
582 struct ast_module_user
*u
;
584 u
= ast_module_user_add(chan
);
586 set_peers(&parker
, &parkee
, peer
, chan
, sense
);
587 /* Setup the exten/priority to be s/1 since we don't know
588 where this call should return */
589 strcpy(chan
->exten
, "s");
591 if (chan
->_state
!= AST_STATE_UP
)
592 res
= ast_answer(chan
);
594 res
= ast_safe_sleep(chan
, 1000);
596 res
= ast_park_call(parkee
, parker
, 0, NULL
);
598 ast_module_user_remove(u
);
601 if (sense
== FEATURE_SENSE_CHAN
)
602 res
= AST_PBX_NO_HANGUP_PEER
;
604 res
= AST_PBX_KEEPALIVE
;
610 static int builtin_automonitor(struct ast_channel
*chan
, struct ast_channel
*peer
, struct ast_bridge_config
*config
, char *code
, int sense
, void *data
)
612 char *caller_chan_id
= NULL
, *callee_chan_id
= NULL
, *args
= NULL
, *touch_filename
= NULL
;
615 struct ast_channel
*caller_chan
, *callee_chan
;
618 ast_log(LOG_ERROR
,"Cannot record the call. The monitor application is disabled.\n");
622 if (!monitor_app
&& !(monitor_app
= pbx_findapp("Monitor"))) {
624 ast_log(LOG_ERROR
,"Cannot record the call. The monitor application is disabled.\n");
628 set_peers(&caller_chan
, &callee_chan
, peer
, chan
, sense
);
630 if (!ast_strlen_zero(courtesytone
)) {
631 if (ast_autoservice_start(callee_chan
))
633 if (ast_stream_and_wait(caller_chan
, courtesytone
, caller_chan
->language
, "")) {
634 ast_log(LOG_WARNING
, "Failed to play courtesy tone!\n");
635 ast_autoservice_stop(callee_chan
);
638 if (ast_autoservice_stop(callee_chan
))
642 if (callee_chan
->monitor
) {
643 if (option_verbose
> 3)
644 ast_verbose(VERBOSE_PREFIX_3
"User hit '%s' to stop recording call.\n", code
);
645 ast_monitor_stop(callee_chan
, 1);
646 return FEATURE_RETURN_SUCCESS
;
649 if (caller_chan
&& callee_chan
) {
650 const char *touch_format
= pbx_builtin_getvar_helper(caller_chan
, "TOUCH_MONITOR_FORMAT");
651 const char *touch_monitor
= pbx_builtin_getvar_helper(caller_chan
, "TOUCH_MONITOR");
654 touch_format
= pbx_builtin_getvar_helper(callee_chan
, "TOUCH_MONITOR_FORMAT");
657 touch_monitor
= pbx_builtin_getvar_helper(callee_chan
, "TOUCH_MONITOR");
660 len
= strlen(touch_monitor
) + 50;
662 touch_filename
= alloca(len
);
663 snprintf(touch_filename
, len
, "auto-%ld-%s", (long)time(NULL
), touch_monitor
);
664 snprintf(args
, len
, "%s|%s|m", (touch_format
) ? touch_format
: "wav", touch_filename
);
666 caller_chan_id
= ast_strdupa(S_OR(caller_chan
->cid
.cid_num
, caller_chan
->name
));
667 callee_chan_id
= ast_strdupa(S_OR(callee_chan
->cid
.cid_num
, callee_chan
->name
));
668 len
= strlen(caller_chan_id
) + strlen(callee_chan_id
) + 50;
670 touch_filename
= alloca(len
);
671 snprintf(touch_filename
, len
, "auto-%ld-%s-%s", (long)time(NULL
), caller_chan_id
, callee_chan_id
);
672 snprintf(args
, len
, "%s|%s|m", S_OR(touch_format
, "wav"), touch_filename
);
675 for( x
= 0; x
< strlen(args
); x
++) {
680 if (option_verbose
> 3)
681 ast_verbose(VERBOSE_PREFIX_3
"User hit '%s' to record call. filename: %s\n", code
, args
);
683 pbx_exec(callee_chan
, monitor_app
, args
);
684 pbx_builtin_setvar_helper(callee_chan
, "TOUCH_MONITOR_OUTPUT", touch_filename
);
685 pbx_builtin_setvar_helper(caller_chan
, "TOUCH_MONITOR_OUTPUT", touch_filename
);
687 return FEATURE_RETURN_SUCCESS
;
690 ast_log(LOG_NOTICE
,"Cannot record the call. One or both channels have gone away.\n");
694 static int builtin_disconnect(struct ast_channel
*chan
, struct ast_channel
*peer
, struct ast_bridge_config
*config
, char *code
, int sense
, void *data
)
696 if (option_verbose
> 3)
697 ast_verbose(VERBOSE_PREFIX_3
"User hit '%s' to disconnect call.\n", code
);
698 return FEATURE_RETURN_HANGUP
;
701 static int finishup(struct ast_channel
*chan
)
703 ast_indicate(chan
, AST_CONTROL_UNHOLD
);
705 return ast_autoservice_stop(chan
);
708 /*! \brief Find the context for the transfer */
709 static const char *real_ctx(struct ast_channel
*transferer
, struct ast_channel
*transferee
)
711 const char *s
= pbx_builtin_getvar_helper(transferer
, "TRANSFER_CONTEXT");
712 if (ast_strlen_zero(s
))
713 s
= pbx_builtin_getvar_helper(transferee
, "TRANSFER_CONTEXT");
714 if (ast_strlen_zero(s
)) /* Use the non-macro context to transfer the call XXX ? */
715 s
= transferer
->macrocontext
;
716 if (ast_strlen_zero(s
))
717 s
= transferer
->context
;
721 static int builtin_blindtransfer(struct ast_channel
*chan
, struct ast_channel
*peer
, struct ast_bridge_config
*config
, char *code
, int sense
, void *data
)
723 struct ast_channel
*transferer
;
724 struct ast_channel
*transferee
;
725 const char *transferer_real_context
;
729 set_peers(&transferer
, &transferee
, peer
, chan
, sense
);
730 transferer_real_context
= real_ctx(transferer
, transferee
);
731 /* Start autoservice on chan while we talk to the originator */
732 ast_autoservice_start(transferee
);
733 ast_indicate(transferee
, AST_CONTROL_HOLD
);
735 memset(xferto
, 0, sizeof(xferto
));
738 res
= ast_stream_and_wait(transferer
, "pbx-transfer", transferer
->language
, AST_DIGIT_ANY
);
740 finishup(transferee
);
741 return -1; /* error ? */
743 if (res
> 0) /* If they've typed a digit already, handle it */
744 xferto
[0] = (char) res
;
746 ast_stopstream(transferer
);
747 res
= ast_app_dtget(transferer
, transferer_real_context
, xferto
, sizeof(xferto
), 100, transferdigittimeout
);
748 if (res
< 0) { /* hangup, would be 0 for invalid and 1 for valid */
749 finishup(transferee
);
752 if (!strcmp(xferto
, ast_parking_ext())) {
753 res
= finishup(transferee
);
756 else if (!ast_park_call(transferee
, transferer
, 0, NULL
)) { /* success */
757 /* We return non-zero, but tell the PBX not to hang the channel when
758 the thread dies -- We have to be careful now though. We are responsible for
759 hanging up the channel, else it will never be hung up! */
761 return (transferer
== peer
) ? AST_PBX_KEEPALIVE
: AST_PBX_NO_HANGUP_PEER
;
763 ast_log(LOG_WARNING
, "Unable to park call %s\n", transferee
->name
);
765 /*! \todo XXX Maybe we should have another message here instead of invalid extension XXX */
766 } else if (ast_exists_extension(transferee
, transferer_real_context
, xferto
, 1, transferer
->cid
.cid_num
)) {
767 pbx_builtin_setvar_helper(transferer
, "BLINDTRANSFER", transferee
->name
);
768 pbx_builtin_setvar_helper(transferee
, "BLINDTRANSFER", transferer
->name
);
769 res
=finishup(transferee
);
770 if (!transferer
->cdr
) {
771 transferer
->cdr
=ast_cdr_alloc();
773 ast_cdr_init(transferer
->cdr
, transferer
); /* initilize our channel's cdr */
774 ast_cdr_start(transferer
->cdr
);
777 if (transferer
->cdr
) {
778 ast_cdr_setdestchan(transferer
->cdr
, transferee
->name
);
779 ast_cdr_setapp(transferer
->cdr
, "BLINDTRANSFER","");
781 if (!transferee
->pbx
) {
782 /* Doh! Use our handy async_goto functions */
783 if (option_verbose
> 2)
784 ast_verbose(VERBOSE_PREFIX_3
"Transferring %s to '%s' (context %s) priority 1\n"
785 ,transferee
->name
, xferto
, transferer_real_context
);
786 if (ast_async_goto(transferee
, transferer_real_context
, xferto
, 1))
787 ast_log(LOG_WARNING
, "Async goto failed :-(\n");
790 /* Set the channel's new extension, since it exists, using transferer context */
791 set_c_e_p(transferee
, transferer_real_context
, xferto
, 0);
793 check_goto_on_transfer(transferer
);
796 if (option_verbose
> 2)
797 ast_verbose(VERBOSE_PREFIX_3
"Unable to find extension '%s' in context '%s'\n", xferto
, transferer_real_context
);
799 if (ast_stream_and_wait(transferer
, xferfailsound
, transferer
->language
, AST_DIGIT_ANY
) < 0 ) {
800 finishup(transferee
);
803 ast_stopstream(transferer
);
804 res
= finishup(transferee
);
806 if (option_verbose
> 1)
807 ast_verbose(VERBOSE_PREFIX_2
"Hungup during autoservice stop on '%s'\n", transferee
->name
);
810 return FEATURE_RETURN_SUCCESS
;
813 static int check_compat(struct ast_channel
*c
, struct ast_channel
*newchan
)
815 if (ast_channel_make_compatible(c
, newchan
) < 0) {
816 ast_log(LOG_WARNING
, "Had to drop call because I couldn't make %s compatible with %s\n",
817 c
->name
, newchan
->name
);
824 static int builtin_atxfer(struct ast_channel
*chan
, struct ast_channel
*peer
, struct ast_bridge_config
*config
, char *code
, int sense
, void *data
)
826 struct ast_channel
*transferer
;
827 struct ast_channel
*transferee
;
828 const char *transferer_real_context
;
829 char xferto
[256] = "";
832 struct ast_channel
*newchan
;
833 struct ast_channel
*xferchan
;
834 struct ast_bridge_thread_obj
*tobj
;
835 struct ast_bridge_config bconfig
;
838 struct ast_datastore
*features_datastore
;
839 struct ast_dial_features
*dialfeatures
= NULL
;
842 ast_log(LOG_DEBUG
, "Executing Attended Transfer %s, %s (sense=%d) \n", chan
->name
, peer
->name
, sense
);
843 set_peers(&transferer
, &transferee
, peer
, chan
, sense
);
844 transferer_real_context
= real_ctx(transferer
, transferee
);
845 /* Start autoservice on chan while we talk to the originator */
846 ast_autoservice_start(transferee
);
847 ast_indicate(transferee
, AST_CONTROL_HOLD
);
850 res
= ast_stream_and_wait(transferer
, "pbx-transfer", transferer
->language
, AST_DIGIT_ANY
);
852 finishup(transferee
);
855 if (res
> 0) /* If they've typed a digit already, handle it */
856 xferto
[0] = (char) res
;
858 /* this is specific of atxfer */
859 res
= ast_app_dtget(transferer
, transferer_real_context
, xferto
, sizeof(xferto
), 100, transferdigittimeout
);
860 if (res
< 0) { /* hangup, would be 0 for invalid and 1 for valid */
861 finishup(transferee
);
865 ast_log(LOG_WARNING
, "Did not read data.\n");
866 finishup(transferee
);
867 if (ast_stream_and_wait(transferer
, "beeperr", transferer
->language
, ""))
869 return FEATURE_RETURN_SUCCESS
;
872 /* valid extension, res == 1 */
873 if (!ast_exists_extension(transferer
, transferer_real_context
, xferto
, 1, transferer
->cid
.cid_num
)) {
874 ast_log(LOG_WARNING
, "Extension %s does not exist in context %s\n",xferto
,transferer_real_context
);
875 finishup(transferee
);
876 if (ast_stream_and_wait(transferer
, "beeperr", transferer
->language
, ""))
878 return FEATURE_RETURN_SUCCESS
;
882 snprintf(xferto
+ l
, sizeof(xferto
) - l
, "@%s", transferer_real_context
); /* append context */
883 newchan
= ast_feature_request_and_dial(transferer
, "Local", ast_best_codec(transferer
->nativeformats
),
884 xferto
, atxfernoanswertimeout
, &outstate
, transferer
->cid
.cid_num
, transferer
->cid
.cid_name
, transferer
->language
);
886 /* If we are the callee and we are being transferred, after the masquerade
887 * caller features will really be the original callee features */
888 ast_channel_lock(transferee
);
889 if ((features_datastore
= ast_channel_datastore_find(transferee
, &dial_features_info
, NULL
))) {
890 dialfeatures
= features_datastore
->data
;
892 ast_channel_unlock(transferee
);
894 if (dialfeatures
&& !dialfeatures
->is_caller
) {
895 ast_copy_flags(&(config
->features_caller
), &(dialfeatures
->features_callee
), AST_FLAGS_ALL
);
898 ast_indicate(transferer
, -1);
900 finishup(transferee
);
901 /* any reason besides user requested cancel and busy triggers the failed sound */
902 if (outstate
!= AST_CONTROL_UNHOLD
&& outstate
!= AST_CONTROL_BUSY
&&
903 ast_stream_and_wait(transferer
, xferfailsound
, transferer
->language
, ""))
905 return FEATURE_RETURN_SUCCESS
;
908 if (check_compat(transferer
, newchan
)) {
909 /* we do mean transferee here, NOT transferer */
910 finishup(transferee
);
913 memset(&bconfig
,0,sizeof(struct ast_bridge_config
));
914 ast_set_flag(&(bconfig
.features_caller
), AST_FEATURE_DISCONNECT
);
915 ast_set_flag(&(bconfig
.features_callee
), AST_FEATURE_DISCONNECT
);
916 res
= ast_bridge_call(transferer
, newchan
, &bconfig
);
917 if (newchan
->_softhangup
|| !transferer
->_softhangup
) {
919 if (ast_stream_and_wait(transferer
, xfersound
, transferer
->language
, ""))
920 ast_log(LOG_WARNING
, "Failed to play transfer sound!\n");
921 finishup(transferee
);
922 transferer
->_softhangup
= 0;
923 return FEATURE_RETURN_SUCCESS
;
926 if (check_compat(transferee
, newchan
)) {
927 finishup(transferee
);
931 ast_indicate(transferee
, AST_CONTROL_UNHOLD
);
933 if ((ast_autoservice_stop(transferee
) < 0)
934 || (ast_waitfordigit(transferee
, 100) < 0)
935 || (ast_waitfordigit(newchan
, 100) < 0)
936 || ast_check_hangup(transferee
)
937 || ast_check_hangup(newchan
)) {
942 xferchan
= ast_channel_alloc(0, AST_STATE_DOWN
, 0, 0, "", "", "", 0, "Transfered/%s", transferee
->name
);
947 /* Make formats okay */
948 xferchan
->visible_indication
= transferer
->visible_indication
;
949 xferchan
->readformat
= transferee
->readformat
;
950 xferchan
->writeformat
= transferee
->writeformat
;
951 ast_channel_masquerade(xferchan
, transferee
);
952 ast_explicit_goto(xferchan
, transferee
->context
, transferee
->exten
, transferee
->priority
);
953 xferchan
->_state
= AST_STATE_UP
;
954 ast_clear_flag(xferchan
, AST_FLAGS_ALL
);
955 xferchan
->_softhangup
= 0;
957 if ((f
= ast_read(xferchan
)))
960 newchan
->_state
= AST_STATE_UP
;
961 ast_clear_flag(newchan
, AST_FLAGS_ALL
);
962 newchan
->_softhangup
= 0;
964 tobj
= ast_calloc(1, sizeof(struct ast_bridge_thread_obj
));
966 ast_hangup(xferchan
);
971 /* For the case where the transfer target is being connected with the original
972 caller store the target's original features, and apply to the bridge */
973 ast_channel_lock(newchan
);
974 if ((features_datastore
= ast_channel_datastore_find(newchan
, &dial_features_info
, NULL
))) {
975 dialfeatures
= features_datastore
->data
;
977 ast_channel_unlock(newchan
);
980 ast_copy_flags(&(config
->features_callee
), &(dialfeatures
->features_callee
), AST_FLAGS_ALL
);
983 tobj
->chan
= newchan
;
984 tobj
->peer
= xferchan
;
985 tobj
->bconfig
= *config
;
987 if (ast_stream_and_wait(newchan
, xfersound
, newchan
->language
, ""))
988 ast_log(LOG_WARNING
, "Failed to play transfer sound!\n");
989 ast_bridge_call_thread_launch(tobj
);
990 return -1; /* XXX meaning the channel is bridged ? */
994 /* add atxfer and automon as undefined so you can only use em if you configure them */
995 #define FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0]))
997 AST_RWLOCK_DEFINE_STATIC(features_lock
);
999 static struct ast_call_feature builtin_features
[] =
1001 { AST_FEATURE_REDIRECT
, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer
, AST_FEATURE_FLAG_NEEDSDTMF
, "" },
1002 { AST_FEATURE_REDIRECT
, "Attended Transfer", "atxfer", "", "", builtin_atxfer
, AST_FEATURE_FLAG_NEEDSDTMF
, "" },
1003 { AST_FEATURE_AUTOMON
, "One Touch Monitor", "automon", "", "", builtin_automonitor
, AST_FEATURE_FLAG_NEEDSDTMF
, "" },
1004 { AST_FEATURE_DISCONNECT
, "Disconnect Call", "disconnect", "*", "*", builtin_disconnect
, AST_FEATURE_FLAG_NEEDSDTMF
, "" },
1005 { AST_FEATURE_PARKCALL
, "Park Call", "parkcall", "", "", builtin_parkcall
, AST_FEATURE_FLAG_NEEDSDTMF
, "" },
1009 static AST_LIST_HEAD_STATIC(feature_list
,ast_call_feature
);
1011 /*! \brief register new feature into feature_list*/
1012 void ast_register_feature(struct ast_call_feature
*feature
)
1015 ast_log(LOG_NOTICE
,"You didn't pass a feature!\n");
1019 AST_LIST_LOCK(&feature_list
);
1020 AST_LIST_INSERT_HEAD(&feature_list
,feature
,feature_entry
);
1021 AST_LIST_UNLOCK(&feature_list
);
1023 if (option_verbose
>= 2)
1024 ast_verbose(VERBOSE_PREFIX_2
"Registered Feature '%s'\n",feature
->sname
);
1027 /*! \brief unregister feature from feature_list */
1028 void ast_unregister_feature(struct ast_call_feature
*feature
)
1033 AST_LIST_LOCK(&feature_list
);
1034 AST_LIST_REMOVE(&feature_list
,feature
,feature_entry
);
1035 AST_LIST_UNLOCK(&feature_list
);
1039 /*! \brief Remove all features in the list */
1040 static void ast_unregister_features(void)
1042 struct ast_call_feature
*feature
;
1044 AST_LIST_LOCK(&feature_list
);
1045 while ((feature
= AST_LIST_REMOVE_HEAD(&feature_list
,feature_entry
)))
1047 AST_LIST_UNLOCK(&feature_list
);
1050 /*! \brief find a feature by name */
1051 static struct ast_call_feature
*find_dynamic_feature(const char *name
)
1053 struct ast_call_feature
*tmp
;
1055 AST_LIST_TRAVERSE(&feature_list
, tmp
, feature_entry
) {
1056 if (!strcasecmp(tmp
->sname
, name
))
1063 /*! \brief exec an app by feature */
1064 static int feature_exec_app(struct ast_channel
*chan
, struct ast_channel
*peer
, struct ast_bridge_config
*config
, char *code
, int sense
, void *data
)
1066 struct ast_app
*app
;
1067 struct ast_call_feature
*feature
= data
;
1068 struct ast_channel
*work
, *idle
;
1071 if (!feature
) { /* shouldn't ever happen! */
1072 ast_log(LOG_NOTICE
, "Found feature before, but at execing we've lost it??\n");
1076 if (sense
== FEATURE_SENSE_CHAN
) {
1077 if (!ast_test_flag(feature
, AST_FEATURE_FLAG_BYCALLER
))
1078 return FEATURE_RETURN_KEEPTRYING
;
1079 if (ast_test_flag(feature
, AST_FEATURE_FLAG_ONSELF
)) {
1087 if (!ast_test_flag(feature
, AST_FEATURE_FLAG_BYCALLEE
))
1088 return FEATURE_RETURN_KEEPTRYING
;
1089 if (ast_test_flag(feature
, AST_FEATURE_FLAG_ONSELF
)) {
1098 if (!(app
= pbx_findapp(feature
->app
))) {
1099 ast_log(LOG_WARNING
, "Could not find application (%s)\n", feature
->app
);
1103 ast_autoservice_start(idle
);
1105 if (!ast_strlen_zero(feature
->moh_class
))
1106 ast_moh_start(idle
, feature
->moh_class
, NULL
);
1108 res
= pbx_exec(work
, app
, feature
->app_args
);
1110 if (!ast_strlen_zero(feature
->moh_class
))
1113 ast_autoservice_stop(idle
);
1115 if (res
== AST_PBX_KEEPALIVE
) {
1116 /* do not hangup peer if feature is to be activated on it */
1117 if ((ast_test_flag(feature
, AST_FEATURE_FLAG_ONPEER
) && sense
== FEATURE_SENSE_CHAN
) || (ast_test_flag(feature
, AST_FEATURE_FLAG_ONSELF
) && sense
== FEATURE_SENSE_PEER
))
1118 return FEATURE_RETURN_NO_HANGUP_PEER
;
1120 return FEATURE_RETURN_PBX_KEEPALIVE
;
1122 else if (res
== AST_PBX_NO_HANGUP_PEER
)
1123 return FEATURE_RETURN_NO_HANGUP_PEER
;
1125 return FEATURE_RETURN_SUCCESSBREAK
;
1127 return FEATURE_RETURN_SUCCESS
; /*! \todo XXX should probably return res */
1130 static void unmap_features(void)
1134 ast_rwlock_wrlock(&features_lock
);
1135 for (x
= 0; x
< FEATURES_COUNT
; x
++)
1136 strcpy(builtin_features
[x
].exten
, builtin_features
[x
].default_exten
);
1137 ast_rwlock_unlock(&features_lock
);
1140 static int remap_feature(const char *name
, const char *value
)
1144 ast_rwlock_wrlock(&features_lock
);
1145 for (x
= 0; x
< FEATURES_COUNT
; x
++) {
1146 if (strcasecmp(builtin_features
[x
].sname
, name
))
1149 ast_copy_string(builtin_features
[x
].exten
, value
, sizeof(builtin_features
[x
].exten
));
1153 ast_rwlock_unlock(&features_lock
);
1158 static int ast_feature_interpret(struct ast_channel
*chan
, struct ast_channel
*peer
, struct ast_bridge_config
*config
, char *code
, int sense
)
1161 struct ast_flags features
;
1162 struct ast_call_feature
*feature
;
1163 const char *dynamic_features
;
1165 int res
= FEATURE_RETURN_PASSDIGITS
;
1166 int feature_detected
= 0;
1168 if (sense
== FEATURE_SENSE_CHAN
) {
1169 ast_copy_flags(&features
, &(config
->features_caller
), AST_FLAGS_ALL
);
1170 dynamic_features
= pbx_builtin_getvar_helper(chan
, "DYNAMIC_FEATURES");
1172 ast_copy_flags(&features
, &(config
->features_callee
), AST_FLAGS_ALL
);
1173 dynamic_features
= pbx_builtin_getvar_helper(peer
, "DYNAMIC_FEATURES");
1175 if (option_debug
> 2)
1176 ast_log(LOG_DEBUG
, "Feature interpret: chan=%s, peer=%s, code=%s, sense=%d, features=%d dynamic=%s\n", chan
->name
, peer
->name
, code
, sense
, features
.flags
, dynamic_features
);
1178 ast_rwlock_rdlock(&features_lock
);
1179 for (x
= 0; x
< FEATURES_COUNT
; x
++) {
1180 if ((ast_test_flag(&features
, builtin_features
[x
].feature_mask
)) &&
1181 !ast_strlen_zero(builtin_features
[x
].exten
)) {
1182 /* Feature is up for consideration */
1183 if (!strcmp(builtin_features
[x
].exten
, code
)) {
1184 res
= builtin_features
[x
].operation(chan
, peer
, config
, code
, sense
, NULL
);
1185 feature_detected
= 1;
1187 } else if (!strncmp(builtin_features
[x
].exten
, code
, strlen(code
))) {
1188 if (res
== FEATURE_RETURN_PASSDIGITS
)
1189 res
= FEATURE_RETURN_STOREDIGITS
;
1193 ast_rwlock_unlock(&features_lock
);
1195 if (ast_strlen_zero(dynamic_features
) || feature_detected
)
1198 tmp
= ast_strdupa(dynamic_features
);
1200 while ((tok
= strsep(&tmp
, "#"))) {
1201 AST_LIST_LOCK(&feature_list
);
1202 if (!(feature
= find_dynamic_feature(tok
))) {
1203 AST_LIST_UNLOCK(&feature_list
);
1207 /* Feature is up for consideration */
1208 if (!strcmp(feature
->exten
, code
)) {
1209 if (option_verbose
> 2)
1210 ast_verbose(VERBOSE_PREFIX_3
" Feature Found: %s exten: %s\n",feature
->sname
, tok
);
1211 res
= feature
->operation(chan
, peer
, config
, code
, sense
, feature
);
1212 if (res
!= FEATURE_RETURN_KEEPTRYING
) {
1213 AST_LIST_UNLOCK(&feature_list
);
1216 res
= FEATURE_RETURN_PASSDIGITS
;
1217 } else if (!strncmp(feature
->exten
, code
, strlen(code
)))
1218 res
= FEATURE_RETURN_STOREDIGITS
;
1220 AST_LIST_UNLOCK(&feature_list
);
1226 static void set_config_flags(struct ast_channel
*chan
, struct ast_channel
*peer
, struct ast_bridge_config
*config
)
1230 ast_clear_flag(config
, AST_FLAGS_ALL
);
1232 ast_rwlock_rdlock(&features_lock
);
1233 for (x
= 0; x
< FEATURES_COUNT
; x
++) {
1234 if (!ast_test_flag(builtin_features
+ x
, AST_FEATURE_FLAG_NEEDSDTMF
))
1237 if (ast_test_flag(&(config
->features_caller
), builtin_features
[x
].feature_mask
))
1238 ast_set_flag(config
, AST_BRIDGE_DTMF_CHANNEL_0
);
1240 if (ast_test_flag(&(config
->features_callee
), builtin_features
[x
].feature_mask
))
1241 ast_set_flag(config
, AST_BRIDGE_DTMF_CHANNEL_1
);
1243 ast_rwlock_unlock(&features_lock
);
1245 if (chan
&& peer
&& !(ast_test_flag(config
, AST_BRIDGE_DTMF_CHANNEL_0
) && ast_test_flag(config
, AST_BRIDGE_DTMF_CHANNEL_1
))) {
1246 const char *dynamic_features
= pbx_builtin_getvar_helper(chan
, "DYNAMIC_FEATURES");
1248 if (dynamic_features
) {
1249 char *tmp
= ast_strdupa(dynamic_features
);
1251 struct ast_call_feature
*feature
;
1253 /* while we have a feature */
1254 while ((tok
= strsep(&tmp
, "#"))) {
1255 AST_LIST_LOCK(&feature_list
);
1256 if ((feature
= find_dynamic_feature(tok
)) && ast_test_flag(feature
, AST_FEATURE_FLAG_NEEDSDTMF
)) {
1257 if (ast_test_flag(feature
, AST_FEATURE_FLAG_BYCALLER
))
1258 ast_set_flag(config
, AST_BRIDGE_DTMF_CHANNEL_0
);
1259 if (ast_test_flag(feature
, AST_FEATURE_FLAG_BYCALLEE
))
1260 ast_set_flag(config
, AST_BRIDGE_DTMF_CHANNEL_1
);
1262 AST_LIST_UNLOCK(&feature_list
);
1268 /*! \todo XXX Check - this is very similar to the code in channel.c */
1269 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
, const char *language
)
1274 struct ast_channel
*chan
;
1275 struct ast_channel
*monitor_chans
[2];
1276 struct ast_channel
*active_channel
;
1277 int res
= 0, ready
= 0;
1279 if ((chan
= ast_request(type
, format
, data
, &cause
))) {
1280 ast_set_callerid(chan
, cid_num
, cid_name
, cid_num
);
1281 ast_string_field_set(chan
, language
, language
);
1282 ast_channel_inherit_variables(caller
, chan
);
1283 pbx_builtin_setvar_helper(chan
, "TRANSFERERNAME", caller
->name
);
1285 if (!ast_call(chan
, data
, timeout
)) {
1286 struct timeval started
;
1288 char *disconnect_code
= NULL
, *dialed_code
= NULL
;
1290 ast_indicate(caller
, AST_CONTROL_RINGING
);
1291 /* support dialing of the featuremap disconnect code while performing an attended tranfer */
1292 ast_rwlock_rdlock(&features_lock
);
1293 for (x
= 0; x
< FEATURES_COUNT
; x
++) {
1294 if (strcasecmp(builtin_features
[x
].sname
, "disconnect"))
1297 disconnect_code
= builtin_features
[x
].exten
;
1298 len
= strlen(disconnect_code
) + 1;
1299 dialed_code
= alloca(len
);
1300 memset(dialed_code
, 0, len
);
1303 ast_rwlock_unlock(&features_lock
);
1305 started
= ast_tvnow();
1307 while (!ast_check_hangup(caller
) && timeout
&& (chan
->_state
!= AST_STATE_UP
)) {
1308 struct ast_frame
*f
= NULL
;
1310 monitor_chans
[0] = caller
;
1311 monitor_chans
[1] = chan
;
1312 active_channel
= ast_waitfor_n(monitor_chans
, 2, &to
);
1314 /* see if the timeout has been violated */
1315 if(ast_tvdiff_ms(ast_tvnow(), started
) > timeout
) {
1316 state
= AST_CONTROL_UNHOLD
;
1317 ast_log(LOG_NOTICE
, "We exceeded our AT-timeout\n");
1318 break; /*doh! timeout*/
1321 if (!active_channel
)
1324 if (chan
&& (chan
== active_channel
)){
1326 if (f
== NULL
) { /*doh! where'd he go?*/
1327 state
= AST_CONTROL_HANGUP
;
1332 if (f
->frametype
== AST_FRAME_CONTROL
|| f
->frametype
== AST_FRAME_DTMF
|| f
->frametype
== AST_FRAME_TEXT
) {
1333 if (f
->subclass
== AST_CONTROL_RINGING
) {
1334 state
= f
->subclass
;
1335 if (option_verbose
> 2)
1336 ast_verbose( VERBOSE_PREFIX_3
"%s is ringing\n", chan
->name
);
1337 ast_indicate(caller
, AST_CONTROL_RINGING
);
1338 } else if ((f
->subclass
== AST_CONTROL_BUSY
) || (f
->subclass
== AST_CONTROL_CONGESTION
)) {
1339 state
= f
->subclass
;
1340 if (option_verbose
> 2)
1341 ast_verbose( VERBOSE_PREFIX_3
"%s is busy\n", chan
->name
);
1342 ast_indicate(caller
, AST_CONTROL_BUSY
);
1346 } else if (f
->subclass
== AST_CONTROL_ANSWER
) {
1347 /* This is what we are hoping for */
1348 state
= f
->subclass
;
1353 } else if (f
->subclass
!= -1) {
1354 ast_log(LOG_NOTICE
, "Don't know what to do about control frame: %d\n", f
->subclass
);
1356 /* else who cares */
1359 } else if (caller
&& (active_channel
== caller
)) {
1360 f
= ast_read(caller
);
1361 if (f
== NULL
) { /*doh! where'd he go?*/
1362 if (caller
->_softhangup
&& !chan
->_softhangup
) {
1363 /* make this a blind transfer */
1367 state
= AST_CONTROL_HANGUP
;
1372 if (f
->frametype
== AST_FRAME_DTMF
) {
1373 dialed_code
[x
++] = f
->subclass
;
1374 dialed_code
[x
] = '\0';
1375 if (strlen(dialed_code
) == len
) {
1377 } else if (x
&& strncmp(dialed_code
, disconnect_code
, x
)) {
1379 dialed_code
[x
] = '\0';
1381 if (*dialed_code
&& !strcmp(dialed_code
, disconnect_code
)) {
1382 /* Caller Canceled the call */
1383 state
= AST_CONTROL_UNHOLD
;
1394 ast_log(LOG_NOTICE
, "Unable to call channel %s/%s\n", type
, (char *)data
);
1396 ast_log(LOG_NOTICE
, "Unable to request channel %s/%s\n", type
, (char *)data
);
1398 case AST_CAUSE_BUSY
:
1399 state
= AST_CONTROL_BUSY
;
1401 case AST_CAUSE_CONGESTION
:
1402 state
= AST_CONTROL_CONGESTION
;
1407 ast_indicate(caller
, -1);
1408 if (chan
&& ready
) {
1409 if (chan
->_state
== AST_STATE_UP
)
1410 state
= AST_CONTROL_ANSWER
;
1426 int ast_bridge_call(struct ast_channel
*chan
,struct ast_channel
*peer
,struct ast_bridge_config
*config
)
1428 /* Copy voice back and forth between the two channels. Give the peer
1429 the ability to transfer calls with '#<extension' syntax. */
1430 struct ast_frame
*f
;
1431 struct ast_channel
*who
;
1432 char chan_featurecode
[FEATURE_MAX_LEN
+ 1]="";
1433 char peer_featurecode
[FEATURE_MAX_LEN
+ 1]="";
1434 char orig_channame
[AST_MAX_EXTENSION
];
1435 char orig_peername
[AST_MAX_EXTENSION
];
1441 struct ast_option_header
*aoh
;
1442 struct ast_bridge_config backup_config
;
1443 struct ast_cdr
*bridge_cdr
= NULL
;
1444 struct ast_cdr
*orig_peer_cdr
= NULL
;
1446 memset(&backup_config
, 0, sizeof(backup_config
));
1448 config
->start_time
= ast_tvnow();
1451 pbx_builtin_setvar_helper(chan
, "BRIDGEPEER", peer
->name
);
1452 pbx_builtin_setvar_helper(peer
, "BRIDGEPEER", chan
->name
);
1454 pbx_builtin_setvar_helper(chan
, "BLINDTRANSFER", NULL
);
1457 const char *monitor_exec
;
1458 struct ast_channel
*src
= NULL
;
1460 if (!(monitor_app
= pbx_findapp("Monitor")))
1463 if ((monitor_exec
= pbx_builtin_getvar_helper(chan
, "AUTO_MONITOR")))
1465 else if ((monitor_exec
= pbx_builtin_getvar_helper(peer
, "AUTO_MONITOR")))
1467 if (monitor_app
&& src
) {
1468 char *tmp
= ast_strdupa(monitor_exec
);
1469 pbx_exec(src
, monitor_app
, tmp
);
1473 set_config_flags(chan
, peer
, config
);
1474 config
->firstpass
= 1;
1476 /* Answer if need be */
1477 if (ast_answer(chan
))
1480 ast_copy_string(orig_channame
,chan
->name
,sizeof(orig_channame
));
1481 ast_copy_string(orig_peername
,peer
->name
,sizeof(orig_peername
));
1482 orig_peer_cdr
= peer
->cdr
;
1484 if (!chan
->cdr
|| (chan
->cdr
&& !ast_test_flag(chan
->cdr
, AST_CDR_FLAG_POST_DISABLED
))) {
1487 ast_set_flag(chan
->cdr
, AST_CDR_FLAG_MAIN
);
1488 ast_cdr_update(chan
);
1489 bridge_cdr
= ast_cdr_dup(chan
->cdr
);
1490 ast_copy_string(bridge_cdr
->lastapp
, chan
->appl
, sizeof(bridge_cdr
->lastapp
));
1491 ast_copy_string(bridge_cdr
->lastdata
, chan
->data
, sizeof(bridge_cdr
->lastdata
));
1493 /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */
1494 bridge_cdr
= ast_cdr_alloc(); /* this should be really, really rare/impossible? */
1495 ast_copy_string(bridge_cdr
->channel
, chan
->name
, sizeof(bridge_cdr
->channel
));
1496 ast_copy_string(bridge_cdr
->dstchannel
, peer
->name
, sizeof(bridge_cdr
->dstchannel
));
1497 ast_copy_string(bridge_cdr
->uniqueid
, chan
->uniqueid
, sizeof(bridge_cdr
->uniqueid
));
1498 ast_copy_string(bridge_cdr
->lastapp
, chan
->appl
, sizeof(bridge_cdr
->lastapp
));
1499 ast_copy_string(bridge_cdr
->lastdata
, chan
->data
, sizeof(bridge_cdr
->lastdata
));
1500 ast_cdr_setcid(bridge_cdr
, chan
);
1501 bridge_cdr
->disposition
= (chan
->_state
== AST_STATE_UP
) ? AST_CDR_ANSWERED
: AST_CDR_NULL
;
1502 bridge_cdr
->amaflags
= chan
->amaflags
? chan
->amaflags
: ast_default_amaflags
;
1503 ast_copy_string(bridge_cdr
->accountcode
, chan
->accountcode
, sizeof(bridge_cdr
->accountcode
));
1504 /* Destination information */
1505 ast_copy_string(bridge_cdr
->dst
, chan
->exten
, sizeof(bridge_cdr
->dst
));
1506 ast_copy_string(bridge_cdr
->dcontext
, chan
->context
, sizeof(bridge_cdr
->dcontext
));
1508 bridge_cdr
->start
= peer
->cdr
->start
;
1509 ast_copy_string(bridge_cdr
->userfield
, peer
->cdr
->userfield
, sizeof(bridge_cdr
->userfield
));
1511 ast_cdr_start(bridge_cdr
);
1514 /* peer->cdr->answer will be set when a macro runs on the peer;
1515 in that case, the bridge answer will be delayed while the
1516 macro plays on the peer channel. The peer answered the call
1517 before the macro started playing. To the phone system,
1518 this is billable time for the call, even tho the caller
1519 hears nothing but ringing while the macro does its thing. */
1520 if (peer
->cdr
&& !ast_tvzero(peer
->cdr
->answer
)) {
1521 bridge_cdr
->answer
= peer
->cdr
->answer
;
1522 chan
->cdr
->answer
= peer
->cdr
->answer
;
1524 ast_cdr_answer(bridge_cdr
);
1525 ast_cdr_answer(chan
->cdr
); /* for the sake of cli status checks */
1527 ast_set_flag(chan
->cdr
, AST_CDR_FLAG_BRIDGED
);
1529 ast_set_flag(peer
->cdr
, AST_CDR_FLAG_BRIDGED
);
1534 struct ast_channel
*other
; /* used later */
1536 res
= ast_channel_bridge(chan
, peer
, config
, &f
, &who
);
1538 if (config
->feature_timer
) {
1539 /* Update time limit for next pass */
1540 diff
= ast_tvdiff_ms(ast_tvnow(), config
->start_time
);
1541 config
->feature_timer
-= diff
;
1543 /* Running on backup config, meaning a feature might be being
1544 activated, but that's no excuse to keep things going
1546 if (backup_config
.feature_timer
&& ((backup_config
.feature_timer
-= diff
) <= 0)) {
1548 ast_log(LOG_DEBUG
, "Timed out, realtime this time!\n");
1549 config
->feature_timer
= 0;
1555 } else if (config
->feature_timer
<= 0) {
1556 /* Not *really* out of time, just out of time for
1557 digits to come in for features. */
1559 ast_log(LOG_DEBUG
, "Timed out for feature!\n");
1560 if (!ast_strlen_zero(peer_featurecode
)) {
1561 ast_dtmf_stream(chan
, peer
, peer_featurecode
, 0);
1562 memset(peer_featurecode
, 0, sizeof(peer_featurecode
));
1564 if (!ast_strlen_zero(chan_featurecode
)) {
1565 ast_dtmf_stream(peer
, chan
, chan_featurecode
, 0);
1566 memset(chan_featurecode
, 0, sizeof(chan_featurecode
));
1570 hasfeatures
= !ast_strlen_zero(chan_featurecode
) || !ast_strlen_zero(peer_featurecode
);
1572 /* Restore original (possibly time modified) bridge config */
1573 memcpy(config
, &backup_config
, sizeof(struct ast_bridge_config
));
1574 memset(&backup_config
, 0, sizeof(backup_config
));
1576 hadfeatures
= hasfeatures
;
1577 /* Continue as we were */
1580 /* The bridge returned without a frame and there is a feature in progress.
1581 * However, we don't think the feature has quite yet timed out, so just
1582 * go back into the bridge. */
1586 if (config
->feature_timer
<=0) {
1587 /* We ran out of time */
1588 config
->feature_timer
= 0;
1598 if (!ast_test_flag(chan
, AST_FLAG_ZOMBIE
) && !ast_test_flag(peer
, AST_FLAG_ZOMBIE
) && !ast_check_hangup(chan
) && !ast_check_hangup(peer
))
1599 ast_log(LOG_WARNING
, "Bridge failed on channels %s and %s\n", chan
->name
, peer
->name
);
1603 if (!f
|| (f
->frametype
== AST_FRAME_CONTROL
&&
1604 (f
->subclass
== AST_CONTROL_HANGUP
|| f
->subclass
== AST_CONTROL_BUSY
||
1605 f
->subclass
== AST_CONTROL_CONGESTION
) ) ) {
1609 /* many things should be sent to the 'other' channel */
1610 other
= (who
== chan
) ? peer
: chan
;
1611 if (f
->frametype
== AST_FRAME_CONTROL
) {
1612 switch (f
->subclass
) {
1613 case AST_CONTROL_RINGING
:
1614 case AST_CONTROL_FLASH
:
1616 ast_indicate(other
, f
->subclass
);
1618 case AST_CONTROL_HOLD
:
1619 case AST_CONTROL_UNHOLD
:
1620 ast_indicate_data(other
, f
->subclass
, f
->data
, f
->datalen
);
1622 case AST_CONTROL_OPTION
:
1624 /* Forward option Requests */
1625 if (aoh
&& aoh
->flag
== AST_OPTION_FLAG_REQUEST
) {
1626 ast_channel_setoption(other
, ntohs(aoh
->option
), aoh
->data
,
1627 f
->datalen
- sizeof(struct ast_option_header
), 0);
1631 } else if (f
->frametype
== AST_FRAME_DTMF_BEGIN
) {
1633 } else if (f
->frametype
== AST_FRAME_DTMF
) {
1637 hadfeatures
= hasfeatures
;
1638 /* This cannot overrun because the longest feature is one shorter than our buffer */
1640 sense
= FEATURE_SENSE_CHAN
;
1641 featurecode
= chan_featurecode
;
1643 sense
= FEATURE_SENSE_PEER
;
1644 featurecode
= peer_featurecode
;
1646 /*! append the event to featurecode. we rely on the string being zero-filled, and
1647 * not overflowing it.
1648 * \todo XXX how do we guarantee the latter ?
1650 featurecode
[strlen(featurecode
)] = f
->subclass
;
1651 /* Get rid of the frame before we start doing "stuff" with the channels */
1654 config
->feature_timer
= backup_config
.feature_timer
;
1655 res
= ast_feature_interpret(chan
, peer
, config
, featurecode
, sense
);
1657 case FEATURE_RETURN_PASSDIGITS
:
1658 ast_dtmf_stream(other
, who
, featurecode
, 0);
1660 case FEATURE_RETURN_SUCCESS
:
1661 memset(featurecode
, 0, sizeof(chan_featurecode
));
1664 if (res
>= FEATURE_RETURN_PASSDIGITS
) {
1668 hasfeatures
= !ast_strlen_zero(chan_featurecode
) || !ast_strlen_zero(peer_featurecode
);
1669 if (hadfeatures
&& !hasfeatures
) {
1670 /* Restore backup */
1671 memcpy(config
, &backup_config
, sizeof(struct ast_bridge_config
));
1672 memset(&backup_config
, 0, sizeof(struct ast_bridge_config
));
1673 } else if (hasfeatures
) {
1675 /* Backup configuration */
1676 memcpy(&backup_config
, config
, sizeof(struct ast_bridge_config
));
1677 /* Setup temporary config options */
1678 config
->play_warning
= 0;
1679 ast_clear_flag(&(config
->features_caller
), AST_FEATURE_PLAY_WARNING
);
1680 ast_clear_flag(&(config
->features_callee
), AST_FEATURE_PLAY_WARNING
);
1681 config
->warning_freq
= 0;
1682 config
->warning_sound
= NULL
;
1683 config
->end_sound
= NULL
;
1684 config
->start_sound
= NULL
;
1685 config
->firstpass
= 0;
1687 config
->start_time
= ast_tvnow();
1688 config
->feature_timer
= featuredigittimeout
;
1690 ast_log(LOG_DEBUG
, "Set time limit to %ld\n", config
->feature_timer
);
1698 /* obey the NoCDR() wishes. */
1699 if (!chan
->cdr
|| (chan
->cdr
&& !ast_test_flag(chan
->cdr
, AST_CDR_FLAG_POST_DISABLED
))) {
1701 ast_cdr_end(bridge_cdr
);
1703 ast_cdr_detach(bridge_cdr
);
1705 /* just in case, these channels get bridged again before hangup */
1707 ast_cdr_specialized_reset(chan
->cdr
,0);
1710 struct ast_cdr
*cur
;
1712 ast_channel_lock(peer
);
1713 for (cur
= peer
->cdr
; cur
; cur
= cur
->next
) {
1714 if (cur
== orig_peer_cdr
) {
1720 /* orig_peer_cdr is gone, probably because of a masquerade
1721 * during the bridge. */
1722 ast_channel_unlock(peer
);
1726 /* before resetting the peer cdr, throw a copy of it to the
1727 backend, just in case the cdr.conf file is calling for
1728 unanswered CDR's. */
1730 /* When peer->cdr isn't the same addr as orig_peer_cdr,
1731 this can only happen if there was a transfer, methinks;
1732 at any rate, only pay attention to the original*/
1733 if (ast_cdr_isset_unanswered()) {
1734 struct ast_cdr
*dupd
= ast_cdr_dup(orig_peer_cdr
);
1736 if (ast_tvzero(dupd
->end
) && ast_cdr_isset_unanswered())
1738 ast_cdr_detach(dupd
);
1741 ast_cdr_specialized_reset(orig_peer_cdr
,0);
1742 ast_channel_unlock(peer
);
1748 static void post_manager_event(const char *s
, char *parkingexten
, struct ast_channel
*chan
)
1750 manager_event(EVENT_FLAG_CALL
, s
,
1754 "CallerIDName: %s\r\n\r\n",
1757 S_OR(chan
->cid
.cid_num
, "<unknown>"),
1758 S_OR(chan
->cid
.cid_name
, "<unknown>")
1762 /*! \brief Take care of parked calls and unpark them if needed */
1763 static void *do_parking_thread(void *ignore
)
1765 fd_set rfds
, efds
; /* results from previous select, to be preserved across loops. */
1770 struct parkeduser
*pu
, *pl
, *pt
= NULL
;
1771 int ms
= -1; /* select timeout, uninitialized */
1772 int max
= -1; /* max fd, none there yet */
1773 fd_set nrfds
, nefds
; /* args for the next select */
1777 ast_mutex_lock(&parking_lock
);
1780 /* navigate the list with prev-cur pointers to support removals */
1782 struct ast_channel
*chan
= pu
->chan
; /* shorthand */
1783 int tms
; /* timeout for this item */
1784 int x
; /* fd index in channel */
1785 struct ast_context
*con
;
1787 if (pu
->notquiteyet
) { /* Pretend this one isn't here yet */
1792 tms
= ast_tvdiff_ms(ast_tvnow(), pu
->start
);
1793 if (tms
> pu
->parkingtime
) {
1794 ast_indicate(chan
, AST_CONTROL_UNHOLD
);
1795 /* Get chan, exten from derived kludge */
1796 if (pu
->peername
[0]) {
1797 char *peername
= ast_strdupa(pu
->peername
);
1798 char *cp
= strrchr(peername
, '-');
1801 con
= ast_context_find(parking_con_dial
);
1803 con
= ast_context_create(NULL
, parking_con_dial
, registrar
);
1805 ast_log(LOG_ERROR
, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial
);
1808 char returnexten
[AST_MAX_EXTENSION
];
1809 struct ast_datastore
*features_datastore
;
1810 struct ast_dial_features
*dialfeatures
= NULL
;
1812 ast_channel_lock(chan
);
1814 if ((features_datastore
= ast_channel_datastore_find(chan
, &dial_features_info
, NULL
)))
1815 dialfeatures
= features_datastore
->data
;
1817 ast_channel_unlock(chan
);
1820 snprintf(returnexten
, sizeof(returnexten
), "%s|30|%s", peername
, dialfeatures
->options
);
1821 else /* Existing default */
1822 snprintf(returnexten
, sizeof(returnexten
), "%s|30|t", peername
);
1824 ast_add_extension2(con
, 1, peername
, 1, NULL
, NULL
, "Dial", strdup(returnexten
), ast_free
, registrar
);
1826 set_c_e_p(chan
, parking_con_dial
, peername
, 1);
1828 /* They've been waiting too long, send them back to where they came. Theoretically they
1829 should have their original extensions and such, but we copy to be on the safe side */
1830 set_c_e_p(chan
, pu
->context
, pu
->exten
, pu
->priority
);
1833 post_manager_event("ParkedCallTimeOut", pu
->parkingexten
, chan
);
1835 if (option_verbose
> 1)
1836 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
);
1837 /* Start up the PBX, or hang them up */
1838 if (ast_pbx_start(chan
)) {
1839 ast_log(LOG_WARNING
, "Unable to restart the PBX for user on '%s', hanging them up...\n", chan
->name
);
1842 /* And take them out of the parking lot */
1844 pl
->next
= pu
->next
;
1846 parkinglot
= pu
->next
;
1849 con
= ast_context_find(parking_con
);
1851 if (ast_context_remove_extension2(con
, pt
->parkingexten
, 1, NULL
))
1852 ast_log(LOG_WARNING
, "Whoa, failed to remove the extension!\n");
1854 notify_metermaids(pt
->parkingexten
, parking_con
);
1856 ast_log(LOG_WARNING
, "Whoa, no parking context?\n");
1858 } else { /* still within parking time, process descriptors */
1859 for (x
= 0; x
< AST_MAX_FDS
; x
++) {
1860 struct ast_frame
*f
;
1862 if (chan
->fds
[x
] == -1 || (!FD_ISSET(chan
->fds
[x
], &rfds
) && !FD_ISSET(chan
->fds
[x
], &efds
)))
1863 continue; /* nothing on this descriptor */
1865 if (FD_ISSET(chan
->fds
[x
], &efds
))
1866 ast_set_flag(chan
, AST_FLAG_EXCEPTION
);
1868 ast_clear_flag(chan
, AST_FLAG_EXCEPTION
);
1871 /* See if they need servicing */
1873 if (!f
|| (f
->frametype
== AST_FRAME_CONTROL
&& f
->subclass
== AST_CONTROL_HANGUP
)) {
1876 post_manager_event("ParkedCallGiveUp", pu
->parkingexten
, chan
);
1878 /* There's a problem, hang them up*/
1879 if (option_verbose
> 1)
1880 ast_verbose(VERBOSE_PREFIX_2
"%s got tired of being parked\n", chan
->name
);
1882 /* And take them out of the parking lot */
1884 pl
->next
= pu
->next
;
1886 parkinglot
= pu
->next
;
1889 con
= ast_context_find(parking_con
);
1891 if (ast_context_remove_extension2(con
, pt
->parkingexten
, 1, NULL
))
1892 ast_log(LOG_WARNING
, "Whoa, failed to remove the extension!\n");
1894 notify_metermaids(pt
->parkingexten
, parking_con
);
1896 ast_log(LOG_WARNING
, "Whoa, no parking context?\n");
1900 /*! \todo XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
1902 if (pu
->moh_trys
< 3 && !chan
->generatordata
) {
1904 ast_log(LOG_DEBUG
, "MOH on parked call stopped by outside source. Restarting.\n");
1905 ast_indicate_data(pu
->chan
, AST_CONTROL_HOLD
,
1906 S_OR(parkmohclass
, NULL
),
1907 !ast_strlen_zero(parkmohclass
) ? strlen(parkmohclass
) + 1 : 0);
1910 goto std
; /*! \todo XXX Ick: jumping into an else statement??? XXX */
1914 if (x
>= AST_MAX_FDS
) {
1915 std
: for (x
=0; x
<AST_MAX_FDS
; x
++) { /* mark fds for next round */
1916 if (chan
->fds
[x
] > -1) {
1917 FD_SET(chan
->fds
[x
], &nrfds
);
1918 FD_SET(chan
->fds
[x
], &nefds
);
1919 if (chan
->fds
[x
] > max
)
1923 /* Keep track of our shortest wait */
1924 if (tms
< ms
|| ms
< 0)
1931 ast_mutex_unlock(&parking_lock
);
1935 struct timeval tv
= ast_samp2tv(ms
, 1000);
1936 /* Wait for something to happen */
1937 ast_select(max
+ 1, &rfds
, NULL
, &efds
, (ms
> -1) ? &tv
: NULL
);
1939 pthread_testcancel();
1941 return NULL
; /* Never reached */
1944 /*! \brief Park a call */
1945 static int park_call_exec(struct ast_channel
*chan
, void *data
)
1947 /* Cache the original channel name in case we get masqueraded in the middle
1948 * of a park--it is still theoretically possible for a transfer to happen before
1949 * we get here, but it is _really_ unlikely */
1950 char *orig_chan_name
= ast_strdupa(chan
->name
);
1951 char orig_exten
[AST_MAX_EXTENSION
];
1952 int orig_priority
= chan
->priority
;
1954 /* Data is unused at the moment but could contain a parking
1955 lot context eventually */
1957 struct ast_module_user
*u
;
1959 u
= ast_module_user_add(chan
);
1961 ast_copy_string(orig_exten
, chan
->exten
, sizeof(orig_exten
));
1963 /* Setup the exten/priority to be s/1 since we don't know
1964 where this call should return */
1965 strcpy(chan
->exten
, "s");
1967 /* Answer if call is not up */
1968 if (chan
->_state
!= AST_STATE_UP
)
1969 res
= ast_answer(chan
);
1970 /* Sleep to allow VoIP streams to settle down */
1972 res
= ast_safe_sleep(chan
, 1000);
1975 res
= park_call_full(chan
, chan
, 0, NULL
, orig_chan_name
);
1976 /* Continue on in the dialplan */
1978 ast_copy_string(chan
->exten
, orig_exten
, sizeof(chan
->exten
));
1979 chan
->priority
= orig_priority
;
1982 res
= AST_PBX_KEEPALIVE
;
1985 ast_module_user_remove(u
);
1990 /*! \brief Pickup parked call */
1991 static int park_exec(struct ast_channel
*chan
, void *data
)
1994 struct ast_module_user
*u
;
1995 struct ast_channel
*peer
=NULL
;
1996 struct parkeduser
*pu
, *pl
=NULL
;
1997 struct ast_context
*con
;
2000 struct ast_bridge_config config
;
2003 ast_log(LOG_WARNING
, "Parkedcall requires an argument (extension number)\n");
2007 u
= ast_module_user_add(chan
);
2009 park
= atoi((char *)data
);
2010 ast_mutex_lock(&parking_lock
);
2013 if (pu
->parkingnum
== park
) {
2015 pl
->next
= pu
->next
;
2017 parkinglot
= pu
->next
;
2023 ast_mutex_unlock(&parking_lock
);
2026 con
= ast_context_find(parking_con
);
2028 if (ast_context_remove_extension2(con
, pu
->parkingexten
, 1, NULL
))
2029 ast_log(LOG_WARNING
, "Whoa, failed to remove the extension!\n");
2031 notify_metermaids(pu
->parkingexten
, parking_con
);
2033 ast_log(LOG_WARNING
, "Whoa, no parking context?\n");
2035 manager_event(EVENT_FLAG_CALL
, "UnParkedCall",
2040 "CallerIDName: %s\r\n",
2041 pu
->parkingexten
, pu
->chan
->name
, chan
->name
,
2042 S_OR(pu
->chan
->cid
.cid_num
, "<unknown>"),
2043 S_OR(pu
->chan
->cid
.cid_name
, "<unknown>")
2048 /* JK02: it helps to answer the channel if not already up */
2049 if (chan
->_state
!= AST_STATE_UP
)
2053 /* Play a courtesy to the source(s) configured to prefix the bridge connecting */
2055 if (!ast_strlen_zero(courtesytone
)) {
2057 ast_indicate(peer
, AST_CONTROL_UNHOLD
);
2058 if (parkedplay
== 0) {
2059 error
= ast_stream_and_wait(chan
, courtesytone
, chan
->language
, "");
2060 } else if (parkedplay
== 1) {
2061 error
= ast_stream_and_wait(peer
, courtesytone
, chan
->language
, "");
2062 } else if (parkedplay
== 2) {
2063 if (!ast_streamfile(chan
, courtesytone
, chan
->language
) &&
2064 !ast_streamfile(peer
, courtesytone
, chan
->language
)) {
2065 /*! \todo XXX we would like to wait on both! */
2066 res
= ast_waitstream(chan
, "");
2068 res
= ast_waitstream(peer
, "");
2074 ast_log(LOG_WARNING
, "Failed to play courtesy tone!\n");
2076 ast_module_user_remove(u
);
2080 ast_indicate(peer
, AST_CONTROL_UNHOLD
);
2082 res
= ast_channel_make_compatible(chan
, peer
);
2084 ast_log(LOG_WARNING
, "Could not make channels %s and %s compatible for bridge\n", chan
->name
, peer
->name
);
2086 ast_module_user_remove(u
);
2089 /* This runs sorta backwards, since we give the incoming channel control, as if it
2090 were the person called. */
2091 if (option_verbose
> 2)
2092 ast_verbose(VERBOSE_PREFIX_3
"Channel %s connected to parked call %d\n", chan
->name
, park
);
2094 pbx_builtin_setvar_helper(chan
, "PARKEDCHANNEL", peer
->name
);
2095 ast_cdr_setdestchan(chan
->cdr
, peer
->name
);
2096 memset(&config
, 0, sizeof(struct ast_bridge_config
));
2097 ast_set_flag(&(config
.features_callee
), AST_FEATURE_REDIRECT
);
2098 ast_set_flag(&(config
.features_caller
), AST_FEATURE_REDIRECT
);
2099 res
= ast_bridge_call(chan
, peer
, &config
);
2101 pbx_builtin_setvar_helper(chan
, "PARKEDCHANNEL", peer
->name
);
2102 ast_cdr_setdestchan(chan
->cdr
, peer
->name
);
2104 /* Simulate the PBX hanging up */
2105 if (res
!= AST_PBX_NO_HANGUP_PEER
)
2107 ast_module_user_remove(u
);
2110 /*! \todo XXX Play a message XXX */
2111 if (ast_stream_and_wait(chan
, "pbx-invalidpark", chan
->language
, ""))
2112 ast_log(LOG_WARNING
, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan
->name
);
2113 if (option_verbose
> 2)
2114 ast_verbose(VERBOSE_PREFIX_3
"Channel %s tried to talk to nonexistent parked call %d\n", chan
->name
, park
);
2118 ast_module_user_remove(u
);
2123 int ast_hold_call(struct ast_channel
*chan
, struct ast_channel
*peer
)
2125 /* We put the user in the parking list, then wake up the parking thread to be sure it looks
2126 after these channels too */
2127 struct holdeduser
*pu
;
2128 pu
= malloc(sizeof(struct holdeduser
));
2130 memset(pu
, 0, sizeof(pu
));
2131 ast_mutex_lock(&holding_lock
);
2132 chan
->appl
= "Holded Call";
2136 strncpy(pu
->uniqueid
, chan
->uniqueid
, sizeof(pu
->uniqueid
));
2137 strncpy(pu
->uniqueidpeer
, peer
->uniqueid
, sizeof(pu
->uniqueidpeer
));
2138 /* Start music on hold */
2139 ast_moh_start(pu
->chan
, NULL
, NULL
);
2140 gettimeofday(&pu
->start
, NULL
);
2141 pu
->next
= holdlist
;
2143 ast_mutex_unlock(&holding_lock
);
2144 /* Wake up the (presumably select()ing) thread */
2145 pthread_kill(holding_thread
, SIGURG
);
2147 manager_event(EVENT_FLAG_CALL
, "HoldedCall",
2152 ,pu
->chan
->name
, peer
->name
, pu
->chan
->uniqueid
, peer
->uniqueid
);
2155 ast_log(LOG_WARNING
, "Out of memory\n");
2161 int ast_masq_hold_call(struct ast_channel
*rchan
, struct ast_channel
*peer
)
2163 struct ast_channel
*chan
;
2164 struct ast_frame
*f
;
2165 /* Make a new, fake channel that we'll use to masquerade in the real one */
2166 chan
= ast_channel_alloc(0, AST_STATE_DOWN
, 0, 0, "", "", "", 0, "Onhold/%s",rchan
->name
);
2168 /* Let us keep track of the channel name */
2169 ast_string_field_build(chan
, name
, "Onhold/%s",rchan
->name
);
2170 /* Make formats okay */
2171 chan
->readformat
= rchan
->readformat
;
2172 chan
->writeformat
= rchan
->writeformat
;
2173 ast_channel_masquerade(chan
, rchan
);
2174 /* Setup the extensions and such */
2175 strncpy(chan
->context
, rchan
->context
, sizeof(chan
->context
) - 1);
2176 strncpy(chan
->exten
, rchan
->exten
, sizeof(chan
->exten
) - 1);
2177 chan
->priority
= rchan
->priority
;
2178 /* this might be dirty, but we need to preserve the uniqueid */
2179 ast_string_field_build(chan
, uniqueid
, "%s",rchan
->uniqueid
);
2180 /* Make the masq execute */
2184 ast_hold_call(chan
, peer
);
2187 ast_log(LOG_WARNING
, "Unable to create holded channel\n");
2193 int ast_retrieve_call(struct ast_channel
*chan
, char *uniqueid
)
2195 int res
=-1, dres
=-1;
2196 struct ast_channel
*peer
=NULL
;
2197 struct ast_bridge_config config
;
2199 peer
= ast_get_holded_call(uniqueid
);
2201 /* JK02: it helps to answer the channel if not already up */
2202 if (chan
->_state
!= AST_STATE_UP
) {
2207 ast_mutex_unlock(&peer
->lock
);
2209 res
= ast_channel_make_compatible(chan
, peer
);
2211 ast_log(LOG_WARNING
, "Could not make channels %s and %s compatible for bridge\n", chan
->name
, peer
->name
);
2215 /* This runs sorta backwards, since we give the incoming channel control, as if it
2216 were the person called. */
2217 if (option_verbose
> 2)
2218 ast_verbose(VERBOSE_PREFIX_3
"Channel %s connected to holded call %s\n", chan
->name
, peer
->name
);
2220 memset(&config
,0,sizeof(struct ast_bridge_config
));
2221 ast_set_flag(&(config
.features_callee
), AST_FEATURE_REDIRECT
);
2222 ast_set_flag(&(config
.features_caller
), AST_FEATURE_REDIRECT
);
2223 config
.timelimit
= 0;
2224 config
.play_warning
= 0;
2225 config
.warning_freq
= 0;
2226 config
.warning_sound
=NULL
;
2227 res
= ast_bridge_call(chan
,peer
,&config
);
2229 /* Simulate the PBX hanging up */
2230 if (res
!= AST_PBX_NO_HANGUP_PEER
)
2234 /* XXX Play a message XXX */
2235 dres
= ast_streamfile(chan
, "pbx-invalidpark", chan
->language
);
2237 dres
= ast_waitstream(chan
, "");
2239 ast_log(LOG_WARNING
, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan
->name
);
2246 int ast_retrieve_call_to_death(char *uniqueid
)
2249 struct ast_channel
*peer
=NULL
;
2251 peer
= ast_get_holded_call(uniqueid
);
2255 if (option_verbose
> 2)
2256 ast_verbose(VERBOSE_PREFIX_3
"Channel %s removed from hold.\n", peer
->name
);
2257 ast_mutex_unlock(&peer
->lock
);
2260 ast_log(LOG_WARNING
, "Could not find channel with uniqueid %s to retrieve.\n", uniqueid
);
2265 struct ast_channel
*ast_get_holded_call(char *uniqueid
)
2268 struct ast_channel
*peer
=NULL
;
2269 struct holdeduser
*pu
, *pl
=NULL
;
2271 ast_mutex_lock(&holding_lock
);
2274 if (!strncmp(uniqueid
,pu
->uniqueid
,sizeof(pu
->uniqueid
))) {
2276 pl
->next
= pu
->next
;
2278 holdlist
= pu
->next
;
2284 ast_mutex_unlock(&holding_lock
);
2286 peer
= ast_get_channel_by_uniqueid_locked(pu
->uniqueid
);
2290 if (option_verbose
> 2)
2291 ast_verbose(VERBOSE_PREFIX_3
"Channel %s removed from hold.\n", peer
->name
);
2295 if (option_verbose
> 2)
2296 ast_verbose(VERBOSE_PREFIX_3
"Could not find channel with uniqueid %s.\n", uniqueid
);
2300 ast_log(LOG_WARNING
, "Could not find held channel with uniqueid %s to retrieve.\n", uniqueid
);
2305 /* this is our autmagically service thread that keeps channels onhold happy */
2306 static void *do_holding_thread(void *ignore
)
2309 struct holdeduser
*pu
, *pl
, *pt
= NULL
;
2311 struct ast_frame
*f
;
2314 fd_set nrfds
, nefds
;
2320 ast_mutex_lock(&holding_lock
);
2323 gettimeofday(&tv
, NULL
);
2327 tms
= (tv
.tv_sec
- pu
->start
.tv_sec
) * 1000 + (tv
.tv_usec
- pu
->start
.tv_usec
) / 1000;
2328 for (x
=0;x
<AST_MAX_FDS
;x
++) {
2329 if ((pu
->chan
->fds
[x
] > -1) && (FD_ISSET(pu
->chan
->fds
[x
], &rfds
) || FD_ISSET(pu
->chan
->fds
[x
], &efds
))) {
2330 if (FD_ISSET(pu
->chan
->fds
[x
], &efds
))
2331 ast_set_flag(pu
->chan
, AST_FLAG_EXCEPTION
);
2333 ast_clear_flag(pu
->chan
, AST_FLAG_EXCEPTION
);
2335 /* See if they need servicing */
2336 f
= ast_read(pu
->chan
);
2337 if (!f
|| ((f
->frametype
== AST_FRAME_CONTROL
) && (f
->subclass
== AST_CONTROL_HANGUP
))) {
2338 /* There's a problem, hang them up*/
2339 if (option_verbose
> 1)
2340 ast_verbose(VERBOSE_PREFIX_2
"%s got tired of being onhold\n", pu
->chan
->name
);
2341 ast_hangup(pu
->chan
);
2342 /* find the corresponding channel and hang them up too! */
2343 /* but only if it is not bridged yet! */
2344 /* And take them out of the parking lot */
2346 pl
->next
= pu
->next
;
2348 holdlist
= pu
->next
;
2354 /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
2356 goto std
; /* XXX Ick: jumping into an else statement??? XXX */
2360 if (x
>= AST_MAX_FDS
) {
2361 std
: for (x
=0;x
<AST_MAX_FDS
;x
++) {
2362 /* Keep this one for next one */
2363 if (pu
->chan
->fds
[x
] > -1) {
2364 FD_SET(pu
->chan
->fds
[x
], &nrfds
);
2365 FD_SET(pu
->chan
->fds
[x
], &nefds
);
2366 if (pu
->chan
->fds
[x
] > max
)
2367 max
= pu
->chan
->fds
[x
];
2370 /* Keep track of our longest wait */
2371 if ((tms
< ms
) || (ms
< 0))
2377 ast_mutex_unlock(&holding_lock
);
2380 tv
.tv_sec
= ms
/ 1000;
2381 tv
.tv_usec
= (ms
% 1000) * 1000;
2382 /* Wait for something to happen */
2383 ast_select(max
+ 1, &rfds
, NULL
, &efds
, (ms
> -1) ? &tv
: NULL
);
2384 pthread_testcancel();
2386 return NULL
; /* Never reached */
2389 static int retrieve_call_exec(struct ast_channel
*chan
, void *data
) {
2391 struct ast_module_user
*u
;
2392 char *uniqueid
= (char *)data
;
2393 u
= ast_module_user_add(chan
);
2394 res
= ast_retrieve_call(chan
, uniqueid
);
2395 ast_module_user_remove(u
);
2399 static int handle_showfeatures(int fd
, int argc
, char *argv
[])
2402 struct ast_call_feature
*feature
;
2403 char format
[] = "%-25s %-7s %-7s\n";
2405 ast_cli(fd
, format
, "Builtin Feature", "Default", "Current");
2406 ast_cli(fd
, format
, "---------------", "-------", "-------");
2408 ast_cli(fd
, format
, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */
2410 ast_rwlock_rdlock(&features_lock
);
2411 for (i
= 0; i
< FEATURES_COUNT
; i
++)
2412 ast_cli(fd
, format
, builtin_features
[i
].fname
, builtin_features
[i
].default_exten
, builtin_features
[i
].exten
);
2413 ast_rwlock_unlock(&features_lock
);
2416 ast_cli(fd
, format
, "Dynamic Feature", "Default", "Current");
2417 ast_cli(fd
, format
, "---------------", "-------", "-------");
2418 if (AST_LIST_EMPTY(&feature_list
))
2419 ast_cli(fd
, "(none)\n");
2421 AST_LIST_LOCK(&feature_list
);
2422 AST_LIST_TRAVERSE(&feature_list
, feature
, feature_entry
)
2423 ast_cli(fd
, format
, feature
->sname
, "no def", feature
->exten
);
2424 AST_LIST_UNLOCK(&feature_list
);
2426 ast_cli(fd
, "\nCall parking\n");
2427 ast_cli(fd
, "------------\n");
2428 ast_cli(fd
,"%-20s: %s\n", "Parking extension", parking_ext
);
2429 ast_cli(fd
,"%-20s: %s\n", "Parking context", parking_con
);
2430 ast_cli(fd
,"%-20s: %d-%d\n", "Parked call extensions", parking_start
, parking_stop
);
2433 return RESULT_SUCCESS
;
2436 static char showfeatures_help
[] =
2437 "Usage: feature list\n"
2438 " Lists currently configured features.\n";
2440 static int handle_parkedcalls(int fd
, int argc
, char *argv
[])
2442 struct parkeduser
*cur
;
2445 ast_cli(fd
, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
2446 , "Context", "Extension", "Pri", "Timeout");
2448 ast_mutex_lock(&parking_lock
);
2450 for (cur
= parkinglot
; cur
; cur
= cur
->next
) {
2451 ast_cli(fd
, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n"
2452 ,cur
->parkingexten
, cur
->chan
->name
, cur
->context
, cur
->exten
2453 ,cur
->priority
, cur
->start
.tv_sec
+ (cur
->parkingtime
/1000) - time(NULL
));
2457 ast_mutex_unlock(&parking_lock
);
2458 ast_cli(fd
, "%d parked call%s.\n", numparked
, (numparked
!= 1) ? "s" : "");
2461 return RESULT_SUCCESS
;
2464 static char showparked_help
[] =
2465 "Usage: show parkedcalls\n"
2466 " Lists currently parked calls.\n";
2468 static struct ast_cli_entry cli_show_features_deprecated
= {
2469 { "show", "features", NULL
},
2470 handle_showfeatures
, NULL
,
2473 static struct ast_cli_entry cli_features
[] = {
2474 { { "feature", "show", NULL
},
2475 handle_showfeatures
, "Lists configured features",
2476 showfeatures_help
, NULL
, &cli_show_features_deprecated
},
2478 { { "show", "parkedcalls", NULL
},
2479 handle_parkedcalls
, "Lists parked calls",
2483 /*! \brief Dump lot status */
2484 static int manager_parking_status( struct mansession
*s
, const struct message
*m
)
2486 struct parkeduser
*cur
;
2487 const char *id
= astman_get_header(m
, "ActionID");
2488 char idText
[256] = "";
2490 if (!ast_strlen_zero(id
))
2491 snprintf(idText
, sizeof(idText
), "ActionID: %s\r\n", id
);
2493 astman_send_ack(s
, m
, "Parked calls will follow");
2495 ast_mutex_lock(&parking_lock
);
2497 for (cur
= parkinglot
; cur
; cur
= cur
->next
) {
2498 astman_append(s
, "Event: ParkedCall\r\n"
2504 "CallerIDName: %s\r\n"
2507 cur
->parkingnum
, cur
->chan
->name
, cur
->peername
,
2508 (long) cur
->start
.tv_sec
+ (long) (cur
->parkingtime
/ 1000) - (long) time(NULL
),
2509 S_OR(cur
->chan
->cid
.cid_num
, ""), /* XXX in other places it is <unknown> */
2510 S_OR(cur
->chan
->cid
.cid_name
, ""),
2515 "Event: ParkedCallsComplete\r\n"
2519 ast_mutex_unlock(&parking_lock
);
2521 return RESULT_SUCCESS
;
2524 static char mandescr_park
[] =
2525 "Description: Park a channel.\n"
2526 "Variables: (Names marked with * are required)\n"
2527 " *Channel: Channel name to park\n"
2528 " *Channel2: Channel to announce park info to (and return to if timeout)\n"
2529 " Timeout: Number of milliseconds to wait before callback.\n";
2531 static int manager_park(struct mansession
*s
, const struct message
*m
)
2533 const char *channel
= astman_get_header(m
, "Channel");
2534 const char *channel2
= astman_get_header(m
, "Channel2");
2535 const char *timeout
= astman_get_header(m
, "Timeout");
2540 struct ast_channel
*ch1
, *ch2
;
2542 if (ast_strlen_zero(channel
)) {
2543 astman_send_error(s
, m
, "Channel not specified");
2547 if (ast_strlen_zero(channel2
)) {
2548 astman_send_error(s
, m
, "Channel2 not specified");
2552 ch1
= ast_get_channel_by_name_locked(channel
);
2554 snprintf(buf
, sizeof(buf
), "Channel does not exist: %s", channel
);
2555 astman_send_error(s
, m
, buf
);
2559 ch2
= ast_get_channel_by_name_locked(channel2
);
2561 snprintf(buf
, sizeof(buf
), "Channel does not exist: %s", channel2
);
2562 astman_send_error(s
, m
, buf
);
2563 ast_channel_unlock(ch1
);
2567 if (!ast_strlen_zero(timeout
)) {
2568 sscanf(timeout
, "%d", &to
);
2571 res
= ast_masq_park_call(ch1
, ch2
, to
, &parkExt
);
2573 ast_softhangup(ch2
, AST_SOFTHANGUP_EXPLICIT
);
2574 astman_send_ack(s
, m
, "Park successful");
2576 astman_send_error(s
, m
, "Park failure");
2579 ast_channel_unlock(ch1
);
2580 ast_channel_unlock(ch2
);
2586 int ast_pickup_call(struct ast_channel
*chan
)
2588 struct ast_channel
*cur
= NULL
;
2591 while ( (cur
= ast_channel_walk_locked(cur
)) != NULL
) {
2594 (chan
->pickupgroup
& cur
->callgroup
) &&
2595 ((cur
->_state
== AST_STATE_RINGING
) ||
2596 (cur
->_state
== AST_STATE_RING
))) {
2599 ast_channel_unlock(cur
);
2603 ast_log(LOG_DEBUG
, "Call pickup on chan '%s' by '%s'\n",cur
->name
, chan
->name
);
2604 res
= ast_answer(chan
);
2606 ast_log(LOG_WARNING
, "Unable to answer '%s'\n", chan
->name
);
2607 res
= ast_queue_control(chan
, AST_CONTROL_ANSWER
);
2609 ast_log(LOG_WARNING
, "Unable to queue answer on '%s'\n", chan
->name
);
2610 res
= ast_channel_masquerade(cur
, chan
);
2612 ast_log(LOG_WARNING
, "Unable to masquerade '%s' into '%s'\n", chan
->name
, cur
->name
); /* Done */
2613 ast_channel_unlock(cur
);
2616 ast_log(LOG_DEBUG
, "No call pickup possible...\n");
2621 /*! \brief Add parking hints for all defined parking lots */
2622 static void park_add_hints(char *context
, int start
, int stop
)
2625 char device
[AST_MAX_EXTENSION
];
2628 for (numext
= start
; numext
<= stop
; numext
++) {
2629 snprintf(exten
, sizeof(exten
), "%d", numext
);
2630 snprintf(device
, sizeof(device
), "park:%s@%s", exten
, context
);
2631 ast_add_extension(context
, 1, exten
, PRIORITY_HINT
, NULL
, NULL
, device
, NULL
, NULL
, registrar
);
2636 static int load_config(void)
2638 int start
= 0, end
= 0;
2640 struct ast_context
*con
= NULL
;
2641 struct ast_config
*cfg
= NULL
;
2642 struct ast_variable
*var
= NULL
;
2643 char old_parking_ext
[AST_MAX_EXTENSION
];
2644 char old_parking_con
[AST_MAX_EXTENSION
] = "";
2646 if (!ast_strlen_zero(parking_con
)) {
2647 strcpy(old_parking_ext
, parking_ext
);
2648 strcpy(old_parking_con
, parking_con
);
2651 /* Reset to defaults */
2652 strcpy(parking_con
, "parkedcalls");
2653 strcpy(parking_con_dial
, "park-dial");
2654 strcpy(parking_ext
, "700");
2655 strcpy(pickup_ext
, "*8");
2656 strcpy(parkmohclass
, "default");
2657 courtesytone
[0] = '\0';
2658 strcpy(xfersound
, "beep");
2659 strcpy(xferfailsound
, "pbx-invalid");
2660 parking_start
= 701;
2666 transferdigittimeout
= DEFAULT_TRANSFER_DIGIT_TIMEOUT
;
2667 featuredigittimeout
= DEFAULT_FEATURE_DIGIT_TIMEOUT
;
2668 atxfernoanswertimeout
= DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER
;
2670 cfg
= ast_config_load("features.conf");
2672 ast_log(LOG_WARNING
,"Could not load features.conf\n");
2673 return AST_MODULE_LOAD_DECLINE
;
2675 for (var
= ast_variable_browse(cfg
, "general"); var
; var
= var
->next
) {
2676 if (!strcasecmp(var
->name
, "parkext")) {
2677 ast_copy_string(parking_ext
, var
->value
, sizeof(parking_ext
));
2678 } else if (!strcasecmp(var
->name
, "context")) {
2679 ast_copy_string(parking_con
, var
->value
, sizeof(parking_con
));
2680 } else if (!strcasecmp(var
->name
, "parkingtime")) {
2681 if ((sscanf(var
->value
, "%d", &parkingtime
) != 1) || (parkingtime
< 1)) {
2682 ast_log(LOG_WARNING
, "%s is not a valid parkingtime\n", var
->value
);
2683 parkingtime
= DEFAULT_PARK_TIME
;
2685 parkingtime
= parkingtime
* 1000;
2686 } else if (!strcasecmp(var
->name
, "parkpos")) {
2687 if (sscanf(var
->value
, "%d-%d", &start
, &end
) != 2) {
2688 ast_log(LOG_WARNING
, "Format for parking positions is a-b, where a and b are numbers at line %d of features.conf\n", var
->lineno
);
2690 parking_start
= start
;
2693 } else if (!strcasecmp(var
->name
, "findslot")) {
2694 parkfindnext
= (!strcasecmp(var
->value
, "next"));
2695 } else if (!strcasecmp(var
->name
, "parkinghints")) {
2696 parkaddhints
= ast_true(var
->value
);
2697 } else if (!strcasecmp(var
->name
, "adsipark")) {
2698 adsipark
= ast_true(var
->value
);
2699 } else if (!strcasecmp(var
->name
, "transferdigittimeout")) {
2700 if ((sscanf(var
->value
, "%d", &transferdigittimeout
) != 1) || (transferdigittimeout
< 1)) {
2701 ast_log(LOG_WARNING
, "%s is not a valid transferdigittimeout\n", var
->value
);
2702 transferdigittimeout
= DEFAULT_TRANSFER_DIGIT_TIMEOUT
;
2704 transferdigittimeout
= transferdigittimeout
* 1000;
2705 } else if (!strcasecmp(var
->name
, "featuredigittimeout")) {
2706 if ((sscanf(var
->value
, "%d", &featuredigittimeout
) != 1) || (featuredigittimeout
< 1)) {
2707 ast_log(LOG_WARNING
, "%s is not a valid featuredigittimeout\n", var
->value
);
2708 featuredigittimeout
= DEFAULT_FEATURE_DIGIT_TIMEOUT
;
2710 } else if (!strcasecmp(var
->name
, "atxfernoanswertimeout")) {
2711 if ((sscanf(var
->value
, "%d", &atxfernoanswertimeout
) != 1) || (atxfernoanswertimeout
< 1)) {
2712 ast_log(LOG_WARNING
, "%s is not a valid atxfernoanswertimeout\n", var
->value
);
2713 atxfernoanswertimeout
= DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER
;
2715 atxfernoanswertimeout
= atxfernoanswertimeout
* 1000;
2716 } else if (!strcasecmp(var
->name
, "courtesytone")) {
2717 ast_copy_string(courtesytone
, var
->value
, sizeof(courtesytone
));
2718 } else if (!strcasecmp(var
->name
, "parkedplay")) {
2719 if (!strcasecmp(var
->value
, "both"))
2721 else if (!strcasecmp(var
->value
, "parked"))
2725 } else if (!strcasecmp(var
->name
, "xfersound")) {
2726 ast_copy_string(xfersound
, var
->value
, sizeof(xfersound
));
2727 } else if (!strcasecmp(var
->name
, "xferfailsound")) {
2728 ast_copy_string(xferfailsound
, var
->value
, sizeof(xferfailsound
));
2729 } else if (!strcasecmp(var
->name
, "pickupexten")) {
2730 ast_copy_string(pickup_ext
, var
->value
, sizeof(pickup_ext
));
2731 } else if (!strcasecmp(var
->name
, "parkedmusicclass")) {
2732 ast_copy_string(parkmohclass
, var
->value
, sizeof(parkmohclass
));
2737 for (var
= ast_variable_browse(cfg
, "featuremap"); var
; var
= var
->next
) {
2738 if (remap_feature(var
->name
, var
->value
))
2739 ast_log(LOG_NOTICE
, "Unknown feature '%s'\n", var
->name
);
2742 /* Map a key combination to an application*/
2743 ast_unregister_features();
2744 for (var
= ast_variable_browse(cfg
, "applicationmap"); var
; var
= var
->next
) {
2745 char *tmp_val
= ast_strdupa(var
->value
);
2746 char *exten
, *activateon
, *activatedby
, *app
, *app_args
, *moh_class
;
2747 struct ast_call_feature
*feature
;
2749 /* strsep() sets the argument to NULL if match not found, and it
2750 * is safe to use it with a NULL argument, so we don't check
2753 exten
= strsep(&tmp_val
,",");
2754 activatedby
= strsep(&tmp_val
,",");
2755 app
= strsep(&tmp_val
,",");
2756 app_args
= strsep(&tmp_val
,",");
2757 moh_class
= strsep(&tmp_val
,",");
2759 activateon
= strsep(&activatedby
, "/");
2761 /*! \todo XXX var_name or app_args ? */
2762 if (ast_strlen_zero(app
) || ast_strlen_zero(exten
) || ast_strlen_zero(activateon
) || ast_strlen_zero(var
->name
)) {
2763 ast_log(LOG_NOTICE
, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",
2764 app
, exten
, activateon
, var
->name
);
2768 AST_LIST_LOCK(&feature_list
);
2769 if ((feature
= find_dynamic_feature(var
->name
))) {
2770 AST_LIST_UNLOCK(&feature_list
);
2771 ast_log(LOG_WARNING
, "Dynamic Feature '%s' specified more than once!\n", var
->name
);
2774 AST_LIST_UNLOCK(&feature_list
);
2776 if (!(feature
= ast_calloc(1, sizeof(*feature
))))
2779 ast_copy_string(feature
->sname
, var
->name
, FEATURE_SNAME_LEN
);
2780 ast_copy_string(feature
->app
, app
, FEATURE_APP_LEN
);
2781 ast_copy_string(feature
->exten
, exten
, FEATURE_EXTEN_LEN
);
2784 ast_copy_string(feature
->app_args
, app_args
, FEATURE_APP_ARGS_LEN
);
2787 ast_copy_string(feature
->moh_class
, moh_class
, FEATURE_MOH_LEN
);
2789 ast_copy_string(feature
->exten
, exten
, sizeof(feature
->exten
));
2790 feature
->operation
= feature_exec_app
;
2791 ast_set_flag(feature
, AST_FEATURE_FLAG_NEEDSDTMF
);
2793 /* Allow caller and calle to be specified for backwards compatability */
2794 if (!strcasecmp(activateon
, "self") || !strcasecmp(activateon
, "caller"))
2795 ast_set_flag(feature
, AST_FEATURE_FLAG_ONSELF
);
2796 else if (!strcasecmp(activateon
, "peer") || !strcasecmp(activateon
, "callee"))
2797 ast_set_flag(feature
, AST_FEATURE_FLAG_ONPEER
);
2799 ast_log(LOG_NOTICE
, "Invalid 'ActivateOn' specification for feature '%s',"
2800 " must be 'self', or 'peer'\n", var
->name
);
2804 if (ast_strlen_zero(activatedby
))
2805 ast_set_flag(feature
, AST_FEATURE_FLAG_BYBOTH
);
2806 else if (!strcasecmp(activatedby
, "caller"))
2807 ast_set_flag(feature
, AST_FEATURE_FLAG_BYCALLER
);
2808 else if (!strcasecmp(activatedby
, "callee"))
2809 ast_set_flag(feature
, AST_FEATURE_FLAG_BYCALLEE
);
2810 else if (!strcasecmp(activatedby
, "both"))
2811 ast_set_flag(feature
, AST_FEATURE_FLAG_BYBOTH
);
2813 ast_log(LOG_NOTICE
, "Invalid 'ActivatedBy' specification for feature '%s',"
2814 " must be 'caller', or 'callee', or 'both'\n", var
->name
);
2818 ast_register_feature(feature
);
2820 if (option_verbose
>= 1)
2821 ast_verbose(VERBOSE_PREFIX_2
"Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var
->name
, app
, app_args
, exten
);
2823 ast_config_destroy(cfg
);
2825 /* Remove the old parking extension */
2826 if (!ast_strlen_zero(old_parking_con
) && (con
= ast_context_find(old_parking_con
))) {
2827 if(ast_context_remove_extension2(con
, old_parking_ext
, 1, registrar
))
2828 notify_metermaids(old_parking_ext
, old_parking_con
);
2830 ast_log(LOG_DEBUG
, "Removed old parking extension %s@%s\n", old_parking_ext
, old_parking_con
);
2833 if (!(con
= ast_context_find(parking_con
)) && !(con
= ast_context_create(NULL
, parking_con
, registrar
))) {
2834 ast_log(LOG_ERROR
, "Parking context '%s' does not exist and unable to create\n", parking_con
);
2837 res
= ast_add_extension2(con
, 1, ast_parking_ext(), 1, NULL
, NULL
, parkcall
, NULL
, NULL
, registrar
);
2839 park_add_hints(parking_con
, parking_start
, parking_stop
);
2841 notify_metermaids(ast_parking_ext(), parking_con
);
2846 static int reload(void)
2848 return load_config();
2851 static int load_module(void)
2855 memset(parking_ext
, 0, sizeof(parking_ext
));
2856 memset(parking_con
, 0, sizeof(parking_con
));
2858 if ((res
= load_config()))
2860 ast_cli_register_multiple(cli_features
, sizeof(cli_features
) / sizeof(struct ast_cli_entry
));
2861 ast_pthread_create(&parking_thread
, NULL
, do_parking_thread
, NULL
);
2862 ast_pthread_create(&holding_thread
, NULL
, do_holding_thread
, NULL
);
2863 res
= ast_register_application(parkedcall
, park_exec
, synopsis
, descrip
);
2865 res
= ast_register_application(parkcall
, park_call_exec
, synopsis2
, descrip2
);
2867 ast_manager_register("ParkedCalls", 0, manager_parking_status
, "List parked calls" );
2868 ast_manager_register2("Park", EVENT_FLAG_CALL
, manager_park
,
2869 "Park a channel", mandescr_park
);
2872 res
|= ast_register_application(holdedcall
, retrieve_call_exec
, synopsis
, descrip
);
2873 res
|= ast_devstate_prov_add("Park", metermaidstate
);
2879 static int unload_module(void)
2881 ast_module_user_hangup_all();
2883 ast_manager_unregister("ParkedCalls");
2884 ast_manager_unregister("Park");
2885 ast_cli_unregister_multiple(cli_features
, sizeof(cli_features
) / sizeof(struct ast_cli_entry
));
2886 ast_unregister_application(parkcall
);
2887 ast_unregister_application(holdedcall
);
2888 ast_devstate_prov_del("Park");
2889 return ast_unregister_application(parkedcall
);
2892 AST_MODULE_INFO(ASTERISK_GPL_KEY
, AST_MODFLAG_GLOBAL_SYMBOLS
, "Call Features Resource",
2893 .load
= load_module
,
2894 .unload
= unload_module
,