revert an optimization that broke ABI... thanks russell!
[asterisk-bristuff.git] / res / res_features.c
blobd1a481eeec725b18d68225bc0a6291f925b4c5e0
1 /*
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.
19 /*! \file
21 * \brief Routines implementing call features as call pickup, parking and transfer
23 * \author Mark Spencer <markster@digium.com>
26 /*** MODULEINFO
27 <depend>chan_local</depend>
28 ***/
30 #include "asterisk.h"
32 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
34 #include <pthread.h>
35 #include <stdlib.h>
36 #include <errno.h>
37 #include <unistd.h>
38 #include <string.h>
39 #include <stdlib.h>
40 #include <stdio.h>
41 #include <sys/time.h>
42 #include <sys/signal.h>
43 #include <netinet/in.h>
45 #include "asterisk/lock.h"
46 #include "asterisk/file.h"
47 #include "asterisk/logger.h"
48 #include "asterisk/channel.h"
49 #include "asterisk/pbx.h"
50 #include "asterisk/options.h"
51 #include "asterisk/causes.h"
52 #include "asterisk/module.h"
53 #include "asterisk/translate.h"
54 #include "asterisk/app.h"
55 #include "asterisk/say.h"
56 #include "asterisk/features.h"
57 #include "asterisk/musiconhold.h"
58 #include "asterisk/config.h"
59 #include "asterisk/cli.h"
60 #include "asterisk/manager.h"
61 #include "asterisk/utils.h"
62 #include "asterisk/adsi.h"
63 #include "asterisk/devicestate.h"
64 #include "asterisk/monitor.h"
65 #include "asterisk/global_datastores.h"
67 #define DEFAULT_PARK_TIME 45000
68 #define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000
69 #define DEFAULT_FEATURE_DIGIT_TIMEOUT 500
70 #define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000
72 #define AST_MAX_WATCHERS 256
74 enum {
75 AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0),
76 AST_FEATURE_FLAG_ONPEER = (1 << 1),
77 AST_FEATURE_FLAG_ONSELF = (1 << 2),
78 AST_FEATURE_FLAG_BYCALLEE = (1 << 3),
79 AST_FEATURE_FLAG_BYCALLER = (1 << 4),
80 AST_FEATURE_FLAG_BYBOTH = (3 << 3),
83 static char *parkedcall = "ParkedCall";
85 static int parkaddhints = 0; /*!< Add parking hints automatically */
86 static int parkingtime = DEFAULT_PARK_TIME; /*!< No more than 45 seconds parked before you do something with them */
87 static char parking_con[AST_MAX_EXTENSION]; /*!< Context for which parking is made accessible */
88 static char parking_con_dial[AST_MAX_EXTENSION]; /*!< Context for dialback for parking (KLUDGE) */
89 static char parking_ext[AST_MAX_EXTENSION]; /*!< Extension you type to park the call */
90 static char pickup_ext[AST_MAX_EXTENSION]; /*!< Call pickup extension */
91 static char parkmohclass[MAX_MUSICCLASS]; /*!< Music class used for parking */
92 static int parking_start; /*!< First available extension for parking */
93 static int parking_stop; /*!< Last available extension for parking */
95 static char courtesytone[256]; /*!< Courtesy tone */
96 static int parkedplay = 0; /*!< Who to play the courtesy tone to */
97 static char xfersound[256]; /*!< Call transfer sound */
98 static char xferfailsound[256]; /*!< Call transfer failure sound */
100 static int parking_offset;
101 static int parkfindnext;
103 static int adsipark;
105 static int transferdigittimeout;
106 static int featuredigittimeout;
108 static int atxfernoanswertimeout;
110 static char *registrar = "res_features"; /*!< Registrar for operations */
112 /* module and CLI command definitions */
113 static char *synopsis = "Answer a parked call";
115 static char *descrip = "ParkedCall(exten):"
116 "Used to connect to a parked call. 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"
119 "context.\n";
121 static char *parkcall = "Park";
123 static char *synopsis2 = "Park yourself";
125 static char *descrip2 = "Park():"
126 "Used to park yourself (typically in combination with a supervised\n"
127 "transfer to know the parking space). This application is always\n"
128 "registered internally and does not need to be explicitly added\n"
129 "into the dialplan, although you should include the 'parkedcalls'\n"
130 "context (or the context specified in features.conf).\n\n"
131 "If you set the PARKINGEXTEN variable to an extension in your\n"
132 "parking context, park() will park the call on that extension, unless\n"
133 "it already exists. In that case, execution will continue at next\n"
134 "priority.\n" ;
136 static struct ast_app *monitor_app = NULL;
137 static int monitor_ok = 1;
139 struct parkeduser {
140 struct ast_channel *chan; /*!< Parking channel */
141 struct timeval start; /*!< Time the parking started */
142 int parkingnum; /*!< Parking lot */
143 char parkingexten[AST_MAX_EXTENSION]; /*!< If set beforehand, parking extension used for this call */
144 char context[AST_MAX_CONTEXT]; /*!< Where to go if our parking time expires */
145 char exten[AST_MAX_EXTENSION];
146 int priority;
147 int parkingtime; /*!< Maximum length in parking lot before return */
148 int notquiteyet;
149 char peername[1024];
150 unsigned char moh_trys;
151 struct parkeduser *next;
154 static struct parkeduser *parkinglot;
156 AST_MUTEX_DEFINE_STATIC(parking_lock); /*!< protects all static variables above */
158 static pthread_t parking_thread;
160 char *ast_parking_ext(void)
162 return parking_ext;
165 char *ast_pickup_ext(void)
167 return pickup_ext;
170 struct ast_bridge_thread_obj
172 struct ast_bridge_config bconfig;
173 struct ast_channel *chan;
174 struct ast_channel *peer;
179 /*! \brief store context, priority and extension */
180 static void set_c_e_p(struct ast_channel *chan, const char *context, const char *ext, int pri)
182 ast_copy_string(chan->context, context, sizeof(chan->context));
183 ast_copy_string(chan->exten, ext, sizeof(chan->exten));
184 chan->priority = pri;
187 static void check_goto_on_transfer(struct ast_channel *chan)
189 struct ast_channel *xferchan;
190 const char *val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR");
191 char *x, *goto_on_transfer;
192 struct ast_frame *f;
194 if (ast_strlen_zero(val))
195 return;
197 goto_on_transfer = ast_strdupa(val);
199 if (!(xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, chan->name)))
200 return;
202 for (x = goto_on_transfer; x && *x; x++) {
203 if (*x == '^')
204 *x = '|';
206 /* Make formats okay */
207 xferchan->readformat = chan->readformat;
208 xferchan->writeformat = chan->writeformat;
209 ast_channel_masquerade(xferchan, chan);
210 ast_parseable_goto(xferchan, goto_on_transfer);
211 xferchan->_state = AST_STATE_UP;
212 ast_clear_flag(xferchan, AST_FLAGS_ALL);
213 xferchan->_softhangup = 0;
214 if ((f = ast_read(xferchan))) {
215 ast_frfree(f);
216 f = NULL;
217 ast_pbx_start(xferchan);
218 } else {
219 ast_hangup(xferchan);
223 static struct ast_channel *ast_feature_request_and_dial(struct ast_channel *caller, const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name, const char *language);
226 static void *ast_bridge_call_thread(void *data)
228 struct ast_bridge_thread_obj *tobj = data;
230 tobj->chan->appl = "Transferred Call";
231 tobj->chan->data = tobj->peer->name;
232 tobj->peer->appl = "Transferred Call";
233 tobj->peer->data = tobj->chan->name;
235 ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
236 ast_hangup(tobj->chan);
237 ast_hangup(tobj->peer);
238 bzero(tobj, sizeof(*tobj)); /*! \todo XXX for safety */
239 free(tobj);
240 return NULL;
243 static void ast_bridge_call_thread_launch(void *data)
245 pthread_t thread;
246 pthread_attr_t attr;
247 struct sched_param sched;
249 pthread_attr_init(&attr);
250 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
251 ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data);
252 pthread_attr_destroy(&attr);
253 memset(&sched, 0, sizeof(sched));
254 pthread_setschedparam(thread, SCHED_RR, &sched);
257 static int adsi_announce_park(struct ast_channel *chan, char *parkingexten)
259 int res;
260 int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
261 char tmp[256];
262 char *message[5] = {NULL, NULL, NULL, NULL, NULL};
264 snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten);
265 message[0] = tmp;
266 res = ast_adsi_load_session(chan, NULL, 0, 1);
267 if (res == -1)
268 return res;
269 return ast_adsi_print(chan, message, justify, 1);
272 /*! \brief Notify metermaids that we've changed an extension */
273 static void notify_metermaids(char *exten, char *context)
275 if (option_debug > 3)
276 ast_log(LOG_DEBUG, "Notification of state change to metermaids %s@%s\n", exten, context);
278 /* Send notification to devicestate subsystem */
279 ast_device_state_changed("park:%s@%s", exten, context);
280 return;
283 /*! \brief metermaids callback from devicestate.c */
284 static int metermaidstate(const char *data)
286 int res = AST_DEVICE_INVALID;
287 char *context = ast_strdupa(data);
288 char *exten;
290 exten = strsep(&context, "@");
291 if (!context)
292 return res;
294 if (option_debug > 3)
295 ast_log(LOG_DEBUG, "Checking state of exten %s in context %s\n", exten, context);
297 res = ast_exists_extension(NULL, context, exten, 1, NULL);
299 if (!res)
300 return AST_DEVICE_NOT_INUSE;
301 else
302 return AST_DEVICE_INUSE;
305 static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout, char *orig_chan_name)
307 struct parkeduser *pu, *cur;
308 int i, x = -1, parking_range;
309 struct ast_context *con;
310 const char *parkingexten;
312 /* Allocate memory for parking data */
313 if (!(pu = ast_calloc(1, sizeof(*pu))))
314 return -1;
316 /* Lock parking lot */
317 ast_mutex_lock(&parking_lock);
318 /* Check for channel variable PARKINGEXTEN */
319 parkingexten = pbx_builtin_getvar_helper(chan, "PARKINGEXTEN");
320 if (!ast_strlen_zero(parkingexten)) {
321 /*!\note The API forces us to specify a numeric parking slot, even
322 * though the architecture would tend to support non-numeric extensions
323 * (as are possible with SIP, for example). Hence, we enforce that
324 * limitation here. If extout was not numeric, we could permit
325 * arbitrary non-numeric extensions.
327 if (sscanf(parkingexten, "%d", &x) != 1 || x < 0) {
328 ast_log(LOG_WARNING, "PARKINGEXTEN does not indicate a valid parking slot: '%s'.\n", parkingexten);
329 ast_mutex_unlock(&parking_lock);
330 free(pu);
331 return 1; /* Continue execution if possible */
333 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", x);
335 if (ast_exists_extension(NULL, parking_con, pu->parkingexten, 1, NULL)) {
336 ast_mutex_unlock(&parking_lock);
337 free(pu);
338 ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parking_con);
339 return 1; /* Continue execution if possible */
341 } else {
342 /* Select parking space within range */
343 parking_range = parking_stop - parking_start+1;
344 for (i = 0; i < parking_range; i++) {
345 x = (i + parking_offset) % parking_range + parking_start;
346 cur = parkinglot;
347 while(cur) {
348 if (cur->parkingnum == x)
349 break;
350 cur = cur->next;
352 if (!cur)
353 break;
356 if (!(i < parking_range)) {
357 ast_log(LOG_WARNING, "No more parking spaces\n");
358 free(pu);
359 ast_mutex_unlock(&parking_lock);
360 return -1;
362 /* Set pointer for next parking */
363 if (parkfindnext)
364 parking_offset = x - parking_start + 1;
365 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", x);
368 chan->appl = "Parked Call";
369 chan->data = NULL;
371 pu->chan = chan;
373 /* Put the parked channel on hold if we have two different channels */
374 if (chan != peer) {
375 ast_indicate_data(pu->chan, AST_CONTROL_HOLD,
376 S_OR(parkmohclass, NULL),
377 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
380 pu->start = ast_tvnow();
381 pu->parkingnum = x;
382 pu->parkingtime = (timeout > 0) ? timeout : parkingtime;
383 if (extout)
384 *extout = x;
386 if (peer) {
387 /* This is so ugly that it hurts, but implementing get_base_channel() on local channels
388 could have ugly side effects. We could have transferer<->local,1<->local,2<->parking
389 and we need the callback name to be that of transferer. Since local,1/2 have the same
390 name we can be tricky and just grab the bridged channel from the other side of the local
392 if (!strcasecmp(peer->tech->type, "Local")) {
393 struct ast_channel *tmpchan, *base_peer;
394 char other_side[AST_CHANNEL_NAME];
395 char *c;
396 ast_copy_string(other_side, peer->name, sizeof(other_side));
397 if ((c = strrchr(other_side, ','))) {
398 *++c = '1';
400 if ((tmpchan = ast_get_channel_by_name_locked(other_side))) {
401 if ((base_peer = ast_bridged_channel(tmpchan))) {
402 ast_copy_string(pu->peername, base_peer->name, sizeof(pu->peername));
404 ast_channel_unlock(tmpchan);
406 } else {
407 ast_copy_string(pu->peername, peer->name, sizeof(pu->peername));
411 /* Remember what had been dialed, so that if the parking
412 expires, we try to come back to the same place */
413 ast_copy_string(pu->context, S_OR(chan->macrocontext, chan->context), sizeof(pu->context));
414 ast_copy_string(pu->exten, S_OR(chan->macroexten, chan->exten), sizeof(pu->exten));
415 pu->priority = chan->macropriority ? chan->macropriority : chan->priority;
416 pu->next = parkinglot;
417 parkinglot = pu;
419 /* If parking a channel directly, don't quiet yet get parking running on it */
420 if (peer == chan)
421 pu->notquiteyet = 1;
422 ast_mutex_unlock(&parking_lock);
423 /* Wake up the (presumably select()ing) thread */
424 pthread_kill(parking_thread, SIGURG);
425 if (option_verbose > 1)
426 ast_verbose(VERBOSE_PREFIX_2 "Parked %s on %d@%s. Will timeout back to extension [%s] %s, %d in %d seconds\n", pu->chan->name, pu->parkingnum, parking_con, pu->context, pu->exten, pu->priority, (pu->parkingtime/1000));
428 manager_event(EVENT_FLAG_CALL, "ParkedCall",
429 "Exten: %s\r\n"
430 "Channel: %s\r\n"
431 "From: %s\r\n"
432 "Timeout: %ld\r\n"
433 "CallerID: %s\r\n"
434 "CallerIDName: %s\r\n",
435 pu->parkingexten, pu->chan->name, peer ? peer->name : "",
436 (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL),
437 S_OR(pu->chan->cid.cid_num, "<unknown>"),
438 S_OR(pu->chan->cid.cid_name, "<unknown>")
441 if (peer && adsipark && ast_adsi_available(peer)) {
442 adsi_announce_park(peer, pu->parkingexten); /* Only supports parking numbers */
443 ast_adsi_unload_session(peer);
446 con = ast_context_find(parking_con);
447 if (!con)
448 con = ast_context_create(NULL, parking_con, registrar);
449 if (!con) /* Still no context? Bad */
450 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
451 /* Tell the peer channel the number of the parking space */
452 if (peer && (ast_strlen_zero(orig_chan_name) || !strcasecmp(peer->name, orig_chan_name))) { /* Only say number if it's a number and the channel hasn't been masqueraded away */
453 /* Make sure we don't start saying digits to the channel being parked */
454 ast_set_flag(peer, AST_FLAG_MASQ_NOSTREAM);
455 ast_say_digits(peer, pu->parkingnum, "", peer->language);
456 ast_clear_flag(peer, AST_FLAG_MASQ_NOSTREAM);
458 if (con) {
459 if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, strdup(pu->parkingexten), ast_free, registrar))
460 notify_metermaids(pu->parkingexten, parking_con);
462 if (pu->notquiteyet) {
463 /* Wake up parking thread if we're really done */
464 ast_indicate_data(pu->chan, AST_CONTROL_HOLD,
465 S_OR(parkmohclass, NULL),
466 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
467 pu->notquiteyet = 0;
468 pthread_kill(parking_thread, SIGURG);
470 return 0;
473 /*! \brief Park a call
474 \note We put the user in the parking list, then wake up the parking thread to be sure it looks
475 after these channels too */
476 int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
478 return park_call_full(chan, peer, timeout, extout, NULL);
481 int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
483 struct ast_channel *chan;
484 struct ast_frame *f;
485 char *orig_chan_name = NULL;
486 int park_status;
488 /* Make a new, fake channel that we'll use to masquerade in the real one */
489 if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) {
490 ast_log(LOG_WARNING, "Unable to create parked channel\n");
491 return -1;
494 /* Make formats okay */
495 chan->readformat = rchan->readformat;
496 chan->writeformat = rchan->writeformat;
497 ast_channel_masquerade(chan, rchan);
499 /* Setup the extensions and such */
500 set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority);
502 /* Make the masq execute */
503 f = ast_read(chan);
504 if (f)
505 ast_frfree(f);
507 orig_chan_name = ast_strdupa(chan->name);
509 park_status = park_call_full(chan, peer, timeout, extout, orig_chan_name);
510 if (park_status == 1) {
511 /* would be nice to play: "invalid parking extension" */
512 ast_hangup(chan);
513 return -1;
516 return 0;
520 #define FEATURE_RETURN_HANGUP -1
521 #define FEATURE_RETURN_SUCCESSBREAK 0
522 #define FEATURE_RETURN_PBX_KEEPALIVE AST_PBX_KEEPALIVE
523 #define FEATURE_RETURN_NO_HANGUP_PEER AST_PBX_NO_HANGUP_PEER
524 #define FEATURE_RETURN_PASSDIGITS 21
525 #define FEATURE_RETURN_STOREDIGITS 22
526 #define FEATURE_RETURN_SUCCESS 23
527 #define FEATURE_RETURN_KEEPTRYING 24
529 #define FEATURE_SENSE_CHAN (1 << 0)
530 #define FEATURE_SENSE_PEER (1 << 1)
532 /*! \brief
533 * set caller and callee according to the direction
535 static void set_peers(struct ast_channel **caller, struct ast_channel **callee,
536 struct ast_channel *peer, struct ast_channel *chan, int sense)
538 if (sense == FEATURE_SENSE_PEER) {
539 *caller = peer;
540 *callee = chan;
541 } else {
542 *callee = peer;
543 *caller = chan;
547 /*! \brief support routing for one touch call parking */
548 static int builtin_parkcall(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
550 struct ast_channel *parker;
551 struct ast_channel *parkee;
552 int res = 0;
553 struct ast_module_user *u;
555 u = ast_module_user_add(chan);
557 set_peers(&parker, &parkee, peer, chan, sense);
558 /* Setup the exten/priority to be s/1 since we don't know
559 where this call should return */
560 strcpy(chan->exten, "s");
561 chan->priority = 1;
562 if (chan->_state != AST_STATE_UP)
563 res = ast_answer(chan);
564 if (!res)
565 res = ast_safe_sleep(chan, 1000);
566 if (!res)
567 res = ast_park_call(parkee, parker, 0, NULL);
569 ast_module_user_remove(u);
571 if (!res) {
572 if (sense == FEATURE_SENSE_CHAN)
573 res = AST_PBX_NO_HANGUP_PEER;
574 else
575 res = AST_PBX_KEEPALIVE;
577 return res;
581 static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
583 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
584 int x = 0;
585 size_t len;
586 struct ast_channel *caller_chan, *callee_chan;
588 if (!monitor_ok) {
589 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
590 return -1;
593 if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) {
594 monitor_ok = 0;
595 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
596 return -1;
599 set_peers(&caller_chan, &callee_chan, peer, chan, sense);
601 if (!ast_strlen_zero(courtesytone)) {
602 if (ast_autoservice_start(callee_chan))
603 return -1;
604 if (ast_stream_and_wait(caller_chan, courtesytone, caller_chan->language, "")) {
605 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
606 ast_autoservice_stop(callee_chan);
607 return -1;
609 if (ast_autoservice_stop(callee_chan))
610 return -1;
613 if (callee_chan->monitor) {
614 if (option_verbose > 3)
615 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to stop recording call.\n", code);
616 ast_monitor_stop(callee_chan, 1);
617 return FEATURE_RETURN_SUCCESS;
620 if (caller_chan && callee_chan) {
621 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT");
622 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
624 if (!touch_format)
625 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
627 if (!touch_monitor)
628 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
630 if (touch_monitor) {
631 len = strlen(touch_monitor) + 50;
632 args = alloca(len);
633 touch_filename = alloca(len);
634 snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor);
635 snprintf(args, len, "%s|%s|m", (touch_format) ? touch_format : "wav", touch_filename);
636 } else {
637 caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name));
638 callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name));
639 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
640 args = alloca(len);
641 touch_filename = alloca(len);
642 snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id);
643 snprintf(args, len, "%s|%s|m", S_OR(touch_format, "wav"), touch_filename);
646 for( x = 0; x < strlen(args); x++) {
647 if (args[x] == '/')
648 args[x] = '-';
651 if (option_verbose > 3)
652 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call. filename: %s\n", code, args);
654 pbx_exec(callee_chan, monitor_app, args);
655 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
656 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
658 return FEATURE_RETURN_SUCCESS;
661 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");
662 return -1;
665 static int builtin_disconnect(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
667 if (option_verbose > 3)
668 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code);
669 return FEATURE_RETURN_HANGUP;
672 static int finishup(struct ast_channel *chan)
674 ast_indicate(chan, AST_CONTROL_UNHOLD);
676 return ast_autoservice_stop(chan);
679 /*! \brief Find the context for the transfer */
680 static const char *real_ctx(struct ast_channel *transferer, struct ast_channel *transferee)
682 const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT");
683 if (ast_strlen_zero(s))
684 s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT");
685 if (ast_strlen_zero(s)) /* Use the non-macro context to transfer the call XXX ? */
686 s = transferer->macrocontext;
687 if (ast_strlen_zero(s))
688 s = transferer->context;
689 return s;
692 static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
694 struct ast_channel *transferer;
695 struct ast_channel *transferee;
696 const char *transferer_real_context;
697 char xferto[256];
698 int res;
700 set_peers(&transferer, &transferee, peer, chan, sense);
701 transferer_real_context = real_ctx(transferer, transferee);
702 /* Start autoservice on chan while we talk to the originator */
703 ast_autoservice_start(transferee);
704 ast_indicate(transferee, AST_CONTROL_HOLD);
706 memset(xferto, 0, sizeof(xferto));
708 /* Transfer */
709 res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY);
710 if (res < 0) {
711 finishup(transferee);
712 return -1; /* error ? */
714 if (res > 0) /* If they've typed a digit already, handle it */
715 xferto[0] = (char) res;
717 ast_stopstream(transferer);
718 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
719 if (res < 0) { /* hangup, would be 0 for invalid and 1 for valid */
720 finishup(transferee);
721 return res;
723 if (!strcmp(xferto, ast_parking_ext())) {
724 res = finishup(transferee);
725 if (res)
726 res = -1;
727 else if (!ast_park_call(transferee, transferer, 0, NULL)) { /* success */
728 /* We return non-zero, but tell the PBX not to hang the channel when
729 the thread dies -- We have to be careful now though. We are responsible for
730 hanging up the channel, else it will never be hung up! */
732 return (transferer == peer) ? AST_PBX_KEEPALIVE : AST_PBX_NO_HANGUP_PEER;
733 } else {
734 ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name);
736 /*! \todo XXX Maybe we should have another message here instead of invalid extension XXX */
737 } else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
738 pbx_builtin_setvar_helper(transferer, "BLINDTRANSFER", transferee->name);
739 pbx_builtin_setvar_helper(transferee, "BLINDTRANSFER", transferer->name);
740 res=finishup(transferee);
741 if (!transferer->cdr) {
742 transferer->cdr=ast_cdr_alloc();
743 if (transferer) {
744 ast_cdr_init(transferer->cdr, transferer); /* initilize our channel's cdr */
745 ast_cdr_start(transferer->cdr);
748 if (transferer->cdr) {
749 ast_cdr_setdestchan(transferer->cdr, transferee->name);
750 ast_cdr_setapp(transferer->cdr, "BLINDTRANSFER","");
752 if (!transferee->pbx) {
753 /* Doh! Use our handy async_goto functions */
754 if (option_verbose > 2)
755 ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n"
756 ,transferee->name, xferto, transferer_real_context);
757 if (ast_async_goto(transferee, transferer_real_context, xferto, 1))
758 ast_log(LOG_WARNING, "Async goto failed :-(\n");
759 res = -1;
760 } else {
761 /* Set the channel's new extension, since it exists, using transferer context */
762 set_c_e_p(transferee, transferer_real_context, xferto, 0);
764 check_goto_on_transfer(transferer);
765 return res;
766 } else {
767 if (option_verbose > 2)
768 ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context);
770 if (ast_stream_and_wait(transferer, xferfailsound, transferer->language, AST_DIGIT_ANY) < 0 ) {
771 finishup(transferee);
772 return -1;
774 ast_stopstream(transferer);
775 res = finishup(transferee);
776 if (res) {
777 if (option_verbose > 1)
778 ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name);
779 return res;
781 return FEATURE_RETURN_SUCCESS;
784 static int check_compat(struct ast_channel *c, struct ast_channel *newchan)
786 if (ast_channel_make_compatible(c, newchan) < 0) {
787 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n",
788 c->name, newchan->name);
789 ast_hangup(newchan);
790 return -1;
792 return 0;
795 static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
797 struct ast_channel *transferer;
798 struct ast_channel *transferee;
799 const char *transferer_real_context;
800 char xferto[256] = "";
801 int res;
802 int outstate=0;
803 struct ast_channel *newchan;
804 struct ast_channel *xferchan;
805 struct ast_bridge_thread_obj *tobj;
806 struct ast_bridge_config bconfig;
807 struct ast_frame *f;
808 int l;
809 struct ast_datastore *features_datastore;
810 struct ast_dial_features *dialfeatures = NULL;
812 if (option_debug)
813 ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense);
814 set_peers(&transferer, &transferee, peer, chan, sense);
815 transferer_real_context = real_ctx(transferer, transferee);
816 /* Start autoservice on chan while we talk to the originator */
817 ast_autoservice_start(transferee);
818 ast_indicate(transferee, AST_CONTROL_HOLD);
820 /* Transfer */
821 res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY);
822 if (res < 0) {
823 finishup(transferee);
824 return res;
826 if (res > 0) /* If they've typed a digit already, handle it */
827 xferto[0] = (char) res;
829 /* this is specific of atxfer */
830 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
831 if (res < 0) { /* hangup, would be 0 for invalid and 1 for valid */
832 finishup(transferee);
833 return res;
835 if (res == 0) {
836 ast_log(LOG_WARNING, "Did not read data.\n");
837 finishup(transferee);
838 if (ast_stream_and_wait(transferer, "beeperr", transferer->language, ""))
839 return -1;
840 return FEATURE_RETURN_SUCCESS;
843 /* valid extension, res == 1 */
844 if (!ast_exists_extension(transferer, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
845 ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context);
846 finishup(transferee);
847 if (ast_stream_and_wait(transferer, "beeperr", transferer->language, ""))
848 return -1;
849 return FEATURE_RETURN_SUCCESS;
852 l = strlen(xferto);
853 snprintf(xferto + l, sizeof(xferto) - l, "@%s", transferer_real_context); /* append context */
854 newchan = ast_feature_request_and_dial(transferer, "Local", ast_best_codec(transferer->nativeformats),
855 xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, transferer->language);
857 /* If we are the callee and we are being transferred, after the masquerade
858 * caller features will really be the original callee features */
859 ast_channel_lock(transferee);
860 if ((features_datastore = ast_channel_datastore_find(transferee, &dial_features_info, NULL))) {
861 dialfeatures = features_datastore->data;
863 ast_channel_unlock(transferee);
865 if (dialfeatures && !dialfeatures->is_caller) {
866 ast_copy_flags(&(config->features_caller), &(dialfeatures->features_callee), AST_FLAGS_ALL);
869 ast_indicate(transferer, -1);
870 if (!newchan) {
871 finishup(transferee);
872 /* any reason besides user requested cancel and busy triggers the failed sound */
873 if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY &&
874 ast_stream_and_wait(transferer, xferfailsound, transferer->language, ""))
875 return -1;
876 return FEATURE_RETURN_SUCCESS;
879 if (check_compat(transferer, newchan)) {
880 /* we do mean transferee here, NOT transferer */
881 finishup(transferee);
882 return -1;
884 memset(&bconfig,0,sizeof(struct ast_bridge_config));
885 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
886 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
887 res = ast_bridge_call(transferer, newchan, &bconfig);
888 if (newchan->_softhangup || !transferer->_softhangup) {
889 ast_hangup(newchan);
890 if (ast_stream_and_wait(transferer, xfersound, transferer->language, ""))
891 ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
892 finishup(transferee);
893 transferer->_softhangup = 0;
894 return FEATURE_RETURN_SUCCESS;
897 if (check_compat(transferee, newchan)) {
898 finishup(transferee);
899 return -1;
902 ast_indicate(transferee, AST_CONTROL_UNHOLD);
904 if ((ast_autoservice_stop(transferee) < 0)
905 || (ast_waitfordigit(transferee, 100) < 0)
906 || (ast_waitfordigit(newchan, 100) < 0)
907 || ast_check_hangup(transferee)
908 || ast_check_hangup(newchan)) {
909 ast_hangup(newchan);
910 return -1;
913 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name);
914 if (!xferchan) {
915 ast_hangup(newchan);
916 return -1;
918 /* Make formats okay */
919 xferchan->visible_indication = transferer->visible_indication;
920 xferchan->readformat = transferee->readformat;
921 xferchan->writeformat = transferee->writeformat;
922 ast_channel_masquerade(xferchan, transferee);
923 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
924 xferchan->_state = AST_STATE_UP;
925 ast_clear_flag(xferchan, AST_FLAGS_ALL);
926 xferchan->_softhangup = 0;
928 if ((f = ast_read(xferchan)))
929 ast_frfree(f);
931 newchan->_state = AST_STATE_UP;
932 ast_clear_flag(newchan, AST_FLAGS_ALL);
933 newchan->_softhangup = 0;
935 tobj = ast_calloc(1, sizeof(struct ast_bridge_thread_obj));
936 if (!tobj) {
937 ast_hangup(xferchan);
938 ast_hangup(newchan);
939 return -1;
942 /* For the case where the transfer target is being connected with the original
943 caller store the target's original features, and apply to the bridge */
944 ast_channel_lock(newchan);
945 if ((features_datastore = ast_channel_datastore_find(newchan, &dial_features_info, NULL))) {
946 dialfeatures = features_datastore->data;
948 ast_channel_unlock(newchan);
950 if (dialfeatures) {
951 ast_copy_flags(&(config->features_callee), &(dialfeatures->features_callee), AST_FLAGS_ALL);
954 tobj->chan = newchan;
955 tobj->peer = xferchan;
956 tobj->bconfig = *config;
958 if (ast_stream_and_wait(newchan, xfersound, newchan->language, ""))
959 ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
960 ast_bridge_call_thread_launch(tobj);
961 return -1; /* XXX meaning the channel is bridged ? */
965 /* add atxfer and automon as undefined so you can only use em if you configure them */
966 #define FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0]))
968 AST_RWLOCK_DEFINE_STATIC(features_lock);
970 static struct ast_call_feature builtin_features[] =
972 { AST_FEATURE_REDIRECT, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
973 { AST_FEATURE_REDIRECT, "Attended Transfer", "atxfer", "", "", builtin_atxfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
974 { AST_FEATURE_AUTOMON, "One Touch Monitor", "automon", "", "", builtin_automonitor, AST_FEATURE_FLAG_NEEDSDTMF, "" },
975 { AST_FEATURE_DISCONNECT, "Disconnect Call", "disconnect", "*", "*", builtin_disconnect, AST_FEATURE_FLAG_NEEDSDTMF, "" },
976 { AST_FEATURE_PARKCALL, "Park Call", "parkcall", "", "", builtin_parkcall, AST_FEATURE_FLAG_NEEDSDTMF, "" },
980 static AST_LIST_HEAD_STATIC(feature_list,ast_call_feature);
982 /*! \brief register new feature into feature_list*/
983 void ast_register_feature(struct ast_call_feature *feature)
985 if (!feature) {
986 ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
987 return;
990 AST_LIST_LOCK(&feature_list);
991 AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry);
992 AST_LIST_UNLOCK(&feature_list);
994 if (option_verbose >= 2)
995 ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
998 /*! \brief unregister feature from feature_list */
999 void ast_unregister_feature(struct ast_call_feature *feature)
1001 if (!feature)
1002 return;
1004 AST_LIST_LOCK(&feature_list);
1005 AST_LIST_REMOVE(&feature_list,feature,feature_entry);
1006 AST_LIST_UNLOCK(&feature_list);
1007 free(feature);
1010 /*! \brief Remove all features in the list */
1011 static void ast_unregister_features(void)
1013 struct ast_call_feature *feature;
1015 AST_LIST_LOCK(&feature_list);
1016 while ((feature = AST_LIST_REMOVE_HEAD(&feature_list,feature_entry)))
1017 free(feature);
1018 AST_LIST_UNLOCK(&feature_list);
1021 /*! \brief find a feature by name */
1022 static struct ast_call_feature *find_dynamic_feature(const char *name)
1024 struct ast_call_feature *tmp;
1026 AST_LIST_TRAVERSE(&feature_list, tmp, feature_entry) {
1027 if (!strcasecmp(tmp->sname, name))
1028 break;
1031 return tmp;
1034 /*! \brief exec an app by feature */
1035 static int feature_exec_app(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
1037 struct ast_app *app;
1038 struct ast_call_feature *feature = data;
1039 struct ast_channel *work, *idle;
1040 int res;
1042 if (!feature) { /* shouldn't ever happen! */
1043 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
1044 return -1;
1047 if (sense == FEATURE_SENSE_CHAN) {
1048 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
1049 return FEATURE_RETURN_KEEPTRYING;
1050 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
1051 work = chan;
1052 idle = peer;
1053 } else {
1054 work = peer;
1055 idle = chan;
1057 } else {
1058 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
1059 return FEATURE_RETURN_KEEPTRYING;
1060 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
1061 work = peer;
1062 idle = chan;
1063 } else {
1064 work = chan;
1065 idle = peer;
1069 if (!(app = pbx_findapp(feature->app))) {
1070 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
1071 return -2;
1074 ast_autoservice_start(idle);
1076 if (!ast_strlen_zero(feature->moh_class))
1077 ast_moh_start(idle, feature->moh_class, NULL);
1079 res = pbx_exec(work, app, feature->app_args);
1081 if (!ast_strlen_zero(feature->moh_class))
1082 ast_moh_stop(idle);
1084 ast_autoservice_stop(idle);
1086 if (res == AST_PBX_KEEPALIVE)
1087 return FEATURE_RETURN_PBX_KEEPALIVE;
1088 else if (res == AST_PBX_NO_HANGUP_PEER)
1089 return FEATURE_RETURN_NO_HANGUP_PEER;
1090 else if (res)
1091 return FEATURE_RETURN_SUCCESSBREAK;
1093 return FEATURE_RETURN_SUCCESS; /*! \todo XXX should probably return res */
1096 static void unmap_features(void)
1098 int x;
1100 ast_rwlock_wrlock(&features_lock);
1101 for (x = 0; x < FEATURES_COUNT; x++)
1102 strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
1103 ast_rwlock_unlock(&features_lock);
1106 static int remap_feature(const char *name, const char *value)
1108 int x, res = -1;
1110 ast_rwlock_wrlock(&features_lock);
1111 for (x = 0; x < FEATURES_COUNT; x++) {
1112 if (strcasecmp(builtin_features[x].sname, name))
1113 continue;
1115 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
1116 res = 0;
1117 break;
1119 ast_rwlock_unlock(&features_lock);
1121 return res;
1124 static int ast_feature_interpret(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
1126 int x;
1127 struct ast_flags features;
1128 int res = FEATURE_RETURN_PASSDIGITS;
1129 struct ast_call_feature *feature;
1130 const char *dynamic_features;
1131 char *tmp, *tok;
1133 if (sense == FEATURE_SENSE_CHAN) {
1134 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
1135 dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
1136 } else {
1137 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);
1138 dynamic_features = pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES");
1140 if (option_debug > 2)
1141 ast_log(LOG_DEBUG, "Feature interpret: chan=%s, peer=%s, code=%s, sense=%d, features=%d dynamic=%s\n", chan->name, peer->name, code, sense, features.flags, dynamic_features);
1143 ast_rwlock_rdlock(&features_lock);
1144 for (x = 0; x < FEATURES_COUNT; x++) {
1145 if ((ast_test_flag(&features, builtin_features[x].feature_mask)) &&
1146 !ast_strlen_zero(builtin_features[x].exten)) {
1147 /* Feature is up for consideration */
1148 if (!strcmp(builtin_features[x].exten, code)) {
1149 res = builtin_features[x].operation(chan, peer, config, code, sense, NULL);
1150 break;
1151 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
1152 if (res == FEATURE_RETURN_PASSDIGITS)
1153 res = FEATURE_RETURN_STOREDIGITS;
1157 ast_rwlock_unlock(&features_lock);
1159 if (ast_strlen_zero(dynamic_features))
1160 return res;
1162 tmp = ast_strdupa(dynamic_features);
1164 while ((tok = strsep(&tmp, "#"))) {
1165 AST_LIST_LOCK(&feature_list);
1166 if (!(feature = find_dynamic_feature(tok))) {
1167 AST_LIST_UNLOCK(&feature_list);
1168 continue;
1171 /* Feature is up for consideration */
1172 if (!strcmp(feature->exten, code)) {
1173 if (option_verbose > 2)
1174 ast_verbose(VERBOSE_PREFIX_3 " Feature Found: %s exten: %s\n",feature->sname, tok);
1175 res = feature->operation(chan, peer, config, code, sense, feature);
1176 if (res != FEATURE_RETURN_KEEPTRYING) {
1177 AST_LIST_UNLOCK(&feature_list);
1178 break;
1180 res = FEATURE_RETURN_PASSDIGITS;
1181 } else if (!strncmp(feature->exten, code, strlen(code)))
1182 res = FEATURE_RETURN_STOREDIGITS;
1184 AST_LIST_UNLOCK(&feature_list);
1187 return res;
1190 static void set_config_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
1192 int x;
1194 ast_clear_flag(config, AST_FLAGS_ALL);
1196 ast_rwlock_rdlock(&features_lock);
1197 for (x = 0; x < FEATURES_COUNT; x++) {
1198 if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF))
1199 continue;
1201 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
1202 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
1204 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
1205 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
1207 ast_rwlock_unlock(&features_lock);
1209 if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
1210 const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
1212 if (dynamic_features) {
1213 char *tmp = ast_strdupa(dynamic_features);
1214 char *tok;
1215 struct ast_call_feature *feature;
1217 /* while we have a feature */
1218 while ((tok = strsep(&tmp, "#"))) {
1219 AST_LIST_LOCK(&feature_list);
1220 if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
1221 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
1222 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
1223 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
1224 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
1226 AST_LIST_UNLOCK(&feature_list);
1232 /*! \todo XXX Check - this is very similar to the code in channel.c */
1233 static struct ast_channel *ast_feature_request_and_dial(struct ast_channel *caller, const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name, const char *language)
1235 int state = 0;
1236 int cause = 0;
1237 int to;
1238 struct ast_channel *chan;
1239 struct ast_channel *monitor_chans[2];
1240 struct ast_channel *active_channel;
1241 int res = 0, ready = 0;
1243 if ((chan = ast_request(type, format, data, &cause))) {
1244 ast_set_callerid(chan, cid_num, cid_name, cid_num);
1245 ast_string_field_set(chan, language, language);
1246 ast_channel_inherit_variables(caller, chan);
1247 pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name);
1249 if (!ast_call(chan, data, timeout)) {
1250 struct timeval started;
1251 int x, len = 0;
1252 char *disconnect_code = NULL, *dialed_code = NULL;
1254 ast_indicate(caller, AST_CONTROL_RINGING);
1255 /* support dialing of the featuremap disconnect code while performing an attended tranfer */
1256 ast_rwlock_rdlock(&features_lock);
1257 for (x = 0; x < FEATURES_COUNT; x++) {
1258 if (strcasecmp(builtin_features[x].sname, "disconnect"))
1259 continue;
1261 disconnect_code = builtin_features[x].exten;
1262 len = strlen(disconnect_code) + 1;
1263 dialed_code = alloca(len);
1264 memset(dialed_code, 0, len);
1265 break;
1267 ast_rwlock_unlock(&features_lock);
1268 x = 0;
1269 started = ast_tvnow();
1270 to = timeout;
1271 while (!ast_check_hangup(caller) && timeout && (chan->_state != AST_STATE_UP)) {
1272 struct ast_frame *f = NULL;
1274 monitor_chans[0] = caller;
1275 monitor_chans[1] = chan;
1276 active_channel = ast_waitfor_n(monitor_chans, 2, &to);
1278 /* see if the timeout has been violated */
1279 if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
1280 state = AST_CONTROL_UNHOLD;
1281 ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n");
1282 break; /*doh! timeout*/
1285 if (!active_channel)
1286 continue;
1288 if (chan && (chan == active_channel)){
1289 f = ast_read(chan);
1290 if (f == NULL) { /*doh! where'd he go?*/
1291 state = AST_CONTROL_HANGUP;
1292 res = 0;
1293 break;
1296 if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) {
1297 if (f->subclass == AST_CONTROL_RINGING) {
1298 state = f->subclass;
1299 if (option_verbose > 2)
1300 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", chan->name);
1301 ast_indicate(caller, AST_CONTROL_RINGING);
1302 } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) {
1303 state = f->subclass;
1304 if (option_verbose > 2)
1305 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", chan->name);
1306 ast_indicate(caller, AST_CONTROL_BUSY);
1307 ast_frfree(f);
1308 f = NULL;
1309 break;
1310 } else if (f->subclass == AST_CONTROL_ANSWER) {
1311 /* This is what we are hoping for */
1312 state = f->subclass;
1313 ast_frfree(f);
1314 f = NULL;
1315 ready=1;
1316 break;
1317 } else if (f->subclass != -1) {
1318 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass);
1320 /* else who cares */
1323 } else if (caller && (active_channel == caller)) {
1324 f = ast_read(caller);
1325 if (f == NULL) { /*doh! where'd he go?*/
1326 if (caller->_softhangup && !chan->_softhangup) {
1327 /* make this a blind transfer */
1328 ready = 1;
1329 break;
1331 state = AST_CONTROL_HANGUP;
1332 res = 0;
1333 break;
1336 if (f->frametype == AST_FRAME_DTMF) {
1337 dialed_code[x++] = f->subclass;
1338 dialed_code[x] = '\0';
1339 if (strlen(dialed_code) == len) {
1340 x = 0;
1341 } else if (x && strncmp(dialed_code, disconnect_code, x)) {
1342 x = 0;
1343 dialed_code[x] = '\0';
1345 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
1346 /* Caller Canceled the call */
1347 state = AST_CONTROL_UNHOLD;
1348 ast_frfree(f);
1349 f = NULL;
1350 break;
1354 if (f)
1355 ast_frfree(f);
1356 } /* end while */
1357 } else
1358 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
1359 } else {
1360 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
1361 switch(cause) {
1362 case AST_CAUSE_BUSY:
1363 state = AST_CONTROL_BUSY;
1364 break;
1365 case AST_CAUSE_CONGESTION:
1366 state = AST_CONTROL_CONGESTION;
1367 break;
1371 ast_indicate(caller, -1);
1372 if (chan && ready) {
1373 if (chan->_state == AST_STATE_UP)
1374 state = AST_CONTROL_ANSWER;
1375 res = 0;
1376 } else if(chan) {
1377 res = -1;
1378 ast_hangup(chan);
1379 chan = NULL;
1380 } else {
1381 res = -1;
1384 if (outstate)
1385 *outstate = state;
1387 return chan;
1390 int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast_bridge_config *config)
1392 /* Copy voice back and forth between the two channels. Give the peer
1393 the ability to transfer calls with '#<extension' syntax. */
1394 struct ast_frame *f;
1395 struct ast_channel *who;
1396 char chan_featurecode[FEATURE_MAX_LEN + 1]="";
1397 char peer_featurecode[FEATURE_MAX_LEN + 1]="";
1398 char orig_channame[AST_MAX_EXTENSION];
1399 char orig_peername[AST_MAX_EXTENSION];
1401 int res;
1402 int diff;
1403 int hasfeatures=0;
1404 int hadfeatures=0;
1405 struct ast_option_header *aoh;
1406 struct ast_bridge_config backup_config;
1407 struct ast_cdr *bridge_cdr = NULL;
1409 memset(&backup_config, 0, sizeof(backup_config));
1411 config->start_time = ast_tvnow();
1413 if (chan && peer) {
1414 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
1415 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
1416 } else if (chan)
1417 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
1419 if (monitor_ok) {
1420 const char *monitor_exec;
1421 struct ast_channel *src = NULL;
1422 if (!monitor_app) {
1423 if (!(monitor_app = pbx_findapp("Monitor")))
1424 monitor_ok=0;
1426 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR")))
1427 src = chan;
1428 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
1429 src = peer;
1430 if (monitor_app && src) {
1431 char *tmp = ast_strdupa(monitor_exec);
1432 pbx_exec(src, monitor_app, tmp);
1436 set_config_flags(chan, peer, config);
1437 config->firstpass = 1;
1439 /* Answer if need be */
1440 if (ast_answer(chan))
1441 return -1;
1443 ast_copy_string(orig_channame,chan->name,sizeof(orig_channame));
1444 ast_copy_string(orig_peername,peer->name,sizeof(orig_peername));
1446 if (!chan->cdr || (chan->cdr && !ast_test_flag(chan->cdr, AST_CDR_FLAG_POST_DISABLED))) {
1448 if (chan->cdr) {
1449 ast_set_flag(chan->cdr, AST_CDR_FLAG_MAIN);
1450 ast_cdr_update(chan);
1451 bridge_cdr = ast_cdr_dup(chan->cdr);
1452 ast_copy_string(bridge_cdr->lastapp, chan->appl, sizeof(bridge_cdr->lastapp));
1453 ast_copy_string(bridge_cdr->lastdata, chan->data, sizeof(bridge_cdr->lastdata));
1454 } else {
1455 /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */
1456 bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */
1457 ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel));
1458 ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel));
1459 ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid));
1460 ast_copy_string(bridge_cdr->lastapp, chan->appl, sizeof(bridge_cdr->lastapp));
1461 ast_copy_string(bridge_cdr->lastdata, chan->data, sizeof(bridge_cdr->lastdata));
1462 ast_cdr_setcid(bridge_cdr, chan);
1463 bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ? AST_CDR_ANSWERED : AST_CDR_NULL;
1464 bridge_cdr->amaflags = chan->amaflags ? chan->amaflags : ast_default_amaflags;
1465 ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode));
1466 /* Destination information */
1467 ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst));
1468 ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext));
1469 if (peer->cdr) {
1470 bridge_cdr->start = peer->cdr->start;
1471 ast_copy_string(bridge_cdr->userfield, peer->cdr->userfield, sizeof(bridge_cdr->userfield));
1472 } else {
1473 ast_cdr_start(bridge_cdr);
1476 ast_cdr_answer(bridge_cdr);
1477 ast_cdr_answer(chan->cdr); /* for the sake of cli status checks */
1478 ast_set_flag(chan->cdr, AST_CDR_FLAG_BRIDGED);
1479 if (peer->cdr)
1480 ast_set_flag(peer->cdr, AST_CDR_FLAG_BRIDGED);
1483 for (;;) {
1484 struct ast_channel *other; /* used later */
1486 res = ast_channel_bridge(chan, peer, config, &f, &who);
1488 if (config->feature_timer) {
1489 /* Update time limit for next pass */
1490 diff = ast_tvdiff_ms(ast_tvnow(), config->start_time);
1491 config->feature_timer -= diff;
1492 if (hasfeatures) {
1493 /* Running on backup config, meaning a feature might be being
1494 activated, but that's no excuse to keep things going
1495 indefinitely! */
1496 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
1497 if (option_debug)
1498 ast_log(LOG_DEBUG, "Timed out, realtime this time!\n");
1499 config->feature_timer = 0;
1500 who = chan;
1501 if (f)
1502 ast_frfree(f);
1503 f = NULL;
1504 res = 0;
1505 } else if (config->feature_timer <= 0) {
1506 /* Not *really* out of time, just out of time for
1507 digits to come in for features. */
1508 if (option_debug)
1509 ast_log(LOG_DEBUG, "Timed out for feature!\n");
1510 if (!ast_strlen_zero(peer_featurecode)) {
1511 ast_dtmf_stream(chan, peer, peer_featurecode, 0);
1512 memset(peer_featurecode, 0, sizeof(peer_featurecode));
1514 if (!ast_strlen_zero(chan_featurecode)) {
1515 ast_dtmf_stream(peer, chan, chan_featurecode, 0);
1516 memset(chan_featurecode, 0, sizeof(chan_featurecode));
1518 if (f)
1519 ast_frfree(f);
1520 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
1521 if (!hasfeatures) {
1522 /* Restore original (possibly time modified) bridge config */
1523 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
1524 memset(&backup_config, 0, sizeof(backup_config));
1526 hadfeatures = hasfeatures;
1527 /* Continue as we were */
1528 continue;
1529 } else if (!f) {
1530 /* The bridge returned without a frame and there is a feature in progress.
1531 * However, we don't think the feature has quite yet timed out, so just
1532 * go back into the bridge. */
1533 continue;
1535 } else {
1536 if (config->feature_timer <=0) {
1537 /* We ran out of time */
1538 config->feature_timer = 0;
1539 who = chan;
1540 if (f)
1541 ast_frfree(f);
1542 f = NULL;
1543 res = 0;
1547 if (res < 0) {
1548 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer))
1549 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
1550 return -1;
1553 if (!f || (f->frametype == AST_FRAME_CONTROL &&
1554 (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY ||
1555 f->subclass == AST_CONTROL_CONGESTION ) ) ) {
1556 res = -1;
1557 break;
1559 /* many things should be sent to the 'other' channel */
1560 other = (who == chan) ? peer : chan;
1561 if (f->frametype == AST_FRAME_CONTROL) {
1562 switch (f->subclass) {
1563 case AST_CONTROL_RINGING:
1564 case AST_CONTROL_FLASH:
1565 case -1:
1566 ast_indicate(other, f->subclass);
1567 break;
1568 case AST_CONTROL_HOLD:
1569 case AST_CONTROL_UNHOLD:
1570 ast_indicate_data(other, f->subclass, f->data, f->datalen);
1571 break;
1572 case AST_CONTROL_OPTION:
1573 aoh = f->data;
1574 /* Forward option Requests */
1575 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) {
1576 ast_channel_setoption(other, ntohs(aoh->option), aoh->data,
1577 f->datalen - sizeof(struct ast_option_header), 0);
1579 break;
1581 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
1582 /* eat it */
1583 } else if (f->frametype == AST_FRAME_DTMF) {
1584 char *featurecode;
1585 int sense;
1587 hadfeatures = hasfeatures;
1588 /* This cannot overrun because the longest feature is one shorter than our buffer */
1589 if (who == chan) {
1590 sense = FEATURE_SENSE_CHAN;
1591 featurecode = chan_featurecode;
1592 } else {
1593 sense = FEATURE_SENSE_PEER;
1594 featurecode = peer_featurecode;
1596 /*! append the event to featurecode. we rely on the string being zero-filled, and
1597 * not overflowing it.
1598 * \todo XXX how do we guarantee the latter ?
1600 featurecode[strlen(featurecode)] = f->subclass;
1601 /* Get rid of the frame before we start doing "stuff" with the channels */
1602 ast_frfree(f);
1603 f = NULL;
1604 config->feature_timer = backup_config.feature_timer;
1605 res = ast_feature_interpret(chan, peer, config, featurecode, sense);
1606 switch(res) {
1607 case FEATURE_RETURN_PASSDIGITS:
1608 ast_dtmf_stream(other, who, featurecode, 0);
1609 /* Fall through */
1610 case FEATURE_RETURN_SUCCESS:
1611 memset(featurecode, 0, sizeof(chan_featurecode));
1612 break;
1614 if (res >= FEATURE_RETURN_PASSDIGITS) {
1615 res = 0;
1616 } else
1617 break;
1618 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
1619 if (hadfeatures && !hasfeatures) {
1620 /* Restore backup */
1621 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
1622 memset(&backup_config, 0, sizeof(struct ast_bridge_config));
1623 } else if (hasfeatures) {
1624 if (!hadfeatures) {
1625 /* Backup configuration */
1626 memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
1627 /* Setup temporary config options */
1628 config->play_warning = 0;
1629 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
1630 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
1631 config->warning_freq = 0;
1632 config->warning_sound = NULL;
1633 config->end_sound = NULL;
1634 config->start_sound = NULL;
1635 config->firstpass = 0;
1637 config->start_time = ast_tvnow();
1638 config->feature_timer = featuredigittimeout;
1639 if (option_debug)
1640 ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer);
1643 if (f)
1644 ast_frfree(f);
1647 /* obey the NoCDR() wishes. */
1648 if (!chan->cdr || (chan->cdr && !ast_test_flag(chan->cdr, AST_CDR_FLAG_POST_DISABLED))) {
1650 ast_cdr_end(bridge_cdr);
1652 ast_cdr_detach(bridge_cdr);
1654 /* just in case, these channels get bridged again before hangup */
1655 if (chan->cdr)
1656 ast_cdr_specialized_reset(chan->cdr,0);
1657 if (peer->cdr)
1658 ast_cdr_specialized_reset(peer->cdr,0);
1661 return res;
1664 static void post_manager_event(const char *s, char *parkingexten, struct ast_channel *chan)
1666 manager_event(EVENT_FLAG_CALL, s,
1667 "Exten: %s\r\n"
1668 "Channel: %s\r\n"
1669 "CallerID: %s\r\n"
1670 "CallerIDName: %s\r\n\r\n",
1671 parkingexten,
1672 chan->name,
1673 S_OR(chan->cid.cid_num, "<unknown>"),
1674 S_OR(chan->cid.cid_name, "<unknown>")
1678 /*! \brief Take care of parked calls and unpark them if needed */
1679 static void *do_parking_thread(void *ignore)
1681 fd_set rfds, efds; /* results from previous select, to be preserved across loops. */
1682 FD_ZERO(&rfds);
1683 FD_ZERO(&efds);
1685 for (;;) {
1686 struct parkeduser *pu, *pl, *pt = NULL;
1687 int ms = -1; /* select timeout, uninitialized */
1688 int max = -1; /* max fd, none there yet */
1689 fd_set nrfds, nefds; /* args for the next select */
1690 FD_ZERO(&nrfds);
1691 FD_ZERO(&nefds);
1693 ast_mutex_lock(&parking_lock);
1694 pl = NULL;
1695 pu = parkinglot;
1696 /* navigate the list with prev-cur pointers to support removals */
1697 while (pu) {
1698 struct ast_channel *chan = pu->chan; /* shorthand */
1699 int tms; /* timeout for this item */
1700 int x; /* fd index in channel */
1701 struct ast_context *con;
1703 if (pu->notquiteyet) { /* Pretend this one isn't here yet */
1704 pl = pu;
1705 pu = pu->next;
1706 continue;
1708 tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
1709 if (tms > pu->parkingtime) {
1710 ast_indicate(chan, AST_CONTROL_UNHOLD);
1711 /* Get chan, exten from derived kludge */
1712 if (pu->peername[0]) {
1713 char *peername = ast_strdupa(pu->peername);
1714 char *cp = strrchr(peername, '-');
1715 if (cp)
1716 *cp = 0;
1717 con = ast_context_find(parking_con_dial);
1718 if (!con) {
1719 con = ast_context_create(NULL, parking_con_dial, registrar);
1720 if (!con)
1721 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
1723 if (con) {
1724 char returnexten[AST_MAX_EXTENSION];
1725 struct ast_datastore *features_datastore;
1726 struct ast_dial_features *dialfeatures = NULL;
1728 ast_channel_lock(chan);
1730 if ((features_datastore = ast_channel_datastore_find(chan, &dial_features_info, NULL)))
1731 dialfeatures = features_datastore->data;
1733 ast_channel_unlock(chan);
1735 if (dialfeatures)
1736 snprintf(returnexten, sizeof(returnexten), "%s|30|%s", peername, dialfeatures->options);
1737 else /* Existing default */
1738 snprintf(returnexten, sizeof(returnexten), "%s|30|t", peername);
1740 ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), ast_free, registrar);
1742 set_c_e_p(chan, parking_con_dial, peername, 1);
1743 } else {
1744 /* They've been waiting too long, send them back to where they came. Theoretically they
1745 should have their original extensions and such, but we copy to be on the safe side */
1746 set_c_e_p(chan, pu->context, pu->exten, pu->priority);
1749 post_manager_event("ParkedCallTimeOut", pu->parkingexten, chan);
1751 if (option_verbose > 1)
1752 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);
1753 /* Start up the PBX, or hang them up */
1754 if (ast_pbx_start(chan)) {
1755 ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", chan->name);
1756 ast_hangup(chan);
1758 /* And take them out of the parking lot */
1759 if (pl)
1760 pl->next = pu->next;
1761 else
1762 parkinglot = pu->next;
1763 pt = pu;
1764 pu = pu->next;
1765 con = ast_context_find(parking_con);
1766 if (con) {
1767 if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL))
1768 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1769 else
1770 notify_metermaids(pt->parkingexten, parking_con);
1771 } else
1772 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1773 free(pt);
1774 } else { /* still within parking time, process descriptors */
1775 for (x = 0; x < AST_MAX_FDS; x++) {
1776 struct ast_frame *f;
1778 if (chan->fds[x] == -1 || (!FD_ISSET(chan->fds[x], &rfds) && !FD_ISSET(chan->fds[x], &efds)))
1779 continue; /* nothing on this descriptor */
1781 if (FD_ISSET(chan->fds[x], &efds))
1782 ast_set_flag(chan, AST_FLAG_EXCEPTION);
1783 else
1784 ast_clear_flag(chan, AST_FLAG_EXCEPTION);
1785 chan->fdno = x;
1787 /* See if they need servicing */
1788 f = ast_read(chan);
1789 if (!f || (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_HANGUP)) {
1790 if (f)
1791 ast_frfree(f);
1792 post_manager_event("ParkedCallGiveUp", pu->parkingexten, chan);
1794 /* There's a problem, hang them up*/
1795 if (option_verbose > 1)
1796 ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", chan->name);
1797 ast_hangup(chan);
1798 /* And take them out of the parking lot */
1799 if (pl)
1800 pl->next = pu->next;
1801 else
1802 parkinglot = pu->next;
1803 pt = pu;
1804 pu = pu->next;
1805 con = ast_context_find(parking_con);
1806 if (con) {
1807 if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL))
1808 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1809 else
1810 notify_metermaids(pt->parkingexten, parking_con);
1811 } else
1812 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1813 free(pt);
1814 break;
1815 } else {
1816 /*! \todo XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
1817 ast_frfree(f);
1818 if (pu->moh_trys < 3 && !chan->generatordata) {
1819 if (option_debug)
1820 ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source. Restarting.\n");
1821 ast_indicate_data(pu->chan, AST_CONTROL_HOLD,
1822 S_OR(parkmohclass, NULL),
1823 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
1824 pu->moh_trys++;
1826 goto std; /*! \todo XXX Ick: jumping into an else statement??? XXX */
1829 } /* end for */
1830 if (x >= AST_MAX_FDS) {
1831 std: for (x=0; x<AST_MAX_FDS; x++) { /* mark fds for next round */
1832 if (chan->fds[x] > -1) {
1833 FD_SET(chan->fds[x], &nrfds);
1834 FD_SET(chan->fds[x], &nefds);
1835 if (chan->fds[x] > max)
1836 max = chan->fds[x];
1839 /* Keep track of our shortest wait */
1840 if (tms < ms || ms < 0)
1841 ms = tms;
1842 pl = pu;
1843 pu = pu->next;
1846 } /* end while */
1847 ast_mutex_unlock(&parking_lock);
1848 rfds = nrfds;
1849 efds = nefds;
1851 struct timeval tv = ast_samp2tv(ms, 1000);
1852 /* Wait for something to happen */
1853 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
1855 pthread_testcancel();
1857 return NULL; /* Never reached */
1860 /*! \brief Park a call */
1861 static int park_call_exec(struct ast_channel *chan, void *data)
1863 /* Cache the original channel name in case we get masqueraded in the middle
1864 * of a park--it is still theoretically possible for a transfer to happen before
1865 * we get here, but it is _really_ unlikely */
1866 char *orig_chan_name = ast_strdupa(chan->name);
1867 char orig_exten[AST_MAX_EXTENSION];
1868 int orig_priority = chan->priority;
1870 /* Data is unused at the moment but could contain a parking
1871 lot context eventually */
1872 int res = 0;
1873 struct ast_module_user *u;
1875 u = ast_module_user_add(chan);
1877 ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten));
1879 /* Setup the exten/priority to be s/1 since we don't know
1880 where this call should return */
1881 strcpy(chan->exten, "s");
1882 chan->priority = 1;
1883 /* Answer if call is not up */
1884 if (chan->_state != AST_STATE_UP)
1885 res = ast_answer(chan);
1886 /* Sleep to allow VoIP streams to settle down */
1887 if (!res)
1888 res = ast_safe_sleep(chan, 1000);
1889 /* Park the call */
1890 if (!res) {
1891 res = park_call_full(chan, chan, 0, NULL, orig_chan_name);
1892 /* Continue on in the dialplan */
1893 if (res == 1) {
1894 ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten));
1895 chan->priority = orig_priority;
1896 res = 0;
1897 } else if (!res)
1898 res = AST_PBX_KEEPALIVE;
1901 ast_module_user_remove(u);
1903 return res;
1906 /*! \brief Pickup parked call */
1907 static int park_exec(struct ast_channel *chan, void *data)
1909 int res = 0;
1910 struct ast_module_user *u;
1911 struct ast_channel *peer=NULL;
1912 struct parkeduser *pu, *pl=NULL;
1913 struct ast_context *con;
1915 int park;
1916 struct ast_bridge_config config;
1918 if (!data) {
1919 ast_log(LOG_WARNING, "Parkedcall requires an argument (extension number)\n");
1920 return -1;
1923 u = ast_module_user_add(chan);
1925 park = atoi((char *)data);
1926 ast_mutex_lock(&parking_lock);
1927 pu = parkinglot;
1928 while(pu) {
1929 if (pu->parkingnum == park) {
1930 if (pl)
1931 pl->next = pu->next;
1932 else
1933 parkinglot = pu->next;
1934 break;
1936 pl = pu;
1937 pu = pu->next;
1939 ast_mutex_unlock(&parking_lock);
1940 if (pu) {
1941 peer = pu->chan;
1942 con = ast_context_find(parking_con);
1943 if (con) {
1944 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL))
1945 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1946 else
1947 notify_metermaids(pu->parkingexten, parking_con);
1948 } else
1949 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1951 manager_event(EVENT_FLAG_CALL, "UnParkedCall",
1952 "Exten: %s\r\n"
1953 "Channel: %s\r\n"
1954 "From: %s\r\n"
1955 "CallerID: %s\r\n"
1956 "CallerIDName: %s\r\n",
1957 pu->parkingexten, pu->chan->name, chan->name,
1958 S_OR(pu->chan->cid.cid_num, "<unknown>"),
1959 S_OR(pu->chan->cid.cid_name, "<unknown>")
1962 free(pu);
1964 /* JK02: it helps to answer the channel if not already up */
1965 if (chan->_state != AST_STATE_UP)
1966 ast_answer(chan);
1968 if (peer) {
1969 /* Play a courtesy to the source(s) configured to prefix the bridge connecting */
1971 if (!ast_strlen_zero(courtesytone)) {
1972 int error = 0;
1973 ast_indicate(peer, AST_CONTROL_UNHOLD);
1974 if (parkedplay == 0) {
1975 error = ast_stream_and_wait(chan, courtesytone, chan->language, "");
1976 } else if (parkedplay == 1) {
1977 error = ast_stream_and_wait(peer, courtesytone, chan->language, "");
1978 } else if (parkedplay == 2) {
1979 if (!ast_streamfile(chan, courtesytone, chan->language) &&
1980 !ast_streamfile(peer, courtesytone, chan->language)) {
1981 /*! \todo XXX we would like to wait on both! */
1982 res = ast_waitstream(chan, "");
1983 if (res >= 0)
1984 res = ast_waitstream(peer, "");
1985 if (res < 0)
1986 error = 1;
1989 if (error) {
1990 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
1991 ast_hangup(peer);
1992 ast_module_user_remove(u);
1993 return -1;
1995 } else
1996 ast_indicate(peer, AST_CONTROL_UNHOLD);
1998 res = ast_channel_make_compatible(chan, peer);
1999 if (res < 0) {
2000 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
2001 ast_hangup(peer);
2002 ast_module_user_remove(u);
2003 return -1;
2005 /* This runs sorta backwards, since we give the incoming channel control, as if it
2006 were the person called. */
2007 if (option_verbose > 2)
2008 ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
2010 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
2011 ast_cdr_setdestchan(chan->cdr, peer->name);
2012 memset(&config, 0, sizeof(struct ast_bridge_config));
2013 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
2014 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
2015 res = ast_bridge_call(chan, peer, &config);
2017 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
2018 ast_cdr_setdestchan(chan->cdr, peer->name);
2020 /* Simulate the PBX hanging up */
2021 if (res != AST_PBX_NO_HANGUP_PEER)
2022 ast_hangup(peer);
2023 ast_module_user_remove(u);
2024 return res;
2025 } else {
2026 /*! \todo XXX Play a message XXX */
2027 if (ast_stream_and_wait(chan, "pbx-invalidpark", chan->language, ""))
2028 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
2029 if (option_verbose > 2)
2030 ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
2031 res = -1;
2034 ast_module_user_remove(u);
2036 return res;
2039 static int handle_showfeatures(int fd, int argc, char *argv[])
2041 int i;
2042 struct ast_call_feature *feature;
2043 char format[] = "%-25s %-7s %-7s\n";
2045 ast_cli(fd, format, "Builtin Feature", "Default", "Current");
2046 ast_cli(fd, format, "---------------", "-------", "-------");
2048 ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */
2050 ast_rwlock_rdlock(&features_lock);
2051 for (i = 0; i < FEATURES_COUNT; i++)
2052 ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
2053 ast_rwlock_unlock(&features_lock);
2055 ast_cli(fd, "\n");
2056 ast_cli(fd, format, "Dynamic Feature", "Default", "Current");
2057 ast_cli(fd, format, "---------------", "-------", "-------");
2058 if (AST_LIST_EMPTY(&feature_list))
2059 ast_cli(fd, "(none)\n");
2060 else {
2061 AST_LIST_LOCK(&feature_list);
2062 AST_LIST_TRAVERSE(&feature_list, feature, feature_entry)
2063 ast_cli(fd, format, feature->sname, "no def", feature->exten);
2064 AST_LIST_UNLOCK(&feature_list);
2066 ast_cli(fd, "\nCall parking\n");
2067 ast_cli(fd, "------------\n");
2068 ast_cli(fd,"%-20s: %s\n", "Parking extension", parking_ext);
2069 ast_cli(fd,"%-20s: %s\n", "Parking context", parking_con);
2070 ast_cli(fd,"%-20s: %d-%d\n", "Parked call extensions", parking_start, parking_stop);
2071 ast_cli(fd,"\n");
2073 return RESULT_SUCCESS;
2076 static char showfeatures_help[] =
2077 "Usage: feature list\n"
2078 " Lists currently configured features.\n";
2080 static int handle_parkedcalls(int fd, int argc, char *argv[])
2082 struct parkeduser *cur;
2083 int numparked = 0;
2085 ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
2086 , "Context", "Extension", "Pri", "Timeout");
2088 ast_mutex_lock(&parking_lock);
2090 for (cur = parkinglot; cur; cur = cur->next) {
2091 ast_cli(fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n"
2092 ,cur->parkingexten, cur->chan->name, cur->context, cur->exten
2093 ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
2095 numparked++;
2097 ast_mutex_unlock(&parking_lock);
2098 ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : "");
2101 return RESULT_SUCCESS;
2104 static char showparked_help[] =
2105 "Usage: show parkedcalls\n"
2106 " Lists currently parked calls.\n";
2108 static struct ast_cli_entry cli_show_features_deprecated = {
2109 { "show", "features", NULL },
2110 handle_showfeatures, NULL,
2111 NULL };
2113 static struct ast_cli_entry cli_features[] = {
2114 { { "feature", "show", NULL },
2115 handle_showfeatures, "Lists configured features",
2116 showfeatures_help, NULL, &cli_show_features_deprecated },
2118 { { "show", "parkedcalls", NULL },
2119 handle_parkedcalls, "Lists parked calls",
2120 showparked_help },
2123 /*! \brief Dump lot status */
2124 static int manager_parking_status( struct mansession *s, const struct message *m)
2126 struct parkeduser *cur;
2127 const char *id = astman_get_header(m, "ActionID");
2128 char idText[256] = "";
2130 if (!ast_strlen_zero(id))
2131 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
2133 astman_send_ack(s, m, "Parked calls will follow");
2135 ast_mutex_lock(&parking_lock);
2137 for (cur = parkinglot; cur; cur = cur->next) {
2138 astman_append(s, "Event: ParkedCall\r\n"
2139 "Exten: %d\r\n"
2140 "Channel: %s\r\n"
2141 "From: %s\r\n"
2142 "Timeout: %ld\r\n"
2143 "CallerID: %s\r\n"
2144 "CallerIDName: %s\r\n"
2145 "%s"
2146 "\r\n",
2147 cur->parkingnum, cur->chan->name, cur->peername,
2148 (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
2149 S_OR(cur->chan->cid.cid_num, ""), /* XXX in other places it is <unknown> */
2150 S_OR(cur->chan->cid.cid_name, ""),
2151 idText);
2154 astman_append(s,
2155 "Event: ParkedCallsComplete\r\n"
2156 "%s"
2157 "\r\n",idText);
2159 ast_mutex_unlock(&parking_lock);
2161 return RESULT_SUCCESS;
2164 static char mandescr_park[] =
2165 "Description: Park a channel.\n"
2166 "Variables: (Names marked with * are required)\n"
2167 " *Channel: Channel name to park\n"
2168 " *Channel2: Channel to announce park info to (and return to if timeout)\n"
2169 " Timeout: Number of milliseconds to wait before callback.\n";
2171 static int manager_park(struct mansession *s, const struct message *m)
2173 const char *channel = astman_get_header(m, "Channel");
2174 const char *channel2 = astman_get_header(m, "Channel2");
2175 const char *timeout = astman_get_header(m, "Timeout");
2176 char buf[BUFSIZ];
2177 int to = 0;
2178 int res = 0;
2179 int parkExt = 0;
2180 struct ast_channel *ch1, *ch2;
2182 if (ast_strlen_zero(channel)) {
2183 astman_send_error(s, m, "Channel not specified");
2184 return 0;
2187 if (ast_strlen_zero(channel2)) {
2188 astman_send_error(s, m, "Channel2 not specified");
2189 return 0;
2192 ch1 = ast_get_channel_by_name_locked(channel);
2193 if (!ch1) {
2194 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
2195 astman_send_error(s, m, buf);
2196 return 0;
2199 ch2 = ast_get_channel_by_name_locked(channel2);
2200 if (!ch2) {
2201 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
2202 astman_send_error(s, m, buf);
2203 ast_channel_unlock(ch1);
2204 return 0;
2207 if (!ast_strlen_zero(timeout)) {
2208 sscanf(timeout, "%d", &to);
2211 res = ast_masq_park_call(ch1, ch2, to, &parkExt);
2212 if (!res) {
2213 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
2214 astman_send_ack(s, m, "Park successful");
2215 } else {
2216 astman_send_error(s, m, "Park failure");
2219 ast_channel_unlock(ch1);
2220 ast_channel_unlock(ch2);
2222 return 0;
2226 int ast_pickup_call(struct ast_channel *chan)
2228 struct ast_channel *cur = NULL;
2229 int res = -1;
2231 while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
2232 if (!cur->pbx &&
2233 (cur != chan) &&
2234 (chan->pickupgroup & cur->callgroup) &&
2235 ((cur->_state == AST_STATE_RINGING) ||
2236 (cur->_state == AST_STATE_RING))) {
2237 break;
2239 ast_channel_unlock(cur);
2241 if (cur) {
2242 if (option_debug)
2243 ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
2244 res = ast_answer(chan);
2245 if (res)
2246 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
2247 res = ast_queue_control(chan, AST_CONTROL_ANSWER);
2248 if (res)
2249 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
2250 res = ast_channel_masquerade(cur, chan);
2251 if (res)
2252 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */
2253 ast_channel_unlock(cur);
2254 } else {
2255 if (option_debug)
2256 ast_log(LOG_DEBUG, "No call pickup possible...\n");
2258 return res;
2261 /*! \brief Add parking hints for all defined parking lots */
2262 static void park_add_hints(char *context, int start, int stop)
2264 int numext;
2265 char device[AST_MAX_EXTENSION];
2266 char exten[10];
2268 for (numext = start; numext <= stop; numext++) {
2269 snprintf(exten, sizeof(exten), "%d", numext);
2270 snprintf(device, sizeof(device), "park:%s@%s", exten, context);
2271 ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
2276 static int load_config(void)
2278 int start = 0, end = 0;
2279 int res;
2280 struct ast_context *con = NULL;
2281 struct ast_config *cfg = NULL;
2282 struct ast_variable *var = NULL;
2283 char old_parking_ext[AST_MAX_EXTENSION];
2284 char old_parking_con[AST_MAX_EXTENSION] = "";
2286 if (!ast_strlen_zero(parking_con)) {
2287 strcpy(old_parking_ext, parking_ext);
2288 strcpy(old_parking_con, parking_con);
2291 /* Reset to defaults */
2292 strcpy(parking_con, "parkedcalls");
2293 strcpy(parking_con_dial, "park-dial");
2294 strcpy(parking_ext, "700");
2295 strcpy(pickup_ext, "*8");
2296 strcpy(parkmohclass, "default");
2297 courtesytone[0] = '\0';
2298 strcpy(xfersound, "beep");
2299 strcpy(xferfailsound, "pbx-invalid");
2300 parking_start = 701;
2301 parking_stop = 750;
2302 parkfindnext = 0;
2303 adsipark = 0;
2304 parkaddhints = 0;
2306 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
2307 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
2308 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
2310 cfg = ast_config_load("features.conf");
2311 if (!cfg) {
2312 ast_log(LOG_WARNING,"Could not load features.conf\n");
2313 return AST_MODULE_LOAD_DECLINE;
2315 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
2316 if (!strcasecmp(var->name, "parkext")) {
2317 ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
2318 } else if (!strcasecmp(var->name, "context")) {
2319 ast_copy_string(parking_con, var->value, sizeof(parking_con));
2320 } else if (!strcasecmp(var->name, "parkingtime")) {
2321 if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) {
2322 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
2323 parkingtime = DEFAULT_PARK_TIME;
2324 } else
2325 parkingtime = parkingtime * 1000;
2326 } else if (!strcasecmp(var->name, "parkpos")) {
2327 if (sscanf(var->value, "%d-%d", &start, &end) != 2) {
2328 ast_log(LOG_WARNING, "Format for parking positions is a-b, where a and b are numbers at line %d of features.conf\n", var->lineno);
2329 } else {
2330 parking_start = start;
2331 parking_stop = end;
2333 } else if (!strcasecmp(var->name, "findslot")) {
2334 parkfindnext = (!strcasecmp(var->value, "next"));
2335 } else if (!strcasecmp(var->name, "parkinghints")) {
2336 parkaddhints = ast_true(var->value);
2337 } else if (!strcasecmp(var->name, "adsipark")) {
2338 adsipark = ast_true(var->value);
2339 } else if (!strcasecmp(var->name, "transferdigittimeout")) {
2340 if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
2341 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
2342 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
2343 } else
2344 transferdigittimeout = transferdigittimeout * 1000;
2345 } else if (!strcasecmp(var->name, "featuredigittimeout")) {
2346 if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
2347 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
2348 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
2350 } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) {
2351 if ((sscanf(var->value, "%d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) {
2352 ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value);
2353 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
2354 } else
2355 atxfernoanswertimeout = atxfernoanswertimeout * 1000;
2356 } else if (!strcasecmp(var->name, "courtesytone")) {
2357 ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
2358 } else if (!strcasecmp(var->name, "parkedplay")) {
2359 if (!strcasecmp(var->value, "both"))
2360 parkedplay = 2;
2361 else if (!strcasecmp(var->value, "parked"))
2362 parkedplay = 1;
2363 else
2364 parkedplay = 0;
2365 } else if (!strcasecmp(var->name, "xfersound")) {
2366 ast_copy_string(xfersound, var->value, sizeof(xfersound));
2367 } else if (!strcasecmp(var->name, "xferfailsound")) {
2368 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
2369 } else if (!strcasecmp(var->name, "pickupexten")) {
2370 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
2371 } else if (!strcasecmp(var->name, "parkedmusicclass")) {
2372 ast_copy_string(parkmohclass, var->value, sizeof(parkmohclass));
2376 unmap_features();
2377 for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) {
2378 if (remap_feature(var->name, var->value))
2379 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
2382 /* Map a key combination to an application*/
2383 ast_unregister_features();
2384 for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) {
2385 char *tmp_val = ast_strdupa(var->value);
2386 char *exten, *activateon, *activatedby, *app, *app_args, *moh_class;
2387 struct ast_call_feature *feature;
2389 /* strsep() sets the argument to NULL if match not found, and it
2390 * is safe to use it with a NULL argument, so we don't check
2391 * between calls.
2393 exten = strsep(&tmp_val,",");
2394 activatedby = strsep(&tmp_val,",");
2395 app = strsep(&tmp_val,",");
2396 app_args = strsep(&tmp_val,",");
2397 moh_class = strsep(&tmp_val,",");
2399 activateon = strsep(&activatedby, "/");
2401 /*! \todo XXX var_name or app_args ? */
2402 if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) {
2403 ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",
2404 app, exten, activateon, var->name);
2405 continue;
2408 AST_LIST_LOCK(&feature_list);
2409 if ((feature = find_dynamic_feature(var->name))) {
2410 AST_LIST_UNLOCK(&feature_list);
2411 ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name);
2412 continue;
2414 AST_LIST_UNLOCK(&feature_list);
2416 if (!(feature = ast_calloc(1, sizeof(*feature))))
2417 continue;
2419 ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN);
2420 ast_copy_string(feature->app, app, FEATURE_APP_LEN);
2421 ast_copy_string(feature->exten, exten, FEATURE_EXTEN_LEN);
2423 if (app_args)
2424 ast_copy_string(feature->app_args, app_args, FEATURE_APP_ARGS_LEN);
2426 if (moh_class)
2427 ast_copy_string(feature->moh_class, moh_class, FEATURE_MOH_LEN);
2429 ast_copy_string(feature->exten, exten, sizeof(feature->exten));
2430 feature->operation = feature_exec_app;
2431 ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF);
2433 /* Allow caller and calle to be specified for backwards compatability */
2434 if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller"))
2435 ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF);
2436 else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee"))
2437 ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER);
2438 else {
2439 ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s',"
2440 " must be 'self', or 'peer'\n", var->name);
2441 continue;
2444 if (ast_strlen_zero(activatedby))
2445 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
2446 else if (!strcasecmp(activatedby, "caller"))
2447 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER);
2448 else if (!strcasecmp(activatedby, "callee"))
2449 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE);
2450 else if (!strcasecmp(activatedby, "both"))
2451 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
2452 else {
2453 ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s',"
2454 " must be 'caller', or 'callee', or 'both'\n", var->name);
2455 continue;
2458 ast_register_feature(feature);
2460 if (option_verbose >= 1)
2461 ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, app, app_args, exten);
2463 ast_config_destroy(cfg);
2465 /* Remove the old parking extension */
2466 if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) {
2467 if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar))
2468 notify_metermaids(old_parking_ext, old_parking_con);
2469 if (option_debug)
2470 ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
2473 if (!(con = ast_context_find(parking_con)) && !(con = ast_context_create(NULL, parking_con, registrar))) {
2474 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
2475 return -1;
2477 res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar);
2478 if (parkaddhints)
2479 park_add_hints(parking_con, parking_start, parking_stop);
2480 if (!res)
2481 notify_metermaids(ast_parking_ext(), parking_con);
2482 return res;
2486 static int reload(void)
2488 return load_config();
2491 static int load_module(void)
2493 int res;
2495 memset(parking_ext, 0, sizeof(parking_ext));
2496 memset(parking_con, 0, sizeof(parking_con));
2498 if ((res = load_config()))
2499 return res;
2500 ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
2501 ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
2502 res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
2503 if (!res)
2504 res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
2505 if (!res) {
2506 ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" );
2507 ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park,
2508 "Park a channel", mandescr_park);
2511 res |= ast_devstate_prov_add("Park", metermaidstate);
2513 return res;
2517 static int unload_module(void)
2519 ast_module_user_hangup_all();
2521 ast_manager_unregister("ParkedCalls");
2522 ast_manager_unregister("Park");
2523 ast_cli_unregister_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
2524 ast_unregister_application(parkcall);
2525 ast_devstate_prov_del("Park");
2526 return ast_unregister_application(parkedcall);
2529 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Call Features Resource",
2530 .load = load_module,
2531 .unload = unload_module,
2532 .reload = reload,