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>
34 #include <sys/signal.h>
35 #include <netinet/in.h>
39 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
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/monitor.h"
61 #ifdef __AST_DEBUG_MALLOC
62 static void FREE(void *ptr)
70 #define DEFAULT_PARK_TIME 45000
71 #define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000
72 #define DEFAULT_FEATURE_DIGIT_TIMEOUT 500
74 #define AST_MAX_WATCHERS 256
76 static char *parkedcall = "ParkedCall";
78 static int parkingtime = DEFAULT_PARK_TIME; /*!< No more than 45 seconds parked before you do something with them */
79 static char parking_con[AST_MAX_EXTENSION]; /*!< Context for which parking is made accessible */
80 static char parking_con_dial[AST_MAX_EXTENSION]; /*!< Context for dialback for parking (KLUDGE) */
81 static char parking_ext[AST_MAX_EXTENSION]; /*!< Extension you type to park the call */
82 static char pickup_ext[AST_MAX_EXTENSION]; /*!< Call pickup extension */
83 static int parking_start; /*!< First available extension for parking */
84 static int parking_stop; /*!< Last available extension for parking */
86 static char courtesytone[256]; /*!< Courtesy tone */
87 static int parkedplay = 0; /*!< Who to play the courtesy tone to */
88 static char xfersound[256]; /*!< Call transfer sound */
89 static char xferfailsound[256]; /*!< Call transfer failure sound */
91 static int parking_offset;
92 static int parkfindnext;
96 static int transferdigittimeout;
97 static int featuredigittimeout;
99 static char *registrar = "res_features"; /*!< Registrar for operations */
101 /* module and CLI command definitions */
102 static char *synopsis = "Answer a parked call";
104 static char *descrip = "ParkedCall(exten):"
105 "Used to connect to a parked call. This application is always\n"
106 "registered internally and does not need to be explicitly added\n"
107 "into the dialplan, although you should include the 'parkedcalls'\n"
110 static char *parkcall = "Park";
112 static char *synopsis2 = "Park yourself";
114 static char *descrip2 = "Park():"
115 "Used to park yourself (typically in combination with a supervised\n"
116 "transfer to know the parking space). This application is always\n"
117 "registered internally and does not need to be explicitly added\n"
118 "into the dialplan, although you should include the 'parkedcalls'\n"
121 static struct ast_app *monitor_app = NULL;
122 static int monitor_ok = 1;
125 struct ast_channel *chan;
126 struct timeval start;
128 /* Where to go if our parking time expires */
129 char context[AST_MAX_CONTEXT];
130 char exten[AST_MAX_EXTENSION];
135 unsigned char moh_trys;
136 struct parkeduser *next;
139 static struct parkeduser *parkinglot;
141 AST_MUTEX_DEFINE_STATIC(parking_lock); /* protects all static variables above */
143 static pthread_t parking_thread;
145 char *ast_parking_ext(void)
150 char *ast_pickup_ext(void)
155 struct ast_bridge_thread_obj
157 struct ast_bridge_config bconfig;
158 struct ast_channel *chan;
159 struct ast_channel *peer;
162 static void check_goto_on_transfer(struct ast_channel *chan)
164 struct ast_channel *xferchan;
165 const char *val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR");
166 char *x, *goto_on_transfer;
169 if (!ast_strlen_zero(val) && (goto_on_transfer = ast_strdupa(val)) && (xferchan = ast_channel_alloc(0))) {
170 for (x = goto_on_transfer; x && *x; x++)
173 ast_string_field_set(xferchan, name, chan->name);
174 /* Make formats okay */
175 xferchan->readformat = chan->readformat;
176 xferchan->writeformat = chan->writeformat;
177 ast_channel_masquerade(xferchan, chan);
178 ast_parseable_goto(xferchan, goto_on_transfer);
179 xferchan->_state = AST_STATE_UP;
180 ast_clear_flag(xferchan, AST_FLAGS_ALL);
181 xferchan->_softhangup = 0;
182 if ((f = ast_read(xferchan))) {
185 ast_pbx_start(xferchan);
187 ast_hangup(xferchan);
192 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);
195 static void *ast_bridge_call_thread(void *data)
197 struct ast_bridge_thread_obj *tobj = data;
199 tobj->chan->appl = "Transferred Call";
200 tobj->chan->data = tobj->peer->name;
201 tobj->peer->appl = "Transferred Call";
202 tobj->peer->data = tobj->chan->name;
203 if (tobj->chan->cdr) {
204 ast_cdr_reset(tobj->chan->cdr, NULL);
205 ast_cdr_setdestchan(tobj->chan->cdr, tobj->peer->name);
207 if (tobj->peer->cdr) {
208 ast_cdr_reset(tobj->peer->cdr, NULL);
209 ast_cdr_setdestchan(tobj->peer->cdr, tobj->chan->name);
212 ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
213 ast_hangup(tobj->chan);
214 ast_hangup(tobj->peer);
215 tobj->chan = tobj->peer = NULL;
220 static void ast_bridge_call_thread_launch(void *data)
224 struct sched_param sched;
226 pthread_attr_init(&attr);
227 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
228 ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data);
229 pthread_attr_destroy(&attr);
230 memset(&sched, 0, sizeof(sched));
231 pthread_setschedparam(thread, SCHED_RR, &sched);
236 static int adsi_announce_park(struct ast_channel *chan, int parkingnum)
239 int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
241 char *message[5] = {NULL, NULL, NULL, NULL, NULL};
243 snprintf(tmp, sizeof(tmp), "Parked on %d", parkingnum);
245 res = adsi_load_session(chan, NULL, 0, 1);
248 return adsi_print(chan, message, justify, 1);
251 /*! \brief Park a call
252 We put the user in the parking list, then wake up the parking thread to be sure it looks
253 after these channels too */
254 int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
256 struct parkeduser *pu, *cur;
257 int i,x,parking_range;
258 char exten[AST_MAX_EXTENSION];
259 struct ast_context *con;
261 if (!(pu = ast_calloc(1, sizeof(*pu)))) {
264 ast_mutex_lock(&parking_lock);
265 parking_range = parking_stop - parking_start+1;
266 for (i = 0; i < parking_range; i++) {
267 x = (i + parking_offset) % parking_range + parking_start;
270 if (cur->parkingnum == x)
278 if (!(i < parking_range)) {
279 ast_log(LOG_WARNING, "No more parking spaces\n");
281 ast_mutex_unlock(&parking_lock);
285 parking_offset = x - parking_start + 1;
286 chan->appl = "Parked Call";
290 /* Start music on hold */
292 ast_indicate(pu->chan, AST_CONTROL_HOLD);
293 ast_moh_start(pu->chan, NULL);
295 pu->start = ast_tvnow();
298 pu->parkingtime = timeout;
300 pu->parkingtime = parkingtime;
304 ast_copy_string(pu->peername, peer->name, sizeof(pu->peername));
306 /* Remember what had been dialed, so that if the parking
307 expires, we try to come back to the same place */
308 ast_copy_string(pu->context, S_OR(chan->macrocontext, chan->context), sizeof(pu->context));
309 ast_copy_string(pu->exten, S_OR(chan->macroexten, chan->exten), sizeof(pu->exten));
310 pu->priority = chan->macropriority ? chan->macropriority : chan->priority;
311 pu->next = parkinglot;
313 /* If parking a channel directly, don't quiet yet get parking running on it */
316 ast_mutex_unlock(&parking_lock);
317 /* Wake up the (presumably select()ing) thread */
318 pthread_kill(parking_thread, SIGURG);
319 if (option_verbose > 1)
320 ast_verbose(VERBOSE_PREFIX_2 "Parked %s on %d. Will timeout back to extension [%s] %s, %d in %d seconds\n", pu->chan->name, pu->parkingnum, pu->context, pu->exten, pu->priority, (pu->parkingtime/1000));
322 manager_event(EVENT_FLAG_CALL, "ParkedCall",
328 "CallerIDName: %s\r\n"
329 ,pu->parkingnum, pu->chan->name, peer ? peer->name : ""
330 ,(long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL)
331 ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
332 ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
336 if (adsipark && adsi_available(peer))
337 adsi_announce_park(peer, pu->parkingnum);
338 if (adsipark && adsi_available(peer))
339 adsi_unload_session(peer);
341 con = ast_context_find(parking_con);
343 con = ast_context_create(NULL, parking_con, registrar);
345 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
348 snprintf(exten, sizeof(exten), "%d", x);
349 ast_add_extension2(con, 1, exten, 1, NULL, NULL, parkedcall, strdup(exten), FREE, registrar);
352 ast_say_digits(peer, pu->parkingnum, "", peer->language);
353 if (pu->notquiteyet) {
354 /* Wake up parking thread if we're really done */
355 ast_moh_start(pu->chan, NULL);
357 pthread_kill(parking_thread, SIGURG);
362 int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
364 struct ast_channel *chan;
367 /* Make a new, fake channel that we'll use to masquerade in the real one */
368 if ((chan = ast_channel_alloc(0))) {
369 /* Let us keep track of the channel name */
370 ast_string_field_build(chan, name, "Parked/%s",rchan->name);
372 /* Make formats okay */
373 chan->readformat = rchan->readformat;
374 chan->writeformat = rchan->writeformat;
375 ast_channel_masquerade(chan, rchan);
377 /* Setup the extensions and such */
378 ast_copy_string(chan->context, rchan->context, sizeof(chan->context));
379 ast_copy_string(chan->exten, rchan->exten, sizeof(chan->exten));
380 chan->priority = rchan->priority;
382 /* Make the masq execute */
386 ast_park_call(chan, peer, timeout, extout);
388 ast_log(LOG_WARNING, "Unable to create parked channel\n");
395 #define FEATURE_RETURN_HANGUP -1
396 #define FEATURE_RETURN_SUCCESSBREAK 0
397 #define FEATURE_RETURN_PBX_KEEPALIVE AST_PBX_KEEPALIVE
398 #define FEATURE_RETURN_NO_HANGUP_PEER AST_PBX_NO_HANGUP_PEER
399 #define FEATURE_RETURN_PASSDIGITS 21
400 #define FEATURE_RETURN_STOREDIGITS 22
401 #define FEATURE_RETURN_SUCCESS 23
403 #define FEATURE_SENSE_CHAN (1 << 0)
404 #define FEATURE_SENSE_PEER (1 << 1)
407 static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
409 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
412 struct ast_channel *caller_chan = NULL, *callee_chan = NULL;
424 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
429 if (!(monitor_app = pbx_findapp("Monitor"))) {
431 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
435 if (!ast_strlen_zero(courtesytone)) {
436 if (ast_autoservice_start(callee_chan))
438 if (!ast_streamfile(caller_chan, courtesytone, caller_chan->language)) {
439 if (ast_waitstream(caller_chan, "") < 0) {
440 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
441 ast_autoservice_stop(callee_chan);
445 if (ast_autoservice_stop(callee_chan))
449 if (callee_chan->monitor) {
450 if (option_verbose > 3)
451 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to stop recording call.\n", code);
452 ast_monitor_stop(callee_chan, 1);
453 return FEATURE_RETURN_SUCCESS;
456 if (caller_chan && callee_chan) {
457 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT");
458 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
461 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
464 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
467 len = strlen(touch_monitor) + 50;
469 touch_filename = alloca(len);
470 snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor);
471 snprintf(args, len, "%s|%s|m", (touch_format) ? touch_format : "wav", touch_filename);
473 caller_chan_id = ast_strdupa(caller_chan->cid.cid_num ? caller_chan->cid.cid_num : caller_chan->name);
474 callee_chan_id = ast_strdupa(callee_chan->cid.cid_num ? callee_chan->cid.cid_num : callee_chan->name);
475 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
477 touch_filename = alloca(len);
478 snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id);
479 snprintf(args, len, "%s|%s|m", (touch_format) ? touch_format : "wav", touch_filename);
482 for( x = 0; x < strlen(args); x++) {
487 if (option_verbose > 3)
488 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call. filename: %s\n", code, args);
490 pbx_exec(callee_chan, monitor_app, args);
491 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
492 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
494 return FEATURE_RETURN_SUCCESS;
497 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");
501 static int builtin_disconnect(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
503 if (option_verbose > 3)
504 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code);
505 return FEATURE_RETURN_HANGUP;
508 static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
510 struct ast_channel *transferer;
511 struct ast_channel *transferee;
512 const char *transferer_real_context;
516 if (sense == FEATURE_SENSE_PEER) {
523 if (!(transferer_real_context = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT")) &&
524 !(transferer_real_context = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"))) {
525 /* Use the non-macro context to transfer the call */
526 if (!ast_strlen_zero(transferer->macrocontext))
527 transferer_real_context = transferer->macrocontext;
529 transferer_real_context = transferer->context;
531 /* Start autoservice on chan while we talk
533 ast_indicate(transferee, AST_CONTROL_HOLD);
534 ast_autoservice_start(transferee);
535 ast_moh_start(transferee, NULL);
537 memset(newext, 0, sizeof(newext));
540 if ((res=ast_streamfile(transferer, "pbx-transfer", transferer->language))) {
541 ast_moh_stop(transferee);
542 ast_autoservice_stop(transferee);
543 ast_indicate(transferee, AST_CONTROL_UNHOLD);
546 if ((res=ast_waitstream(transferer, AST_DIGIT_ANY)) < 0) {
547 ast_moh_stop(transferee);
548 ast_autoservice_stop(transferee);
549 ast_indicate(transferee, AST_CONTROL_UNHOLD);
551 } else if (res > 0) {
552 /* If they've typed a digit already, handle it */
553 newext[0] = (char) res;
556 ast_stopstream(transferer);
557 res = ast_app_dtget(transferer, transferer_real_context, newext, sizeof(newext), 100, transferdigittimeout);
559 ast_moh_stop(transferee);
560 ast_autoservice_stop(transferee);
561 ast_indicate(transferee, AST_CONTROL_UNHOLD);
564 if (!strcmp(newext, ast_parking_ext())) {
565 ast_moh_stop(transferee);
567 res = ast_autoservice_stop(transferee);
568 ast_indicate(transferee, AST_CONTROL_UNHOLD);
571 else if (!ast_park_call(transferee, transferer, 0, NULL)) {
572 /* We return non-zero, but tell the PBX not to hang the channel when
573 the thread dies -- We have to be careful now though. We are responsible for
574 hanging up the channel, else it will never be hung up! */
576 return (transferer == peer) ? AST_PBX_KEEPALIVE : AST_PBX_NO_HANGUP_PEER;
578 ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name);
580 /* XXX Maybe we should have another message here instead of invalid extension XXX */
581 } else if (ast_exists_extension(transferee, transferer_real_context, newext, 1, transferer->cid.cid_num)) {
582 pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", chan->name);
583 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", peer->name);
584 ast_moh_stop(transferee);
585 res=ast_autoservice_stop(transferee);
586 ast_indicate(transferee, AST_CONTROL_UNHOLD);
587 if (!transferee->pbx) {
588 /* Doh! Use our handy async_goto functions */
589 if (option_verbose > 2)
590 ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n"
591 ,transferee->name, newext, transferer_real_context);
592 if (ast_async_goto(transferee, transferer_real_context, newext, 1))
593 ast_log(LOG_WARNING, "Async goto failed :-(\n");
596 /* Set the channel's new extension, since it exists, using transferer context */
597 ast_copy_string(transferee->exten, newext, sizeof(transferee->exten));
598 ast_copy_string(transferee->context, transferer_real_context, sizeof(transferee->context));
599 transferee->priority = 0;
601 check_goto_on_transfer(transferer);
604 if (option_verbose > 2)
605 ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", newext, transferer_real_context);
607 if (!ast_strlen_zero(xferfailsound))
608 res = ast_streamfile(transferer, xferfailsound, transferee->language);
612 ast_moh_stop(transferee);
613 ast_autoservice_stop(transferee);
614 ast_indicate(transferee, AST_CONTROL_UNHOLD);
617 res = ast_waitstream(transferer, AST_DIGIT_ANY);
618 ast_stopstream(transferer);
619 ast_moh_stop(transferee);
620 res = ast_autoservice_stop(transferee);
621 ast_indicate(transferee, AST_CONTROL_UNHOLD);
623 if (option_verbose > 1)
624 ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name);
627 return FEATURE_RETURN_SUCCESS;
630 static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
632 struct ast_channel *transferer;
633 struct ast_channel *transferee;
634 struct ast_channel *newchan, *xferchan=NULL;
636 struct ast_bridge_config bconfig;
637 const char *transferer_real_context;
638 char xferto[256],dialstr[265];
642 struct ast_frame *f = NULL;
643 struct ast_bridge_thread_obj *tobj;
645 ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) XXX\n", chan->name, peer->name, sense);
646 if (sense == FEATURE_SENSE_PEER) {
653 if (!(transferer_real_context=pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT")) &&
654 !(transferer_real_context=pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"))) {
655 /* Use the non-macro context to transfer the call */
656 if (!ast_strlen_zero(transferer->macrocontext))
657 transferer_real_context = transferer->macrocontext;
659 transferer_real_context = transferer->context;
661 /* Start autoservice on chan while we talk
663 ast_indicate(transferee, AST_CONTROL_HOLD);
664 ast_autoservice_start(transferee);
665 ast_moh_start(transferee, NULL);
666 memset(xferto, 0, sizeof(xferto));
668 if ((res = ast_streamfile(transferer, "pbx-transfer", transferer->language))) {
669 ast_moh_stop(transferee);
670 ast_autoservice_stop(transferee);
671 ast_indicate(transferee, AST_CONTROL_UNHOLD);
674 if ((res=ast_waitstream(transferer, AST_DIGIT_ANY)) < 0) {
675 ast_moh_stop(transferee);
676 ast_autoservice_stop(transferee);
677 ast_indicate(transferee, AST_CONTROL_UNHOLD);
680 /* If they've typed a digit already, handle it */
681 xferto[0] = (char) res;
683 if ((ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout))) {
684 cid_num = transferer->cid.cid_num;
685 cid_name = transferer->cid.cid_name;
686 if (ast_exists_extension(transferer, transferer_real_context,xferto, 1, cid_num)) {
687 snprintf(dialstr, sizeof(dialstr), "%s@%s/n", xferto, transferer_real_context);
688 newchan = ast_feature_request_and_dial(transferer, "Local", ast_best_codec(transferer->nativeformats), dialstr, 15000, &outstate, cid_num, cid_name);
689 ast_indicate(transferer, -1);
691 res = ast_channel_make_compatible(transferer, newchan);
693 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", transferer->name, newchan->name);
697 memset(&bconfig,0,sizeof(struct ast_bridge_config));
698 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
699 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
700 res = ast_bridge_call(transferer,newchan,&bconfig);
701 if (newchan->_softhangup || newchan->_state != AST_STATE_UP || !transferer->_softhangup) {
707 if (!ast_strlen_zero(xfersound) && !ast_streamfile(transferer, xfersound, transferer->language)) {
708 if (ast_waitstream(transferer, "") < 0) {
709 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
712 ast_moh_stop(transferee);
713 ast_autoservice_stop(transferee);
714 ast_indicate(transferee, AST_CONTROL_UNHOLD);
715 transferer->_softhangup = 0;
716 return FEATURE_RETURN_SUCCESS;
719 res = ast_channel_make_compatible(transferee, newchan);
721 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", transferee->name, newchan->name);
727 ast_moh_stop(transferee);
729 if ((ast_autoservice_stop(transferee) < 0)
730 || (ast_waitfordigit(transferee, 100) < 0)
731 || (ast_waitfordigit(newchan, 100) < 0)
732 || ast_check_hangup(transferee)
733 || ast_check_hangup(newchan)) {
739 if ((xferchan = ast_channel_alloc(0))) {
740 ast_string_field_build(xferchan, name, "Transfered/%s", transferee->name);
741 /* Make formats okay */
742 xferchan->readformat = transferee->readformat;
743 xferchan->writeformat = transferee->writeformat;
744 ast_channel_masquerade(xferchan, transferee);
745 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
746 xferchan->_state = AST_STATE_UP;
747 ast_clear_flag(xferchan, AST_FLAGS_ALL);
748 xferchan->_softhangup = 0;
750 if ((f = ast_read(xferchan))) {
760 newchan->_state = AST_STATE_UP;
761 ast_clear_flag(newchan, AST_FLAGS_ALL);
762 newchan->_softhangup = 0;
764 if ((tobj = ast_calloc(1, sizeof(*tobj)))) {
765 tobj->chan = xferchan;
766 tobj->peer = newchan;
767 tobj->bconfig = *config;
769 if (!ast_strlen_zero(xfersound) && !ast_streamfile(newchan, xfersound, newchan->language) &&
770 ast_waitstream(newchan, "") < 0) {
771 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
773 ast_bridge_call_thread_launch(tobj);
775 ast_hangup(xferchan);
781 ast_moh_stop(transferee);
782 ast_autoservice_stop(transferee);
783 ast_indicate(transferee, AST_CONTROL_UNHOLD);
784 /* any reason besides user requested cancel and busy triggers the failed sound */
785 if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY && !ast_strlen_zero(xferfailsound)) {
786 res = ast_streamfile(transferer, xferfailsound, transferer->language);
787 if (!res && (ast_waitstream(transferer, "") < 0)) {
791 return FEATURE_RETURN_SUCCESS;
794 ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context);
795 ast_moh_stop(transferee);
796 ast_autoservice_stop(transferee);
797 ast_indicate(transferee, AST_CONTROL_UNHOLD);
798 res = ast_streamfile(transferer, "beeperr", transferer->language);
799 if (!res && (ast_waitstream(transferer, "") < 0)) {
804 ast_log(LOG_WARNING, "Did not read data.\n");
805 res = ast_streamfile(transferer, "beeperr", transferer->language);
806 if (ast_waitstream(transferer, "") < 0) {
810 ast_moh_stop(transferee);
811 ast_autoservice_stop(transferee);
812 ast_indicate(transferee, AST_CONTROL_UNHOLD);
814 return FEATURE_RETURN_SUCCESS;
818 /* add atxfer and automon as undefined so you can only use em if you configure them */
819 #define FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0]))
821 struct ast_call_feature builtin_features[] =
823 { AST_FEATURE_REDIRECT, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer, AST_FEATURE_FLAG_NEEDSDTMF },
824 { AST_FEATURE_REDIRECT, "Attended Transfer", "atxfer", "", "", builtin_atxfer, AST_FEATURE_FLAG_NEEDSDTMF },
825 { AST_FEATURE_AUTOMON, "One Touch Monitor", "automon", "", "", builtin_automonitor, AST_FEATURE_FLAG_NEEDSDTMF },
826 { AST_FEATURE_DISCONNECT, "Disconnect Call", "disconnect", "*", "*", builtin_disconnect, AST_FEATURE_FLAG_NEEDSDTMF },
830 static AST_LIST_HEAD(feature_list,ast_call_feature) feature_list;
832 /*! \brief register new feature into feature_list*/
833 void ast_register_feature(struct ast_call_feature *feature)
836 ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
840 AST_LIST_LOCK(&feature_list);
841 AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry);
842 AST_LIST_UNLOCK(&feature_list);
844 if (option_verbose >= 2)
845 ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
848 /*! \brief unregister feature from feature_list */
849 void ast_unregister_feature(struct ast_call_feature *feature)
851 if (!feature) return;
853 AST_LIST_LOCK(&feature_list);
854 AST_LIST_REMOVE(&feature_list,feature,feature_entry);
855 AST_LIST_UNLOCK(&feature_list);
859 static void ast_unregister_features(void)
861 struct ast_call_feature *feature;
863 AST_LIST_LOCK(&feature_list);
864 while ((feature = AST_LIST_REMOVE_HEAD(&feature_list,feature_entry)))
866 AST_LIST_UNLOCK(&feature_list);
869 /*! \brief find a feature by name */
870 static struct ast_call_feature *find_feature(char *name)
872 struct ast_call_feature *tmp;
874 AST_LIST_LOCK(&feature_list);
875 AST_LIST_TRAVERSE(&feature_list, tmp, feature_entry) {
876 if (!strcasecmp(tmp->sname, name))
879 AST_LIST_UNLOCK(&feature_list);
884 /*! \brief exec an app by feature */
885 static int feature_exec_app(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
888 struct ast_call_feature *feature;
891 AST_LIST_LOCK(&feature_list);
892 AST_LIST_TRAVERSE(&feature_list,feature,feature_entry) {
893 if (!strcasecmp(feature->exten,code))
896 AST_LIST_UNLOCK(&feature_list);
898 if (!feature) { /* shouldn't ever happen! */
899 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
903 app = pbx_findapp(feature->app);
905 struct ast_channel *work = chan;
906 if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLEE))
908 res = pbx_exec(work, app, feature->app_args);
912 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
916 return FEATURE_RETURN_SUCCESS;
919 static void unmap_features(void)
922 for (x = 0; x < FEATURES_COUNT; x++)
923 strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
926 static int remap_feature(const char *name, const char *value)
930 for (x = 0; x < FEATURES_COUNT; x++) {
931 if (!strcasecmp(name, builtin_features[x].sname)) {
932 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
933 if (option_verbose > 1)
934 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);
936 } else if (!strcmp(value, builtin_features[x].exten))
937 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);
942 static int ast_feature_interpret(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
945 struct ast_flags features;
946 int res = FEATURE_RETURN_PASSDIGITS;
947 struct ast_call_feature *feature;
948 const char *dynamic_features=pbx_builtin_getvar_helper(chan,"DYNAMIC_FEATURES");
950 if (sense == FEATURE_SENSE_CHAN)
951 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
953 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);
954 ast_log(LOG_DEBUG, "Feature interpret: chan=%s, peer=%s, sense=%d, features=%d\n", chan->name, peer->name, sense, features.flags);
956 for (x=0; x < FEATURES_COUNT; x++) {
957 if ((ast_test_flag(&features, builtin_features[x].feature_mask)) &&
958 !ast_strlen_zero(builtin_features[x].exten)) {
959 /* Feature is up for consideration */
960 if (!strcmp(builtin_features[x].exten, code)) {
961 res = builtin_features[x].operation(chan, peer, config, code, sense);
963 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
964 if (res == FEATURE_RETURN_PASSDIGITS)
965 res = FEATURE_RETURN_STOREDIGITS;
971 if (!ast_strlen_zero(dynamic_features)) {
972 char *tmp = ast_strdupa(dynamic_features);
978 while ((tok = strsep(&tmp, "#")) != NULL) {
979 feature = find_feature(tok);
982 /* Feature is up for consideration */
983 if (!strcmp(feature->exten, code)) {
984 if (option_verbose > 2)
985 ast_verbose(VERBOSE_PREFIX_3 " Feature Found: %s exten: %s\n",feature->sname, tok);
986 res = feature->operation(chan, peer, config, code, sense);
988 } else if (!strncmp(feature->exten, code, strlen(code))) {
989 res = FEATURE_RETURN_STOREDIGITS;
998 static void set_config_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
1002 ast_clear_flag(config, AST_FLAGS_ALL);
1003 for (x = 0; x < FEATURES_COUNT; x++) {
1004 if (ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF)) {
1005 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
1006 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
1008 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
1009 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
1013 if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
1014 const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
1016 if (dynamic_features) {
1017 char *tmp = ast_strdupa(dynamic_features);
1019 struct ast_call_feature *feature;
1025 /* while we have a feature */
1026 while (NULL != (tok = strsep(&tmp, "#"))) {
1027 if ((feature = find_feature(tok))) {
1028 if (ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
1029 if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLER))
1030 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
1031 if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLEE))
1032 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
1041 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)
1046 struct ast_channel *chan;
1047 struct ast_channel *monitor_chans[2];
1048 struct ast_channel *active_channel;
1049 struct ast_frame *f = NULL;
1050 int res = 0, ready = 0;
1052 if ((chan = ast_request(type, format, data, &cause))) {
1053 ast_set_callerid(chan, cid_num, cid_name, cid_num);
1054 ast_channel_inherit_variables(caller, chan);
1055 if (!ast_call(chan, data, timeout)) {
1056 struct timeval started;
1058 char *disconnect_code = NULL, *dialed_code = NULL;
1060 ast_indicate(caller, AST_CONTROL_RINGING);
1061 /* support dialing of the featuremap disconnect code while performing an attended tranfer */
1062 for (x=0; x < FEATURES_COUNT; x++) {
1063 if (strcasecmp(builtin_features[x].sname, "disconnect"))
1066 disconnect_code = builtin_features[x].exten;
1067 len = strlen(disconnect_code) + 1;
1068 dialed_code = alloca(len);
1069 memset(dialed_code, 0, len);
1073 started = ast_tvnow();
1075 while (!ast_check_hangup(caller) && timeout && (chan->_state != AST_STATE_UP)) {
1076 monitor_chans[0] = caller;
1077 monitor_chans[1] = chan;
1078 active_channel = ast_waitfor_n(monitor_chans, 2, &to);
1080 /* see if the timeout has been violated */
1081 if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
1082 state = AST_CONTROL_UNHOLD;
1083 ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n");
1084 break; /*doh! timeout*/
1087 if (!active_channel) {
1091 if (chan && (chan == active_channel)){
1093 if (f == NULL) { /*doh! where'd he go?*/
1094 state = AST_CONTROL_HANGUP;
1099 if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) {
1100 if (f->subclass == AST_CONTROL_RINGING) {
1101 state = f->subclass;
1102 if (option_verbose > 2)
1103 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", chan->name);
1104 ast_indicate(caller, AST_CONTROL_RINGING);
1105 } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) {
1106 state = f->subclass;
1107 if (option_verbose > 2)
1108 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", chan->name);
1109 ast_indicate(caller, AST_CONTROL_BUSY);
1113 } else if (f->subclass == AST_CONTROL_ANSWER) {
1114 /* This is what we are hoping for */
1115 state = f->subclass;
1121 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass);
1123 /* else who cares */
1126 } else if (caller && (active_channel == caller)) {
1127 f = ast_read(caller);
1128 if (f == NULL) { /*doh! where'd he go?*/
1129 if (caller->_softhangup && !chan->_softhangup) {
1130 /* make this a blind transfer */
1134 state = AST_CONTROL_HANGUP;
1139 if (f->frametype == AST_FRAME_DTMF) {
1140 dialed_code[x++] = f->subclass;
1141 dialed_code[x] = '\0';
1142 if (strlen(dialed_code) == len) {
1144 } else if (x && strncmp(dialed_code, disconnect_code, x)) {
1146 dialed_code[x] = '\0';
1148 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
1149 /* Caller Canceled the call */
1150 state = AST_CONTROL_UNHOLD;
1162 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
1164 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
1166 case AST_CAUSE_BUSY:
1167 state = AST_CONTROL_BUSY;
1169 case AST_CAUSE_CONGESTION:
1170 state = AST_CONTROL_CONGESTION;
1175 ast_indicate(caller, -1);
1176 if (chan && ready) {
1177 if (chan->_state == AST_STATE_UP)
1178 state = AST_CONTROL_ANSWER;
1191 if (chan && res <= 0) {
1192 if (chan->cdr || (chan->cdr = ast_cdr_alloc())) {
1194 ast_cdr_init(chan->cdr, chan);
1195 snprintf(tmp, 256, "%s/%s", type, (char *)data);
1196 ast_cdr_setapp(chan->cdr,"Dial",tmp);
1197 ast_cdr_update(chan);
1198 ast_cdr_start(chan->cdr);
1199 ast_cdr_end(chan->cdr);
1200 /* If the cause wasn't handled properly */
1201 if (ast_cdr_disposition(chan->cdr,chan->hangupcause))
1202 ast_cdr_failed(chan->cdr);
1204 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
1211 int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast_bridge_config *config)
1213 /* Copy voice back and forth between the two channels. Give the peer
1214 the ability to transfer calls with '#<extension' syntax. */
1215 struct ast_frame *f;
1216 struct ast_channel *who;
1217 char chan_featurecode[FEATURE_MAX_LEN + 1]="";
1218 char peer_featurecode[FEATURE_MAX_LEN + 1]="";
1223 struct ast_option_header *aoh;
1224 struct timeval start = { 0 , 0 };
1225 struct ast_bridge_config backup_config;
1227 memset(&backup_config, 0, sizeof(backup_config));
1229 config->start_time = ast_tvnow();
1232 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
1233 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
1235 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
1238 const char *monitor_exec;
1239 struct ast_channel *src = NULL;
1241 if (!(monitor_app = pbx_findapp("Monitor")))
1244 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR")))
1246 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
1248 if (monitor_app && src) {
1249 char *tmp = ast_strdupa(monitor_exec);
1251 pbx_exec(src, monitor_app, tmp);
1253 ast_log(LOG_ERROR, "Monitor failed: out of memory\n");
1258 set_config_flags(chan, peer, config);
1259 config->firstpass = 1;
1261 /* Answer if need be */
1262 if (ast_answer(chan))
1264 peer->appl = "Bridged Call";
1265 peer->data = (char *) chan->name;
1267 /* copy the userfield from the B-leg to A-leg if applicable */
1268 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
1270 if (!ast_strlen_zero(chan->cdr->userfield)) {
1271 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield);
1272 ast_cdr_appenduserfield(chan, tmp);
1274 ast_cdr_setuserfield(chan, peer->cdr->userfield);
1275 /* free the peer's cdr without ast_cdr_free complaining */
1280 struct ast_channel *other; /* used later */
1281 if (config->feature_timer)
1282 start = ast_tvnow();
1284 res = ast_channel_bridge(chan, peer, config, &f, &who);
1286 if (config->feature_timer) {
1287 /* Update time limit for next pass */
1288 diff = ast_tvdiff_ms(ast_tvnow(), start);
1289 config->feature_timer -= diff;
1291 /* Running on backup config, meaning a feature might be being
1292 activated, but that's no excuse to keep things going
1294 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
1295 ast_log(LOG_DEBUG, "Timed out, realtime this time!\n");
1296 config->feature_timer = 0;
1302 } else if (config->feature_timer <= 0) {
1303 /* Not *really* out of time, just out of time for
1304 digits to come in for features. */
1305 ast_log(LOG_DEBUG, "Timed out for feature!\n");
1306 if (!ast_strlen_zero(peer_featurecode)) {
1307 ast_dtmf_stream(chan, peer, peer_featurecode, 0);
1308 memset(peer_featurecode, 0, sizeof(peer_featurecode));
1310 if (!ast_strlen_zero(chan_featurecode)) {
1311 ast_dtmf_stream(peer, chan, chan_featurecode, 0);
1312 memset(chan_featurecode, 0, sizeof(chan_featurecode));
1316 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
1318 /* Restore original (possibly time modified) bridge config */
1319 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
1320 memset(&backup_config, 0, sizeof(backup_config));
1322 hadfeatures = hasfeatures;
1323 /* Continue as we were */
1327 if (config->feature_timer <=0) {
1328 /* We ran out of time */
1329 config->feature_timer = 0;
1339 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
1343 if (!f || ((f->frametype == AST_FRAME_CONTROL) && ((f->subclass == AST_CONTROL_HANGUP) || (f->subclass == AST_CONTROL_BUSY) ||
1344 (f->subclass == AST_CONTROL_CONGESTION)))) {
1348 /* many things should be sent to the 'other' channel */
1349 other = (who == chan) ? peer : chan;
1350 if (f->frametype == AST_FRAME_CONTROL) {
1351 if (f->subclass == AST_CONTROL_RINGING)
1352 ast_indicate(other, AST_CONTROL_RINGING);
1353 else if (f->subclass == -1)
1354 ast_indicate(other, -1);
1355 else if (f->subclass == AST_CONTROL_FLASH)
1356 ast_indicate(other, AST_CONTROL_FLASH);
1357 else if (f->subclass == AST_CONTROL_OPTION) {
1359 /* Forward option Requests */
1360 if (aoh && (aoh->flag == AST_OPTION_FLAG_REQUEST))
1361 ast_channel_setoption(other, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
1364 /* check for '*', if we find it it's time to disconnect */
1365 if (f && (f->frametype == AST_FRAME_DTMF)) {
1369 hadfeatures = hasfeatures;
1370 /* This cannot overrun because the longest feature is one shorter than our buffer */
1372 sense = FEATURE_SENSE_CHAN;
1373 featurecode = chan_featurecode;
1375 sense = FEATURE_SENSE_PEER;
1376 featurecode = peer_featurecode;
1378 /* append the event to featurecode. we rely on the string being zero-filled, and
1379 * not overflowing it. XXX how do we guarantee the latter ?
1381 featurecode[strlen(featurecode)] = f->subclass;
1382 config->feature_timer = backup_config.feature_timer;
1383 res = ast_feature_interpret(chan, peer, config, featurecode, sense);
1385 case FEATURE_RETURN_PASSDIGITS:
1386 ast_dtmf_stream(other, who, featurecode, 0);
1388 case FEATURE_RETURN_SUCCESS:
1389 memset(featurecode, 0, sizeof(chan_featurecode));
1392 if (res >= FEATURE_RETURN_PASSDIGITS) {
1398 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
1399 if (hadfeatures && !hasfeatures) {
1400 /* Restore backup */
1401 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
1402 memset(&backup_config, 0, sizeof(struct ast_bridge_config));
1403 } else if (hasfeatures) {
1405 /* Backup configuration */
1406 memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
1407 /* Setup temporary config options */
1408 config->play_warning = 0;
1409 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
1410 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
1411 config->warning_freq = 0;
1412 config->warning_sound = NULL;
1413 config->end_sound = NULL;
1414 config->start_sound = NULL;
1415 config->firstpass = 0;
1417 config->feature_timer = featuredigittimeout;
1418 ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer);
1427 /*! \brief Take care of parked calls and unpark them if needed */
1428 static void *do_parking_thread(void *ignore)
1431 struct parkeduser *pu, *pl, *pt = NULL;
1433 struct ast_frame *f;
1434 char exten[AST_MAX_EXTENSION];
1436 char returnexten[AST_MAX_EXTENSION];
1437 struct ast_context *con;
1440 fd_set nrfds, nefds;
1447 ast_mutex_lock(&parking_lock);
1453 if (pu->notquiteyet) {
1454 /* Pretend this one isn't here yet */
1459 tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
1460 if (tms > pu->parkingtime) {
1461 /* Stop music on hold */
1462 ast_moh_stop(pu->chan);
1463 ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
1464 /* Get chan, exten from derived kludge */
1465 if (pu->peername[0]) {
1466 peername = ast_strdupa(pu->peername);
1467 cp = strrchr(peername, '-');
1470 con = ast_context_find(parking_con_dial);
1472 con = ast_context_create(NULL, parking_con_dial, registrar);
1474 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
1478 snprintf(returnexten, sizeof(returnexten), "%s||t", peername);
1479 ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), FREE, registrar);
1481 ast_copy_string(pu->chan->exten, peername, sizeof(pu->chan->exten));
1482 ast_copy_string(pu->chan->context, parking_con_dial, sizeof(pu->chan->context));
1483 pu->chan->priority = 1;
1486 /* They've been waiting too long, send them back to where they came. Theoretically they
1487 should have their original extensions and such, but we copy to be on the safe side */
1488 ast_copy_string(pu->chan->exten, pu->exten, sizeof(pu->chan->exten));
1489 ast_copy_string(pu->chan->context, pu->context, sizeof(pu->chan->context));
1490 pu->chan->priority = pu->priority;
1493 manager_event(EVENT_FLAG_CALL, "ParkedCallTimeOut",
1497 "CallerIDName: %s\r\n"
1498 ,pu->parkingnum, pu->chan->name
1499 ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
1500 ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
1503 if (option_verbose > 1)
1504 ast_verbose(VERBOSE_PREFIX_2 "Timeout for %s parked on %d. Returning to %s,%s,%d\n", pu->chan->name, pu->parkingnum, pu->chan->context, pu->chan->exten, pu->chan->priority);
1505 /* Start up the PBX, or hang them up */
1506 if (ast_pbx_start(pu->chan)) {
1507 ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name);
1508 ast_hangup(pu->chan);
1510 /* And take them out of the parking lot */
1512 pl->next = pu->next;
1514 parkinglot = pu->next;
1517 con = ast_context_find(parking_con);
1519 snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
1520 if (ast_context_remove_extension2(con, exten, 1, NULL))
1521 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1523 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1526 for (x = 0; x < AST_MAX_FDS; x++) {
1527 if ((pu->chan->fds[x] > -1) && (FD_ISSET(pu->chan->fds[x], &rfds) || FD_ISSET(pu->chan->fds[x], &efds))) {
1528 if (FD_ISSET(pu->chan->fds[x], &efds))
1529 ast_set_flag(pu->chan, AST_FLAG_EXCEPTION);
1531 ast_clear_flag(pu->chan, AST_FLAG_EXCEPTION);
1533 /* See if they need servicing */
1534 f = ast_read(pu->chan);
1535 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
1538 manager_event(EVENT_FLAG_CALL, "ParkedCallGiveUp",
1542 "CallerIDName: %s\r\n"
1543 ,pu->parkingnum, pu->chan->name
1544 ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
1545 ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
1548 /* There's a problem, hang them up*/
1549 if (option_verbose > 1)
1550 ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", pu->chan->name);
1551 ast_hangup(pu->chan);
1552 /* And take them out of the parking lot */
1554 pl->next = pu->next;
1556 parkinglot = pu->next;
1559 con = ast_context_find(parking_con);
1561 snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
1562 if (ast_context_remove_extension2(con, exten, 1, NULL))
1563 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1565 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1569 /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
1571 if (pu->moh_trys < 3 && !pu->chan->generatordata) {
1572 ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source. Restarting.\n");
1573 ast_moh_start(pu->chan, NULL);
1576 goto std; /* XXX Ick: jumping into an else statement??? XXX */
1580 if (x >= AST_MAX_FDS) {
1581 std: for (x=0; x<AST_MAX_FDS; x++) {
1582 /* Keep this one for next one */
1583 if (pu->chan->fds[x] > -1) {
1584 FD_SET(pu->chan->fds[x], &nrfds);
1585 FD_SET(pu->chan->fds[x], &nefds);
1586 if (pu->chan->fds[x] > max)
1587 max = pu->chan->fds[x];
1590 /* Keep track of our longest wait */
1591 if ((tms < ms) || (ms < 0))
1598 ast_mutex_unlock(&parking_lock);
1601 tv = ast_samp2tv(ms, 1000);
1602 /* Wait for something to happen */
1603 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
1604 pthread_testcancel();
1606 return NULL; /* Never reached */
1609 static int park_call_exec(struct ast_channel *chan, void *data)
1611 /* Data is unused at the moment but could contain a parking
1612 lot context eventually */
1614 struct localuser *u;
1616 /* Setup the exten/priority to be s/1 since we don't know
1617 where this call should return */
1618 strcpy(chan->exten, "s");
1620 if (chan->_state != AST_STATE_UP)
1621 res = ast_answer(chan);
1623 res = ast_safe_sleep(chan, 1000);
1625 res = ast_park_call(chan, chan, 0, NULL);
1626 LOCAL_USER_REMOVE(u);
1628 res = AST_PBX_KEEPALIVE;
1632 static int park_exec(struct ast_channel *chan, void *data)
1635 struct localuser *u;
1636 struct ast_channel *peer=NULL;
1637 struct parkeduser *pu, *pl=NULL;
1638 char exten[AST_MAX_EXTENSION];
1639 struct ast_context *con;
1642 struct ast_bridge_config config;
1645 ast_log(LOG_WARNING, "Park requires an argument (extension number)\n");
1649 park = atoi((char *)data);
1650 ast_mutex_lock(&parking_lock);
1653 if (pu->parkingnum == park) {
1655 pl->next = pu->next;
1657 parkinglot = pu->next;
1663 ast_mutex_unlock(&parking_lock);
1666 con = ast_context_find(parking_con);
1668 snprintf(exten, sizeof(exten), "%d", pu->parkingnum);
1669 if (ast_context_remove_extension2(con, exten, 1, NULL))
1670 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1672 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1674 manager_event(EVENT_FLAG_CALL, "UnParkedCall",
1679 "CallerIDName: %s\r\n"
1680 ,pu->parkingnum, pu->chan->name, chan->name
1681 ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
1682 ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
1687 /* JK02: it helps to answer the channel if not already up */
1688 if (chan->_state != AST_STATE_UP) {
1693 /* Play a courtesy to the source(s) configured to prefix the bridge connecting */
1695 if (!ast_strlen_zero(courtesytone)) {
1696 if (parkedplay == 0) {
1697 if (!ast_streamfile(chan, courtesytone, chan->language)) {
1698 if (ast_waitstream(chan, "") < 0) {
1699 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
1705 ast_indicate(peer, AST_CONTROL_UNHOLD);
1708 ast_indicate(peer, AST_CONTROL_UNHOLD);
1709 if (parkedplay == 2) {
1710 if (!ast_streamfile(chan, courtesytone, chan->language) && !ast_streamfile(peer, courtesytone, chan->language)) {
1711 res = ast_waitstream(chan, "");
1713 res = ast_waitstream(peer, "");
1715 ast_log(LOG_WARNING, "Failed to play courtesy tones!\n");
1720 } else if (parkedplay == 1) {
1721 if (!ast_streamfile(peer, courtesytone, chan->language)) {
1722 if (ast_waitstream(peer, "") < 0) {
1723 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
1732 res = ast_channel_make_compatible(chan, peer);
1734 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
1738 /* This runs sorta backwards, since we give the incoming channel control, as if it
1739 were the person called. */
1740 if (option_verbose > 2)
1741 ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
1743 memset(&config, 0, sizeof(struct ast_bridge_config));
1744 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
1745 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
1746 config.timelimit = 0;
1747 config.play_warning = 0;
1748 config.warning_freq = 0;
1749 config.warning_sound=NULL;
1750 res = ast_bridge_call(chan, peer, &config);
1752 /* Simulate the PBX hanging up */
1753 if (res != AST_PBX_NO_HANGUP_PEER)
1757 /* XXX Play a message XXX */
1758 dres = ast_streamfile(chan, "pbx-invalidpark", chan->language);
1760 dres = ast_waitstream(chan, "");
1762 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
1765 if (option_verbose > 2)
1766 ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
1769 LOCAL_USER_REMOVE(u);
1773 static int handle_showfeatures(int fd, int argc, char *argv[])
1777 struct ast_call_feature *feature;
1778 char format[] = "%-25s %-7s %-7s\n";
1780 ast_cli(fd, format, "Builtin Feature", "Default", "Current");
1781 ast_cli(fd, format, "---------------", "-------", "-------");
1783 ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */
1785 fcount = sizeof(builtin_features) / sizeof(builtin_features[0]);
1787 for (i = 0; i < fcount; i++)
1789 ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
1792 ast_cli(fd, format, "Dynamic Feature", "Default", "Current");
1793 ast_cli(fd, format, "---------------", "-------", "-------");
1794 if (AST_LIST_EMPTY(&feature_list)) {
1795 ast_cli(fd, "(none)\n");
1798 AST_LIST_LOCK(&feature_list);
1799 AST_LIST_TRAVERSE(&feature_list, feature, feature_entry) {
1800 ast_cli(fd, format, feature->sname, "no def", feature->exten);
1802 AST_LIST_UNLOCK(&feature_list);
1804 ast_cli(fd, "\nCall parking\n");
1805 ast_cli(fd, "------------\n");
1806 ast_cli(fd,"%-20s: %s\n", "Parking extension", parking_ext);
1807 ast_cli(fd,"%-20s: %s\n", "Parking context", parking_con);
1808 ast_cli(fd,"%-20s: %d-%d\n", "Parked call extensions", parking_start, parking_stop);
1811 return RESULT_SUCCESS;
1814 static char showfeatures_help[] =
1815 "Usage: show features\n"
1816 " Lists currently configured features.\n";
1818 static struct ast_cli_entry showfeatures =
1819 { { "show", "features", NULL }, handle_showfeatures, "Lists configured features", showfeatures_help };
1821 static int handle_parkedcalls(int fd, int argc, char *argv[])
1823 struct parkeduser *cur;
1826 ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
1827 , "Context", "Extension", "Pri", "Timeout");
1829 ast_mutex_lock(&parking_lock);
1833 ast_cli(fd, "%4d %25s (%-15s %-12s %-4d) %6lds\n"
1834 ,cur->parkingnum, cur->chan->name, cur->context, cur->exten
1835 ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
1840 ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : "");
1842 ast_mutex_unlock(&parking_lock);
1844 return RESULT_SUCCESS;
1847 static char showparked_help[] =
1848 "Usage: show parkedcalls\n"
1849 " Lists currently parked calls.\n";
1851 static struct ast_cli_entry showparked =
1852 { { "show", "parkedcalls", NULL }, handle_parkedcalls, "Lists parked calls", showparked_help };
1854 /*! \brief Dump lot status */
1855 static int manager_parking_status( struct mansession *s, struct message *m )
1857 struct parkeduser *cur;
1858 char *id = astman_get_header(m,"ActionID");
1859 char idText[256] = "";
1861 if (!ast_strlen_zero(id))
1862 snprintf(idText,256,"ActionID: %s\r\n",id);
1864 astman_send_ack(s, m, "Parked calls will follow");
1866 ast_mutex_lock(&parking_lock);
1870 astman_append(s, "Event: ParkedCall\r\n"
1876 "CallerIDName: %s\r\n"
1879 ,cur->parkingnum, cur->chan->name, cur->peername
1880 ,(long)cur->start.tv_sec + (long)(cur->parkingtime/1000) - (long)time(NULL)
1881 ,(cur->chan->cid.cid_num ? cur->chan->cid.cid_num : "")
1882 ,(cur->chan->cid.cid_name ? cur->chan->cid.cid_name : "")
1889 "Event: ParkedCallsComplete\r\n"
1893 ast_mutex_unlock(&parking_lock);
1895 return RESULT_SUCCESS;
1898 static char mandescr_park[] =
1899 "Description: Park a channel.\n"
1900 "Variables: (Names marked with * are required)\n"
1901 " *Channel: Channel name to park\n"
1902 " *Channel2: Channel to announce park info to (and return to if timeout)\n"
1903 " Timeout: Number of milliseconds to wait before callback.\n";
1905 static int manager_park(struct mansession *s, struct message *m)
1907 char *channel = astman_get_header(m, "Channel");
1908 char *channel2 = astman_get_header(m, "Channel2");
1909 char *timeout = astman_get_header(m, "Timeout");
1914 struct ast_channel *ch1, *ch2;
1916 if (ast_strlen_zero(channel)) {
1917 astman_send_error(s, m, "Channel not specified");
1921 if (ast_strlen_zero(channel2)) {
1922 astman_send_error(s, m, "Channel2 not specified");
1926 ch1 = ast_get_channel_by_name_locked(channel);
1928 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
1929 astman_send_error(s, m, buf);
1933 ch2 = ast_get_channel_by_name_locked(channel2);
1935 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
1936 astman_send_error(s, m, buf);
1937 ast_mutex_unlock(&ch1->lock);
1941 if (!ast_strlen_zero(timeout)) {
1942 sscanf(timeout, "%d", &to);
1945 res = ast_masq_park_call(ch1, ch2, to, &parkExt);
1947 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
1948 astman_send_ack(s, m, "Park successful");
1950 astman_send_error(s, m, "Park failure");
1953 ast_mutex_unlock(&ch1->lock);
1954 ast_mutex_unlock(&ch2->lock);
1960 int ast_pickup_call(struct ast_channel *chan)
1962 struct ast_channel *cur = NULL;
1965 while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
1968 (chan->pickupgroup & cur->callgroup) &&
1969 ((cur->_state == AST_STATE_RINGING) ||
1970 (cur->_state == AST_STATE_RING))) {
1973 ast_mutex_unlock(&cur->lock);
1977 ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
1978 res = ast_answer(chan);
1980 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
1981 res = ast_queue_control(chan, AST_CONTROL_ANSWER);
1983 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
1984 res = ast_channel_masquerade(cur, chan);
1986 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */
1987 ast_mutex_unlock(&cur->lock);
1990 ast_log(LOG_DEBUG, "No call pickup possible...\n");
1995 static int load_config(void)
1997 int start = 0, end = 0;
1998 struct ast_context *con = NULL;
1999 struct ast_config *cfg = NULL;
2000 struct ast_variable *var = NULL;
2001 char old_parking_ext[AST_MAX_EXTENSION];
2002 char old_parking_con[AST_MAX_EXTENSION] = "";
2004 if (!ast_strlen_zero(parking_con)) {
2005 strcpy(old_parking_ext, parking_ext);
2006 strcpy(old_parking_con, parking_con);
2009 /* Reset to defaults */
2010 strcpy(parking_con, "parkedcalls");
2011 strcpy(parking_con_dial, "park-dial");
2012 strcpy(parking_ext, "700");
2013 strcpy(pickup_ext, "*8");
2014 courtesytone[0] = '\0';
2015 strcpy(xfersound, "beep");
2016 strcpy(xferfailsound, "pbx-invalid");
2017 parking_start = 701;
2022 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
2023 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
2025 cfg = ast_config_load("features.conf");
2027 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
2028 if (!strcasecmp(var->name, "parkext")) {
2029 ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
2030 } else if (!strcasecmp(var->name, "context")) {
2031 ast_copy_string(parking_con, var->value, sizeof(parking_con));
2032 } else if (!strcasecmp(var->name, "parkingtime")) {
2033 if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) {
2034 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
2035 parkingtime = DEFAULT_PARK_TIME;
2037 parkingtime = parkingtime * 1000;
2038 } else if (!strcasecmp(var->name, "parkpos")) {
2039 if (sscanf(var->value, "%d-%d", &start, &end) != 2) {
2040 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);
2042 parking_start = start;
2045 } else if (!strcasecmp(var->name, "findslot")) {
2046 parkfindnext = (!strcasecmp(var->value, "next"));
2047 } else if (!strcasecmp(var->name, "adsipark")) {
2048 adsipark = ast_true(var->value);
2049 } else if (!strcasecmp(var->name, "transferdigittimeout")) {
2050 if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
2051 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
2052 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
2054 transferdigittimeout = transferdigittimeout * 1000;
2055 } else if (!strcasecmp(var->name, "featuredigittimeout")) {
2056 if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
2057 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
2058 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
2060 } else if (!strcasecmp(var->name, "courtesytone")) {
2061 ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
2062 } else if (!strcasecmp(var->name, "parkedplay")) {
2063 if (!strcasecmp(var->value, "both"))
2065 else if (!strcasecmp(var->value, "parked"))
2069 } else if (!strcasecmp(var->name, "xfersound")) {
2070 ast_copy_string(xfersound, var->value, sizeof(xfersound));
2071 } else if (!strcasecmp(var->name, "xferfailsound")) {
2072 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
2073 } else if (!strcasecmp(var->name, "pickupexten")) {
2074 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
2079 for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) {
2080 if (remap_feature(var->name, var->value))
2081 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
2084 /* Map a key combination to an application*/
2085 ast_unregister_features();
2086 for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) {
2087 char *tmp_val = ast_strdup(var->value);
2088 char *exten, *party=NULL, *app=NULL, *app_args=NULL;
2091 /* XXX No memory. We should probably break, but at least we do not
2092 * insist on this entry or we could be stuck in an
2098 /* strsep() sets the argument to NULL if match not found, and it
2099 * is safe to use it with a NULL argument, so we don't check
2102 exten = strsep(&tmp_val,",");
2103 party = strsep(&tmp_val,",");
2104 app = strsep(&tmp_val,",");
2105 app_args = strsep(&tmp_val,",");
2107 /* XXX var_name or app_args ? */
2108 if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(party) || ast_strlen_zero(var->name)) {
2109 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);
2115 struct ast_call_feature *feature;
2118 if (!(feature = find_feature(var->name))) {
2121 if (!(feature = ast_calloc(1, sizeof(*feature)))) {
2127 ast_copy_string(feature->sname,var->name,FEATURE_SNAME_LEN);
2128 ast_copy_string(feature->app,app,FEATURE_APP_LEN);
2129 ast_copy_string(feature->exten, exten,FEATURE_EXTEN_LEN);
2133 ast_copy_string(feature->app_args,app_args,FEATURE_APP_ARGS_LEN);
2135 ast_copy_string(feature->exten, exten,sizeof(feature->exten));
2136 feature->operation=feature_exec_app;
2137 ast_set_flag(feature,AST_FEATURE_FLAG_NEEDSDTMF);
2139 if (!strcasecmp(party,"caller"))
2140 ast_set_flag(feature,AST_FEATURE_FLAG_CALLER);
2141 else if (!strcasecmp(party, "callee"))
2142 ast_set_flag(feature,AST_FEATURE_FLAG_CALLEE);
2144 ast_log(LOG_NOTICE, "Invalid party specification for feature '%s', must be caller, or callee\n", var->name);
2148 ast_register_feature(feature);
2150 if (option_verbose >=1)
2151 ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s' with code '%s'\n", var->name, app, exten);
2155 ast_config_destroy(cfg);
2157 /* Remove the old parking extension */
2158 if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) {
2159 ast_context_remove_extension2(con, old_parking_ext, 1, registrar);
2160 ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
2163 if (!(con = ast_context_find(parking_con)) && !(con = ast_context_create(NULL, parking_con, registrar))) {
2164 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
2167 return ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, strdup(""), FREE, registrar);
2170 static int reload(void *mod)
2172 return load_config();
2175 static int load_module(void *mod)
2180 AST_LIST_HEAD_INIT(&feature_list);
2181 memset(parking_ext, 0, sizeof(parking_ext));
2182 memset(parking_con, 0, sizeof(parking_con));
2184 if ((res = load_config()))
2186 ast_cli_register(&showparked);
2187 ast_cli_register(&showfeatures);
2188 ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
2189 res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
2191 res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
2193 ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" );
2194 ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park,
2195 "Park a channel", mandescr_park);
2201 static int unload_module(void *mod)
2203 STANDARD_HANGUP_LOCALUSERS;
2205 ast_manager_unregister("ParkedCalls");
2206 ast_manager_unregister("Park");
2207 ast_cli_unregister(&showfeatures);
2208 ast_cli_unregister(&showparked);
2209 ast_unregister_application(parkcall);
2210 return ast_unregister_application(parkedcall);
2213 static const char *description(void)
2215 return "Call Features Resource";
2218 static const char *key(void)
2220 return ASTERISK_GPL_KEY;
2223 STD_MOD(MOD_0 | NO_UNLOAD, reload, NULL, NULL);