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 /*! \brief store context, priority and extension */
163 static void set_c_e_p(struct ast_channel *chan, const char *context, const char *ext, int pri)
165 ast_copy_string(chan->context, context, 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)); /*! \todo 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);
242 static int adsi_announce_park(struct ast_channel *chan, int parkingnum)
245 int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
247 char *message[5] = {NULL, NULL, NULL, NULL, NULL};
249 snprintf(tmp, sizeof(tmp), "Parked on %d", parkingnum);
251 res = adsi_load_session(chan, NULL, 0, 1);
254 return adsi_print(chan, message, justify, 1);
257 /*! \brief Park a call
258 We put the user in the parking list, then wake up the parking thread to be sure it looks
259 after these channels too */
260 int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
262 struct parkeduser *pu, *cur;
263 int i,x,parking_range;
264 char exten[AST_MAX_EXTENSION];
265 struct ast_context *con;
267 if (!(pu = ast_calloc(1, sizeof(*pu)))) {
270 ast_mutex_lock(&parking_lock);
271 parking_range = parking_stop - parking_start+1;
272 for (i = 0; i < parking_range; i++) {
273 x = (i + parking_offset) % parking_range + parking_start;
276 if (cur->parkingnum == x)
284 if (!(i < parking_range)) {
285 ast_log(LOG_WARNING, "No more parking spaces\n");
287 ast_mutex_unlock(&parking_lock);
291 parking_offset = x - parking_start + 1;
292 chan->appl = "Parked Call";
296 /* Start music on hold */
298 ast_indicate(pu->chan, AST_CONTROL_HOLD);
299 ast_moh_start(pu->chan, NULL);
301 pu->start = ast_tvnow();
303 pu->parkingtime = (timeout > 0) ? timeout : parkingtime;
307 ast_copy_string(pu->peername, peer->name, sizeof(pu->peername));
309 /* Remember what had been dialed, so that if the parking
310 expires, we try to come back to the same place */
311 ast_copy_string(pu->context, S_OR(chan->macrocontext, chan->context), sizeof(pu->context));
312 ast_copy_string(pu->exten, S_OR(chan->macroexten, chan->exten), sizeof(pu->exten));
313 pu->priority = chan->macropriority ? chan->macropriority : chan->priority;
314 pu->next = parkinglot;
316 /* If parking a channel directly, don't quiet yet get parking running on it */
319 ast_mutex_unlock(&parking_lock);
320 /* Wake up the (presumably select()ing) thread */
321 pthread_kill(parking_thread, SIGURG);
322 if (option_verbose > 1)
323 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));
325 manager_event(EVENT_FLAG_CALL, "ParkedCall",
331 "CallerIDName: %s\r\n",
332 pu->parkingnum, pu->chan->name, peer ? peer->name : "",
333 (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL),
334 S_OR(pu->chan->cid.cid_num, "<unknown>"),
335 S_OR(pu->chan->cid.cid_name, "<unknown>")
339 if (adsipark && adsi_available(peer))
340 adsi_announce_park(peer, pu->parkingnum);
341 if (adsipark && adsi_available(peer))
342 adsi_unload_session(peer);
344 con = ast_context_find(parking_con);
346 con = ast_context_create(NULL, parking_con, registrar);
348 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
351 snprintf(exten, sizeof(exten), "%d", x);
352 ast_add_extension2(con, 1, exten, 1, NULL, NULL, parkedcall, strdup(exten), FREE, registrar);
355 ast_say_digits(peer, pu->parkingnum, "", peer->language);
356 if (pu->notquiteyet) {
357 /* Wake up parking thread if we're really done */
358 ast_moh_start(pu->chan, NULL);
360 pthread_kill(parking_thread, SIGURG);
365 int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
367 struct ast_channel *chan;
370 /* Make a new, fake channel that we'll use to masquerade in the real one */
371 if ((chan = ast_channel_alloc(0))) {
372 /* Let us keep track of the channel name */
373 ast_string_field_build(chan, name, "Parked/%s",rchan->name);
375 /* Make formats okay */
376 chan->readformat = rchan->readformat;
377 chan->writeformat = rchan->writeformat;
378 ast_channel_masquerade(chan, rchan);
380 /* Setup the extensions and such */
381 set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority);
383 /* Make the masq execute */
387 ast_park_call(chan, peer, timeout, extout);
389 ast_log(LOG_WARNING, "Unable to create parked channel\n");
396 #define FEATURE_RETURN_HANGUP -1
397 #define FEATURE_RETURN_SUCCESSBREAK 0
398 #define FEATURE_RETURN_PBX_KEEPALIVE AST_PBX_KEEPALIVE
399 #define FEATURE_RETURN_NO_HANGUP_PEER AST_PBX_NO_HANGUP_PEER
400 #define FEATURE_RETURN_PASSDIGITS 21
401 #define FEATURE_RETURN_STOREDIGITS 22
402 #define FEATURE_RETURN_SUCCESS 23
404 #define FEATURE_SENSE_CHAN (1 << 0)
405 #define FEATURE_SENSE_PEER (1 << 1)
408 * set caller and callee according to the direction
410 static void set_peers(struct ast_channel **caller, struct ast_channel **callee,
411 struct ast_channel *peer, struct ast_channel *chan, int sense)
413 if (sense == FEATURE_SENSE_PEER) {
422 static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
424 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
427 struct ast_channel *caller_chan, *callee_chan;
430 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
434 if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) {
436 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
440 set_peers(&caller_chan, &callee_chan, peer, chan, sense);
442 if (!ast_strlen_zero(courtesytone)) {
443 if (ast_autoservice_start(callee_chan))
445 if (ast_stream_and_wait(caller_chan, courtesytone, caller_chan->language, "")) {
446 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
447 ast_autoservice_stop(callee_chan);
450 if (ast_autoservice_stop(callee_chan))
454 if (callee_chan->monitor) {
455 if (option_verbose > 3)
456 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to stop recording call.\n", code);
457 ast_monitor_stop(callee_chan, 1);
458 return FEATURE_RETURN_SUCCESS;
461 if (caller_chan && callee_chan) {
462 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT");
463 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
466 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
469 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
472 len = strlen(touch_monitor) + 50;
474 touch_filename = alloca(len);
475 snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor);
476 snprintf(args, len, "%s|%s|m", (touch_format) ? touch_format : "wav", touch_filename);
478 caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name));
479 callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name));
480 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
482 touch_filename = alloca(len);
483 snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id);
484 snprintf(args, len, "%s|%s|m", S_OR(touch_format, "wav"), touch_filename);
487 for( x = 0; x < strlen(args); x++) {
492 if (option_verbose > 3)
493 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call. filename: %s\n", code, args);
495 pbx_exec(callee_chan, monitor_app, args);
496 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
497 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
499 return FEATURE_RETURN_SUCCESS;
502 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");
506 static int builtin_disconnect(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
508 if (option_verbose > 3)
509 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code);
510 return FEATURE_RETURN_HANGUP;
513 static int finishup(struct ast_channel *chan)
518 res = ast_autoservice_stop(chan);
519 ast_indicate(chan, AST_CONTROL_UNHOLD);
523 static const char *real_ctx(struct ast_channel *transferer, struct ast_channel *transferee)
525 const char *s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT");
526 if (ast_strlen_zero(s))
527 s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT");
528 if (ast_strlen_zero(s)) /* Use the non-macro context to transfer the call XXX ? */
529 s = transferer->macrocontext;
530 if (ast_strlen_zero(s))
531 s = transferer->context;
535 static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
537 struct ast_channel *transferer;
538 struct ast_channel *transferee;
539 const char *transferer_real_context;
543 set_peers(&transferer, &transferee, peer, chan, sense);
544 transferer_real_context = real_ctx(transferer, transferee);
545 /* Start autoservice on chan while we talk to the originator */
546 ast_indicate(transferee, AST_CONTROL_HOLD);
547 ast_autoservice_start(transferee);
548 ast_moh_start(transferee, NULL);
550 memset(xferto, 0, sizeof(xferto));
553 res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY);
555 finishup(transferee);
556 return -1; /* error ? */
558 if (res > 0) /* If they've typed a digit already, handle it */
559 xferto[0] = (char) res;
561 ast_stopstream(transferer);
562 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
563 if (res < 0) { /* hangup, would be 0 for invalid and 1 for valid */
564 finishup(transferee);
567 if (!strcmp(xferto, ast_parking_ext())) {
568 res = finishup(transferee);
571 else if (!ast_park_call(transferee, transferer, 0, NULL)) { /* success */
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 /*! \todo XXX Maybe we should have another message here instead of invalid extension XXX */
581 } else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
582 pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", chan->name);
583 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", peer->name);
584 res=finishup(transferee);
585 if (!transferee->pbx) {
586 /* Doh! Use our handy async_goto functions */
587 if (option_verbose > 2)
588 ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n"
589 ,transferee->name, xferto, transferer_real_context);
590 if (ast_async_goto(transferee, transferer_real_context, xferto, 1))
591 ast_log(LOG_WARNING, "Async goto failed :-(\n");
594 /* Set the channel's new extension, since it exists, using transferer context */
595 set_c_e_p(transferee, transferer_real_context, xferto, 0);
597 check_goto_on_transfer(transferer);
600 if (option_verbose > 2)
601 ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context);
603 if (ast_stream_and_wait(transferer, xferfailsound, transferee->language, AST_DIGIT_ANY) < 0 ) {
604 finishup(transferee);
607 ast_stopstream(transferer);
608 res = finishup(transferee);
610 if (option_verbose > 1)
611 ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name);
614 return FEATURE_RETURN_SUCCESS;
617 static int check_compat(struct ast_channel *c, struct ast_channel *newchan)
619 if (ast_channel_make_compatible(c, newchan) < 0) {
620 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n",
621 c->name, newchan->name);
628 static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
630 struct ast_channel *transferer;
631 struct ast_channel *transferee;
632 const char *transferer_real_context;
636 struct ast_channel *newchan;
637 struct ast_channel *xferchan;
638 struct ast_bridge_thread_obj *tobj;
639 struct ast_bridge_config bconfig;
644 ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense);
645 set_peers(&transferer, &transferee, peer, chan, sense);
646 transferer_real_context = real_ctx(transferer, transferee);
647 /* Start autoservice on chan while we talk to the originator */
648 ast_indicate(transferee, AST_CONTROL_HOLD);
649 ast_autoservice_start(transferee);
650 ast_moh_start(transferee, NULL);
651 memset(xferto, 0, sizeof(xferto));
653 res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY);
655 finishup(transferee);
658 if (res > 0) /* If they've typed a digit already, handle it */
659 xferto[0] = (char) res;
661 /* this is specific of atxfer */
662 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
663 if (res < 0) { /* hangup, would be 0 for invalid and 1 for valid */
664 finishup(transferee);
668 ast_log(LOG_WARNING, "Did not read data.\n");
669 finishup(transferee);
670 if (ast_stream_and_wait(transferer, "beeperr", transferer->language, ""))
672 return FEATURE_RETURN_SUCCESS;
675 /* valid extension, res == 1 */
676 if (!ast_exists_extension(transferer, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
677 ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context);
678 finishup(transferee);
679 if (ast_stream_and_wait(transferer, "beeperr", transferer->language, ""))
681 return FEATURE_RETURN_SUCCESS;
685 snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context); /* append context */
686 newchan = ast_feature_request_and_dial(transferer, "Local", ast_best_codec(transferer->nativeformats),
687 xferto, 15000, &outstate, transferer->cid.cid_num, transferer->cid.cid_name);
688 ast_indicate(transferer, -1);
690 finishup(transferee);
691 /* any reason besides user requested cancel and busy triggers the failed sound */
692 if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY &&
693 ast_stream_and_wait(transferer, xferfailsound, transferer->language, ""))
695 return FEATURE_RETURN_SUCCESS;
698 if (check_compat(transferer, newchan))
700 memset(&bconfig,0,sizeof(struct ast_bridge_config));
701 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
702 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
703 res = ast_bridge_call(transferer, newchan, &bconfig);
704 if (newchan->_softhangup || newchan->_state != AST_STATE_UP || !transferer->_softhangup) {
706 if (ast_stream_and_wait(transferer, xfersound, transferer->language, ""))
707 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
708 finishup(transferee);
709 transferer->_softhangup = 0;
710 return FEATURE_RETURN_SUCCESS;
713 if (check_compat(transferee, newchan))
716 ast_moh_stop(transferee);
718 if ((ast_autoservice_stop(transferee) < 0)
719 || (ast_waitfordigit(transferee, 100) < 0)
720 || (ast_waitfordigit(newchan, 100) < 0)
721 || ast_check_hangup(transferee)
722 || ast_check_hangup(newchan)) {
727 xferchan = ast_channel_alloc(0);
732 ast_string_field_build(xferchan, name, "Transfered/%s", transferee->name);
733 /* Make formats okay */
734 xferchan->readformat = transferee->readformat;
735 xferchan->writeformat = transferee->writeformat;
736 ast_channel_masquerade(xferchan, transferee);
737 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
738 xferchan->_state = AST_STATE_UP;
739 ast_clear_flag(xferchan, AST_FLAGS_ALL);
740 xferchan->_softhangup = 0;
742 if ((f = ast_read(xferchan)))
745 newchan->_state = AST_STATE_UP;
746 ast_clear_flag(newchan, AST_FLAGS_ALL);
747 newchan->_softhangup = 0;
749 tobj = ast_calloc(1, sizeof(struct ast_bridge_thread_obj));
751 ast_hangup(xferchan);
755 tobj->chan = xferchan;
756 tobj->peer = newchan;
757 tobj->bconfig = *config;
759 if (ast_stream_and_wait(newchan, xfersound, newchan->language, ""))
760 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
761 ast_bridge_call_thread_launch(tobj);
762 return -1; /* XXX meaning the channel is bridged ? */
766 /* add atxfer and automon as undefined so you can only use em if you configure them */
767 #define FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0]))
769 struct ast_call_feature builtin_features[] =
771 { AST_FEATURE_REDIRECT, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer, AST_FEATURE_FLAG_NEEDSDTMF },
772 { AST_FEATURE_REDIRECT, "Attended Transfer", "atxfer", "", "", builtin_atxfer, AST_FEATURE_FLAG_NEEDSDTMF },
773 { AST_FEATURE_AUTOMON, "One Touch Monitor", "automon", "", "", builtin_automonitor, AST_FEATURE_FLAG_NEEDSDTMF },
774 { AST_FEATURE_DISCONNECT, "Disconnect Call", "disconnect", "*", "*", builtin_disconnect, AST_FEATURE_FLAG_NEEDSDTMF },
778 static AST_LIST_HEAD(feature_list,ast_call_feature) feature_list;
780 /*! \brief register new feature into feature_list*/
781 void ast_register_feature(struct ast_call_feature *feature)
784 ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
788 AST_LIST_LOCK(&feature_list);
789 AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry);
790 AST_LIST_UNLOCK(&feature_list);
792 if (option_verbose >= 2)
793 ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
796 /*! \brief unregister feature from feature_list */
797 void ast_unregister_feature(struct ast_call_feature *feature)
802 AST_LIST_LOCK(&feature_list);
803 AST_LIST_REMOVE(&feature_list,feature,feature_entry);
804 AST_LIST_UNLOCK(&feature_list);
808 static void ast_unregister_features(void)
810 struct ast_call_feature *feature;
812 AST_LIST_LOCK(&feature_list);
813 while ((feature = AST_LIST_REMOVE_HEAD(&feature_list,feature_entry)))
815 AST_LIST_UNLOCK(&feature_list);
818 /*! \brief find a feature by name */
819 static struct ast_call_feature *find_feature(char *name)
821 struct ast_call_feature *tmp;
823 AST_LIST_LOCK(&feature_list);
824 AST_LIST_TRAVERSE(&feature_list, tmp, feature_entry) {
825 if (!strcasecmp(tmp->sname, name))
828 AST_LIST_UNLOCK(&feature_list);
833 /*! \brief exec an app by feature */
834 static int feature_exec_app(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
837 struct ast_call_feature *feature;
840 AST_LIST_LOCK(&feature_list);
841 AST_LIST_TRAVERSE(&feature_list,feature,feature_entry) {
842 if (!strcasecmp(feature->exten,code))
845 AST_LIST_UNLOCK(&feature_list);
847 if (!feature) { /* shouldn't ever happen! */
848 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
852 app = pbx_findapp(feature->app);
854 struct ast_channel *work = ast_test_flag(feature,AST_FEATURE_FLAG_CALLEE) ? peer : chan;
855 res = pbx_exec(work, app, feature->app_args);
859 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
863 return FEATURE_RETURN_SUCCESS; /*! \todo XXX should probably return res */
866 static void unmap_features(void)
869 for (x = 0; x < FEATURES_COUNT; x++)
870 strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
873 static int remap_feature(const char *name, const char *value)
877 for (x = 0; x < FEATURES_COUNT; x++) {
878 if (!strcasecmp(name, builtin_features[x].sname)) {
879 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
880 if (option_verbose > 1)
881 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);
883 } else if (!strcmp(value, builtin_features[x].exten))
884 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);
889 static int ast_feature_interpret(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
892 struct ast_flags features;
893 int res = FEATURE_RETURN_PASSDIGITS;
894 struct ast_call_feature *feature;
895 const char *dynamic_features=pbx_builtin_getvar_helper(chan,"DYNAMIC_FEATURES");
897 if (sense == FEATURE_SENSE_CHAN)
898 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
900 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);
901 if (option_debug > 2)
902 ast_log(LOG_DEBUG, "Feature interpret: chan=%s, peer=%s, sense=%d, features=%d\n", chan->name, peer->name, sense, features.flags);
904 for (x=0; x < FEATURES_COUNT; x++) {
905 if ((ast_test_flag(&features, builtin_features[x].feature_mask)) &&
906 !ast_strlen_zero(builtin_features[x].exten)) {
907 /* Feature is up for consideration */
908 if (!strcmp(builtin_features[x].exten, code)) {
909 res = builtin_features[x].operation(chan, peer, config, code, sense);
911 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
912 if (res == FEATURE_RETURN_PASSDIGITS)
913 res = FEATURE_RETURN_STOREDIGITS;
919 if (!ast_strlen_zero(dynamic_features)) {
920 char *tmp = ast_strdupa(dynamic_features);
926 while ((tok = strsep(&tmp, "#")) != NULL) {
927 feature = find_feature(tok);
930 /* Feature is up for consideration */
931 if (!strcmp(feature->exten, code)) {
932 if (option_verbose > 2)
933 ast_verbose(VERBOSE_PREFIX_3 " Feature Found: %s exten: %s\n",feature->sname, tok);
934 res = feature->operation(chan, peer, config, code, sense);
936 } else if (!strncmp(feature->exten, code, strlen(code))) {
937 res = FEATURE_RETURN_STOREDIGITS;
946 static void set_config_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
950 ast_clear_flag(config, AST_FLAGS_ALL);
951 for (x = 0; x < FEATURES_COUNT; x++) {
952 if (ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF)) {
953 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
954 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
956 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
957 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
961 if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
962 const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
964 if (dynamic_features) {
965 char *tmp = ast_strdupa(dynamic_features);
967 struct ast_call_feature *feature;
969 if (!tmp) /* no memory */
972 /* while we have a feature */
973 while (NULL != (tok = strsep(&tmp, "#"))) {
974 if ((feature = find_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
975 if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLER))
976 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
977 if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLEE))
978 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
985 /*! \todo XXX Check - this is very similar to the code in channel.c */
986 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)
991 struct ast_channel *chan;
992 struct ast_channel *monitor_chans[2];
993 struct ast_channel *active_channel;
994 int res = 0, ready = 0;
996 if ((chan = ast_request(type, format, data, &cause))) {
997 ast_set_callerid(chan, cid_num, cid_name, cid_num);
998 ast_channel_inherit_variables(caller, chan);
999 if (!ast_call(chan, data, timeout)) {
1000 struct timeval started;
1002 char *disconnect_code = NULL, *dialed_code = NULL;
1004 ast_indicate(caller, AST_CONTROL_RINGING);
1005 /* support dialing of the featuremap disconnect code while performing an attended tranfer */
1006 for (x=0; x < FEATURES_COUNT; x++) {
1007 if (strcasecmp(builtin_features[x].sname, "disconnect"))
1010 disconnect_code = builtin_features[x].exten;
1011 len = strlen(disconnect_code) + 1;
1012 dialed_code = alloca(len);
1013 memset(dialed_code, 0, len);
1017 started = ast_tvnow();
1019 while (!ast_check_hangup(caller) && timeout && (chan->_state != AST_STATE_UP)) {
1020 struct ast_frame *f = NULL;
1022 monitor_chans[0] = caller;
1023 monitor_chans[1] = chan;
1024 active_channel = ast_waitfor_n(monitor_chans, 2, &to);
1026 /* see if the timeout has been violated */
1027 if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
1028 state = AST_CONTROL_UNHOLD;
1029 ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n");
1030 break; /*doh! timeout*/
1033 if (!active_channel)
1036 if (chan && (chan == active_channel)){
1038 if (f == NULL) { /*doh! where'd he go?*/
1039 state = AST_CONTROL_HANGUP;
1044 if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) {
1045 if (f->subclass == AST_CONTROL_RINGING) {
1046 state = f->subclass;
1047 if (option_verbose > 2)
1048 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", chan->name);
1049 ast_indicate(caller, AST_CONTROL_RINGING);
1050 } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) {
1051 state = f->subclass;
1052 if (option_verbose > 2)
1053 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", chan->name);
1054 ast_indicate(caller, AST_CONTROL_BUSY);
1058 } else if (f->subclass == AST_CONTROL_ANSWER) {
1059 /* This is what we are hoping for */
1060 state = f->subclass;
1066 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass);
1068 /* else who cares */
1071 } else if (caller && (active_channel == caller)) {
1072 f = ast_read(caller);
1073 if (f == NULL) { /*doh! where'd he go?*/
1074 if (caller->_softhangup && !chan->_softhangup) {
1075 /* make this a blind transfer */
1079 state = AST_CONTROL_HANGUP;
1084 if (f->frametype == AST_FRAME_DTMF) {
1085 dialed_code[x++] = f->subclass;
1086 dialed_code[x] = '\0';
1087 if (strlen(dialed_code) == len) {
1089 } else if (x && strncmp(dialed_code, disconnect_code, x)) {
1091 dialed_code[x] = '\0';
1093 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
1094 /* Caller Canceled the call */
1095 state = AST_CONTROL_UNHOLD;
1106 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
1108 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
1110 case AST_CAUSE_BUSY:
1111 state = AST_CONTROL_BUSY;
1113 case AST_CAUSE_CONGESTION:
1114 state = AST_CONTROL_CONGESTION;
1119 ast_indicate(caller, -1);
1120 if (chan && ready) {
1121 if (chan->_state == AST_STATE_UP)
1122 state = AST_CONTROL_ANSWER;
1135 if (chan && res <= 0) {
1136 if (chan->cdr || (chan->cdr = ast_cdr_alloc())) {
1138 ast_cdr_init(chan->cdr, chan);
1139 snprintf(tmp, 256, "%s/%s", type, (char *)data);
1140 ast_cdr_setapp(chan->cdr,"Dial",tmp);
1141 ast_cdr_update(chan);
1142 ast_cdr_start(chan->cdr);
1143 ast_cdr_end(chan->cdr);
1144 /* If the cause wasn't handled properly */
1145 if (ast_cdr_disposition(chan->cdr,chan->hangupcause))
1146 ast_cdr_failed(chan->cdr);
1148 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
1155 int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast_bridge_config *config)
1157 /* Copy voice back and forth between the two channels. Give the peer
1158 the ability to transfer calls with '#<extension' syntax. */
1159 struct ast_frame *f;
1160 struct ast_channel *who;
1161 char chan_featurecode[FEATURE_MAX_LEN + 1]="";
1162 char peer_featurecode[FEATURE_MAX_LEN + 1]="";
1167 struct ast_option_header *aoh;
1168 struct timeval start = { 0 , 0 };
1169 struct ast_bridge_config backup_config;
1171 memset(&backup_config, 0, sizeof(backup_config));
1173 config->start_time = ast_tvnow();
1176 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
1177 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
1179 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
1182 const char *monitor_exec;
1183 struct ast_channel *src = NULL;
1185 if (!(monitor_app = pbx_findapp("Monitor")))
1188 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR")))
1190 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
1192 if (monitor_app && src) {
1193 char *tmp = ast_strdupa(monitor_exec);
1195 pbx_exec(src, monitor_app, tmp);
1197 ast_log(LOG_ERROR, "Monitor failed: out of memory\n");
1202 set_config_flags(chan, peer, config);
1203 config->firstpass = 1;
1205 /* Answer if need be */
1206 if (ast_answer(chan))
1208 peer->appl = "Bridged Call";
1209 peer->data = chan->name;
1211 /* copy the userfield from the B-leg to A-leg if applicable */
1212 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
1214 if (!ast_strlen_zero(chan->cdr->userfield)) {
1215 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield);
1216 ast_cdr_appenduserfield(chan, tmp);
1218 ast_cdr_setuserfield(chan, peer->cdr->userfield);
1219 /* free the peer's cdr without ast_cdr_free complaining */
1224 struct ast_channel *other; /* used later */
1225 if (config->feature_timer)
1226 start = ast_tvnow();
1228 res = ast_channel_bridge(chan, peer, config, &f, &who);
1230 if (config->feature_timer) {
1231 /* Update time limit for next pass */
1232 diff = ast_tvdiff_ms(ast_tvnow(), start);
1233 config->feature_timer -= diff;
1235 /* Running on backup config, meaning a feature might be being
1236 activated, but that's no excuse to keep things going
1238 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
1240 ast_log(LOG_DEBUG, "Timed out, realtime this time!\n");
1241 config->feature_timer = 0;
1247 } else if (config->feature_timer <= 0) {
1248 /* Not *really* out of time, just out of time for
1249 digits to come in for features. */
1251 ast_log(LOG_DEBUG, "Timed out for feature!\n");
1252 if (!ast_strlen_zero(peer_featurecode)) {
1253 ast_dtmf_stream(chan, peer, peer_featurecode, 0);
1254 memset(peer_featurecode, 0, sizeof(peer_featurecode));
1256 if (!ast_strlen_zero(chan_featurecode)) {
1257 ast_dtmf_stream(peer, chan, chan_featurecode, 0);
1258 memset(chan_featurecode, 0, sizeof(chan_featurecode));
1262 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
1264 /* Restore original (possibly time modified) bridge config */
1265 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
1266 memset(&backup_config, 0, sizeof(backup_config));
1268 hadfeatures = hasfeatures;
1269 /* Continue as we were */
1273 if (config->feature_timer <=0) {
1274 /* We ran out of time */
1275 config->feature_timer = 0;
1285 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
1289 if (!f || (f->frametype == AST_FRAME_CONTROL &&
1290 (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY ||
1291 f->subclass == AST_CONTROL_CONGESTION ) ) ) {
1295 /* many things should be sent to the 'other' channel */
1296 other = (who == chan) ? peer : chan;
1297 if (f->frametype == AST_FRAME_CONTROL) {
1298 if (f->subclass == AST_CONTROL_RINGING)
1299 ast_indicate(other, AST_CONTROL_RINGING);
1300 else if (f->subclass == -1)
1301 ast_indicate(other, -1);
1302 else if (f->subclass == AST_CONTROL_FLASH)
1303 ast_indicate(other, AST_CONTROL_FLASH);
1304 else if (f->subclass == AST_CONTROL_OPTION) {
1306 /* Forward option Requests */
1307 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST)
1308 ast_channel_setoption(other, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
1311 /* check for '*', if we find it it's time to disconnect */
1312 if (f->frametype == AST_FRAME_DTMF) {
1316 hadfeatures = hasfeatures;
1317 /* This cannot overrun because the longest feature is one shorter than our buffer */
1319 sense = FEATURE_SENSE_CHAN;
1320 featurecode = chan_featurecode;
1322 sense = FEATURE_SENSE_PEER;
1323 featurecode = peer_featurecode;
1325 /*! append the event to featurecode. we rely on the string being zero-filled, and
1326 * not overflowing it.
1327 * \todo XXX how do we guarantee the latter ?
1329 featurecode[strlen(featurecode)] = f->subclass;
1330 config->feature_timer = backup_config.feature_timer;
1331 res = ast_feature_interpret(chan, peer, config, featurecode, sense);
1333 case FEATURE_RETURN_PASSDIGITS:
1334 ast_dtmf_stream(other, who, featurecode, 0);
1336 case FEATURE_RETURN_SUCCESS:
1337 memset(featurecode, 0, sizeof(chan_featurecode));
1340 if (res >= FEATURE_RETURN_PASSDIGITS) {
1346 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
1347 if (hadfeatures && !hasfeatures) {
1348 /* Restore backup */
1349 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
1350 memset(&backup_config, 0, sizeof(struct ast_bridge_config));
1351 } else if (hasfeatures) {
1353 /* Backup configuration */
1354 memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
1355 /* Setup temporary config options */
1356 config->play_warning = 0;
1357 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
1358 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
1359 config->warning_freq = 0;
1360 config->warning_sound = NULL;
1361 config->end_sound = NULL;
1362 config->start_sound = NULL;
1363 config->firstpass = 0;
1365 config->feature_timer = featuredigittimeout;
1367 ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer);
1376 static void post_manager_event(const char *s, int num, struct ast_channel *chan)
1378 manager_event(EVENT_FLAG_CALL, s,
1382 "CallerIDName: %s\r\n\r\n",
1384 S_OR(chan->cid.cid_num, "<unknown>"),
1385 S_OR(chan->cid.cid_name, "<unknown>")
1389 /*! \brief Take care of parked calls and unpark them if needed */
1390 static void *do_parking_thread(void *ignore)
1392 fd_set rfds, efds; /* results from previous select, to be preserved across loops. */
1397 struct parkeduser *pu, *pl, *pt = NULL;
1398 int ms = -1; /* select timeout, uninitialized */
1399 int max = -1; /* max fd, none there yet */
1400 fd_set nrfds, nefds; /* args for the next select */
1404 ast_mutex_lock(&parking_lock);
1407 /* navigate the list with prev-cur pointers to support removals */
1409 struct ast_channel *chan = pu->chan; /* shorthand */
1410 int tms; /* timeout for this item */
1411 int x; /* fd index in channel */
1412 struct ast_context *con;
1414 if (pu->notquiteyet) { /* Pretend this one isn't here yet */
1419 tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
1420 if (tms > pu->parkingtime) {
1421 /* Stop music on hold */
1423 ast_indicate(chan, AST_CONTROL_UNHOLD);
1424 /* Get chan, exten from derived kludge */
1425 if (pu->peername[0]) {
1426 char *peername = ast_strdupa(pu->peername);
1427 char *cp = strrchr(peername, '-');
1430 con = ast_context_find(parking_con_dial);
1432 con = ast_context_create(NULL, parking_con_dial, registrar);
1434 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
1438 char returnexten[AST_MAX_EXTENSION];
1439 snprintf(returnexten, sizeof(returnexten), "%s||t", peername);
1440 ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), FREE, registrar);
1442 set_c_e_p(chan, parking_con_dial, peername, 1);
1444 /* They've been waiting too long, send them back to where they came. Theoretically they
1445 should have their original extensions and such, but we copy to be on the safe side */
1446 set_c_e_p(chan, pu->context, pu->exten, pu->priority);
1449 post_manager_event("ParkedCallTimeOut", pu->parkingnum, chan);
1451 if (option_verbose > 1)
1452 ast_verbose(VERBOSE_PREFIX_2 "Timeout for %s parked on %d. Returning to %s,%s,%d\n", chan->name, pu->parkingnum, chan->context, chan->exten, chan->priority);
1453 /* Start up the PBX, or hang them up */
1454 if (ast_pbx_start(chan)) {
1455 ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", chan->name);
1458 /* And take them out of the parking lot */
1460 pl->next = pu->next;
1462 parkinglot = pu->next;
1465 con = ast_context_find(parking_con);
1467 char exten[AST_MAX_EXTENSION];
1468 snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
1469 if (ast_context_remove_extension2(con, exten, 1, NULL))
1470 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1472 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1474 } else { /* still within parking time, process descriptors */
1475 for (x = 0; x < AST_MAX_FDS; x++) {
1476 struct ast_frame *f;
1478 if (chan->fds[x] == -1 || (!FD_ISSET(chan->fds[x], &rfds) && !FD_ISSET(chan->fds[x], &efds)))
1479 continue; /* nothing on this descriptor */
1481 if (FD_ISSET(chan->fds[x], &efds))
1482 ast_set_flag(chan, AST_FLAG_EXCEPTION);
1484 ast_clear_flag(chan, AST_FLAG_EXCEPTION);
1486 /* See if they need servicing */
1488 if (!f || (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_HANGUP)) {
1491 post_manager_event("ParkedCallGiveUp", pu->parkingnum, chan);
1493 /* There's a problem, hang them up*/
1494 if (option_verbose > 1)
1495 ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", chan->name);
1497 /* And take them out of the parking lot */
1499 pl->next = pu->next;
1501 parkinglot = pu->next;
1504 con = ast_context_find(parking_con);
1506 char exten[AST_MAX_EXTENSION];
1507 snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
1508 if (ast_context_remove_extension2(con, exten, 1, NULL))
1509 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1511 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1515 /*! \todo XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
1517 if (pu->moh_trys < 3 && !chan->generatordata) {
1519 ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source. Restarting.\n");
1520 ast_moh_start(chan, NULL);
1523 goto std; /*! \todo XXX Ick: jumping into an else statement??? XXX */
1527 if (x >= AST_MAX_FDS) {
1528 std: for (x=0; x<AST_MAX_FDS; x++) { /* mark fds for next round */
1529 if (chan->fds[x] > -1) {
1530 FD_SET(chan->fds[x], &nrfds);
1531 FD_SET(chan->fds[x], &nefds);
1532 if (chan->fds[x] > max)
1536 /* Keep track of our shortest wait */
1537 if (tms < ms || ms < 0)
1544 ast_mutex_unlock(&parking_lock);
1548 struct timeval tv = ast_samp2tv(ms, 1000);
1549 /* Wait for something to happen */
1550 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
1552 pthread_testcancel();
1554 return NULL; /* Never reached */
1557 static int park_call_exec(struct ast_channel *chan, void *data)
1559 /* Data is unused at the moment but could contain a parking
1560 lot context eventually */
1562 struct localuser *u;
1564 /* Setup the exten/priority to be s/1 since we don't know
1565 where this call should return */
1566 strcpy(chan->exten, "s");
1568 if (chan->_state != AST_STATE_UP)
1569 res = ast_answer(chan);
1571 res = ast_safe_sleep(chan, 1000);
1573 res = ast_park_call(chan, chan, 0, NULL);
1574 LOCAL_USER_REMOVE(u);
1576 res = AST_PBX_KEEPALIVE;
1580 static int park_exec(struct ast_channel *chan, void *data)
1583 struct localuser *u;
1584 struct ast_channel *peer=NULL;
1585 struct parkeduser *pu, *pl=NULL;
1586 struct ast_context *con;
1588 struct ast_bridge_config config;
1591 ast_log(LOG_WARNING, "Park requires an argument (extension number)\n");
1595 park = atoi((char *)data);
1596 ast_mutex_lock(&parking_lock);
1599 if (pu->parkingnum == park) {
1601 pl->next = pu->next;
1603 parkinglot = pu->next;
1609 ast_mutex_unlock(&parking_lock);
1612 con = ast_context_find(parking_con);
1614 char exten[AST_MAX_EXTENSION];
1615 snprintf(exten, sizeof(exten), "%d", pu->parkingnum);
1616 if (ast_context_remove_extension2(con, exten, 1, NULL))
1617 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1619 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1621 manager_event(EVENT_FLAG_CALL, "UnParkedCall",
1626 "CallerIDName: %s\r\n",
1627 pu->parkingnum, pu->chan->name, chan->name,
1628 S_OR(pu->chan->cid.cid_num, "<unknown>"),
1629 S_OR(pu->chan->cid.cid_name, "<unknown>")
1634 /* JK02: it helps to answer the channel if not already up */
1635 if (chan->_state != AST_STATE_UP)
1639 /* Play a courtesy to the source(s) configured to prefix the bridge connecting */
1641 if (!ast_strlen_zero(courtesytone)) {
1644 ast_indicate(peer, AST_CONTROL_UNHOLD);
1645 if (parkedplay == 0) {
1646 error = ast_stream_and_wait(chan, courtesytone, chan->language, "");
1647 } else if (parkedplay == 1) {
1648 error = ast_stream_and_wait(peer, courtesytone, chan->language, "");
1649 } else if (parkedplay == 2) {
1650 if (!ast_streamfile(chan, courtesytone, chan->language) &&
1651 !ast_streamfile(peer, courtesytone, chan->language)) {
1652 /*! \todo XXX we would like to wait on both! */
1653 res = ast_waitstream(chan, "");
1655 res = ast_waitstream(peer, "");
1661 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
1667 res = ast_channel_make_compatible(chan, peer);
1669 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
1673 /* This runs sorta backwards, since we give the incoming channel control, as if it
1674 were the person called. */
1675 if (option_verbose > 2)
1676 ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
1678 memset(&config, 0, sizeof(struct ast_bridge_config));
1679 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
1680 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
1681 config.timelimit = 0;
1682 config.play_warning = 0;
1683 config.warning_freq = 0;
1684 config.warning_sound=NULL;
1685 res = ast_bridge_call(chan, peer, &config);
1687 /* Simulate the PBX hanging up */
1688 if (res != AST_PBX_NO_HANGUP_PEER)
1692 /*! \todo XXX Play a message XXX */
1693 if (ast_stream_and_wait(chan, "pbx-invalidpark", chan->language, ""))
1694 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
1695 if (option_verbose > 2)
1696 ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
1699 LOCAL_USER_REMOVE(u);
1703 static int handle_showfeatures(int fd, int argc, char *argv[])
1707 struct ast_call_feature *feature;
1708 char format[] = "%-25s %-7s %-7s\n";
1710 ast_cli(fd, format, "Builtin Feature", "Default", "Current");
1711 ast_cli(fd, format, "---------------", "-------", "-------");
1713 ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */
1715 fcount = sizeof(builtin_features) / sizeof(builtin_features[0]);
1717 for (i = 0; i < fcount; i++)
1719 ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
1722 ast_cli(fd, format, "Dynamic Feature", "Default", "Current");
1723 ast_cli(fd, format, "---------------", "-------", "-------");
1724 if (AST_LIST_EMPTY(&feature_list)) {
1725 ast_cli(fd, "(none)\n");
1728 AST_LIST_LOCK(&feature_list);
1729 AST_LIST_TRAVERSE(&feature_list, feature, feature_entry) {
1730 ast_cli(fd, format, feature->sname, "no def", feature->exten);
1732 AST_LIST_UNLOCK(&feature_list);
1734 ast_cli(fd, "\nCall parking\n");
1735 ast_cli(fd, "------------\n");
1736 ast_cli(fd,"%-20s: %s\n", "Parking extension", parking_ext);
1737 ast_cli(fd,"%-20s: %s\n", "Parking context", parking_con);
1738 ast_cli(fd,"%-20s: %d-%d\n", "Parked call extensions", parking_start, parking_stop);
1741 return RESULT_SUCCESS;
1744 static char showfeatures_help[] =
1745 "Usage: show features\n"
1746 " Lists currently configured features.\n";
1748 static struct ast_cli_entry showfeatures =
1749 { { "show", "features", NULL }, handle_showfeatures, "Lists configured features", showfeatures_help };
1751 static int handle_parkedcalls(int fd, int argc, char *argv[])
1753 struct parkeduser *cur;
1756 ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
1757 , "Context", "Extension", "Pri", "Timeout");
1759 ast_mutex_lock(&parking_lock);
1761 for (cur = parkinglot; cur; cur = cur->next) {
1762 ast_cli(fd, "%4d %25s (%-15s %-12s %-4d) %6lds\n"
1763 ,cur->parkingnum, cur->chan->name, cur->context, cur->exten
1764 ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
1768 ast_mutex_unlock(&parking_lock);
1769 ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : "");
1772 return RESULT_SUCCESS;
1775 static char showparked_help[] =
1776 "Usage: show parkedcalls\n"
1777 " Lists currently parked calls.\n";
1779 static struct ast_cli_entry showparked =
1780 { { "show", "parkedcalls", NULL }, handle_parkedcalls, "Lists parked calls", showparked_help };
1782 /*! \brief Dump lot status */
1783 static int manager_parking_status( struct mansession *s, struct message *m )
1785 struct parkeduser *cur;
1786 char *id = astman_get_header(m,"ActionID");
1787 char idText[256] = "";
1789 if (!ast_strlen_zero(id))
1790 snprintf(idText,256,"ActionID: %s\r\n",id);
1792 astman_send_ack(s, m, "Parked calls will follow");
1794 ast_mutex_lock(&parking_lock);
1796 for (cur=parkinglot; cur; cur = cur->next) {
1797 astman_append(s, "Event: ParkedCall\r\n"
1803 "CallerIDName: %s\r\n"
1806 cur->parkingnum, cur->chan->name, cur->peername,
1807 (long)cur->start.tv_sec + (long)(cur->parkingtime/1000) - (long)time(NULL),
1808 S_OR(cur->chan->cid.cid_num, ""), /* XXX in other places it is <unknown> */
1809 S_OR(cur->chan->cid.cid_name, ""),
1814 "Event: ParkedCallsComplete\r\n"
1818 ast_mutex_unlock(&parking_lock);
1820 return RESULT_SUCCESS;
1823 static char mandescr_park[] =
1824 "Description: Park a channel.\n"
1825 "Variables: (Names marked with * are required)\n"
1826 " *Channel: Channel name to park\n"
1827 " *Channel2: Channel to announce park info to (and return to if timeout)\n"
1828 " Timeout: Number of milliseconds to wait before callback.\n";
1830 static int manager_park(struct mansession *s, struct message *m)
1832 char *channel = astman_get_header(m, "Channel");
1833 char *channel2 = astman_get_header(m, "Channel2");
1834 char *timeout = astman_get_header(m, "Timeout");
1839 struct ast_channel *ch1, *ch2;
1841 if (ast_strlen_zero(channel)) {
1842 astman_send_error(s, m, "Channel not specified");
1846 if (ast_strlen_zero(channel2)) {
1847 astman_send_error(s, m, "Channel2 not specified");
1851 ch1 = ast_get_channel_by_name_locked(channel);
1853 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
1854 astman_send_error(s, m, buf);
1858 ch2 = ast_get_channel_by_name_locked(channel2);
1860 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
1861 astman_send_error(s, m, buf);
1862 ast_mutex_unlock(&ch1->lock);
1866 if (!ast_strlen_zero(timeout)) {
1867 sscanf(timeout, "%d", &to);
1870 res = ast_masq_park_call(ch1, ch2, to, &parkExt);
1872 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
1873 astman_send_ack(s, m, "Park successful");
1875 astman_send_error(s, m, "Park failure");
1878 ast_mutex_unlock(&ch1->lock);
1879 ast_mutex_unlock(&ch2->lock);
1885 int ast_pickup_call(struct ast_channel *chan)
1887 struct ast_channel *cur = NULL;
1890 while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
1893 (chan->pickupgroup & cur->callgroup) &&
1894 ((cur->_state == AST_STATE_RINGING) ||
1895 (cur->_state == AST_STATE_RING))) {
1898 ast_mutex_unlock(&cur->lock);
1902 ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
1903 res = ast_answer(chan);
1905 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
1906 res = ast_queue_control(chan, AST_CONTROL_ANSWER);
1908 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
1909 res = ast_channel_masquerade(cur, chan);
1911 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */
1912 ast_mutex_unlock(&cur->lock);
1915 ast_log(LOG_DEBUG, "No call pickup possible...\n");
1920 static int load_config(void)
1922 int start = 0, end = 0;
1923 struct ast_context *con = NULL;
1924 struct ast_config *cfg = NULL;
1925 struct ast_variable *var = NULL;
1926 char old_parking_ext[AST_MAX_EXTENSION];
1927 char old_parking_con[AST_MAX_EXTENSION] = "";
1929 if (!ast_strlen_zero(parking_con)) {
1930 strcpy(old_parking_ext, parking_ext);
1931 strcpy(old_parking_con, parking_con);
1934 /* Reset to defaults */
1935 strcpy(parking_con, "parkedcalls");
1936 strcpy(parking_con_dial, "park-dial");
1937 strcpy(parking_ext, "700");
1938 strcpy(pickup_ext, "*8");
1939 courtesytone[0] = '\0';
1940 strcpy(xfersound, "beep");
1941 strcpy(xferfailsound, "pbx-invalid");
1942 parking_start = 701;
1947 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
1948 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
1950 cfg = ast_config_load("features.conf");
1952 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
1953 if (!strcasecmp(var->name, "parkext")) {
1954 ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
1955 } else if (!strcasecmp(var->name, "context")) {
1956 ast_copy_string(parking_con, var->value, sizeof(parking_con));
1957 } else if (!strcasecmp(var->name, "parkingtime")) {
1958 if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) {
1959 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
1960 parkingtime = DEFAULT_PARK_TIME;
1962 parkingtime = parkingtime * 1000;
1963 } else if (!strcasecmp(var->name, "parkpos")) {
1964 if (sscanf(var->value, "%d-%d", &start, &end) != 2) {
1965 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);
1967 parking_start = start;
1970 } else if (!strcasecmp(var->name, "findslot")) {
1971 parkfindnext = (!strcasecmp(var->value, "next"));
1972 } else if (!strcasecmp(var->name, "adsipark")) {
1973 adsipark = ast_true(var->value);
1974 } else if (!strcasecmp(var->name, "transferdigittimeout")) {
1975 if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
1976 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
1977 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
1979 transferdigittimeout = transferdigittimeout * 1000;
1980 } else if (!strcasecmp(var->name, "featuredigittimeout")) {
1981 if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
1982 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
1983 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
1985 } else if (!strcasecmp(var->name, "courtesytone")) {
1986 ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
1987 } else if (!strcasecmp(var->name, "parkedplay")) {
1988 if (!strcasecmp(var->value, "both"))
1990 else if (!strcasecmp(var->value, "parked"))
1994 } else if (!strcasecmp(var->name, "xfersound")) {
1995 ast_copy_string(xfersound, var->value, sizeof(xfersound));
1996 } else if (!strcasecmp(var->name, "xferfailsound")) {
1997 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
1998 } else if (!strcasecmp(var->name, "pickupexten")) {
1999 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
2004 for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) {
2005 if (remap_feature(var->name, var->value))
2006 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
2009 /* Map a key combination to an application*/
2010 ast_unregister_features();
2011 for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) {
2012 char *tmp_val = ast_strdup(var->value);
2013 char *exten, *party=NULL, *app=NULL, *app_args=NULL;
2016 /*! \todo XXX No memory. We should probably break, but at least we do not
2017 * insist on this entry or we could be stuck in an
2023 /* strsep() sets the argument to NULL if match not found, and it
2024 * is safe to use it with a NULL argument, so we don't check
2027 exten = strsep(&tmp_val,",");
2028 party = strsep(&tmp_val,",");
2029 app = strsep(&tmp_val,",");
2030 app_args = strsep(&tmp_val,",");
2032 /*! \todo XXX var_name or app_args ? */
2033 if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(party) || ast_strlen_zero(var->name)) {
2034 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);
2040 struct ast_call_feature *feature;
2043 if (!(feature = find_feature(var->name))) {
2046 if (!(feature = ast_calloc(1, sizeof(*feature)))) {
2052 ast_copy_string(feature->sname,var->name,FEATURE_SNAME_LEN);
2053 ast_copy_string(feature->app,app,FEATURE_APP_LEN);
2054 ast_copy_string(feature->exten, exten,FEATURE_EXTEN_LEN);
2058 ast_copy_string(feature->app_args,app_args,FEATURE_APP_ARGS_LEN);
2060 ast_copy_string(feature->exten, exten,sizeof(feature->exten));
2061 feature->operation=feature_exec_app;
2062 ast_set_flag(feature,AST_FEATURE_FLAG_NEEDSDTMF);
2064 if (!strcasecmp(party,"caller"))
2065 ast_set_flag(feature,AST_FEATURE_FLAG_CALLER);
2066 else if (!strcasecmp(party, "callee"))
2067 ast_set_flag(feature,AST_FEATURE_FLAG_CALLEE);
2069 ast_log(LOG_NOTICE, "Invalid party specification for feature '%s', must be caller, or callee\n", var->name);
2073 ast_register_feature(feature);
2074 /* XXX do we need to free it if mallocd ? */
2076 if (option_verbose >=1)
2077 ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s' with code '%s'\n", var->name, app, exten);
2081 ast_config_destroy(cfg);
2083 /* Remove the old parking extension */
2084 if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) {
2085 ast_context_remove_extension2(con, old_parking_ext, 1, registrar);
2087 ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
2090 if (!(con = ast_context_find(parking_con)) && !(con = ast_context_create(NULL, parking_con, registrar))) {
2091 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
2094 return ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, strdup(""), FREE, registrar);
2097 static int reload(void *mod)
2099 return load_config();
2102 static int load_module(void *mod)
2107 AST_LIST_HEAD_INIT(&feature_list);
2108 memset(parking_ext, 0, sizeof(parking_ext));
2109 memset(parking_con, 0, sizeof(parking_con));
2111 if ((res = load_config()))
2113 ast_cli_register(&showparked);
2114 ast_cli_register(&showfeatures);
2115 ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
2116 res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
2118 res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
2120 ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" );
2121 ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park,
2122 "Park a channel", mandescr_park);
2128 static int unload_module(void *mod)
2130 STANDARD_HANGUP_LOCALUSERS;
2132 ast_manager_unregister("ParkedCalls");
2133 ast_manager_unregister("Park");
2134 ast_cli_unregister(&showfeatures);
2135 ast_cli_unregister(&showparked);
2136 ast_unregister_application(parkcall);
2137 return ast_unregister_application(parkedcall);
2140 static const char *description(void)
2142 return "Call Features Resource";
2145 static const char *key(void)
2147 return ASTERISK_GPL_KEY;
2150 STD_MOD(MOD_0 | NO_UNLOAD, reload, NULL, NULL);