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 #ifdef __AST_DEBUG_MALLOC
63 static void FREE(void *ptr)
71 #define DEFAULT_PARK_TIME 45000
72 #define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000
73 #define DEFAULT_FEATURE_DIGIT_TIMEOUT 500
74 #define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000
76 #define AST_MAX_WATCHERS 256
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 int parking_start; /*!< First available extension for parking */
87 static int parking_stop; /*!< Last available extension for parking */
89 static char courtesytone[256]; /*!< Courtesy tone */
90 static int parkedplay = 0; /*!< Who to play the courtesy tone to */
91 static char xfersound[256]; /*!< Call transfer sound */
92 static char xferfailsound[256]; /*!< Call transfer failure sound */
94 static int parking_offset;
95 static int parkfindnext;
99 static int transferdigittimeout;
100 static int featuredigittimeout;
102 static int atxfernoanswertimeout;
104 static char *registrar = "res_features"; /*!< Registrar for operations */
106 /* module and CLI command definitions */
107 static char *synopsis = "Answer a parked call";
109 static char *descrip = "ParkedCall(exten):"
110 "Used to connect to a parked call. This application is always\n"
111 "registered internally and does not need to be explicitly added\n"
112 "into the dialplan, although you should include the 'parkedcalls'\n"
115 static char *parkcall = "Park";
117 static char *synopsis2 = "Park yourself";
119 static char *descrip2 = "Park():"
120 "Used to park yourself (typically in combination with a supervised\n"
121 "transfer to know the parking space). This application is always\n"
122 "registered internally and does not need to be explicitly added\n"
123 "into the dialplan, although you should include the 'parkedcalls'\n"
124 "context (or the context specified in features.conf).\n\n"
125 "If you set the PARKINGEXTEN variable to an extension in your\n"
126 "parking context, park() will park the call on that extension, unless\n"
127 "it already exists. In that case, execution will continue at next\n"
130 static struct ast_app *monitor_app = NULL;
131 static int monitor_ok = 1;
134 struct ast_channel *chan; /*!< Parking channel */
135 struct timeval start; /*!< Time the parking started */
136 int parkingnum; /*!< Parking lot */
137 char parkingexten[AST_MAX_EXTENSION]; /*!< If set beforehand, parking extension used for this call */
138 char context[AST_MAX_CONTEXT]; /*!< Where to go if our parking time expires */
139 char exten[AST_MAX_EXTENSION];
141 int parkingtime; /*!< Maximum length in parking lot before return */
144 unsigned char moh_trys;
145 struct parkeduser *next;
148 static struct parkeduser *parkinglot;
150 AST_MUTEX_DEFINE_STATIC(parking_lock); /*!< protects all static variables above */
152 static pthread_t parking_thread;
154 char *ast_parking_ext(void)
159 char *ast_pickup_ext(void)
164 struct ast_bridge_thread_obj
166 struct ast_bridge_config bconfig;
167 struct ast_channel *chan;
168 struct ast_channel *peer;
171 /*! \brief store context, priority and extension */
172 static void set_c_e_p(struct ast_channel *chan, const char *context, const char *ext, int pri)
174 ast_copy_string(chan->context, context, sizeof(chan->context));
175 ast_copy_string(chan->exten, ext, sizeof(chan->exten));
176 chan->priority = pri;
179 static void check_goto_on_transfer(struct ast_channel *chan)
181 struct ast_channel *xferchan;
182 const char *val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR");
183 char *x, *goto_on_transfer;
186 if (ast_strlen_zero(val))
189 goto_on_transfer = ast_strdupa(val);
191 if (!(xferchan = ast_channel_alloc(0)))
194 for (x = goto_on_transfer; x && *x; x++) {
198 ast_string_field_set(xferchan, name, chan->name);
199 /* Make formats okay */
200 xferchan->readformat = chan->readformat;
201 xferchan->writeformat = chan->writeformat;
202 ast_channel_masquerade(xferchan, chan);
203 ast_parseable_goto(xferchan, goto_on_transfer);
204 xferchan->_state = AST_STATE_UP;
205 ast_clear_flag(xferchan, AST_FLAGS_ALL);
206 xferchan->_softhangup = 0;
207 if ((f = ast_read(xferchan))) {
210 ast_pbx_start(xferchan);
212 ast_hangup(xferchan);
216 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);
219 static void *ast_bridge_call_thread(void *data)
221 struct ast_bridge_thread_obj *tobj = data;
223 tobj->chan->appl = "Transferred Call";
224 tobj->chan->data = tobj->peer->name;
225 tobj->peer->appl = "Transferred Call";
226 tobj->peer->data = tobj->chan->name;
227 if (tobj->chan->cdr) {
228 ast_cdr_reset(tobj->chan->cdr, NULL);
229 ast_cdr_setdestchan(tobj->chan->cdr, tobj->peer->name);
231 if (tobj->peer->cdr) {
232 ast_cdr_reset(tobj->peer->cdr, NULL);
233 ast_cdr_setdestchan(tobj->peer->cdr, tobj->chan->name);
236 ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
237 ast_hangup(tobj->chan);
238 ast_hangup(tobj->peer);
239 bzero(tobj, sizeof(*tobj)); /*! \todo XXX for safety */
244 static void ast_bridge_call_thread_launch(void *data)
248 struct sched_param sched;
250 pthread_attr_init(&attr);
251 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
252 ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data);
253 pthread_attr_destroy(&attr);
254 memset(&sched, 0, sizeof(sched));
255 pthread_setschedparam(thread, SCHED_RR, &sched);
258 static int adsi_announce_park(struct ast_channel *chan, char *parkingexten)
261 int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
263 char *message[5] = {NULL, NULL, NULL, NULL, NULL};
265 snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten);
267 res = adsi_load_session(chan, NULL, 0, 1);
270 return adsi_print(chan, message, justify, 1);
273 /*! \brief Notify metermaids that we've changed an extension */
274 static void notify_metermaids(char *exten, char *context)
276 if (option_debug > 3)
277 ast_log(LOG_DEBUG, "Notification of state change to metermaids %s@%s\n", exten, context);
279 /* Send notification to devicestate subsystem */
280 ast_device_state_changed("park:%s@%s", exten, context);
284 /*! \brief metermaids callback from devicestate.c */
285 static int metermaidstate(const char *data)
287 int res = AST_DEVICE_INVALID;
288 char *context = ast_strdupa(data);
291 exten = strsep(&context, "@");
295 if (option_debug > 3)
296 ast_log(LOG_DEBUG, "Checking state of exten %s in context %s\n", exten, context);
298 res = ast_exists_extension(NULL, context, exten, 1, NULL);
301 return AST_DEVICE_NOT_INUSE;
303 return AST_DEVICE_INUSE;
306 /*! \brief Park a call
307 \note We put the user in the parking list, then wake up the parking thread to be sure it looks
308 after these channels too */
309 int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
311 struct parkeduser *pu, *cur;
312 int i, x = -1, parking_range;
313 struct ast_context *con;
314 const char *parkingexten;
316 /* Allocate memory for parking data */
317 if (!(pu = ast_calloc(1, sizeof(*pu))))
320 /* Lock parking lot */
321 ast_mutex_lock(&parking_lock);
322 /* Check for channel variable PARKINGEXTEN */
323 parkingexten = pbx_builtin_getvar_helper(chan, "PARKINGEXTEN");
324 if (!ast_strlen_zero(parkingexten)) {
325 if (ast_exists_extension(NULL, parking_con, parkingexten, 1, NULL)) {
326 ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parking_con);
327 return 0; /* Continue execution if possible */
329 ast_copy_string(pu->parkingexten, parkingexten, sizeof(pu->parkingexten));
331 /* Select parking space within range */
332 parking_range = parking_stop - parking_start+1;
333 for (i = 0; i < parking_range; i++) {
334 x = (i + parking_offset) % parking_range + parking_start;
337 if (cur->parkingnum == x)
345 if (!(i < parking_range)) {
346 ast_log(LOG_WARNING, "No more parking spaces\n");
348 ast_mutex_unlock(&parking_lock);
351 /* Set pointer for next parking */
353 parking_offset = x - parking_start + 1;
356 chan->appl = "Parked Call";
361 /* Start music on hold if we have two different channels */
363 ast_indicate(pu->chan, AST_CONTROL_HOLD); /* Indicate to peer that we're on hold */
364 ast_moh_start(pu->chan, NULL);
366 pu->start = ast_tvnow();
368 pu->parkingtime = (timeout > 0) ? timeout : parkingtime;
373 ast_copy_string(pu->peername, peer->name, sizeof(pu->peername));
375 /* Remember what had been dialed, so that if the parking
376 expires, we try to come back to the same place */
377 ast_copy_string(pu->context, S_OR(chan->macrocontext, chan->context), sizeof(pu->context));
378 ast_copy_string(pu->exten, S_OR(chan->macroexten, chan->exten), sizeof(pu->exten));
379 pu->priority = chan->macropriority ? chan->macropriority : chan->priority;
380 pu->next = parkinglot;
383 /* If parking a channel directly, don't quiet yet get parking running on it */
386 ast_mutex_unlock(&parking_lock);
387 /* Wake up the (presumably select()ing) thread */
388 pthread_kill(parking_thread, SIGURG);
389 if (option_verbose > 1)
390 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));
392 if (pu->parkingnum != -1)
393 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", x);
394 manager_event(EVENT_FLAG_CALL, "ParkedCall",
400 "CallerIDName: %s\r\n",
401 pu->parkingexten, pu->chan->name, peer ? peer->name : "",
402 (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL),
403 S_OR(pu->chan->cid.cid_num, "<unknown>"),
404 S_OR(pu->chan->cid.cid_name, "<unknown>")
407 if (peer && adsipark && adsi_available(peer)) {
408 adsi_announce_park(peer, pu->parkingexten); /* Only supports parking numbers */
409 adsi_unload_session(peer);
412 con = ast_context_find(parking_con);
414 con = ast_context_create(NULL, parking_con, registrar);
415 if (!con) /* Still no context? Bad */
416 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
417 else { /* Add extension to context */
418 if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, strdup(pu->parkingexten), FREE, registrar))
419 notify_metermaids(pu->parkingexten, parking_con);
421 /* Tell the peer channel the number of the parking space */
422 if (peer && !pu->parkingnum == -1) /* Only say number if it's a number */
423 ast_say_digits(peer, pu->parkingnum, "", peer->language);
424 if (pu->notquiteyet) {
425 /* Wake up parking thread if we're really done */
426 ast_moh_start(pu->chan, NULL);
428 pthread_kill(parking_thread, SIGURG);
433 int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
435 struct ast_channel *chan;
438 /* Make a new, fake channel that we'll use to masquerade in the real one */
439 if (!(chan = ast_channel_alloc(0))) {
440 ast_log(LOG_WARNING, "Unable to create parked channel\n");
443 /* Let us keep track of the channel name */
444 ast_string_field_build(chan, name, "Parked/%s",rchan->name);
446 /* Make formats okay */
447 chan->readformat = rchan->readformat;
448 chan->writeformat = rchan->writeformat;
449 ast_channel_masquerade(chan, rchan);
451 /* Setup the extensions and such */
452 set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority);
454 /* Make the masq execute */
459 ast_park_call(chan, peer, timeout, extout);
464 #define FEATURE_RETURN_HANGUP -1
465 #define FEATURE_RETURN_SUCCESSBREAK 0
466 #define FEATURE_RETURN_PBX_KEEPALIVE AST_PBX_KEEPALIVE
467 #define FEATURE_RETURN_NO_HANGUP_PEER AST_PBX_NO_HANGUP_PEER
468 #define FEATURE_RETURN_PASSDIGITS 21
469 #define FEATURE_RETURN_STOREDIGITS 22
470 #define FEATURE_RETURN_SUCCESS 23
472 #define FEATURE_SENSE_CHAN (1 << 0)
473 #define FEATURE_SENSE_PEER (1 << 1)
476 * set caller and callee according to the direction
478 static void set_peers(struct ast_channel **caller, struct ast_channel **callee,
479 struct ast_channel *peer, struct ast_channel *chan, int sense)
481 if (sense == FEATURE_SENSE_PEER) {
490 /*! \brief support routing for one touch call parking */
491 static int builtin_parkcall(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
493 struct ast_channel *parker;
494 struct ast_channel *parkee;
500 set_peers(&parker, &parkee, peer, chan, sense);
501 /* Setup the exten/priority to be s/1 since we don't know
502 where this call should return */
503 strcpy(chan->exten, "s");
505 if (chan->_state != AST_STATE_UP)
506 res = ast_answer(chan);
508 res = ast_safe_sleep(chan, 1000);
510 res = ast_park_call(parkee, parker, 0, NULL);
511 LOCAL_USER_REMOVE(u);
513 if (sense == FEATURE_SENSE_CHAN)
514 res = AST_PBX_NO_HANGUP_PEER;
516 res = AST_PBX_KEEPALIVE;
522 static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
524 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
527 struct ast_channel *caller_chan, *callee_chan;
530 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
534 if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) {
536 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
540 set_peers(&caller_chan, &callee_chan, peer, chan, sense);
542 if (!ast_strlen_zero(courtesytone)) {
543 if (ast_autoservice_start(callee_chan))
545 if (ast_stream_and_wait(caller_chan, courtesytone, caller_chan->language, "")) {
546 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
547 ast_autoservice_stop(callee_chan);
550 if (ast_autoservice_stop(callee_chan))
554 if (callee_chan->monitor) {
555 if (option_verbose > 3)
556 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to stop recording call.\n", code);
557 ast_monitor_stop(callee_chan, 1);
558 return FEATURE_RETURN_SUCCESS;
561 if (caller_chan && callee_chan) {
562 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT");
563 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
566 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
569 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
572 len = strlen(touch_monitor) + 50;
574 touch_filename = alloca(len);
575 snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor);
576 snprintf(args, len, "%s|%s|m", (touch_format) ? touch_format : "wav", touch_filename);
578 caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name));
579 callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name));
580 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
582 touch_filename = alloca(len);
583 snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id);
584 snprintf(args, len, "%s|%s|m", S_OR(touch_format, "wav"), touch_filename);
587 for( x = 0; x < strlen(args); x++) {
592 if (option_verbose > 3)
593 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call. filename: %s\n", code, args);
595 pbx_exec(callee_chan, monitor_app, args);
596 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
597 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
599 return FEATURE_RETURN_SUCCESS;
602 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");
606 static int builtin_disconnect(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
608 if (option_verbose > 3)
609 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code);
610 return FEATURE_RETURN_HANGUP;
613 static int finishup(struct ast_channel *chan)
618 res = ast_autoservice_stop(chan);
619 ast_indicate(chan, AST_CONTROL_UNHOLD);
623 /*! \brief Find the context for the transfer */
624 static const char *real_ctx(struct ast_channel *transferer, struct ast_channel *transferee)
626 const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT");
627 if (ast_strlen_zero(s))
628 s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT");
629 if (ast_strlen_zero(s)) /* Use the non-macro context to transfer the call XXX ? */
630 s = transferer->macrocontext;
631 if (ast_strlen_zero(s))
632 s = transferer->context;
636 static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
638 struct ast_channel *transferer;
639 struct ast_channel *transferee;
640 const char *transferer_real_context;
644 set_peers(&transferer, &transferee, peer, chan, sense);
645 transferer_real_context = real_ctx(transferer, transferee);
646 /* Start autoservice on chan while we talk to the originator */
647 ast_indicate(transferee, AST_CONTROL_HOLD);
648 ast_autoservice_start(transferee);
649 ast_moh_start(transferee, NULL);
651 memset(xferto, 0, sizeof(xferto));
654 res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY);
656 finishup(transferee);
657 return -1; /* error ? */
659 if (res > 0) /* If they've typed a digit already, handle it */
660 xferto[0] = (char) res;
662 ast_stopstream(transferer);
663 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
664 if (res < 0) { /* hangup, would be 0 for invalid and 1 for valid */
665 finishup(transferee);
668 if (!strcmp(xferto, ast_parking_ext())) {
669 res = finishup(transferee);
672 else if (!ast_park_call(transferee, transferer, 0, NULL)) { /* success */
673 /* We return non-zero, but tell the PBX not to hang the channel when
674 the thread dies -- We have to be careful now though. We are responsible for
675 hanging up the channel, else it will never be hung up! */
677 return (transferer == peer) ? AST_PBX_KEEPALIVE : AST_PBX_NO_HANGUP_PEER;
679 ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name);
681 /*! \todo XXX Maybe we should have another message here instead of invalid extension XXX */
682 } else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
683 pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", chan->name);
684 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", peer->name);
685 res=finishup(transferee);
686 if (!transferee->pbx) {
687 /* Doh! Use our handy async_goto functions */
688 if (option_verbose > 2)
689 ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n"
690 ,transferee->name, xferto, transferer_real_context);
691 if (ast_async_goto(transferee, transferer_real_context, xferto, 1))
692 ast_log(LOG_WARNING, "Async goto failed :-(\n");
695 /* Set the channel's new extension, since it exists, using transferer context */
696 set_c_e_p(transferee, transferer_real_context, xferto, 0);
698 check_goto_on_transfer(transferer);
701 if (option_verbose > 2)
702 ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context);
704 if (ast_stream_and_wait(transferer, xferfailsound, transferer->language, AST_DIGIT_ANY) < 0 ) {
705 finishup(transferee);
708 ast_stopstream(transferer);
709 res = finishup(transferee);
711 if (option_verbose > 1)
712 ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name);
715 return FEATURE_RETURN_SUCCESS;
718 static int check_compat(struct ast_channel *c, struct ast_channel *newchan)
720 if (ast_channel_make_compatible(c, newchan) < 0) {
721 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n",
722 c->name, newchan->name);
729 static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
731 struct ast_channel *transferer;
732 struct ast_channel *transferee;
733 const char *transferer_real_context;
737 struct ast_channel *newchan;
738 struct ast_channel *xferchan;
739 struct ast_bridge_thread_obj *tobj;
740 struct ast_bridge_config bconfig;
745 ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense);
746 set_peers(&transferer, &transferee, peer, chan, sense);
747 transferer_real_context = real_ctx(transferer, transferee);
748 /* Start autoservice on chan while we talk to the originator */
749 ast_indicate(transferee, AST_CONTROL_HOLD);
750 ast_autoservice_start(transferee);
751 ast_moh_start(transferee, NULL);
752 memset(xferto, 0, sizeof(xferto));
754 res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY);
756 finishup(transferee);
759 if (res > 0) /* If they've typed a digit already, handle it */
760 xferto[0] = (char) res;
762 /* this is specific of atxfer */
763 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
764 if (res < 0) { /* hangup, would be 0 for invalid and 1 for valid */
765 finishup(transferee);
769 ast_log(LOG_WARNING, "Did not read data.\n");
770 finishup(transferee);
771 if (ast_stream_and_wait(transferer, "beeperr", transferer->language, ""))
773 return FEATURE_RETURN_SUCCESS;
776 /* valid extension, res == 1 */
777 if (!ast_exists_extension(transferer, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
778 ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context);
779 finishup(transferee);
780 if (ast_stream_and_wait(transferer, "beeperr", transferer->language, ""))
782 return FEATURE_RETURN_SUCCESS;
786 snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context); /* append context */
787 newchan = ast_feature_request_and_dial(transferer, "Local", ast_best_codec(transferer->nativeformats),
788 xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name);
789 ast_indicate(transferer, -1);
791 finishup(transferee);
792 /* any reason besides user requested cancel and busy triggers the failed sound */
793 if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY &&
794 ast_stream_and_wait(transferer, xferfailsound, transferer->language, ""))
796 return FEATURE_RETURN_SUCCESS;
799 if (check_compat(transferer, newchan))
801 memset(&bconfig,0,sizeof(struct ast_bridge_config));
802 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
803 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
804 res = ast_bridge_call(transferer, newchan, &bconfig);
805 if (newchan->_softhangup || newchan->_state != AST_STATE_UP || !transferer->_softhangup) {
807 if (ast_stream_and_wait(transferer, xfersound, transferer->language, ""))
808 ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
809 finishup(transferee);
810 transferer->_softhangup = 0;
811 return FEATURE_RETURN_SUCCESS;
814 if (check_compat(transferee, newchan))
817 ast_moh_stop(transferee);
819 if ((ast_autoservice_stop(transferee) < 0)
820 || (ast_waitfordigit(transferee, 100) < 0)
821 || (ast_waitfordigit(newchan, 100) < 0)
822 || ast_check_hangup(transferee)
823 || ast_check_hangup(newchan)) {
828 xferchan = ast_channel_alloc(0);
833 ast_string_field_build(xferchan, name, "Transfered/%s", transferee->name);
834 /* Make formats okay */
835 xferchan->readformat = transferee->readformat;
836 xferchan->writeformat = transferee->writeformat;
837 ast_channel_masquerade(xferchan, transferee);
838 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
839 xferchan->_state = AST_STATE_UP;
840 ast_clear_flag(xferchan, AST_FLAGS_ALL);
841 xferchan->_softhangup = 0;
843 if ((f = ast_read(xferchan)))
846 newchan->_state = AST_STATE_UP;
847 ast_clear_flag(newchan, AST_FLAGS_ALL);
848 newchan->_softhangup = 0;
850 tobj = ast_calloc(1, sizeof(struct ast_bridge_thread_obj));
852 ast_hangup(xferchan);
856 tobj->chan = xferchan;
857 tobj->peer = newchan;
858 tobj->bconfig = *config;
860 if (ast_stream_and_wait(newchan, xfersound, newchan->language, ""))
861 ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
862 ast_bridge_call_thread_launch(tobj);
863 return -1; /* XXX meaning the channel is bridged ? */
867 /* add atxfer and automon as undefined so you can only use em if you configure them */
868 #define FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0]))
870 struct ast_call_feature builtin_features[] =
872 { AST_FEATURE_REDIRECT, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer, AST_FEATURE_FLAG_NEEDSDTMF },
873 { AST_FEATURE_REDIRECT, "Attended Transfer", "atxfer", "", "", builtin_atxfer, AST_FEATURE_FLAG_NEEDSDTMF },
874 { AST_FEATURE_AUTOMON, "One Touch Monitor", "automon", "", "", builtin_automonitor, AST_FEATURE_FLAG_NEEDSDTMF },
875 { AST_FEATURE_DISCONNECT, "Disconnect Call", "disconnect", "*", "*", builtin_disconnect, AST_FEATURE_FLAG_NEEDSDTMF },
876 { AST_FEATURE_PARKCALL, "Park Call", "parkcall", "", "", builtin_parkcall, AST_FEATURE_FLAG_NEEDSDTMF },
880 static AST_LIST_HEAD_STATIC(feature_list,ast_call_feature);
882 /*! \brief register new feature into feature_list*/
883 void ast_register_feature(struct ast_call_feature *feature)
886 ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
890 AST_LIST_LOCK(&feature_list);
891 AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry);
892 AST_LIST_UNLOCK(&feature_list);
894 if (option_verbose >= 2)
895 ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
898 /*! \brief unregister feature from feature_list */
899 void ast_unregister_feature(struct ast_call_feature *feature)
904 AST_LIST_LOCK(&feature_list);
905 AST_LIST_REMOVE(&feature_list,feature,feature_entry);
906 AST_LIST_UNLOCK(&feature_list);
910 /*! \brief Remove all features in the list */
911 static void ast_unregister_features(void)
913 struct ast_call_feature *feature;
915 AST_LIST_LOCK(&feature_list);
916 while ((feature = AST_LIST_REMOVE_HEAD(&feature_list,feature_entry)))
918 AST_LIST_UNLOCK(&feature_list);
921 /*! \brief find a feature by name */
922 static struct ast_call_feature *find_feature(char *name)
924 struct ast_call_feature *tmp;
926 AST_LIST_LOCK(&feature_list);
927 AST_LIST_TRAVERSE(&feature_list, tmp, feature_entry) {
928 if (!strcasecmp(tmp->sname, name))
931 AST_LIST_UNLOCK(&feature_list);
936 /*! \brief exec an app by feature */
937 static int feature_exec_app(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
940 struct ast_call_feature *feature;
943 AST_LIST_LOCK(&feature_list);
944 AST_LIST_TRAVERSE(&feature_list,feature,feature_entry) {
945 if (!strcasecmp(feature->exten,code))
948 AST_LIST_UNLOCK(&feature_list);
950 if (!feature) { /* shouldn't ever happen! */
951 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
955 app = pbx_findapp(feature->app);
957 struct ast_channel *work = ast_test_flag(feature,AST_FEATURE_FLAG_CALLEE) ? peer : chan;
958 res = pbx_exec(work, app, feature->app_args);
959 if (res == AST_PBX_KEEPALIVE)
960 return FEATURE_RETURN_PBX_KEEPALIVE;
961 else if (res == AST_PBX_NO_HANGUP_PEER)
962 return FEATURE_RETURN_NO_HANGUP_PEER;
964 return FEATURE_RETURN_SUCCESSBREAK;
966 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
970 return FEATURE_RETURN_SUCCESS; /*! \todo XXX should probably return res */
973 static void unmap_features(void)
976 for (x = 0; x < FEATURES_COUNT; x++)
977 strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
980 static int remap_feature(const char *name, const char *value)
984 for (x = 0; x < FEATURES_COUNT; x++) {
985 if (!strcasecmp(name, builtin_features[x].sname)) {
986 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
987 if (option_verbose > 1)
988 ast_verbose(VERBOSE_PREFIX_2 "Remapping feature %s (%s) to sequence '%s'\n", builtin_features[x].fname, builtin_features[x].sname, builtin_features[x].exten);
990 } else if (!strcmp(value, builtin_features[x].exten))
991 ast_log(LOG_WARNING, "Sequence '%s' already mapped to function %s (%s) while assigning to %s\n", value, builtin_features[x].fname, builtin_features[x].sname, name);
996 static int ast_feature_interpret(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
999 struct ast_flags features;
1000 int res = FEATURE_RETURN_PASSDIGITS;
1001 struct ast_call_feature *feature;
1002 const char *dynamic_features=pbx_builtin_getvar_helper(chan,"DYNAMIC_FEATURES");
1004 if (sense == FEATURE_SENSE_CHAN)
1005 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
1007 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);
1008 if (option_debug > 2)
1009 ast_log(LOG_DEBUG, "Feature interpret: chan=%s, peer=%s, sense=%d, features=%d\n", chan->name, peer->name, sense, features.flags);
1011 for (x=0; x < FEATURES_COUNT; x++) {
1012 if ((ast_test_flag(&features, builtin_features[x].feature_mask)) &&
1013 !ast_strlen_zero(builtin_features[x].exten)) {
1014 /* Feature is up for consideration */
1015 if (!strcmp(builtin_features[x].exten, code)) {
1016 res = builtin_features[x].operation(chan, peer, config, code, sense);
1018 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
1019 if (res == FEATURE_RETURN_PASSDIGITS)
1020 res = FEATURE_RETURN_STOREDIGITS;
1026 if (!ast_strlen_zero(dynamic_features)) {
1027 char *tmp = ast_strdupa(dynamic_features);
1030 while ((tok = strsep(&tmp, "#")) != NULL) {
1031 feature = find_feature(tok);
1034 /* Feature is up for consideration */
1035 if (!strcmp(feature->exten, code)) {
1036 if (option_verbose > 2)
1037 ast_verbose(VERBOSE_PREFIX_3 " Feature Found: %s exten: %s\n",feature->sname, tok);
1038 if (sense == FEATURE_SENSE_CHAN)
1039 res = feature->operation(chan, peer, config, code, sense);
1041 res = feature->operation(peer, chan, config, code, sense);
1043 } else if (!strncmp(feature->exten, code, strlen(code))) {
1044 res = FEATURE_RETURN_STOREDIGITS;
1053 static void set_config_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
1057 ast_clear_flag(config, AST_FLAGS_ALL);
1058 for (x = 0; x < FEATURES_COUNT; x++) {
1059 if (ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF)) {
1060 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
1061 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
1063 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
1064 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
1068 if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
1069 const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
1071 if (dynamic_features) {
1072 char *tmp = ast_strdupa(dynamic_features);
1074 struct ast_call_feature *feature;
1076 /* while we have a feature */
1077 while ((tok = strsep(&tmp, "#"))) {
1078 if ((feature = find_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
1079 if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLER))
1080 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
1081 if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLEE))
1082 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
1089 /*! \todo XXX Check - this is very similar to the code in channel.c */
1090 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)
1095 struct ast_channel *chan;
1096 struct ast_channel *monitor_chans[2];
1097 struct ast_channel *active_channel;
1098 int res = 0, ready = 0;
1100 if ((chan = ast_request(type, format, data, &cause))) {
1101 ast_set_callerid(chan, cid_num, cid_name, cid_num);
1102 ast_channel_inherit_variables(caller, chan);
1103 pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name);
1104 if (!ast_call(chan, data, timeout)) {
1105 struct timeval started;
1107 char *disconnect_code = NULL, *dialed_code = NULL;
1109 ast_indicate(caller, AST_CONTROL_RINGING);
1110 /* support dialing of the featuremap disconnect code while performing an attended tranfer */
1111 for (x=0; x < FEATURES_COUNT; x++) {
1112 if (strcasecmp(builtin_features[x].sname, "disconnect"))
1115 disconnect_code = builtin_features[x].exten;
1116 len = strlen(disconnect_code) + 1;
1117 dialed_code = alloca(len);
1118 memset(dialed_code, 0, len);
1122 started = ast_tvnow();
1124 while (!ast_check_hangup(caller) && timeout && (chan->_state != AST_STATE_UP)) {
1125 struct ast_frame *f = NULL;
1127 monitor_chans[0] = caller;
1128 monitor_chans[1] = chan;
1129 active_channel = ast_waitfor_n(monitor_chans, 2, &to);
1131 /* see if the timeout has been violated */
1132 if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
1133 state = AST_CONTROL_UNHOLD;
1134 ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n");
1135 break; /*doh! timeout*/
1138 if (!active_channel)
1141 if (chan && (chan == active_channel)){
1143 if (f == NULL) { /*doh! where'd he go?*/
1144 state = AST_CONTROL_HANGUP;
1149 if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) {
1150 if (f->subclass == AST_CONTROL_RINGING) {
1151 state = f->subclass;
1152 if (option_verbose > 2)
1153 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", chan->name);
1154 ast_indicate(caller, AST_CONTROL_RINGING);
1155 } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) {
1156 state = f->subclass;
1157 if (option_verbose > 2)
1158 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", chan->name);
1159 ast_indicate(caller, AST_CONTROL_BUSY);
1163 } else if (f->subclass == AST_CONTROL_ANSWER) {
1164 /* This is what we are hoping for */
1165 state = f->subclass;
1171 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass);
1173 /* else who cares */
1176 } else if (caller && (active_channel == caller)) {
1177 f = ast_read(caller);
1178 if (f == NULL) { /*doh! where'd he go?*/
1179 if (caller->_softhangup && !chan->_softhangup) {
1180 /* make this a blind transfer */
1184 state = AST_CONTROL_HANGUP;
1189 if (f->frametype == AST_FRAME_DTMF) {
1190 dialed_code[x++] = f->subclass;
1191 dialed_code[x] = '\0';
1192 if (strlen(dialed_code) == len) {
1194 } else if (x && strncmp(dialed_code, disconnect_code, x)) {
1196 dialed_code[x] = '\0';
1198 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
1199 /* Caller Canceled the call */
1200 state = AST_CONTROL_UNHOLD;
1211 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
1213 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
1215 case AST_CAUSE_BUSY:
1216 state = AST_CONTROL_BUSY;
1218 case AST_CAUSE_CONGESTION:
1219 state = AST_CONTROL_CONGESTION;
1224 ast_indicate(caller, -1);
1225 if (chan && ready) {
1226 if (chan->_state == AST_STATE_UP)
1227 state = AST_CONTROL_ANSWER;
1240 if (chan && res <= 0) {
1241 if (chan->cdr || (chan->cdr = ast_cdr_alloc())) {
1243 ast_cdr_init(chan->cdr, chan);
1244 snprintf(tmp, 256, "%s/%s", type, (char *)data);
1245 ast_cdr_setapp(chan->cdr,"Dial",tmp);
1246 ast_cdr_update(chan);
1247 ast_cdr_start(chan->cdr);
1248 ast_cdr_end(chan->cdr);
1249 /* If the cause wasn't handled properly */
1250 if (ast_cdr_disposition(chan->cdr,chan->hangupcause))
1251 ast_cdr_failed(chan->cdr);
1253 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
1260 int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast_bridge_config *config)
1262 /* Copy voice back and forth between the two channels. Give the peer
1263 the ability to transfer calls with '#<extension' syntax. */
1264 struct ast_frame *f;
1265 struct ast_channel *who;
1266 char chan_featurecode[FEATURE_MAX_LEN + 1]="";
1267 char peer_featurecode[FEATURE_MAX_LEN + 1]="";
1272 struct ast_option_header *aoh;
1273 struct timeval start = { 0 , 0 };
1274 struct ast_bridge_config backup_config;
1276 memset(&backup_config, 0, sizeof(backup_config));
1278 config->start_time = ast_tvnow();
1281 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
1282 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
1284 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
1287 const char *monitor_exec;
1288 struct ast_channel *src = NULL;
1290 if (!(monitor_app = pbx_findapp("Monitor")))
1293 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR")))
1295 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
1297 if (monitor_app && src) {
1298 char *tmp = ast_strdupa(monitor_exec);
1299 pbx_exec(src, monitor_app, tmp);
1303 set_config_flags(chan, peer, config);
1304 config->firstpass = 1;
1306 /* Answer if need be */
1307 if (ast_answer(chan))
1309 peer->appl = "Bridged Call";
1310 peer->data = chan->name;
1312 /* copy the userfield from the B-leg to A-leg if applicable */
1313 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
1315 if (!ast_strlen_zero(chan->cdr->userfield)) {
1316 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield);
1317 ast_cdr_appenduserfield(chan, tmp);
1319 ast_cdr_setuserfield(chan, peer->cdr->userfield);
1320 /* free the peer's cdr without ast_cdr_free complaining */
1325 struct ast_channel *other; /* used later */
1326 if (config->feature_timer)
1327 start = ast_tvnow();
1329 res = ast_channel_bridge(chan, peer, config, &f, &who);
1331 if (config->feature_timer) {
1332 /* Update time limit for next pass */
1333 diff = ast_tvdiff_ms(ast_tvnow(), start);
1334 config->feature_timer -= diff;
1336 /* Running on backup config, meaning a feature might be being
1337 activated, but that's no excuse to keep things going
1339 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
1341 ast_log(LOG_DEBUG, "Timed out, realtime this time!\n");
1342 config->feature_timer = 0;
1348 } else if (config->feature_timer <= 0) {
1349 /* Not *really* out of time, just out of time for
1350 digits to come in for features. */
1352 ast_log(LOG_DEBUG, "Timed out for feature!\n");
1353 if (!ast_strlen_zero(peer_featurecode)) {
1354 ast_dtmf_stream(chan, peer, peer_featurecode, 0);
1355 memset(peer_featurecode, 0, sizeof(peer_featurecode));
1357 if (!ast_strlen_zero(chan_featurecode)) {
1358 ast_dtmf_stream(peer, chan, chan_featurecode, 0);
1359 memset(chan_featurecode, 0, sizeof(chan_featurecode));
1363 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
1365 /* Restore original (possibly time modified) bridge config */
1366 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
1367 memset(&backup_config, 0, sizeof(backup_config));
1369 hadfeatures = hasfeatures;
1370 /* Continue as we were */
1374 if (config->feature_timer <=0) {
1375 /* We ran out of time */
1376 config->feature_timer = 0;
1386 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
1390 if (!f || (f->frametype == AST_FRAME_CONTROL &&
1391 (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY ||
1392 f->subclass == AST_CONTROL_CONGESTION ) ) ) {
1396 /* many things should be sent to the 'other' channel */
1397 other = (who == chan) ? peer : chan;
1398 if (f->frametype == AST_FRAME_CONTROL) {
1399 if (f->subclass == AST_CONTROL_RINGING)
1400 ast_indicate(other, AST_CONTROL_RINGING);
1401 else if (f->subclass == -1)
1402 ast_indicate(other, -1);
1403 else if (f->subclass == AST_CONTROL_FLASH)
1404 ast_indicate(other, AST_CONTROL_FLASH);
1405 else if (f->subclass == AST_CONTROL_OPTION) {
1407 /* Forward option Requests */
1408 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST)
1409 ast_channel_setoption(other, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
1412 /* check for '*', if we find it it's time to disconnect */
1413 if (f->frametype == AST_FRAME_DTMF) {
1417 hadfeatures = hasfeatures;
1418 /* This cannot overrun because the longest feature is one shorter than our buffer */
1420 sense = FEATURE_SENSE_CHAN;
1421 featurecode = chan_featurecode;
1423 sense = FEATURE_SENSE_PEER;
1424 featurecode = peer_featurecode;
1426 /*! append the event to featurecode. we rely on the string being zero-filled, and
1427 * not overflowing it.
1428 * \todo XXX how do we guarantee the latter ?
1430 featurecode[strlen(featurecode)] = f->subclass;
1431 /* Get rid of the frame before we start doing "stuff" with the channels */
1434 config->feature_timer = backup_config.feature_timer;
1435 res = ast_feature_interpret(chan, peer, config, featurecode, sense);
1437 case FEATURE_RETURN_PASSDIGITS:
1438 ast_dtmf_stream(other, who, featurecode, 0);
1440 case FEATURE_RETURN_SUCCESS:
1441 memset(featurecode, 0, sizeof(chan_featurecode));
1444 if (res >= FEATURE_RETURN_PASSDIGITS) {
1448 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
1449 if (hadfeatures && !hasfeatures) {
1450 /* Restore backup */
1451 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
1452 memset(&backup_config, 0, sizeof(struct ast_bridge_config));
1453 } else if (hasfeatures) {
1455 /* Backup configuration */
1456 memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
1457 /* Setup temporary config options */
1458 config->play_warning = 0;
1459 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
1460 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
1461 config->warning_freq = 0;
1462 config->warning_sound = NULL;
1463 config->end_sound = NULL;
1464 config->start_sound = NULL;
1465 config->firstpass = 0;
1467 config->feature_timer = featuredigittimeout;
1469 ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer);
1478 static void post_manager_event(const char *s, char *parkingexten, struct ast_channel *chan)
1480 manager_event(EVENT_FLAG_CALL, s,
1484 "CallerIDName: %s\r\n\r\n",
1487 S_OR(chan->cid.cid_num, "<unknown>"),
1488 S_OR(chan->cid.cid_name, "<unknown>")
1492 /*! \brief Take care of parked calls and unpark them if needed */
1493 static void *do_parking_thread(void *ignore)
1495 fd_set rfds, efds; /* results from previous select, to be preserved across loops. */
1500 struct parkeduser *pu, *pl, *pt = NULL;
1501 int ms = -1; /* select timeout, uninitialized */
1502 int max = -1; /* max fd, none there yet */
1503 fd_set nrfds, nefds; /* args for the next select */
1507 ast_mutex_lock(&parking_lock);
1510 /* navigate the list with prev-cur pointers to support removals */
1512 struct ast_channel *chan = pu->chan; /* shorthand */
1513 int tms; /* timeout for this item */
1514 int x; /* fd index in channel */
1515 struct ast_context *con;
1517 if (pu->notquiteyet) { /* Pretend this one isn't here yet */
1522 tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
1523 if (tms > pu->parkingtime) {
1524 /* Stop music on hold */
1526 ast_indicate(chan, AST_CONTROL_UNHOLD);
1527 /* Get chan, exten from derived kludge */
1528 if (pu->peername[0]) {
1529 char *peername = ast_strdupa(pu->peername);
1530 char *cp = strrchr(peername, '-');
1533 con = ast_context_find(parking_con_dial);
1535 con = ast_context_create(NULL, parking_con_dial, registrar);
1537 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
1540 char returnexten[AST_MAX_EXTENSION];
1541 snprintf(returnexten, sizeof(returnexten), "%s||t", peername);
1542 ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), FREE, registrar);
1544 set_c_e_p(chan, parking_con_dial, peername, 1);
1546 /* They've been waiting too long, send them back to where they came. Theoretically they
1547 should have their original extensions and such, but we copy to be on the safe side */
1548 set_c_e_p(chan, pu->context, pu->exten, pu->priority);
1551 post_manager_event("ParkedCallTimeOut", pu->parkingexten, chan);
1553 if (option_verbose > 1)
1554 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);
1555 /* Start up the PBX, or hang them up */
1556 if (ast_pbx_start(chan)) {
1557 ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", chan->name);
1560 /* And take them out of the parking lot */
1562 pl->next = pu->next;
1564 parkinglot = pu->next;
1567 con = ast_context_find(parking_con);
1569 if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL))
1570 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1572 notify_metermaids(pu->parkingexten, parking_con);
1574 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1576 } else { /* still within parking time, process descriptors */
1577 for (x = 0; x < AST_MAX_FDS; x++) {
1578 struct ast_frame *f;
1580 if (chan->fds[x] == -1 || (!FD_ISSET(chan->fds[x], &rfds) && !FD_ISSET(chan->fds[x], &efds)))
1581 continue; /* nothing on this descriptor */
1583 if (FD_ISSET(chan->fds[x], &efds))
1584 ast_set_flag(chan, AST_FLAG_EXCEPTION);
1586 ast_clear_flag(chan, AST_FLAG_EXCEPTION);
1589 /* See if they need servicing */
1591 if (!f || (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_HANGUP)) {
1594 post_manager_event("ParkedCallGiveUp", pu->parkingexten, chan);
1596 /* There's a problem, hang them up*/
1597 if (option_verbose > 1)
1598 ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", chan->name);
1600 /* And take them out of the parking lot */
1602 pl->next = pu->next;
1604 parkinglot = pu->next;
1607 con = ast_context_find(parking_con);
1609 if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL))
1610 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1612 notify_metermaids(pt->parkingexten, parking_con);
1614 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1618 /*! \todo XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
1620 if (pu->moh_trys < 3 && !chan->generatordata) {
1622 ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source. Restarting.\n");
1623 ast_moh_start(chan, NULL);
1626 goto std; /*! \todo XXX Ick: jumping into an else statement??? XXX */
1630 if (x >= AST_MAX_FDS) {
1631 std: for (x=0; x<AST_MAX_FDS; x++) { /* mark fds for next round */
1632 if (chan->fds[x] > -1) {
1633 FD_SET(chan->fds[x], &nrfds);
1634 FD_SET(chan->fds[x], &nefds);
1635 if (chan->fds[x] > max)
1639 /* Keep track of our shortest wait */
1640 if (tms < ms || ms < 0)
1647 ast_mutex_unlock(&parking_lock);
1651 struct timeval tv = ast_samp2tv(ms, 1000);
1652 /* Wait for something to happen */
1653 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
1655 pthread_testcancel();
1657 return NULL; /* Never reached */
1660 /*! \brief Park a call */
1661 static int park_call_exec(struct ast_channel *chan, void *data)
1663 /* Data is unused at the moment but could contain a parking
1664 lot context eventually */
1666 struct localuser *u;
1668 /* Setup the exten/priority to be s/1 since we don't know
1669 where this call should return */
1670 strcpy(chan->exten, "s");
1672 /* Answer if call is not up */
1673 if (chan->_state != AST_STATE_UP)
1674 res = ast_answer(chan);
1675 /* Sleep to allow VoIP streams to settle down */
1677 res = ast_safe_sleep(chan, 1000);
1680 res = ast_park_call(chan, chan, 0, NULL);
1681 LOCAL_USER_REMOVE(u);
1683 res = AST_PBX_KEEPALIVE;
1687 /*! \brief Pickup parked call */
1688 static int park_exec(struct ast_channel *chan, void *data)
1691 struct localuser *u;
1692 struct ast_channel *peer=NULL;
1693 struct parkeduser *pu, *pl=NULL;
1694 struct ast_context *con;
1696 struct ast_bridge_config config;
1699 ast_log(LOG_WARNING, "Parkedcall requires an argument (extension number)\n");
1703 park = atoi((char *)data);
1704 ast_mutex_lock(&parking_lock);
1707 if (pu->parkingnum == park) {
1709 pl->next = pu->next;
1711 parkinglot = pu->next;
1717 ast_mutex_unlock(&parking_lock);
1720 con = ast_context_find(parking_con);
1722 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL))
1723 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1725 notify_metermaids(pu->parkingexten, parking_con);
1727 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1729 manager_event(EVENT_FLAG_CALL, "UnParkedCall",
1734 "CallerIDName: %s\r\n",
1735 pu->parkingexten, pu->chan->name, chan->name,
1736 S_OR(pu->chan->cid.cid_num, "<unknown>"),
1737 S_OR(pu->chan->cid.cid_name, "<unknown>")
1742 /* JK02: it helps to answer the channel if not already up */
1743 if (chan->_state != AST_STATE_UP)
1747 /* Play a courtesy to the source(s) configured to prefix the bridge connecting */
1749 if (!ast_strlen_zero(courtesytone)) {
1752 ast_indicate(peer, AST_CONTROL_UNHOLD);
1753 if (parkedplay == 0) {
1754 error = ast_stream_and_wait(chan, courtesytone, chan->language, "");
1755 } else if (parkedplay == 1) {
1756 error = ast_stream_and_wait(peer, courtesytone, chan->language, "");
1757 } else if (parkedplay == 2) {
1758 if (!ast_streamfile(chan, courtesytone, chan->language) &&
1759 !ast_streamfile(peer, courtesytone, chan->language)) {
1760 /*! \todo XXX we would like to wait on both! */
1761 res = ast_waitstream(chan, "");
1763 res = ast_waitstream(peer, "");
1769 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
1775 ast_indicate(peer, AST_CONTROL_UNHOLD);
1778 res = ast_channel_make_compatible(chan, peer);
1780 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
1784 /* This runs sorta backwards, since we give the incoming channel control, as if it
1785 were the person called. */
1786 if (option_verbose > 2)
1787 ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
1789 memset(&config, 0, sizeof(struct ast_bridge_config));
1790 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
1791 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
1792 config.timelimit = 0;
1793 config.play_warning = 0;
1794 config.warning_freq = 0;
1795 config.warning_sound=NULL;
1796 res = ast_bridge_call(chan, peer, &config);
1798 /* Simulate the PBX hanging up */
1799 if (res != AST_PBX_NO_HANGUP_PEER)
1803 /*! \todo XXX Play a message XXX */
1804 if (ast_stream_and_wait(chan, "pbx-invalidpark", chan->language, ""))
1805 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
1806 if (option_verbose > 2)
1807 ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
1810 LOCAL_USER_REMOVE(u);
1814 static int handle_showfeatures(int fd, int argc, char *argv[])
1818 struct ast_call_feature *feature;
1819 char format[] = "%-25s %-7s %-7s\n";
1821 ast_cli(fd, format, "Builtin Feature", "Default", "Current");
1822 ast_cli(fd, format, "---------------", "-------", "-------");
1824 ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */
1826 fcount = sizeof(builtin_features) / sizeof(builtin_features[0]);
1828 for (i = 0; i < fcount; i++)
1830 ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
1833 ast_cli(fd, format, "Dynamic Feature", "Default", "Current");
1834 ast_cli(fd, format, "---------------", "-------", "-------");
1835 if (AST_LIST_EMPTY(&feature_list)) {
1836 ast_cli(fd, "(none)\n");
1839 AST_LIST_LOCK(&feature_list);
1840 AST_LIST_TRAVERSE(&feature_list, feature, feature_entry) {
1841 ast_cli(fd, format, feature->sname, "no def", feature->exten);
1843 AST_LIST_UNLOCK(&feature_list);
1845 ast_cli(fd, "\nCall parking\n");
1846 ast_cli(fd, "------------\n");
1847 ast_cli(fd,"%-20s: %s\n", "Parking extension", parking_ext);
1848 ast_cli(fd,"%-20s: %s\n", "Parking context", parking_con);
1849 ast_cli(fd,"%-20s: %d-%d\n", "Parked call extensions", parking_start, parking_stop);
1852 return RESULT_SUCCESS;
1855 static char showfeatures_help[] =
1856 "Usage: show features\n"
1857 " Lists currently configured features.\n";
1859 static struct ast_cli_entry showfeatures =
1860 { { "show", "features", NULL }, handle_showfeatures, "Lists configured features", showfeatures_help };
1862 static int handle_parkedcalls(int fd, int argc, char *argv[])
1864 struct parkeduser *cur;
1867 ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
1868 , "Context", "Extension", "Pri", "Timeout");
1870 ast_mutex_lock(&parking_lock);
1872 for (cur = parkinglot; cur; cur = cur->next) {
1873 ast_cli(fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n"
1874 ,cur->parkingexten, cur->chan->name, cur->context, cur->exten
1875 ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
1879 ast_mutex_unlock(&parking_lock);
1880 ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : "");
1883 return RESULT_SUCCESS;
1886 static char showparked_help[] =
1887 "Usage: show parkedcalls\n"
1888 " Lists currently parked calls.\n";
1890 static struct ast_cli_entry showparked =
1891 { { "show", "parkedcalls", NULL }, handle_parkedcalls, "Lists parked calls", showparked_help };
1893 /*! \brief Dump lot status */
1894 static int manager_parking_status( struct mansession *s, struct message *m )
1896 struct parkeduser *cur;
1897 char *id = astman_get_header(m,"ActionID");
1898 char idText[256] = "";
1900 if (!ast_strlen_zero(id))
1901 snprintf(idText, 256, "ActionID: %s\r\n", id);
1903 astman_send_ack(s, m, "Parked calls will follow");
1905 ast_mutex_lock(&parking_lock);
1907 for (cur=parkinglot; cur; cur = cur->next) {
1908 astman_append(s, "Event: ParkedCall\r\n"
1914 "CallerIDName: %s\r\n"
1917 cur->parkingnum, cur->chan->name, cur->peername,
1918 (long)cur->start.tv_sec + (long)(cur->parkingtime/1000) - (long)time(NULL),
1919 S_OR(cur->chan->cid.cid_num, ""), /* XXX in other places it is <unknown> */
1920 S_OR(cur->chan->cid.cid_name, ""),
1925 "Event: ParkedCallsComplete\r\n"
1929 ast_mutex_unlock(&parking_lock);
1931 return RESULT_SUCCESS;
1934 static char mandescr_park[] =
1935 "Description: Park a channel.\n"
1936 "Variables: (Names marked with * are required)\n"
1937 " *Channel: Channel name to park\n"
1938 " *Channel2: Channel to announce park info to (and return to if timeout)\n"
1939 " Timeout: Number of milliseconds to wait before callback.\n";
1941 static int manager_park(struct mansession *s, struct message *m)
1943 char *channel = astman_get_header(m, "Channel");
1944 char *channel2 = astman_get_header(m, "Channel2");
1945 char *timeout = astman_get_header(m, "Timeout");
1950 struct ast_channel *ch1, *ch2;
1952 if (ast_strlen_zero(channel)) {
1953 astman_send_error(s, m, "Channel not specified");
1957 if (ast_strlen_zero(channel2)) {
1958 astman_send_error(s, m, "Channel2 not specified");
1962 ch1 = ast_get_channel_by_name_locked(channel);
1964 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
1965 astman_send_error(s, m, buf);
1969 ch2 = ast_get_channel_by_name_locked(channel2);
1971 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
1972 astman_send_error(s, m, buf);
1973 ast_channel_unlock(ch1);
1977 if (!ast_strlen_zero(timeout)) {
1978 sscanf(timeout, "%d", &to);
1981 res = ast_masq_park_call(ch1, ch2, to, &parkExt);
1983 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
1984 astman_send_ack(s, m, "Park successful");
1986 astman_send_error(s, m, "Park failure");
1989 ast_channel_unlock(ch1);
1990 ast_channel_unlock(ch2);
1996 int ast_pickup_call(struct ast_channel *chan)
1998 struct ast_channel *cur = NULL;
2001 while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
2004 (chan->pickupgroup & cur->callgroup) &&
2005 ((cur->_state == AST_STATE_RINGING) ||
2006 (cur->_state == AST_STATE_RING))) {
2009 ast_channel_unlock(cur);
2013 ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
2014 res = ast_answer(chan);
2016 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
2017 res = ast_queue_control(chan, AST_CONTROL_ANSWER);
2019 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
2020 res = ast_channel_masquerade(cur, chan);
2022 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */
2023 ast_channel_unlock(cur);
2026 ast_log(LOG_DEBUG, "No call pickup possible...\n");
2031 /*! \brief Add parking hints for all defined parking lots */
2032 static void park_add_hints(char *context, int start, int stop)
2035 char device[AST_MAX_EXTENSION];
2038 for (numext = start; numext <= stop; numext++) {
2039 snprintf(exten, sizeof(exten), "%d", numext);
2040 snprintf(device, sizeof(device), "park:%s@%s", exten, context);
2041 ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
2046 static int load_config(void)
2048 int start = 0, end = 0;
2050 struct ast_context *con = NULL;
2051 struct ast_config *cfg = NULL;
2052 struct ast_variable *var = NULL;
2053 char old_parking_ext[AST_MAX_EXTENSION];
2054 char old_parking_con[AST_MAX_EXTENSION] = "";
2056 if (!ast_strlen_zero(parking_con)) {
2057 strcpy(old_parking_ext, parking_ext);
2058 strcpy(old_parking_con, parking_con);
2061 /* Reset to defaults */
2062 strcpy(parking_con, "parkedcalls");
2063 strcpy(parking_con_dial, "park-dial");
2064 strcpy(parking_ext, "700");
2065 strcpy(pickup_ext, "*8");
2066 courtesytone[0] = '\0';
2067 strcpy(xfersound, "beep");
2068 strcpy(xferfailsound, "pbx-invalid");
2069 parking_start = 701;
2075 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
2076 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
2077 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
2079 cfg = ast_config_load("features.conf");
2081 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
2082 if (!strcasecmp(var->name, "parkext")) {
2083 ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
2084 } else if (!strcasecmp(var->name, "context")) {
2085 ast_copy_string(parking_con, var->value, sizeof(parking_con));
2086 } else if (!strcasecmp(var->name, "parkingtime")) {
2087 if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) {
2088 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
2089 parkingtime = DEFAULT_PARK_TIME;
2091 parkingtime = parkingtime * 1000;
2092 } else if (!strcasecmp(var->name, "parkpos")) {
2093 if (sscanf(var->value, "%d-%d", &start, &end) != 2) {
2094 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);
2096 parking_start = start;
2099 } else if (!strcasecmp(var->name, "findslot")) {
2100 parkfindnext = (!strcasecmp(var->value, "next"));
2101 } else if (!strcasecmp(var->name, "parkinghints")) {
2102 parkaddhints = ast_true(var->value);
2103 } else if (!strcasecmp(var->name, "adsipark")) {
2104 adsipark = ast_true(var->value);
2105 } else if (!strcasecmp(var->name, "transferdigittimeout")) {
2106 if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
2107 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
2108 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
2110 transferdigittimeout = transferdigittimeout * 1000;
2111 } else if (!strcasecmp(var->name, "featuredigittimeout")) {
2112 if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
2113 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
2114 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
2116 } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) {
2117 if ((sscanf(var->value, "%d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) {
2118 ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value);
2119 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
2121 atxfernoanswertimeout = atxfernoanswertimeout * 1000;
2122 } else if (!strcasecmp(var->name, "courtesytone")) {
2123 ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
2124 } else if (!strcasecmp(var->name, "parkedplay")) {
2125 if (!strcasecmp(var->value, "both"))
2127 else if (!strcasecmp(var->value, "parked"))
2131 } else if (!strcasecmp(var->name, "xfersound")) {
2132 ast_copy_string(xfersound, var->value, sizeof(xfersound));
2133 } else if (!strcasecmp(var->name, "xferfailsound")) {
2134 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
2135 } else if (!strcasecmp(var->name, "pickupexten")) {
2136 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
2141 for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) {
2142 if (remap_feature(var->name, var->value))
2143 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
2146 /* Map a key combination to an application*/
2147 ast_unregister_features();
2148 for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) {
2149 char *tmp_val = ast_strdup(var->value);
2150 char *exten, *party=NULL, *app=NULL, *app_args=NULL;
2153 /*! \todo XXX No memory. We should probably break, but at least we do not
2154 * insist on this entry or we could be stuck in an
2160 /* strsep() sets the argument to NULL if match not found, and it
2161 * is safe to use it with a NULL argument, so we don't check
2164 exten = strsep(&tmp_val,",");
2165 party = strsep(&tmp_val,",");
2166 app = strsep(&tmp_val,",");
2167 app_args = strsep(&tmp_val,",");
2169 /*! \todo XXX var_name or app_args ? */
2170 if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(party) || ast_strlen_zero(var->name)) {
2171 ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",app,exten,party,var->name);
2177 struct ast_call_feature *feature;
2180 if (!(feature = find_feature(var->name))) {
2183 if (!(feature = ast_calloc(1, sizeof(*feature)))) {
2189 ast_copy_string(feature->sname,var->name,FEATURE_SNAME_LEN);
2190 ast_copy_string(feature->app,app,FEATURE_APP_LEN);
2191 ast_copy_string(feature->exten, exten,FEATURE_EXTEN_LEN);
2195 ast_copy_string(feature->app_args,app_args,FEATURE_APP_ARGS_LEN);
2197 ast_copy_string(feature->exten, exten,sizeof(feature->exten));
2198 feature->operation=feature_exec_app;
2199 ast_set_flag(feature,AST_FEATURE_FLAG_NEEDSDTMF);
2201 if (!strcasecmp(party,"caller"))
2202 ast_set_flag(feature,AST_FEATURE_FLAG_CALLER);
2203 else if (!strcasecmp(party, "callee"))
2204 ast_set_flag(feature,AST_FEATURE_FLAG_CALLEE);
2206 ast_log(LOG_NOTICE, "Invalid party specification for feature '%s', must be caller, or callee\n", var->name);
2210 ast_register_feature(feature);
2211 /* XXX do we need to free it if mallocd ? */
2213 if (option_verbose >=1)
2214 ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s' with code '%s'\n", var->name, app, exten);
2218 ast_config_destroy(cfg);
2220 /* Remove the old parking extension */
2221 if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) {
2222 if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar))
2223 notify_metermaids(old_parking_ext, old_parking_con);
2225 ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
2228 if (!(con = ast_context_find(parking_con)) && !(con = ast_context_create(NULL, parking_con, registrar))) {
2229 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
2232 res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, strdup(""), FREE, registrar);
2234 park_add_hints(parking_con, parking_start, parking_stop);
2236 notify_metermaids(ast_parking_ext(), parking_con);
2241 static int reload(void *mod)
2243 return load_config();
2246 static int load_module(void *mod)
2251 memset(parking_ext, 0, sizeof(parking_ext));
2252 memset(parking_con, 0, sizeof(parking_con));
2254 if ((res = load_config()))
2256 ast_cli_register(&showparked);
2257 ast_cli_register(&showfeatures);
2258 ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
2259 res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
2261 res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
2263 ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" );
2264 ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park,
2265 "Park a channel", mandescr_park);
2268 res |= ast_devstate_prov_add("Park", metermaidstate);
2274 static int unload_module(void *mod)
2276 STANDARD_HANGUP_LOCALUSERS;
2278 ast_manager_unregister("ParkedCalls");
2279 ast_manager_unregister("Park");
2280 ast_cli_unregister(&showfeatures);
2281 ast_cli_unregister(&showparked);
2282 ast_unregister_application(parkcall);
2283 ast_devstate_prov_del("Park");
2284 return ast_unregister_application(parkedcall);
2287 static const char *description(void)
2289 return "Call Features Resource";
2292 static const char *key(void)
2294 return ASTERISK_GPL_KEY;
2297 STD_MOD(MOD_0 | NO_UNLOAD, reload, NULL, NULL);