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 /* store context, priority and extension */
163 static void set_c_e_p(struct ast_channel *chan, const char *ctx, const char *ext, int pri)
165 ast_copy_string(chan->context, ctx, sizeof(chan->context));
166 ast_copy_string(chan->exten, ext, sizeof(chan->exten));
167 chan->priority = pri;
170 static void check_goto_on_transfer(struct ast_channel *chan)
172 struct ast_channel *xferchan;
173 const char *val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR");
174 char *x, *goto_on_transfer;
177 if (!ast_strlen_zero(val) && (goto_on_transfer = ast_strdupa(val)) && (xferchan = ast_channel_alloc(0))) {
178 for (x = goto_on_transfer; x && *x; x++)
181 ast_string_field_set(xferchan, name, chan->name);
182 /* Make formats okay */
183 xferchan->readformat = chan->readformat;
184 xferchan->writeformat = chan->writeformat;
185 ast_channel_masquerade(xferchan, chan);
186 ast_parseable_goto(xferchan, goto_on_transfer);
187 xferchan->_state = AST_STATE_UP;
188 ast_clear_flag(xferchan, AST_FLAGS_ALL);
189 xferchan->_softhangup = 0;
190 if ((f = ast_read(xferchan))) {
193 ast_pbx_start(xferchan);
195 ast_hangup(xferchan);
200 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);
203 static void *ast_bridge_call_thread(void *data)
205 struct ast_bridge_thread_obj *tobj = data;
207 tobj->chan->appl = "Transferred Call";
208 tobj->chan->data = tobj->peer->name;
209 tobj->peer->appl = "Transferred Call";
210 tobj->peer->data = tobj->chan->name;
211 if (tobj->chan->cdr) {
212 ast_cdr_reset(tobj->chan->cdr, NULL);
213 ast_cdr_setdestchan(tobj->chan->cdr, tobj->peer->name);
215 if (tobj->peer->cdr) {
216 ast_cdr_reset(tobj->peer->cdr, NULL);
217 ast_cdr_setdestchan(tobj->peer->cdr, tobj->chan->name);
220 ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
221 ast_hangup(tobj->chan);
222 ast_hangup(tobj->peer);
223 bzero(tobj, sizeof(*tobj)); /* XXX for safety */
228 static void ast_bridge_call_thread_launch(void *data)
232 struct sched_param sched;
234 pthread_attr_init(&attr);
235 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
236 ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data);
237 pthread_attr_destroy(&attr);
238 memset(&sched, 0, sizeof(sched));
239 pthread_setschedparam(thread, SCHED_RR, &sched);
244 static int adsi_announce_park(struct ast_channel *chan, int parkingnum)
247 int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
249 char *message[5] = {NULL, NULL, NULL, NULL, NULL};
251 snprintf(tmp, sizeof(tmp), "Parked on %d", parkingnum);
253 res = adsi_load_session(chan, NULL, 0, 1);
256 return adsi_print(chan, message, justify, 1);
259 /*! \brief Park a call
260 We put the user in the parking list, then wake up the parking thread to be sure it looks
261 after these channels too */
262 int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
264 struct parkeduser *pu, *cur;
265 int i,x,parking_range;
266 char exten[AST_MAX_EXTENSION];
267 struct ast_context *con;
269 if (!(pu = ast_calloc(1, sizeof(*pu)))) {
272 ast_mutex_lock(&parking_lock);
273 parking_range = parking_stop - parking_start+1;
274 for (i = 0; i < parking_range; i++) {
275 x = (i + parking_offset) % parking_range + parking_start;
278 if (cur->parkingnum == x)
286 if (!(i < parking_range)) {
287 ast_log(LOG_WARNING, "No more parking spaces\n");
289 ast_mutex_unlock(&parking_lock);
293 parking_offset = x - parking_start + 1;
294 chan->appl = "Parked Call";
298 /* Start music on hold */
300 ast_indicate(pu->chan, AST_CONTROL_HOLD);
301 ast_moh_start(pu->chan, NULL);
303 pu->start = ast_tvnow();
305 pu->parkingtime = (timeout > 0) ? timeout : parkingtime;
309 ast_copy_string(pu->peername, peer->name, sizeof(pu->peername));
311 /* Remember what had been dialed, so that if the parking
312 expires, we try to come back to the same place */
313 ast_copy_string(pu->context, S_OR(chan->macrocontext, chan->context), sizeof(pu->context));
314 ast_copy_string(pu->exten, S_OR(chan->macroexten, chan->exten), sizeof(pu->exten));
315 pu->priority = chan->macropriority ? chan->macropriority : chan->priority;
316 pu->next = parkinglot;
318 /* If parking a channel directly, don't quiet yet get parking running on it */
321 ast_mutex_unlock(&parking_lock);
322 /* Wake up the (presumably select()ing) thread */
323 pthread_kill(parking_thread, SIGURG);
324 if (option_verbose > 1)
325 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));
327 manager_event(EVENT_FLAG_CALL, "ParkedCall",
333 "CallerIDName: %s\r\n"
334 ,pu->parkingnum, pu->chan->name, peer ? peer->name : ""
335 ,(long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL)
336 ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
337 ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
341 if (adsipark && adsi_available(peer))
342 adsi_announce_park(peer, pu->parkingnum);
343 if (adsipark && adsi_available(peer))
344 adsi_unload_session(peer);
346 con = ast_context_find(parking_con);
348 con = ast_context_create(NULL, parking_con, registrar);
350 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
353 snprintf(exten, sizeof(exten), "%d", x);
354 ast_add_extension2(con, 1, exten, 1, NULL, NULL, parkedcall, strdup(exten), FREE, registrar);
357 ast_say_digits(peer, pu->parkingnum, "", peer->language);
358 if (pu->notquiteyet) {
359 /* Wake up parking thread if we're really done */
360 ast_moh_start(pu->chan, NULL);
362 pthread_kill(parking_thread, SIGURG);
367 int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
369 struct ast_channel *chan;
372 /* Make a new, fake channel that we'll use to masquerade in the real one */
373 if ((chan = ast_channel_alloc(0))) {
374 /* Let us keep track of the channel name */
375 ast_string_field_build(chan, name, "Parked/%s",rchan->name);
377 /* Make formats okay */
378 chan->readformat = rchan->readformat;
379 chan->writeformat = rchan->writeformat;
380 ast_channel_masquerade(chan, rchan);
382 /* Setup the extensions and such */
383 set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority);
385 /* Make the masq execute */
389 ast_park_call(chan, peer, timeout, extout);
391 ast_log(LOG_WARNING, "Unable to create parked channel\n");
398 #define FEATURE_RETURN_HANGUP -1
399 #define FEATURE_RETURN_SUCCESSBREAK 0
400 #define FEATURE_RETURN_PBX_KEEPALIVE AST_PBX_KEEPALIVE
401 #define FEATURE_RETURN_NO_HANGUP_PEER AST_PBX_NO_HANGUP_PEER
402 #define FEATURE_RETURN_PASSDIGITS 21
403 #define FEATURE_RETURN_STOREDIGITS 22
404 #define FEATURE_RETURN_SUCCESS 23
406 #define FEATURE_SENSE_CHAN (1 << 0)
407 #define FEATURE_SENSE_PEER (1 << 1)
410 static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
412 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
415 struct ast_channel *caller_chan = NULL, *callee_chan = NULL;
427 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
431 if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) {
433 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
436 if (!ast_strlen_zero(courtesytone)) {
437 if (ast_autoservice_start(callee_chan))
439 if (!ast_streamfile(caller_chan, courtesytone, caller_chan->language)) {
440 if (ast_waitstream(caller_chan, "") < 0) {
441 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
442 ast_autoservice_stop(callee_chan);
446 if (ast_autoservice_stop(callee_chan))
450 if (callee_chan->monitor) {
451 if (option_verbose > 3)
452 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to stop recording call.\n", code);
453 ast_monitor_stop(callee_chan, 1);
454 return FEATURE_RETURN_SUCCESS;
457 if (caller_chan && callee_chan) {
458 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT");
459 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
462 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
465 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
468 len = strlen(touch_monitor) + 50;
470 touch_filename = alloca(len);
471 snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor);
472 snprintf(args, len, "%s|%s|m", (touch_format) ? touch_format : "wav", touch_filename);
474 caller_chan_id = ast_strdupa(caller_chan->cid.cid_num ? caller_chan->cid.cid_num : caller_chan->name);
475 callee_chan_id = ast_strdupa(callee_chan->cid.cid_num ? callee_chan->cid.cid_num : callee_chan->name);
476 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
478 touch_filename = alloca(len);
479 snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id);
480 snprintf(args, len, "%s|%s|m", (touch_format) ? touch_format : "wav", touch_filename);
483 for( x = 0; x < strlen(args); x++) {
488 if (option_verbose > 3)
489 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call. filename: %s\n", code, args);
491 pbx_exec(callee_chan, monitor_app, args);
492 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
493 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
495 return FEATURE_RETURN_SUCCESS;
498 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");
502 static int builtin_disconnect(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
504 if (option_verbose > 3)
505 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code);
506 return FEATURE_RETURN_HANGUP;
509 static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
511 struct ast_channel *transferer;
512 struct ast_channel *transferee;
513 const char *transferer_real_context;
517 if (sense == FEATURE_SENSE_PEER) {
524 if (!(transferer_real_context = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT")) &&
525 !(transferer_real_context = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"))) {
526 /* Use the non-macro context to transfer the call */
527 if (!ast_strlen_zero(transferer->macrocontext))
528 transferer_real_context = transferer->macrocontext;
530 transferer_real_context = transferer->context;
532 /* Start autoservice on chan while we talk
534 ast_indicate(transferee, AST_CONTROL_HOLD);
535 ast_autoservice_start(transferee);
536 ast_moh_start(transferee, NULL);
538 memset(newext, 0, sizeof(newext));
541 if ((res=ast_streamfile(transferer, "pbx-transfer", transferer->language))) {
542 ast_moh_stop(transferee);
543 ast_autoservice_stop(transferee);
544 ast_indicate(transferee, AST_CONTROL_UNHOLD);
547 if ((res=ast_waitstream(transferer, AST_DIGIT_ANY)) < 0) {
548 ast_moh_stop(transferee);
549 ast_autoservice_stop(transferee);
550 ast_indicate(transferee, AST_CONTROL_UNHOLD);
552 } else if (res > 0) {
553 /* If they've typed a digit already, handle it */
554 newext[0] = (char) res;
557 ast_stopstream(transferer);
558 res = ast_app_dtget(transferer, transferer_real_context, newext, sizeof(newext), 100, transferdigittimeout);
560 ast_moh_stop(transferee);
561 ast_autoservice_stop(transferee);
562 ast_indicate(transferee, AST_CONTROL_UNHOLD);
565 if (!strcmp(newext, ast_parking_ext())) {
566 ast_moh_stop(transferee);
568 res = ast_autoservice_stop(transferee);
569 ast_indicate(transferee, AST_CONTROL_UNHOLD);
572 else if (!ast_park_call(transferee, transferer, 0, NULL)) {
573 /* We return non-zero, but tell the PBX not to hang the channel when
574 the thread dies -- We have to be careful now though. We are responsible for
575 hanging up the channel, else it will never be hung up! */
577 return (transferer == peer) ? AST_PBX_KEEPALIVE : AST_PBX_NO_HANGUP_PEER;
579 ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name);
581 /* XXX Maybe we should have another message here instead of invalid extension XXX */
582 } else if (ast_exists_extension(transferee, transferer_real_context, newext, 1, transferer->cid.cid_num)) {
583 pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", chan->name);
584 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", peer->name);
585 ast_moh_stop(transferee);
586 res=ast_autoservice_stop(transferee);
587 ast_indicate(transferee, AST_CONTROL_UNHOLD);
588 if (!transferee->pbx) {
589 /* Doh! Use our handy async_goto functions */
590 if (option_verbose > 2)
591 ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n"
592 ,transferee->name, newext, transferer_real_context);
593 if (ast_async_goto(transferee, transferer_real_context, newext, 1))
594 ast_log(LOG_WARNING, "Async goto failed :-(\n");
597 /* Set the channel's new extension, since it exists, using transferer context */
598 set_c_e_p(transferee, transferer_real_context, newext, 0);
600 check_goto_on_transfer(transferer);
603 if (option_verbose > 2)
604 ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", newext, transferer_real_context);
606 if (!ast_strlen_zero(xferfailsound))
607 res = ast_streamfile(transferer, xferfailsound, transferee->language);
611 ast_moh_stop(transferee);
612 ast_autoservice_stop(transferee);
613 ast_indicate(transferee, AST_CONTROL_UNHOLD);
616 res = ast_waitstream(transferer, AST_DIGIT_ANY);
617 ast_stopstream(transferer);
618 ast_moh_stop(transferee);
619 res = ast_autoservice_stop(transferee);
620 ast_indicate(transferee, AST_CONTROL_UNHOLD);
622 if (option_verbose > 1)
623 ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name);
626 return FEATURE_RETURN_SUCCESS;
629 static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
631 struct ast_channel *transferer;
632 struct ast_channel *transferee;
633 struct ast_channel *newchan, *xferchan=NULL;
635 struct ast_bridge_config bconfig;
636 const char *transferer_real_context;
637 char xferto[256],dialstr[265];
641 struct ast_frame *f = NULL;
642 struct ast_bridge_thread_obj *tobj;
644 ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) XXX\n", chan->name, peer->name, sense);
645 if (sense == FEATURE_SENSE_PEER) {
652 if (!(transferer_real_context=pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT")) &&
653 !(transferer_real_context=pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"))) {
654 /* Use the non-macro context to transfer the call */
655 if (!ast_strlen_zero(transferer->macrocontext))
656 transferer_real_context = transferer->macrocontext;
658 transferer_real_context = transferer->context;
660 /* Start autoservice on chan while we talk
662 ast_indicate(transferee, AST_CONTROL_HOLD);
663 ast_autoservice_start(transferee);
664 ast_moh_start(transferee, NULL);
665 memset(xferto, 0, sizeof(xferto));
667 if ((res = ast_streamfile(transferer, "pbx-transfer", transferer->language))) {
668 ast_moh_stop(transferee);
669 ast_autoservice_stop(transferee);
670 ast_indicate(transferee, AST_CONTROL_UNHOLD);
673 if ((res=ast_waitstream(transferer, AST_DIGIT_ANY)) < 0) {
674 ast_moh_stop(transferee);
675 ast_autoservice_stop(transferee);
676 ast_indicate(transferee, AST_CONTROL_UNHOLD);
679 /* If they've typed a digit already, handle it */
680 xferto[0] = (char) res;
682 if ((ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout))) {
683 cid_num = transferer->cid.cid_num;
684 cid_name = transferer->cid.cid_name;
685 if (ast_exists_extension(transferer, transferer_real_context,xferto, 1, cid_num)) {
686 snprintf(dialstr, sizeof(dialstr), "%s@%s/n", xferto, transferer_real_context);
687 newchan = ast_feature_request_and_dial(transferer, "Local", ast_best_codec(transferer->nativeformats), dialstr, 15000, &outstate, cid_num, cid_name);
688 ast_indicate(transferer, -1);
690 res = ast_channel_make_compatible(transferer, newchan);
692 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", transferer->name, newchan->name);
696 memset(&bconfig,0,sizeof(struct ast_bridge_config));
697 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
698 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
699 res = ast_bridge_call(transferer,newchan,&bconfig);
700 if (newchan->_softhangup || newchan->_state != AST_STATE_UP || !transferer->_softhangup) {
706 if (!ast_strlen_zero(xfersound) && !ast_streamfile(transferer, xfersound, transferer->language)) {
707 if (ast_waitstream(transferer, "") < 0) {
708 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
711 ast_moh_stop(transferee);
712 ast_autoservice_stop(transferee);
713 ast_indicate(transferee, AST_CONTROL_UNHOLD);
714 transferer->_softhangup = 0;
715 return FEATURE_RETURN_SUCCESS;
718 res = ast_channel_make_compatible(transferee, newchan);
720 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", transferee->name, newchan->name);
726 ast_moh_stop(transferee);
728 if ((ast_autoservice_stop(transferee) < 0)
729 || (ast_waitfordigit(transferee, 100) < 0)
730 || (ast_waitfordigit(newchan, 100) < 0)
731 || ast_check_hangup(transferee)
732 || ast_check_hangup(newchan)) {
738 if ((xferchan = ast_channel_alloc(0))) {
739 ast_string_field_build(xferchan, name, "Transfered/%s", transferee->name);
740 /* Make formats okay */
741 xferchan->readformat = transferee->readformat;
742 xferchan->writeformat = transferee->writeformat;
743 ast_channel_masquerade(xferchan, transferee);
744 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
745 xferchan->_state = AST_STATE_UP;
746 ast_clear_flag(xferchan, AST_FLAGS_ALL);
747 xferchan->_softhangup = 0;
749 if ((f = ast_read(xferchan))) {
759 newchan->_state = AST_STATE_UP;
760 ast_clear_flag(newchan, AST_FLAGS_ALL);
761 newchan->_softhangup = 0;
763 if ((tobj = ast_calloc(1, sizeof(*tobj)))) {
764 tobj->chan = xferchan;
765 tobj->peer = newchan;
766 tobj->bconfig = *config;
768 if (!ast_strlen_zero(xfersound) && !ast_streamfile(newchan, xfersound, newchan->language) &&
769 ast_waitstream(newchan, "") < 0) {
770 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
772 ast_bridge_call_thread_launch(tobj);
774 ast_hangup(xferchan);
780 ast_moh_stop(transferee);
781 ast_autoservice_stop(transferee);
782 ast_indicate(transferee, AST_CONTROL_UNHOLD);
783 /* any reason besides user requested cancel and busy triggers the failed sound */
784 if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY && !ast_strlen_zero(xferfailsound)) {
785 res = ast_streamfile(transferer, xferfailsound, transferer->language);
786 if (!res && (ast_waitstream(transferer, "") < 0)) {
790 return FEATURE_RETURN_SUCCESS;
793 ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context);
794 ast_moh_stop(transferee);
795 ast_autoservice_stop(transferee);
796 ast_indicate(transferee, AST_CONTROL_UNHOLD);
797 res = ast_streamfile(transferer, "beeperr", transferer->language);
798 if (!res && (ast_waitstream(transferer, "") < 0)) {
803 ast_log(LOG_WARNING, "Did not read data.\n");
804 res = ast_streamfile(transferer, "beeperr", transferer->language);
805 if (ast_waitstream(transferer, "") < 0) {
809 ast_moh_stop(transferee);
810 ast_autoservice_stop(transferee);
811 ast_indicate(transferee, AST_CONTROL_UNHOLD);
813 return FEATURE_RETURN_SUCCESS;
817 /* add atxfer and automon as undefined so you can only use em if you configure them */
818 #define FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0]))
820 struct ast_call_feature builtin_features[] =
822 { AST_FEATURE_REDIRECT, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer, AST_FEATURE_FLAG_NEEDSDTMF },
823 { AST_FEATURE_REDIRECT, "Attended Transfer", "atxfer", "", "", builtin_atxfer, AST_FEATURE_FLAG_NEEDSDTMF },
824 { AST_FEATURE_AUTOMON, "One Touch Monitor", "automon", "", "", builtin_automonitor, AST_FEATURE_FLAG_NEEDSDTMF },
825 { AST_FEATURE_DISCONNECT, "Disconnect Call", "disconnect", "*", "*", builtin_disconnect, AST_FEATURE_FLAG_NEEDSDTMF },
829 static AST_LIST_HEAD(feature_list,ast_call_feature) feature_list;
831 /*! \brief register new feature into feature_list*/
832 void ast_register_feature(struct ast_call_feature *feature)
835 ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
839 AST_LIST_LOCK(&feature_list);
840 AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry);
841 AST_LIST_UNLOCK(&feature_list);
843 if (option_verbose >= 2)
844 ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
847 /*! \brief unregister feature from feature_list */
848 void ast_unregister_feature(struct ast_call_feature *feature)
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 = ast_test_flag(feature,AST_FEATURE_FLAG_CALLEE) ? peer : chan;
906 res = pbx_exec(work, app, feature->app_args);
910 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
914 return FEATURE_RETURN_SUCCESS; /* XXX should probably return res */
917 static void unmap_features(void)
920 for (x = 0; x < FEATURES_COUNT; x++)
921 strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
924 static int remap_feature(const char *name, const char *value)
928 for (x = 0; x < FEATURES_COUNT; x++) {
929 if (!strcasecmp(name, builtin_features[x].sname)) {
930 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
931 if (option_verbose > 1)
932 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);
934 } else if (!strcmp(value, builtin_features[x].exten))
935 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);
940 static int ast_feature_interpret(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
943 struct ast_flags features;
944 int res = FEATURE_RETURN_PASSDIGITS;
945 struct ast_call_feature *feature;
946 const char *dynamic_features=pbx_builtin_getvar_helper(chan,"DYNAMIC_FEATURES");
948 if (sense == FEATURE_SENSE_CHAN)
949 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
951 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);
952 ast_log(LOG_DEBUG, "Feature interpret: chan=%s, peer=%s, sense=%d, features=%d\n", chan->name, peer->name, sense, features.flags);
954 for (x=0; x < FEATURES_COUNT; x++) {
955 if ((ast_test_flag(&features, builtin_features[x].feature_mask)) &&
956 !ast_strlen_zero(builtin_features[x].exten)) {
957 /* Feature is up for consideration */
958 if (!strcmp(builtin_features[x].exten, code)) {
959 res = builtin_features[x].operation(chan, peer, config, code, sense);
961 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
962 if (res == FEATURE_RETURN_PASSDIGITS)
963 res = FEATURE_RETURN_STOREDIGITS;
969 if (!ast_strlen_zero(dynamic_features)) {
970 char *tmp = ast_strdupa(dynamic_features);
976 while ((tok = strsep(&tmp, "#")) != NULL) {
977 feature = find_feature(tok);
980 /* Feature is up for consideration */
981 if (!strcmp(feature->exten, code)) {
982 if (option_verbose > 2)
983 ast_verbose(VERBOSE_PREFIX_3 " Feature Found: %s exten: %s\n",feature->sname, tok);
984 res = feature->operation(chan, peer, config, code, sense);
986 } else if (!strncmp(feature->exten, code, strlen(code))) {
987 res = FEATURE_RETURN_STOREDIGITS;
996 static void set_config_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
1000 ast_clear_flag(config, AST_FLAGS_ALL);
1001 for (x = 0; x < FEATURES_COUNT; x++) {
1002 if (ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF)) {
1003 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
1004 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
1006 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
1007 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
1011 if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
1012 const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
1014 if (dynamic_features) {
1015 char *tmp = ast_strdupa(dynamic_features);
1017 struct ast_call_feature *feature;
1019 if (!tmp) /* no memory */
1022 /* while we have a feature */
1023 while (NULL != (tok = strsep(&tmp, "#"))) {
1024 if ((feature = find_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
1025 if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLER))
1026 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
1027 if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLEE))
1028 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
1035 /* XXX this is very similar to the code in channel.c */
1036 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)
1041 struct ast_channel *chan;
1042 struct ast_channel *monitor_chans[2];
1043 struct ast_channel *active_channel;
1044 struct ast_frame *f = NULL;
1045 int res = 0, ready = 0;
1047 if ((chan = ast_request(type, format, data, &cause))) {
1048 ast_set_callerid(chan, cid_num, cid_name, cid_num);
1049 ast_channel_inherit_variables(caller, chan);
1050 if (!ast_call(chan, data, timeout)) {
1051 struct timeval started;
1053 char *disconnect_code = NULL, *dialed_code = NULL;
1055 ast_indicate(caller, AST_CONTROL_RINGING);
1056 /* support dialing of the featuremap disconnect code while performing an attended tranfer */
1057 for (x=0; x < FEATURES_COUNT; x++) {
1058 if (strcasecmp(builtin_features[x].sname, "disconnect"))
1061 disconnect_code = builtin_features[x].exten;
1062 len = strlen(disconnect_code) + 1;
1063 dialed_code = alloca(len);
1064 memset(dialed_code, 0, len);
1068 started = ast_tvnow();
1070 while (!ast_check_hangup(caller) && timeout && (chan->_state != AST_STATE_UP)) {
1071 monitor_chans[0] = caller;
1072 monitor_chans[1] = chan;
1073 active_channel = ast_waitfor_n(monitor_chans, 2, &to);
1075 /* see if the timeout has been violated */
1076 if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
1077 state = AST_CONTROL_UNHOLD;
1078 ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n");
1079 break; /*doh! timeout*/
1082 if (!active_channel) {
1086 if (chan && (chan == active_channel)){
1088 if (f == NULL) { /*doh! where'd he go?*/
1089 state = AST_CONTROL_HANGUP;
1094 if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) {
1095 if (f->subclass == AST_CONTROL_RINGING) {
1096 state = f->subclass;
1097 if (option_verbose > 2)
1098 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", chan->name);
1099 ast_indicate(caller, AST_CONTROL_RINGING);
1100 } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) {
1101 state = f->subclass;
1102 if (option_verbose > 2)
1103 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", chan->name);
1104 ast_indicate(caller, AST_CONTROL_BUSY);
1108 } else if (f->subclass == AST_CONTROL_ANSWER) {
1109 /* This is what we are hoping for */
1110 state = f->subclass;
1116 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass);
1118 /* else who cares */
1121 } else if (caller && (active_channel == caller)) {
1122 f = ast_read(caller);
1123 if (f == NULL) { /*doh! where'd he go?*/
1124 if (caller->_softhangup && !chan->_softhangup) {
1125 /* make this a blind transfer */
1129 state = AST_CONTROL_HANGUP;
1134 if (f->frametype == AST_FRAME_DTMF) {
1135 dialed_code[x++] = f->subclass;
1136 dialed_code[x] = '\0';
1137 if (strlen(dialed_code) == len) {
1139 } else if (x && strncmp(dialed_code, disconnect_code, x)) {
1141 dialed_code[x] = '\0';
1143 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
1144 /* Caller Canceled the call */
1145 state = AST_CONTROL_UNHOLD;
1157 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
1159 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
1161 case AST_CAUSE_BUSY:
1162 state = AST_CONTROL_BUSY;
1164 case AST_CAUSE_CONGESTION:
1165 state = AST_CONTROL_CONGESTION;
1170 ast_indicate(caller, -1);
1171 if (chan && ready) {
1172 if (chan->_state == AST_STATE_UP)
1173 state = AST_CONTROL_ANSWER;
1186 if (chan && res <= 0) {
1187 if (chan->cdr || (chan->cdr = ast_cdr_alloc())) {
1189 ast_cdr_init(chan->cdr, chan);
1190 snprintf(tmp, 256, "%s/%s", type, (char *)data);
1191 ast_cdr_setapp(chan->cdr,"Dial",tmp);
1192 ast_cdr_update(chan);
1193 ast_cdr_start(chan->cdr);
1194 ast_cdr_end(chan->cdr);
1195 /* If the cause wasn't handled properly */
1196 if (ast_cdr_disposition(chan->cdr,chan->hangupcause))
1197 ast_cdr_failed(chan->cdr);
1199 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
1206 int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast_bridge_config *config)
1208 /* Copy voice back and forth between the two channels. Give the peer
1209 the ability to transfer calls with '#<extension' syntax. */
1210 struct ast_frame *f;
1211 struct ast_channel *who;
1212 char chan_featurecode[FEATURE_MAX_LEN + 1]="";
1213 char peer_featurecode[FEATURE_MAX_LEN + 1]="";
1218 struct ast_option_header *aoh;
1219 struct timeval start = { 0 , 0 };
1220 struct ast_bridge_config backup_config;
1222 memset(&backup_config, 0, sizeof(backup_config));
1224 config->start_time = ast_tvnow();
1227 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
1228 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
1230 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
1233 const char *monitor_exec;
1234 struct ast_channel *src = NULL;
1236 if (!(monitor_app = pbx_findapp("Monitor")))
1239 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR")))
1241 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
1243 if (monitor_app && src) {
1244 char *tmp = ast_strdupa(monitor_exec);
1246 pbx_exec(src, monitor_app, tmp);
1248 ast_log(LOG_ERROR, "Monitor failed: out of memory\n");
1253 set_config_flags(chan, peer, config);
1254 config->firstpass = 1;
1256 /* Answer if need be */
1257 if (ast_answer(chan))
1259 peer->appl = "Bridged Call";
1260 peer->data = (char *) chan->name;
1262 /* copy the userfield from the B-leg to A-leg if applicable */
1263 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
1265 if (!ast_strlen_zero(chan->cdr->userfield)) {
1266 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield);
1267 ast_cdr_appenduserfield(chan, tmp);
1269 ast_cdr_setuserfield(chan, peer->cdr->userfield);
1270 /* free the peer's cdr without ast_cdr_free complaining */
1275 struct ast_channel *other; /* used later */
1276 if (config->feature_timer)
1277 start = ast_tvnow();
1279 res = ast_channel_bridge(chan, peer, config, &f, &who);
1281 if (config->feature_timer) {
1282 /* Update time limit for next pass */
1283 diff = ast_tvdiff_ms(ast_tvnow(), start);
1284 config->feature_timer -= diff;
1286 /* Running on backup config, meaning a feature might be being
1287 activated, but that's no excuse to keep things going
1289 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
1290 ast_log(LOG_DEBUG, "Timed out, realtime this time!\n");
1291 config->feature_timer = 0;
1297 } else if (config->feature_timer <= 0) {
1298 /* Not *really* out of time, just out of time for
1299 digits to come in for features. */
1300 ast_log(LOG_DEBUG, "Timed out for feature!\n");
1301 if (!ast_strlen_zero(peer_featurecode)) {
1302 ast_dtmf_stream(chan, peer, peer_featurecode, 0);
1303 memset(peer_featurecode, 0, sizeof(peer_featurecode));
1305 if (!ast_strlen_zero(chan_featurecode)) {
1306 ast_dtmf_stream(peer, chan, chan_featurecode, 0);
1307 memset(chan_featurecode, 0, sizeof(chan_featurecode));
1311 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
1313 /* Restore original (possibly time modified) bridge config */
1314 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
1315 memset(&backup_config, 0, sizeof(backup_config));
1317 hadfeatures = hasfeatures;
1318 /* Continue as we were */
1322 if (config->feature_timer <=0) {
1323 /* We ran out of time */
1324 config->feature_timer = 0;
1334 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
1338 if (!f || (f->frametype == AST_FRAME_CONTROL &&
1339 (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY ||
1340 f->subclass == AST_CONTROL_CONGESTION ) ) ) {
1344 /* many things should be sent to the 'other' channel */
1345 other = (who == chan) ? peer : chan;
1346 if (f->frametype == AST_FRAME_CONTROL) {
1347 if (f->subclass == AST_CONTROL_RINGING)
1348 ast_indicate(other, AST_CONTROL_RINGING);
1349 else if (f->subclass == -1)
1350 ast_indicate(other, -1);
1351 else if (f->subclass == AST_CONTROL_FLASH)
1352 ast_indicate(other, AST_CONTROL_FLASH);
1353 else if (f->subclass == AST_CONTROL_OPTION) {
1355 /* Forward option Requests */
1356 if (aoh && (aoh->flag == AST_OPTION_FLAG_REQUEST))
1357 ast_channel_setoption(other, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
1360 /* check for '*', if we find it it's time to disconnect */
1361 if (f && f->frametype == AST_FRAME_DTMF) {
1365 hadfeatures = hasfeatures;
1366 /* This cannot overrun because the longest feature is one shorter than our buffer */
1368 sense = FEATURE_SENSE_CHAN;
1369 featurecode = chan_featurecode;
1371 sense = FEATURE_SENSE_PEER;
1372 featurecode = peer_featurecode;
1374 /* append the event to featurecode. we rely on the string being zero-filled, and
1375 * not overflowing it. XXX how do we guarantee the latter ?
1377 featurecode[strlen(featurecode)] = f->subclass;
1378 config->feature_timer = backup_config.feature_timer;
1379 res = ast_feature_interpret(chan, peer, config, featurecode, sense);
1381 case FEATURE_RETURN_PASSDIGITS:
1382 ast_dtmf_stream(other, who, featurecode, 0);
1384 case FEATURE_RETURN_SUCCESS:
1385 memset(featurecode, 0, sizeof(chan_featurecode));
1388 if (res >= FEATURE_RETURN_PASSDIGITS) {
1394 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
1395 if (hadfeatures && !hasfeatures) {
1396 /* Restore backup */
1397 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
1398 memset(&backup_config, 0, sizeof(struct ast_bridge_config));
1399 } else if (hasfeatures) {
1401 /* Backup configuration */
1402 memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
1403 /* Setup temporary config options */
1404 config->play_warning = 0;
1405 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
1406 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
1407 config->warning_freq = 0;
1408 config->warning_sound = NULL;
1409 config->end_sound = NULL;
1410 config->start_sound = NULL;
1411 config->firstpass = 0;
1413 config->feature_timer = featuredigittimeout;
1414 ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer);
1423 /*! \brief Take care of parked calls and unpark them if needed */
1424 static void *do_parking_thread(void *ignore)
1431 struct parkeduser *pu, *pl, *pt = NULL;
1432 int ms = -1; /* select timeout, uninitialized */
1433 int max = -1; /* max fd, none there yet */
1434 fd_set nrfds, nefds;
1437 char exten[AST_MAX_EXTENSION];
1443 ast_mutex_lock(&parking_lock);
1447 int tms; /* timeout for this item */
1448 int x; /* fd index in channel */
1449 struct ast_context *con;
1451 if (pu->notquiteyet) {
1452 /* Pretend this one isn't here yet */
1457 tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
1458 if (tms > pu->parkingtime) {
1459 /* Stop music on hold */
1460 ast_moh_stop(pu->chan);
1461 ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
1462 /* Get chan, exten from derived kludge */
1463 if (pu->peername[0]) {
1464 peername = ast_strdupa(pu->peername);
1465 cp = strrchr(peername, '-');
1468 con = ast_context_find(parking_con_dial);
1470 con = ast_context_create(NULL, parking_con_dial, registrar);
1472 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
1476 char returnexten[AST_MAX_EXTENSION];
1477 snprintf(returnexten, sizeof(returnexten), "%s||t", peername);
1478 ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), FREE, registrar);
1480 ast_copy_string(pu->chan->exten, peername, sizeof(pu->chan->exten));
1481 ast_copy_string(pu->chan->context, parking_con_dial, sizeof(pu->chan->context));
1482 pu->chan->priority = 1;
1485 /* They've been waiting too long, send them back to where they came. Theoretically they
1486 should have their original extensions and such, but we copy to be on the safe side */
1487 ast_copy_string(pu->chan->exten, pu->exten, sizeof(pu->chan->exten));
1488 ast_copy_string(pu->chan->context, pu->context, sizeof(pu->chan->context));
1489 pu->chan->priority = pu->priority;
1492 manager_event(EVENT_FLAG_CALL, "ParkedCallTimeOut",
1496 "CallerIDName: %s\r\n"
1497 ,pu->parkingnum, pu->chan->name
1498 ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
1499 ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
1502 if (option_verbose > 1)
1503 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);
1504 /* Start up the PBX, or hang them up */
1505 if (ast_pbx_start(pu->chan)) {
1506 ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name);
1507 ast_hangup(pu->chan);
1509 /* And take them out of the parking lot */
1511 pl->next = pu->next;
1513 parkinglot = pu->next;
1516 con = ast_context_find(parking_con);
1518 snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
1519 if (ast_context_remove_extension2(con, exten, 1, NULL))
1520 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1522 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1525 for (x = 0; x < AST_MAX_FDS; x++) {
1526 struct ast_frame *f;
1528 if (pu->chan->fds[x] < 0 || (!FD_ISSET(pu->chan->fds[x], &rfds) && !FD_ISSET(pu->chan->fds[x], &efds)))
1531 /* XXX reindent next block */
1532 if (FD_ISSET(pu->chan->fds[x], &efds))
1533 ast_set_flag(pu->chan, AST_FLAG_EXCEPTION);
1535 ast_clear_flag(pu->chan, AST_FLAG_EXCEPTION);
1537 /* See if they need servicing */
1538 f = ast_read(pu->chan);
1539 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
1542 manager_event(EVENT_FLAG_CALL, "ParkedCallGiveUp",
1546 "CallerIDName: %s\r\n"
1547 ,pu->parkingnum, pu->chan->name
1548 ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
1549 ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
1552 /* There's a problem, hang them up*/
1553 if (option_verbose > 1)
1554 ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", pu->chan->name);
1555 ast_hangup(pu->chan);
1556 /* And take them out of the parking lot */
1558 pl->next = pu->next;
1560 parkinglot = pu->next;
1563 con = ast_context_find(parking_con);
1565 snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
1566 if (ast_context_remove_extension2(con, exten, 1, NULL))
1567 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1569 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1573 /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
1575 if (pu->moh_trys < 3 && !pu->chan->generatordata) {
1576 ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source. Restarting.\n");
1577 ast_moh_start(pu->chan, NULL);
1580 goto std; /* XXX Ick: jumping into an else statement??? XXX */
1584 if (x >= AST_MAX_FDS) {
1585 std: for (x=0; x<AST_MAX_FDS; x++) {
1586 /* Keep this one for next one */
1587 if (pu->chan->fds[x] > -1) {
1588 FD_SET(pu->chan->fds[x], &nrfds);
1589 FD_SET(pu->chan->fds[x], &nefds);
1590 if (pu->chan->fds[x] > max)
1591 max = pu->chan->fds[x];
1594 /* Keep track of our longest wait */
1595 if ((tms < ms) || (ms < 0))
1602 ast_mutex_unlock(&parking_lock);
1605 tv = ast_samp2tv(ms, 1000);
1606 /* Wait for something to happen */
1607 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
1608 pthread_testcancel();
1610 return NULL; /* Never reached */
1613 static int park_call_exec(struct ast_channel *chan, void *data)
1615 /* Data is unused at the moment but could contain a parking
1616 lot context eventually */
1618 struct localuser *u;
1620 /* Setup the exten/priority to be s/1 since we don't know
1621 where this call should return */
1622 strcpy(chan->exten, "s");
1624 if (chan->_state != AST_STATE_UP)
1625 res = ast_answer(chan);
1627 res = ast_safe_sleep(chan, 1000);
1629 res = ast_park_call(chan, chan, 0, NULL);
1630 LOCAL_USER_REMOVE(u);
1632 res = AST_PBX_KEEPALIVE;
1636 static int park_exec(struct ast_channel *chan, void *data)
1639 struct localuser *u;
1640 struct ast_channel *peer=NULL;
1641 struct parkeduser *pu, *pl=NULL;
1642 char exten[AST_MAX_EXTENSION];
1643 struct ast_context *con;
1646 struct ast_bridge_config config;
1649 ast_log(LOG_WARNING, "Park requires an argument (extension number)\n");
1653 park = atoi((char *)data);
1654 ast_mutex_lock(&parking_lock);
1657 if (pu->parkingnum == park) {
1659 pl->next = pu->next;
1661 parkinglot = pu->next;
1667 ast_mutex_unlock(&parking_lock);
1670 con = ast_context_find(parking_con);
1672 snprintf(exten, sizeof(exten), "%d", pu->parkingnum);
1673 if (ast_context_remove_extension2(con, exten, 1, NULL))
1674 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1676 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1678 manager_event(EVENT_FLAG_CALL, "UnParkedCall",
1683 "CallerIDName: %s\r\n"
1684 ,pu->parkingnum, pu->chan->name, chan->name
1685 ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
1686 ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
1691 /* JK02: it helps to answer the channel if not already up */
1692 if (chan->_state != AST_STATE_UP) {
1697 /* Play a courtesy to the source(s) configured to prefix the bridge connecting */
1699 if (!ast_strlen_zero(courtesytone)) {
1700 if (parkedplay == 0) {
1701 if (!ast_streamfile(chan, courtesytone, chan->language)) {
1702 if (ast_waitstream(chan, "") < 0) {
1703 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
1709 ast_indicate(peer, AST_CONTROL_UNHOLD);
1712 ast_indicate(peer, AST_CONTROL_UNHOLD);
1713 if (parkedplay == 2) {
1714 if (!ast_streamfile(chan, courtesytone, chan->language) && !ast_streamfile(peer, courtesytone, chan->language)) {
1715 res = ast_waitstream(chan, "");
1717 res = ast_waitstream(peer, "");
1719 ast_log(LOG_WARNING, "Failed to play courtesy tones!\n");
1724 } else if (parkedplay == 1) {
1725 if (!ast_streamfile(peer, courtesytone, chan->language)) {
1726 if (ast_waitstream(peer, "") < 0) {
1727 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
1736 res = ast_channel_make_compatible(chan, peer);
1738 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
1742 /* This runs sorta backwards, since we give the incoming channel control, as if it
1743 were the person called. */
1744 if (option_verbose > 2)
1745 ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
1747 memset(&config, 0, sizeof(struct ast_bridge_config));
1748 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
1749 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
1750 config.timelimit = 0;
1751 config.play_warning = 0;
1752 config.warning_freq = 0;
1753 config.warning_sound=NULL;
1754 res = ast_bridge_call(chan, peer, &config);
1756 /* Simulate the PBX hanging up */
1757 if (res != AST_PBX_NO_HANGUP_PEER)
1761 /* XXX Play a message XXX */
1762 dres = ast_streamfile(chan, "pbx-invalidpark", chan->language);
1764 dres = ast_waitstream(chan, "");
1766 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
1769 if (option_verbose > 2)
1770 ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
1773 LOCAL_USER_REMOVE(u);
1777 static int handle_showfeatures(int fd, int argc, char *argv[])
1781 struct ast_call_feature *feature;
1782 char format[] = "%-25s %-7s %-7s\n";
1784 ast_cli(fd, format, "Builtin Feature", "Default", "Current");
1785 ast_cli(fd, format, "---------------", "-------", "-------");
1787 ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */
1789 fcount = sizeof(builtin_features) / sizeof(builtin_features[0]);
1791 for (i = 0; i < fcount; i++)
1793 ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
1796 ast_cli(fd, format, "Dynamic Feature", "Default", "Current");
1797 ast_cli(fd, format, "---------------", "-------", "-------");
1798 if (AST_LIST_EMPTY(&feature_list)) {
1799 ast_cli(fd, "(none)\n");
1802 AST_LIST_LOCK(&feature_list);
1803 AST_LIST_TRAVERSE(&feature_list, feature, feature_entry) {
1804 ast_cli(fd, format, feature->sname, "no def", feature->exten);
1806 AST_LIST_UNLOCK(&feature_list);
1808 ast_cli(fd, "\nCall parking\n");
1809 ast_cli(fd, "------------\n");
1810 ast_cli(fd,"%-20s: %s\n", "Parking extension", parking_ext);
1811 ast_cli(fd,"%-20s: %s\n", "Parking context", parking_con);
1812 ast_cli(fd,"%-20s: %d-%d\n", "Parked call extensions", parking_start, parking_stop);
1815 return RESULT_SUCCESS;
1818 static char showfeatures_help[] =
1819 "Usage: show features\n"
1820 " Lists currently configured features.\n";
1822 static struct ast_cli_entry showfeatures =
1823 { { "show", "features", NULL }, handle_showfeatures, "Lists configured features", showfeatures_help };
1825 static int handle_parkedcalls(int fd, int argc, char *argv[])
1827 struct parkeduser *cur;
1830 ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
1831 , "Context", "Extension", "Pri", "Timeout");
1833 ast_mutex_lock(&parking_lock);
1835 for (cur = parkinglot; cur; cur = cur->next) {
1836 ast_cli(fd, "%4d %25s (%-15s %-12s %-4d) %6lds\n"
1837 ,cur->parkingnum, cur->chan->name, cur->context, cur->exten
1838 ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
1842 ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : "");
1844 ast_mutex_unlock(&parking_lock);
1846 return RESULT_SUCCESS;
1849 static char showparked_help[] =
1850 "Usage: show parkedcalls\n"
1851 " Lists currently parked calls.\n";
1853 static struct ast_cli_entry showparked =
1854 { { "show", "parkedcalls", NULL }, handle_parkedcalls, "Lists parked calls", showparked_help };
1856 /*! \brief Dump lot status */
1857 static int manager_parking_status( struct mansession *s, struct message *m )
1859 struct parkeduser *cur;
1860 char *id = astman_get_header(m,"ActionID");
1861 char idText[256] = "";
1863 if (!ast_strlen_zero(id))
1864 snprintf(idText,256,"ActionID: %s\r\n",id);
1866 astman_send_ack(s, m, "Parked calls will follow");
1868 ast_mutex_lock(&parking_lock);
1872 astman_append(s, "Event: ParkedCall\r\n"
1878 "CallerIDName: %s\r\n"
1881 ,cur->parkingnum, cur->chan->name, cur->peername
1882 ,(long)cur->start.tv_sec + (long)(cur->parkingtime/1000) - (long)time(NULL)
1883 ,(cur->chan->cid.cid_num ? cur->chan->cid.cid_num : "")
1884 ,(cur->chan->cid.cid_name ? cur->chan->cid.cid_name : "")
1891 "Event: ParkedCallsComplete\r\n"
1895 ast_mutex_unlock(&parking_lock);
1897 return RESULT_SUCCESS;
1900 static char mandescr_park[] =
1901 "Description: Park a channel.\n"
1902 "Variables: (Names marked with * are required)\n"
1903 " *Channel: Channel name to park\n"
1904 " *Channel2: Channel to announce park info to (and return to if timeout)\n"
1905 " Timeout: Number of milliseconds to wait before callback.\n";
1907 static int manager_park(struct mansession *s, struct message *m)
1909 char *channel = astman_get_header(m, "Channel");
1910 char *channel2 = astman_get_header(m, "Channel2");
1911 char *timeout = astman_get_header(m, "Timeout");
1916 struct ast_channel *ch1, *ch2;
1918 if (ast_strlen_zero(channel)) {
1919 astman_send_error(s, m, "Channel not specified");
1923 if (ast_strlen_zero(channel2)) {
1924 astman_send_error(s, m, "Channel2 not specified");
1928 ch1 = ast_get_channel_by_name_locked(channel);
1930 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
1931 astman_send_error(s, m, buf);
1935 ch2 = ast_get_channel_by_name_locked(channel2);
1937 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
1938 astman_send_error(s, m, buf);
1939 ast_mutex_unlock(&ch1->lock);
1943 if (!ast_strlen_zero(timeout)) {
1944 sscanf(timeout, "%d", &to);
1947 res = ast_masq_park_call(ch1, ch2, to, &parkExt);
1949 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
1950 astman_send_ack(s, m, "Park successful");
1952 astman_send_error(s, m, "Park failure");
1955 ast_mutex_unlock(&ch1->lock);
1956 ast_mutex_unlock(&ch2->lock);
1962 int ast_pickup_call(struct ast_channel *chan)
1964 struct ast_channel *cur = NULL;
1967 while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
1970 (chan->pickupgroup & cur->callgroup) &&
1971 ((cur->_state == AST_STATE_RINGING) ||
1972 (cur->_state == AST_STATE_RING))) {
1975 ast_mutex_unlock(&cur->lock);
1979 ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
1980 res = ast_answer(chan);
1982 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
1983 res = ast_queue_control(chan, AST_CONTROL_ANSWER);
1985 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
1986 res = ast_channel_masquerade(cur, chan);
1988 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */
1989 ast_mutex_unlock(&cur->lock);
1992 ast_log(LOG_DEBUG, "No call pickup possible...\n");
1997 static int load_config(void)
1999 int start = 0, end = 0;
2000 struct ast_context *con = NULL;
2001 struct ast_config *cfg = NULL;
2002 struct ast_variable *var = NULL;
2003 char old_parking_ext[AST_MAX_EXTENSION];
2004 char old_parking_con[AST_MAX_EXTENSION] = "";
2006 if (!ast_strlen_zero(parking_con)) {
2007 strcpy(old_parking_ext, parking_ext);
2008 strcpy(old_parking_con, parking_con);
2011 /* Reset to defaults */
2012 strcpy(parking_con, "parkedcalls");
2013 strcpy(parking_con_dial, "park-dial");
2014 strcpy(parking_ext, "700");
2015 strcpy(pickup_ext, "*8");
2016 courtesytone[0] = '\0';
2017 strcpy(xfersound, "beep");
2018 strcpy(xferfailsound, "pbx-invalid");
2019 parking_start = 701;
2024 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
2025 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
2027 cfg = ast_config_load("features.conf");
2029 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
2030 if (!strcasecmp(var->name, "parkext")) {
2031 ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
2032 } else if (!strcasecmp(var->name, "context")) {
2033 ast_copy_string(parking_con, var->value, sizeof(parking_con));
2034 } else if (!strcasecmp(var->name, "parkingtime")) {
2035 if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) {
2036 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
2037 parkingtime = DEFAULT_PARK_TIME;
2039 parkingtime = parkingtime * 1000;
2040 } else if (!strcasecmp(var->name, "parkpos")) {
2041 if (sscanf(var->value, "%d-%d", &start, &end) != 2) {
2042 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);
2044 parking_start = start;
2047 } else if (!strcasecmp(var->name, "findslot")) {
2048 parkfindnext = (!strcasecmp(var->value, "next"));
2049 } else if (!strcasecmp(var->name, "adsipark")) {
2050 adsipark = ast_true(var->value);
2051 } else if (!strcasecmp(var->name, "transferdigittimeout")) {
2052 if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
2053 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
2054 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
2056 transferdigittimeout = transferdigittimeout * 1000;
2057 } else if (!strcasecmp(var->name, "featuredigittimeout")) {
2058 if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
2059 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
2060 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
2062 } else if (!strcasecmp(var->name, "courtesytone")) {
2063 ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
2064 } else if (!strcasecmp(var->name, "parkedplay")) {
2065 if (!strcasecmp(var->value, "both"))
2067 else if (!strcasecmp(var->value, "parked"))
2071 } else if (!strcasecmp(var->name, "xfersound")) {
2072 ast_copy_string(xfersound, var->value, sizeof(xfersound));
2073 } else if (!strcasecmp(var->name, "xferfailsound")) {
2074 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
2075 } else if (!strcasecmp(var->name, "pickupexten")) {
2076 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
2081 for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) {
2082 if (remap_feature(var->name, var->value))
2083 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
2086 /* Map a key combination to an application*/
2087 ast_unregister_features();
2088 for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) {
2089 char *tmp_val = ast_strdup(var->value);
2090 char *exten, *party=NULL, *app=NULL, *app_args=NULL;
2093 /* XXX No memory. We should probably break, but at least we do not
2094 * insist on this entry or we could be stuck in an
2100 /* strsep() sets the argument to NULL if match not found, and it
2101 * is safe to use it with a NULL argument, so we don't check
2104 exten = strsep(&tmp_val,",");
2105 party = strsep(&tmp_val,",");
2106 app = strsep(&tmp_val,",");
2107 app_args = strsep(&tmp_val,",");
2109 /* XXX var_name or app_args ? */
2110 if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(party) || ast_strlen_zero(var->name)) {
2111 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);
2117 struct ast_call_feature *feature;
2120 if (!(feature = find_feature(var->name))) {
2123 if (!(feature = ast_calloc(1, sizeof(*feature)))) {
2129 ast_copy_string(feature->sname,var->name,FEATURE_SNAME_LEN);
2130 ast_copy_string(feature->app,app,FEATURE_APP_LEN);
2131 ast_copy_string(feature->exten, exten,FEATURE_EXTEN_LEN);
2135 ast_copy_string(feature->app_args,app_args,FEATURE_APP_ARGS_LEN);
2137 ast_copy_string(feature->exten, exten,sizeof(feature->exten));
2138 feature->operation=feature_exec_app;
2139 ast_set_flag(feature,AST_FEATURE_FLAG_NEEDSDTMF);
2141 if (!strcasecmp(party,"caller"))
2142 ast_set_flag(feature,AST_FEATURE_FLAG_CALLER);
2143 else if (!strcasecmp(party, "callee"))
2144 ast_set_flag(feature,AST_FEATURE_FLAG_CALLEE);
2146 ast_log(LOG_NOTICE, "Invalid party specification for feature '%s', must be caller, or callee\n", var->name);
2150 ast_register_feature(feature);
2152 if (option_verbose >=1)
2153 ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s' with code '%s'\n", var->name, app, exten);
2157 ast_config_destroy(cfg);
2159 /* Remove the old parking extension */
2160 if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) {
2161 ast_context_remove_extension2(con, old_parking_ext, 1, registrar);
2162 ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
2165 if (!(con = ast_context_find(parking_con)) && !(con = ast_context_create(NULL, parking_con, registrar))) {
2166 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
2169 return ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, strdup(""), FREE, registrar);
2172 static int reload(void *mod)
2174 return load_config();
2177 static int load_module(void *mod)
2182 AST_LIST_HEAD_INIT(&feature_list);
2183 memset(parking_ext, 0, sizeof(parking_ext));
2184 memset(parking_con, 0, sizeof(parking_con));
2186 if ((res = load_config()))
2188 ast_cli_register(&showparked);
2189 ast_cli_register(&showfeatures);
2190 ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
2191 res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
2193 res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
2195 ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" );
2196 ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park,
2197 "Park a channel", mandescr_park);
2203 static int unload_module(void *mod)
2205 STANDARD_HANGUP_LOCALUSERS;
2207 ast_manager_unregister("ParkedCalls");
2208 ast_manager_unregister("Park");
2209 ast_cli_unregister(&showfeatures);
2210 ast_cli_unregister(&showparked);
2211 ast_unregister_application(parkcall);
2212 return ast_unregister_application(parkedcall);
2215 static const char *description(void)
2217 return "Call Features Resource";
2220 static const char *key(void)
2222 return ASTERISK_GPL_KEY;
2225 STD_MOD(MOD_0 | NO_UNLOAD, reload, NULL, NULL);