change the required dependency for codec_dahdi to only be satisfied by DAHDI and...
[asterisk-bristuff.git] / res / res_features.c
blob75e1ccbd91daa085ae494b71d7fa817767fed53f
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;
1408 struct ast_cdr *orig_peer_cdr = NULL;
1410 memset(&backup_config, 0, sizeof(backup_config));
1412 config->start_time = ast_tvnow();
1414 if (chan && peer) {
1415 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
1416 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
1417 } else if (chan)
1418 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
1420 if (monitor_ok) {
1421 const char *monitor_exec;
1422 struct ast_channel *src = NULL;
1423 if (!monitor_app) {
1424 if (!(monitor_app = pbx_findapp("Monitor")))
1425 monitor_ok=0;
1427 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR")))
1428 src = chan;
1429 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
1430 src = peer;
1431 if (monitor_app && src) {
1432 char *tmp = ast_strdupa(monitor_exec);
1433 pbx_exec(src, monitor_app, tmp);
1437 set_config_flags(chan, peer, config);
1438 config->firstpass = 1;
1440 /* Answer if need be */
1441 if (ast_answer(chan))
1442 return -1;
1444 ast_copy_string(orig_channame,chan->name,sizeof(orig_channame));
1445 ast_copy_string(orig_peername,peer->name,sizeof(orig_peername));
1446 orig_peer_cdr = peer->cdr;
1448 if (!chan->cdr || (chan->cdr && !ast_test_flag(chan->cdr, AST_CDR_FLAG_POST_DISABLED))) {
1450 if (chan->cdr) {
1451 ast_set_flag(chan->cdr, AST_CDR_FLAG_MAIN);
1452 ast_cdr_update(chan);
1453 bridge_cdr = ast_cdr_dup(chan->cdr);
1454 ast_copy_string(bridge_cdr->lastapp, chan->appl, sizeof(bridge_cdr->lastapp));
1455 ast_copy_string(bridge_cdr->lastdata, chan->data, sizeof(bridge_cdr->lastdata));
1456 } else {
1457 /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */
1458 bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */
1459 ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel));
1460 ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel));
1461 ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid));
1462 ast_copy_string(bridge_cdr->lastapp, chan->appl, sizeof(bridge_cdr->lastapp));
1463 ast_copy_string(bridge_cdr->lastdata, chan->data, sizeof(bridge_cdr->lastdata));
1464 ast_cdr_setcid(bridge_cdr, chan);
1465 bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ? AST_CDR_ANSWERED : AST_CDR_NULL;
1466 bridge_cdr->amaflags = chan->amaflags ? chan->amaflags : ast_default_amaflags;
1467 ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode));
1468 /* Destination information */
1469 ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst));
1470 ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext));
1471 if (peer->cdr) {
1472 bridge_cdr->start = peer->cdr->start;
1473 ast_copy_string(bridge_cdr->userfield, peer->cdr->userfield, sizeof(bridge_cdr->userfield));
1474 } else {
1475 ast_cdr_start(bridge_cdr);
1478 /* peer->cdr->answer will be set when a macro runs on the peer;
1479 in that case, the bridge answer will be delayed while the
1480 macro plays on the peer channel. The peer answered the call
1481 before the macro started playing. To the phone system,
1482 this is billable time for the call, even tho the caller
1483 hears nothing but ringing while the macro does its thing. */
1484 if (peer->cdr && !ast_tvzero(peer->cdr->answer)) {
1485 bridge_cdr->answer = peer->cdr->answer;
1486 chan->cdr->answer = peer->cdr->answer;
1487 } else {
1488 ast_cdr_answer(bridge_cdr);
1489 ast_cdr_answer(chan->cdr); /* for the sake of cli status checks */
1491 ast_set_flag(chan->cdr, AST_CDR_FLAG_BRIDGED);
1492 if (peer->cdr) {
1493 ast_set_flag(peer->cdr, AST_CDR_FLAG_BRIDGED);
1497 for (;;) {
1498 struct ast_channel *other; /* used later */
1500 res = ast_channel_bridge(chan, peer, config, &f, &who);
1502 if (config->feature_timer) {
1503 /* Update time limit for next pass */
1504 diff = ast_tvdiff_ms(ast_tvnow(), config->start_time);
1505 config->feature_timer -= diff;
1506 if (hasfeatures) {
1507 /* Running on backup config, meaning a feature might be being
1508 activated, but that's no excuse to keep things going
1509 indefinitely! */
1510 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
1511 if (option_debug)
1512 ast_log(LOG_DEBUG, "Timed out, realtime this time!\n");
1513 config->feature_timer = 0;
1514 who = chan;
1515 if (f)
1516 ast_frfree(f);
1517 f = NULL;
1518 res = 0;
1519 } else if (config->feature_timer <= 0) {
1520 /* Not *really* out of time, just out of time for
1521 digits to come in for features. */
1522 if (option_debug)
1523 ast_log(LOG_DEBUG, "Timed out for feature!\n");
1524 if (!ast_strlen_zero(peer_featurecode)) {
1525 ast_dtmf_stream(chan, peer, peer_featurecode, 0);
1526 memset(peer_featurecode, 0, sizeof(peer_featurecode));
1528 if (!ast_strlen_zero(chan_featurecode)) {
1529 ast_dtmf_stream(peer, chan, chan_featurecode, 0);
1530 memset(chan_featurecode, 0, sizeof(chan_featurecode));
1532 if (f)
1533 ast_frfree(f);
1534 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
1535 if (!hasfeatures) {
1536 /* Restore original (possibly time modified) bridge config */
1537 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
1538 memset(&backup_config, 0, sizeof(backup_config));
1540 hadfeatures = hasfeatures;
1541 /* Continue as we were */
1542 continue;
1543 } else if (!f) {
1544 /* The bridge returned without a frame and there is a feature in progress.
1545 * However, we don't think the feature has quite yet timed out, so just
1546 * go back into the bridge. */
1547 continue;
1549 } else {
1550 if (config->feature_timer <=0) {
1551 /* We ran out of time */
1552 config->feature_timer = 0;
1553 who = chan;
1554 if (f)
1555 ast_frfree(f);
1556 f = NULL;
1557 res = 0;
1561 if (res < 0) {
1562 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer))
1563 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
1564 goto before_you_go;
1567 if (!f || (f->frametype == AST_FRAME_CONTROL &&
1568 (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY ||
1569 f->subclass == AST_CONTROL_CONGESTION ) ) ) {
1570 res = -1;
1571 break;
1573 /* many things should be sent to the 'other' channel */
1574 other = (who == chan) ? peer : chan;
1575 if (f->frametype == AST_FRAME_CONTROL) {
1576 switch (f->subclass) {
1577 case AST_CONTROL_RINGING:
1578 case AST_CONTROL_FLASH:
1579 case -1:
1580 ast_indicate(other, f->subclass);
1581 break;
1582 case AST_CONTROL_HOLD:
1583 case AST_CONTROL_UNHOLD:
1584 ast_indicate_data(other, f->subclass, f->data, f->datalen);
1585 break;
1586 case AST_CONTROL_OPTION:
1587 aoh = f->data;
1588 /* Forward option Requests */
1589 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) {
1590 ast_channel_setoption(other, ntohs(aoh->option), aoh->data,
1591 f->datalen - sizeof(struct ast_option_header), 0);
1593 break;
1595 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
1596 /* eat it */
1597 } else if (f->frametype == AST_FRAME_DTMF) {
1598 char *featurecode;
1599 int sense;
1601 hadfeatures = hasfeatures;
1602 /* This cannot overrun because the longest feature is one shorter than our buffer */
1603 if (who == chan) {
1604 sense = FEATURE_SENSE_CHAN;
1605 featurecode = chan_featurecode;
1606 } else {
1607 sense = FEATURE_SENSE_PEER;
1608 featurecode = peer_featurecode;
1610 /*! append the event to featurecode. we rely on the string being zero-filled, and
1611 * not overflowing it.
1612 * \todo XXX how do we guarantee the latter ?
1614 featurecode[strlen(featurecode)] = f->subclass;
1615 /* Get rid of the frame before we start doing "stuff" with the channels */
1616 ast_frfree(f);
1617 f = NULL;
1618 config->feature_timer = backup_config.feature_timer;
1619 res = ast_feature_interpret(chan, peer, config, featurecode, sense);
1620 switch(res) {
1621 case FEATURE_RETURN_PASSDIGITS:
1622 ast_dtmf_stream(other, who, featurecode, 0);
1623 /* Fall through */
1624 case FEATURE_RETURN_SUCCESS:
1625 memset(featurecode, 0, sizeof(chan_featurecode));
1626 break;
1628 if (res >= FEATURE_RETURN_PASSDIGITS) {
1629 res = 0;
1630 } else
1631 break;
1632 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
1633 if (hadfeatures && !hasfeatures) {
1634 /* Restore backup */
1635 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
1636 memset(&backup_config, 0, sizeof(struct ast_bridge_config));
1637 } else if (hasfeatures) {
1638 if (!hadfeatures) {
1639 /* Backup configuration */
1640 memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
1641 /* Setup temporary config options */
1642 config->play_warning = 0;
1643 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
1644 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
1645 config->warning_freq = 0;
1646 config->warning_sound = NULL;
1647 config->end_sound = NULL;
1648 config->start_sound = NULL;
1649 config->firstpass = 0;
1651 config->start_time = ast_tvnow();
1652 config->feature_timer = featuredigittimeout;
1653 if (option_debug)
1654 ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer);
1657 if (f)
1658 ast_frfree(f);
1661 before_you_go:
1662 /* obey the NoCDR() wishes. */
1663 if (!chan->cdr || (chan->cdr && !ast_test_flag(chan->cdr, AST_CDR_FLAG_POST_DISABLED))) {
1665 ast_cdr_end(bridge_cdr);
1667 ast_cdr_detach(bridge_cdr);
1669 /* just in case, these channels get bridged again before hangup */
1670 if (chan->cdr) {
1671 ast_cdr_specialized_reset(chan->cdr,0);
1673 if (peer->cdr) {
1674 /* before resetting the peer cdr, throw a copy of it to the
1675 backend, just in case the cdr.conf file is calling for
1676 unanswered CDR's. */
1678 /* When peer->cdr isn't the same addr as orig_peer_cdr,
1679 this can only happen if there was a transfer, methinks;
1680 at any rate, only pay attention to the original*/
1681 if (ast_cdr_isset_unanswered()) {
1682 struct ast_cdr *dupd = ast_cdr_dup(orig_peer_cdr);
1683 if (dupd) {
1684 if (ast_tvzero(dupd->end) && ast_cdr_isset_unanswered())
1685 ast_cdr_end(dupd);
1686 ast_cdr_detach(dupd);
1689 ast_cdr_specialized_reset(orig_peer_cdr,0);
1692 return res;
1695 static void post_manager_event(const char *s, char *parkingexten, struct ast_channel *chan)
1697 manager_event(EVENT_FLAG_CALL, s,
1698 "Exten: %s\r\n"
1699 "Channel: %s\r\n"
1700 "CallerID: %s\r\n"
1701 "CallerIDName: %s\r\n\r\n",
1702 parkingexten,
1703 chan->name,
1704 S_OR(chan->cid.cid_num, "<unknown>"),
1705 S_OR(chan->cid.cid_name, "<unknown>")
1709 /*! \brief Take care of parked calls and unpark them if needed */
1710 static void *do_parking_thread(void *ignore)
1712 fd_set rfds, efds; /* results from previous select, to be preserved across loops. */
1713 FD_ZERO(&rfds);
1714 FD_ZERO(&efds);
1716 for (;;) {
1717 struct parkeduser *pu, *pl, *pt = NULL;
1718 int ms = -1; /* select timeout, uninitialized */
1719 int max = -1; /* max fd, none there yet */
1720 fd_set nrfds, nefds; /* args for the next select */
1721 FD_ZERO(&nrfds);
1722 FD_ZERO(&nefds);
1724 ast_mutex_lock(&parking_lock);
1725 pl = NULL;
1726 pu = parkinglot;
1727 /* navigate the list with prev-cur pointers to support removals */
1728 while (pu) {
1729 struct ast_channel *chan = pu->chan; /* shorthand */
1730 int tms; /* timeout for this item */
1731 int x; /* fd index in channel */
1732 struct ast_context *con;
1734 if (pu->notquiteyet) { /* Pretend this one isn't here yet */
1735 pl = pu;
1736 pu = pu->next;
1737 continue;
1739 tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
1740 if (tms > pu->parkingtime) {
1741 ast_indicate(chan, AST_CONTROL_UNHOLD);
1742 /* Get chan, exten from derived kludge */
1743 if (pu->peername[0]) {
1744 char *peername = ast_strdupa(pu->peername);
1745 char *cp = strrchr(peername, '-');
1746 if (cp)
1747 *cp = 0;
1748 con = ast_context_find(parking_con_dial);
1749 if (!con) {
1750 con = ast_context_create(NULL, parking_con_dial, registrar);
1751 if (!con)
1752 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
1754 if (con) {
1755 char returnexten[AST_MAX_EXTENSION];
1756 struct ast_datastore *features_datastore;
1757 struct ast_dial_features *dialfeatures = NULL;
1759 ast_channel_lock(chan);
1761 if ((features_datastore = ast_channel_datastore_find(chan, &dial_features_info, NULL)))
1762 dialfeatures = features_datastore->data;
1764 ast_channel_unlock(chan);
1766 if (dialfeatures)
1767 snprintf(returnexten, sizeof(returnexten), "%s|30|%s", peername, dialfeatures->options);
1768 else /* Existing default */
1769 snprintf(returnexten, sizeof(returnexten), "%s|30|t", peername);
1771 ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), ast_free, registrar);
1773 set_c_e_p(chan, parking_con_dial, peername, 1);
1774 } else {
1775 /* They've been waiting too long, send them back to where they came. Theoretically they
1776 should have their original extensions and such, but we copy to be on the safe side */
1777 set_c_e_p(chan, pu->context, pu->exten, pu->priority);
1780 post_manager_event("ParkedCallTimeOut", pu->parkingexten, chan);
1782 if (option_verbose > 1)
1783 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);
1784 /* Start up the PBX, or hang them up */
1785 if (ast_pbx_start(chan)) {
1786 ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", chan->name);
1787 ast_hangup(chan);
1789 /* And take them out of the parking lot */
1790 if (pl)
1791 pl->next = pu->next;
1792 else
1793 parkinglot = pu->next;
1794 pt = pu;
1795 pu = pu->next;
1796 con = ast_context_find(parking_con);
1797 if (con) {
1798 if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL))
1799 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1800 else
1801 notify_metermaids(pt->parkingexten, parking_con);
1802 } else
1803 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1804 free(pt);
1805 } else { /* still within parking time, process descriptors */
1806 for (x = 0; x < AST_MAX_FDS; x++) {
1807 struct ast_frame *f;
1809 if (chan->fds[x] == -1 || (!FD_ISSET(chan->fds[x], &rfds) && !FD_ISSET(chan->fds[x], &efds)))
1810 continue; /* nothing on this descriptor */
1812 if (FD_ISSET(chan->fds[x], &efds))
1813 ast_set_flag(chan, AST_FLAG_EXCEPTION);
1814 else
1815 ast_clear_flag(chan, AST_FLAG_EXCEPTION);
1816 chan->fdno = x;
1818 /* See if they need servicing */
1819 f = ast_read(chan);
1820 if (!f || (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_HANGUP)) {
1821 if (f)
1822 ast_frfree(f);
1823 post_manager_event("ParkedCallGiveUp", pu->parkingexten, chan);
1825 /* There's a problem, hang them up*/
1826 if (option_verbose > 1)
1827 ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", chan->name);
1828 ast_hangup(chan);
1829 /* And take them out of the parking lot */
1830 if (pl)
1831 pl->next = pu->next;
1832 else
1833 parkinglot = pu->next;
1834 pt = pu;
1835 pu = pu->next;
1836 con = ast_context_find(parking_con);
1837 if (con) {
1838 if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL))
1839 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1840 else
1841 notify_metermaids(pt->parkingexten, parking_con);
1842 } else
1843 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1844 free(pt);
1845 break;
1846 } else {
1847 /*! \todo XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
1848 ast_frfree(f);
1849 if (pu->moh_trys < 3 && !chan->generatordata) {
1850 if (option_debug)
1851 ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source. Restarting.\n");
1852 ast_indicate_data(pu->chan, AST_CONTROL_HOLD,
1853 S_OR(parkmohclass, NULL),
1854 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
1855 pu->moh_trys++;
1857 goto std; /*! \todo XXX Ick: jumping into an else statement??? XXX */
1860 } /* end for */
1861 if (x >= AST_MAX_FDS) {
1862 std: for (x=0; x<AST_MAX_FDS; x++) { /* mark fds for next round */
1863 if (chan->fds[x] > -1) {
1864 FD_SET(chan->fds[x], &nrfds);
1865 FD_SET(chan->fds[x], &nefds);
1866 if (chan->fds[x] > max)
1867 max = chan->fds[x];
1870 /* Keep track of our shortest wait */
1871 if (tms < ms || ms < 0)
1872 ms = tms;
1873 pl = pu;
1874 pu = pu->next;
1877 } /* end while */
1878 ast_mutex_unlock(&parking_lock);
1879 rfds = nrfds;
1880 efds = nefds;
1882 struct timeval tv = ast_samp2tv(ms, 1000);
1883 /* Wait for something to happen */
1884 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
1886 pthread_testcancel();
1888 return NULL; /* Never reached */
1891 /*! \brief Park a call */
1892 static int park_call_exec(struct ast_channel *chan, void *data)
1894 /* Cache the original channel name in case we get masqueraded in the middle
1895 * of a park--it is still theoretically possible for a transfer to happen before
1896 * we get here, but it is _really_ unlikely */
1897 char *orig_chan_name = ast_strdupa(chan->name);
1898 char orig_exten[AST_MAX_EXTENSION];
1899 int orig_priority = chan->priority;
1901 /* Data is unused at the moment but could contain a parking
1902 lot context eventually */
1903 int res = 0;
1904 struct ast_module_user *u;
1906 u = ast_module_user_add(chan);
1908 ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten));
1910 /* Setup the exten/priority to be s/1 since we don't know
1911 where this call should return */
1912 strcpy(chan->exten, "s");
1913 chan->priority = 1;
1914 /* Answer if call is not up */
1915 if (chan->_state != AST_STATE_UP)
1916 res = ast_answer(chan);
1917 /* Sleep to allow VoIP streams to settle down */
1918 if (!res)
1919 res = ast_safe_sleep(chan, 1000);
1920 /* Park the call */
1921 if (!res) {
1922 res = park_call_full(chan, chan, 0, NULL, orig_chan_name);
1923 /* Continue on in the dialplan */
1924 if (res == 1) {
1925 ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten));
1926 chan->priority = orig_priority;
1927 res = 0;
1928 } else if (!res)
1929 res = AST_PBX_KEEPALIVE;
1932 ast_module_user_remove(u);
1934 return res;
1937 /*! \brief Pickup parked call */
1938 static int park_exec(struct ast_channel *chan, void *data)
1940 int res = 0;
1941 struct ast_module_user *u;
1942 struct ast_channel *peer=NULL;
1943 struct parkeduser *pu, *pl=NULL;
1944 struct ast_context *con;
1946 int park;
1947 struct ast_bridge_config config;
1949 if (!data) {
1950 ast_log(LOG_WARNING, "Parkedcall requires an argument (extension number)\n");
1951 return -1;
1954 u = ast_module_user_add(chan);
1956 park = atoi((char *)data);
1957 ast_mutex_lock(&parking_lock);
1958 pu = parkinglot;
1959 while(pu) {
1960 if (pu->parkingnum == park) {
1961 if (pl)
1962 pl->next = pu->next;
1963 else
1964 parkinglot = pu->next;
1965 break;
1967 pl = pu;
1968 pu = pu->next;
1970 ast_mutex_unlock(&parking_lock);
1971 if (pu) {
1972 peer = pu->chan;
1973 con = ast_context_find(parking_con);
1974 if (con) {
1975 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL))
1976 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1977 else
1978 notify_metermaids(pu->parkingexten, parking_con);
1979 } else
1980 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1982 manager_event(EVENT_FLAG_CALL, "UnParkedCall",
1983 "Exten: %s\r\n"
1984 "Channel: %s\r\n"
1985 "From: %s\r\n"
1986 "CallerID: %s\r\n"
1987 "CallerIDName: %s\r\n",
1988 pu->parkingexten, pu->chan->name, chan->name,
1989 S_OR(pu->chan->cid.cid_num, "<unknown>"),
1990 S_OR(pu->chan->cid.cid_name, "<unknown>")
1993 free(pu);
1995 /* JK02: it helps to answer the channel if not already up */
1996 if (chan->_state != AST_STATE_UP)
1997 ast_answer(chan);
1999 if (peer) {
2000 /* Play a courtesy to the source(s) configured to prefix the bridge connecting */
2002 if (!ast_strlen_zero(courtesytone)) {
2003 int error = 0;
2004 ast_indicate(peer, AST_CONTROL_UNHOLD);
2005 if (parkedplay == 0) {
2006 error = ast_stream_and_wait(chan, courtesytone, chan->language, "");
2007 } else if (parkedplay == 1) {
2008 error = ast_stream_and_wait(peer, courtesytone, chan->language, "");
2009 } else if (parkedplay == 2) {
2010 if (!ast_streamfile(chan, courtesytone, chan->language) &&
2011 !ast_streamfile(peer, courtesytone, chan->language)) {
2012 /*! \todo XXX we would like to wait on both! */
2013 res = ast_waitstream(chan, "");
2014 if (res >= 0)
2015 res = ast_waitstream(peer, "");
2016 if (res < 0)
2017 error = 1;
2020 if (error) {
2021 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
2022 ast_hangup(peer);
2023 ast_module_user_remove(u);
2024 return -1;
2026 } else
2027 ast_indicate(peer, AST_CONTROL_UNHOLD);
2029 res = ast_channel_make_compatible(chan, peer);
2030 if (res < 0) {
2031 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
2032 ast_hangup(peer);
2033 ast_module_user_remove(u);
2034 return -1;
2036 /* This runs sorta backwards, since we give the incoming channel control, as if it
2037 were the person called. */
2038 if (option_verbose > 2)
2039 ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
2041 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
2042 ast_cdr_setdestchan(chan->cdr, peer->name);
2043 memset(&config, 0, sizeof(struct ast_bridge_config));
2044 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
2045 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
2046 res = ast_bridge_call(chan, peer, &config);
2048 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
2049 ast_cdr_setdestchan(chan->cdr, peer->name);
2051 /* Simulate the PBX hanging up */
2052 if (res != AST_PBX_NO_HANGUP_PEER)
2053 ast_hangup(peer);
2054 ast_module_user_remove(u);
2055 return res;
2056 } else {
2057 /*! \todo XXX Play a message XXX */
2058 if (ast_stream_and_wait(chan, "pbx-invalidpark", chan->language, ""))
2059 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
2060 if (option_verbose > 2)
2061 ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
2062 res = -1;
2065 ast_module_user_remove(u);
2067 return res;
2070 static int handle_showfeatures(int fd, int argc, char *argv[])
2072 int i;
2073 struct ast_call_feature *feature;
2074 char format[] = "%-25s %-7s %-7s\n";
2076 ast_cli(fd, format, "Builtin Feature", "Default", "Current");
2077 ast_cli(fd, format, "---------------", "-------", "-------");
2079 ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */
2081 ast_rwlock_rdlock(&features_lock);
2082 for (i = 0; i < FEATURES_COUNT; i++)
2083 ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
2084 ast_rwlock_unlock(&features_lock);
2086 ast_cli(fd, "\n");
2087 ast_cli(fd, format, "Dynamic Feature", "Default", "Current");
2088 ast_cli(fd, format, "---------------", "-------", "-------");
2089 if (AST_LIST_EMPTY(&feature_list))
2090 ast_cli(fd, "(none)\n");
2091 else {
2092 AST_LIST_LOCK(&feature_list);
2093 AST_LIST_TRAVERSE(&feature_list, feature, feature_entry)
2094 ast_cli(fd, format, feature->sname, "no def", feature->exten);
2095 AST_LIST_UNLOCK(&feature_list);
2097 ast_cli(fd, "\nCall parking\n");
2098 ast_cli(fd, "------------\n");
2099 ast_cli(fd,"%-20s: %s\n", "Parking extension", parking_ext);
2100 ast_cli(fd,"%-20s: %s\n", "Parking context", parking_con);
2101 ast_cli(fd,"%-20s: %d-%d\n", "Parked call extensions", parking_start, parking_stop);
2102 ast_cli(fd,"\n");
2104 return RESULT_SUCCESS;
2107 static char showfeatures_help[] =
2108 "Usage: feature list\n"
2109 " Lists currently configured features.\n";
2111 static int handle_parkedcalls(int fd, int argc, char *argv[])
2113 struct parkeduser *cur;
2114 int numparked = 0;
2116 ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
2117 , "Context", "Extension", "Pri", "Timeout");
2119 ast_mutex_lock(&parking_lock);
2121 for (cur = parkinglot; cur; cur = cur->next) {
2122 ast_cli(fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n"
2123 ,cur->parkingexten, cur->chan->name, cur->context, cur->exten
2124 ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
2126 numparked++;
2128 ast_mutex_unlock(&parking_lock);
2129 ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : "");
2132 return RESULT_SUCCESS;
2135 static char showparked_help[] =
2136 "Usage: show parkedcalls\n"
2137 " Lists currently parked calls.\n";
2139 static struct ast_cli_entry cli_show_features_deprecated = {
2140 { "show", "features", NULL },
2141 handle_showfeatures, NULL,
2142 NULL };
2144 static struct ast_cli_entry cli_features[] = {
2145 { { "feature", "show", NULL },
2146 handle_showfeatures, "Lists configured features",
2147 showfeatures_help, NULL, &cli_show_features_deprecated },
2149 { { "show", "parkedcalls", NULL },
2150 handle_parkedcalls, "Lists parked calls",
2151 showparked_help },
2154 /*! \brief Dump lot status */
2155 static int manager_parking_status( struct mansession *s, const struct message *m)
2157 struct parkeduser *cur;
2158 const char *id = astman_get_header(m, "ActionID");
2159 char idText[256] = "";
2161 if (!ast_strlen_zero(id))
2162 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
2164 astman_send_ack(s, m, "Parked calls will follow");
2166 ast_mutex_lock(&parking_lock);
2168 for (cur = parkinglot; cur; cur = cur->next) {
2169 astman_append(s, "Event: ParkedCall\r\n"
2170 "Exten: %d\r\n"
2171 "Channel: %s\r\n"
2172 "From: %s\r\n"
2173 "Timeout: %ld\r\n"
2174 "CallerID: %s\r\n"
2175 "CallerIDName: %s\r\n"
2176 "%s"
2177 "\r\n",
2178 cur->parkingnum, cur->chan->name, cur->peername,
2179 (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
2180 S_OR(cur->chan->cid.cid_num, ""), /* XXX in other places it is <unknown> */
2181 S_OR(cur->chan->cid.cid_name, ""),
2182 idText);
2185 astman_append(s,
2186 "Event: ParkedCallsComplete\r\n"
2187 "%s"
2188 "\r\n",idText);
2190 ast_mutex_unlock(&parking_lock);
2192 return RESULT_SUCCESS;
2195 static char mandescr_park[] =
2196 "Description: Park a channel.\n"
2197 "Variables: (Names marked with * are required)\n"
2198 " *Channel: Channel name to park\n"
2199 " *Channel2: Channel to announce park info to (and return to if timeout)\n"
2200 " Timeout: Number of milliseconds to wait before callback.\n";
2202 static int manager_park(struct mansession *s, const struct message *m)
2204 const char *channel = astman_get_header(m, "Channel");
2205 const char *channel2 = astman_get_header(m, "Channel2");
2206 const char *timeout = astman_get_header(m, "Timeout");
2207 char buf[BUFSIZ];
2208 int to = 0;
2209 int res = 0;
2210 int parkExt = 0;
2211 struct ast_channel *ch1, *ch2;
2213 if (ast_strlen_zero(channel)) {
2214 astman_send_error(s, m, "Channel not specified");
2215 return 0;
2218 if (ast_strlen_zero(channel2)) {
2219 astman_send_error(s, m, "Channel2 not specified");
2220 return 0;
2223 ch1 = ast_get_channel_by_name_locked(channel);
2224 if (!ch1) {
2225 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
2226 astman_send_error(s, m, buf);
2227 return 0;
2230 ch2 = ast_get_channel_by_name_locked(channel2);
2231 if (!ch2) {
2232 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
2233 astman_send_error(s, m, buf);
2234 ast_channel_unlock(ch1);
2235 return 0;
2238 if (!ast_strlen_zero(timeout)) {
2239 sscanf(timeout, "%d", &to);
2242 res = ast_masq_park_call(ch1, ch2, to, &parkExt);
2243 if (!res) {
2244 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
2245 astman_send_ack(s, m, "Park successful");
2246 } else {
2247 astman_send_error(s, m, "Park failure");
2250 ast_channel_unlock(ch1);
2251 ast_channel_unlock(ch2);
2253 return 0;
2257 int ast_pickup_call(struct ast_channel *chan)
2259 struct ast_channel *cur = NULL;
2260 int res = -1;
2262 while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
2263 if (!cur->pbx &&
2264 (cur != chan) &&
2265 (chan->pickupgroup & cur->callgroup) &&
2266 ((cur->_state == AST_STATE_RINGING) ||
2267 (cur->_state == AST_STATE_RING))) {
2268 break;
2270 ast_channel_unlock(cur);
2272 if (cur) {
2273 if (option_debug)
2274 ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
2275 res = ast_answer(chan);
2276 if (res)
2277 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
2278 res = ast_queue_control(chan, AST_CONTROL_ANSWER);
2279 if (res)
2280 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
2281 res = ast_channel_masquerade(cur, chan);
2282 if (res)
2283 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */
2284 ast_channel_unlock(cur);
2285 } else {
2286 if (option_debug)
2287 ast_log(LOG_DEBUG, "No call pickup possible...\n");
2289 return res;
2292 /*! \brief Add parking hints for all defined parking lots */
2293 static void park_add_hints(char *context, int start, int stop)
2295 int numext;
2296 char device[AST_MAX_EXTENSION];
2297 char exten[10];
2299 for (numext = start; numext <= stop; numext++) {
2300 snprintf(exten, sizeof(exten), "%d", numext);
2301 snprintf(device, sizeof(device), "park:%s@%s", exten, context);
2302 ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
2307 static int load_config(void)
2309 int start = 0, end = 0;
2310 int res;
2311 struct ast_context *con = NULL;
2312 struct ast_config *cfg = NULL;
2313 struct ast_variable *var = NULL;
2314 char old_parking_ext[AST_MAX_EXTENSION];
2315 char old_parking_con[AST_MAX_EXTENSION] = "";
2317 if (!ast_strlen_zero(parking_con)) {
2318 strcpy(old_parking_ext, parking_ext);
2319 strcpy(old_parking_con, parking_con);
2322 /* Reset to defaults */
2323 strcpy(parking_con, "parkedcalls");
2324 strcpy(parking_con_dial, "park-dial");
2325 strcpy(parking_ext, "700");
2326 strcpy(pickup_ext, "*8");
2327 strcpy(parkmohclass, "default");
2328 courtesytone[0] = '\0';
2329 strcpy(xfersound, "beep");
2330 strcpy(xferfailsound, "pbx-invalid");
2331 parking_start = 701;
2332 parking_stop = 750;
2333 parkfindnext = 0;
2334 adsipark = 0;
2335 parkaddhints = 0;
2337 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
2338 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
2339 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
2341 cfg = ast_config_load("features.conf");
2342 if (!cfg) {
2343 ast_log(LOG_WARNING,"Could not load features.conf\n");
2344 return AST_MODULE_LOAD_DECLINE;
2346 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
2347 if (!strcasecmp(var->name, "parkext")) {
2348 ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
2349 } else if (!strcasecmp(var->name, "context")) {
2350 ast_copy_string(parking_con, var->value, sizeof(parking_con));
2351 } else if (!strcasecmp(var->name, "parkingtime")) {
2352 if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) {
2353 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
2354 parkingtime = DEFAULT_PARK_TIME;
2355 } else
2356 parkingtime = parkingtime * 1000;
2357 } else if (!strcasecmp(var->name, "parkpos")) {
2358 if (sscanf(var->value, "%d-%d", &start, &end) != 2) {
2359 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);
2360 } else {
2361 parking_start = start;
2362 parking_stop = end;
2364 } else if (!strcasecmp(var->name, "findslot")) {
2365 parkfindnext = (!strcasecmp(var->value, "next"));
2366 } else if (!strcasecmp(var->name, "parkinghints")) {
2367 parkaddhints = ast_true(var->value);
2368 } else if (!strcasecmp(var->name, "adsipark")) {
2369 adsipark = ast_true(var->value);
2370 } else if (!strcasecmp(var->name, "transferdigittimeout")) {
2371 if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
2372 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
2373 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
2374 } else
2375 transferdigittimeout = transferdigittimeout * 1000;
2376 } else if (!strcasecmp(var->name, "featuredigittimeout")) {
2377 if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
2378 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
2379 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
2381 } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) {
2382 if ((sscanf(var->value, "%d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) {
2383 ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value);
2384 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
2385 } else
2386 atxfernoanswertimeout = atxfernoanswertimeout * 1000;
2387 } else if (!strcasecmp(var->name, "courtesytone")) {
2388 ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
2389 } else if (!strcasecmp(var->name, "parkedplay")) {
2390 if (!strcasecmp(var->value, "both"))
2391 parkedplay = 2;
2392 else if (!strcasecmp(var->value, "parked"))
2393 parkedplay = 1;
2394 else
2395 parkedplay = 0;
2396 } else if (!strcasecmp(var->name, "xfersound")) {
2397 ast_copy_string(xfersound, var->value, sizeof(xfersound));
2398 } else if (!strcasecmp(var->name, "xferfailsound")) {
2399 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
2400 } else if (!strcasecmp(var->name, "pickupexten")) {
2401 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
2402 } else if (!strcasecmp(var->name, "parkedmusicclass")) {
2403 ast_copy_string(parkmohclass, var->value, sizeof(parkmohclass));
2407 unmap_features();
2408 for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) {
2409 if (remap_feature(var->name, var->value))
2410 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
2413 /* Map a key combination to an application*/
2414 ast_unregister_features();
2415 for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) {
2416 char *tmp_val = ast_strdupa(var->value);
2417 char *exten, *activateon, *activatedby, *app, *app_args, *moh_class;
2418 struct ast_call_feature *feature;
2420 /* strsep() sets the argument to NULL if match not found, and it
2421 * is safe to use it with a NULL argument, so we don't check
2422 * between calls.
2424 exten = strsep(&tmp_val,",");
2425 activatedby = strsep(&tmp_val,",");
2426 app = strsep(&tmp_val,",");
2427 app_args = strsep(&tmp_val,",");
2428 moh_class = strsep(&tmp_val,",");
2430 activateon = strsep(&activatedby, "/");
2432 /*! \todo XXX var_name or app_args ? */
2433 if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) {
2434 ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",
2435 app, exten, activateon, var->name);
2436 continue;
2439 AST_LIST_LOCK(&feature_list);
2440 if ((feature = find_dynamic_feature(var->name))) {
2441 AST_LIST_UNLOCK(&feature_list);
2442 ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name);
2443 continue;
2445 AST_LIST_UNLOCK(&feature_list);
2447 if (!(feature = ast_calloc(1, sizeof(*feature))))
2448 continue;
2450 ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN);
2451 ast_copy_string(feature->app, app, FEATURE_APP_LEN);
2452 ast_copy_string(feature->exten, exten, FEATURE_EXTEN_LEN);
2454 if (app_args)
2455 ast_copy_string(feature->app_args, app_args, FEATURE_APP_ARGS_LEN);
2457 if (moh_class)
2458 ast_copy_string(feature->moh_class, moh_class, FEATURE_MOH_LEN);
2460 ast_copy_string(feature->exten, exten, sizeof(feature->exten));
2461 feature->operation = feature_exec_app;
2462 ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF);
2464 /* Allow caller and calle to be specified for backwards compatability */
2465 if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller"))
2466 ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF);
2467 else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee"))
2468 ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER);
2469 else {
2470 ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s',"
2471 " must be 'self', or 'peer'\n", var->name);
2472 continue;
2475 if (ast_strlen_zero(activatedby))
2476 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
2477 else if (!strcasecmp(activatedby, "caller"))
2478 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER);
2479 else if (!strcasecmp(activatedby, "callee"))
2480 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE);
2481 else if (!strcasecmp(activatedby, "both"))
2482 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
2483 else {
2484 ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s',"
2485 " must be 'caller', or 'callee', or 'both'\n", var->name);
2486 continue;
2489 ast_register_feature(feature);
2491 if (option_verbose >= 1)
2492 ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, app, app_args, exten);
2494 ast_config_destroy(cfg);
2496 /* Remove the old parking extension */
2497 if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) {
2498 if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar))
2499 notify_metermaids(old_parking_ext, old_parking_con);
2500 if (option_debug)
2501 ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
2504 if (!(con = ast_context_find(parking_con)) && !(con = ast_context_create(NULL, parking_con, registrar))) {
2505 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
2506 return -1;
2508 res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar);
2509 if (parkaddhints)
2510 park_add_hints(parking_con, parking_start, parking_stop);
2511 if (!res)
2512 notify_metermaids(ast_parking_ext(), parking_con);
2513 return res;
2517 static int reload(void)
2519 return load_config();
2522 static int load_module(void)
2524 int res;
2526 memset(parking_ext, 0, sizeof(parking_ext));
2527 memset(parking_con, 0, sizeof(parking_con));
2529 if ((res = load_config()))
2530 return res;
2531 ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
2532 ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
2533 res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
2534 if (!res)
2535 res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
2536 if (!res) {
2537 ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" );
2538 ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park,
2539 "Park a channel", mandescr_park);
2542 res |= ast_devstate_prov_add("Park", metermaidstate);
2544 return res;
2548 static int unload_module(void)
2550 ast_module_user_hangup_all();
2552 ast_manager_unregister("ParkedCalls");
2553 ast_manager_unregister("Park");
2554 ast_cli_unregister_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
2555 ast_unregister_application(parkcall);
2556 ast_devstate_prov_del("Park");
2557 return ast_unregister_application(parkedcall);
2560 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Call Features Resource",
2561 .load = load_module,
2562 .unload = unload_module,
2563 .reload = reload,