add note that the user will need to enable codec_ilbc to get it to build
[asterisk-bristuff.git] / res / res_features.c
blobe21269640ce4e0cb2174c99aee0a0dc0e76f695e
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"
66 #define DEFAULT_PARK_TIME 45000
67 #define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000
68 #define DEFAULT_FEATURE_DIGIT_TIMEOUT 500
69 #define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000
71 #define AST_MAX_WATCHERS 256
73 enum {
74 AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0),
75 AST_FEATURE_FLAG_ONPEER = (1 << 1),
76 AST_FEATURE_FLAG_ONSELF = (1 << 2),
77 AST_FEATURE_FLAG_BYCALLEE = (1 << 3),
78 AST_FEATURE_FLAG_BYCALLER = (1 << 4),
79 AST_FEATURE_FLAG_BYBOTH = (3 << 3),
82 static char *parkedcall = "ParkedCall";
84 static int parkaddhints = 0; /*!< Add parking hints automatically */
85 static int parkingtime = DEFAULT_PARK_TIME; /*!< No more than 45 seconds parked before you do something with them */
86 static char parking_con[AST_MAX_EXTENSION]; /*!< Context for which parking is made accessible */
87 static char parking_con_dial[AST_MAX_EXTENSION]; /*!< Context for dialback for parking (KLUDGE) */
88 static char parking_ext[AST_MAX_EXTENSION]; /*!< Extension you type to park the call */
89 static char pickup_ext[AST_MAX_EXTENSION]; /*!< Call pickup extension */
90 static char parkmohclass[MAX_MUSICCLASS]; /*!< Music class used for parking */
91 static int parking_start; /*!< First available extension for parking */
92 static int parking_stop; /*!< Last available extension for parking */
94 static char courtesytone[256]; /*!< Courtesy tone */
95 static int parkedplay = 0; /*!< Who to play the courtesy tone to */
96 static char xfersound[256]; /*!< Call transfer sound */
97 static char xferfailsound[256]; /*!< Call transfer failure sound */
99 static int parking_offset;
100 static int parkfindnext;
102 static int adsipark;
104 static int transferdigittimeout;
105 static int featuredigittimeout;
107 static int atxfernoanswertimeout;
109 static char *registrar = "res_features"; /*!< Registrar for operations */
111 /* module and CLI command definitions */
112 static char *synopsis = "Answer a parked call";
114 static char *descrip = "ParkedCall(exten):"
115 "Used to connect to a parked call. This application is always\n"
116 "registered internally and does not need to be explicitly added\n"
117 "into the dialplan, although you should include the 'parkedcalls'\n"
118 "context.\n";
120 static char *parkcall = "Park";
122 static char *synopsis2 = "Park yourself";
124 static char *descrip2 = "Park():"
125 "Used to park yourself (typically in combination with a supervised\n"
126 "transfer to know the parking space). This application is always\n"
127 "registered internally and does not need to be explicitly added\n"
128 "into the dialplan, although you should include the 'parkedcalls'\n"
129 "context (or the context specified in features.conf).\n\n"
130 "If you set the PARKINGEXTEN variable to an extension in your\n"
131 "parking context, park() will park the call on that extension, unless\n"
132 "it already exists. In that case, execution will continue at next\n"
133 "priority.\n" ;
135 static struct ast_app *monitor_app = NULL;
136 static int monitor_ok = 1;
138 struct parkeduser {
139 struct ast_channel *chan; /*!< Parking channel */
140 struct timeval start; /*!< Time the parking started */
141 int parkingnum; /*!< Parking lot */
142 char parkingexten[AST_MAX_EXTENSION]; /*!< If set beforehand, parking extension used for this call */
143 char context[AST_MAX_CONTEXT]; /*!< Where to go if our parking time expires */
144 char exten[AST_MAX_EXTENSION];
145 int priority;
146 int parkingtime; /*!< Maximum length in parking lot before return */
147 int notquiteyet;
148 char peername[1024];
149 unsigned char moh_trys;
150 struct parkeduser *next;
153 static struct parkeduser *parkinglot;
155 AST_MUTEX_DEFINE_STATIC(parking_lock); /*!< protects all static variables above */
157 static pthread_t parking_thread;
159 char *ast_parking_ext(void)
161 return parking_ext;
164 char *ast_pickup_ext(void)
166 return pickup_ext;
169 struct ast_bridge_thread_obj
171 struct ast_bridge_config bconfig;
172 struct ast_channel *chan;
173 struct ast_channel *peer;
178 /*! \brief store context, priority and extension */
179 static void set_c_e_p(struct ast_channel *chan, const char *context, const char *ext, int pri)
181 ast_copy_string(chan->context, context, sizeof(chan->context));
182 ast_copy_string(chan->exten, ext, sizeof(chan->exten));
183 chan->priority = pri;
186 static void check_goto_on_transfer(struct ast_channel *chan)
188 struct ast_channel *xferchan;
189 const char *val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR");
190 char *x, *goto_on_transfer;
191 struct ast_frame *f;
193 if (ast_strlen_zero(val))
194 return;
196 goto_on_transfer = ast_strdupa(val);
198 if (!(xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, chan->name)))
199 return;
201 for (x = goto_on_transfer; x && *x; x++) {
202 if (*x == '^')
203 *x = '|';
205 /* Make formats okay */
206 xferchan->readformat = chan->readformat;
207 xferchan->writeformat = chan->writeformat;
208 ast_channel_masquerade(xferchan, chan);
209 ast_parseable_goto(xferchan, goto_on_transfer);
210 xferchan->_state = AST_STATE_UP;
211 ast_clear_flag(xferchan, AST_FLAGS_ALL);
212 xferchan->_softhangup = 0;
213 if ((f = ast_read(xferchan))) {
214 ast_frfree(f);
215 f = NULL;
216 ast_pbx_start(xferchan);
217 } else {
218 ast_hangup(xferchan);
222 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);
225 static void *ast_bridge_call_thread(void *data)
227 struct ast_bridge_thread_obj *tobj = data;
229 tobj->chan->appl = "Transferred Call";
230 tobj->chan->data = tobj->peer->name;
231 tobj->peer->appl = "Transferred Call";
232 tobj->peer->data = tobj->chan->name;
233 if (tobj->chan->cdr) {
234 ast_cdr_reset(tobj->chan->cdr, NULL);
235 ast_cdr_setdestchan(tobj->chan->cdr, tobj->peer->name);
237 if (tobj->peer->cdr) {
238 ast_cdr_reset(tobj->peer->cdr, NULL);
239 ast_cdr_setdestchan(tobj->peer->cdr, tobj->chan->name);
242 ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
243 ast_hangup(tobj->chan);
244 ast_hangup(tobj->peer);
245 bzero(tobj, sizeof(*tobj)); /*! \todo XXX for safety */
246 free(tobj);
247 return NULL;
250 static void ast_bridge_call_thread_launch(void *data)
252 pthread_t thread;
253 pthread_attr_t attr;
254 struct sched_param sched;
256 pthread_attr_init(&attr);
257 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
258 ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data);
259 pthread_attr_destroy(&attr);
260 memset(&sched, 0, sizeof(sched));
261 pthread_setschedparam(thread, SCHED_RR, &sched);
264 static int adsi_announce_park(struct ast_channel *chan, char *parkingexten)
266 int res;
267 int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
268 char tmp[256];
269 char *message[5] = {NULL, NULL, NULL, NULL, NULL};
271 snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten);
272 message[0] = tmp;
273 res = ast_adsi_load_session(chan, NULL, 0, 1);
274 if (res == -1)
275 return res;
276 return ast_adsi_print(chan, message, justify, 1);
279 /*! \brief Notify metermaids that we've changed an extension */
280 static void notify_metermaids(char *exten, char *context)
282 if (option_debug > 3)
283 ast_log(LOG_DEBUG, "Notification of state change to metermaids %s@%s\n", exten, context);
285 /* Send notification to devicestate subsystem */
286 ast_device_state_changed("park:%s@%s", exten, context);
287 return;
290 /*! \brief metermaids callback from devicestate.c */
291 static int metermaidstate(const char *data)
293 int res = AST_DEVICE_INVALID;
294 char *context = ast_strdupa(data);
295 char *exten;
297 exten = strsep(&context, "@");
298 if (!context)
299 return res;
301 if (option_debug > 3)
302 ast_log(LOG_DEBUG, "Checking state of exten %s in context %s\n", exten, context);
304 res = ast_exists_extension(NULL, context, exten, 1, NULL);
306 if (!res)
307 return AST_DEVICE_NOT_INUSE;
308 else
309 return AST_DEVICE_INUSE;
312 static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout, char *orig_chan_name)
314 struct parkeduser *pu, *cur;
315 int i, x = -1, parking_range;
316 struct ast_context *con;
317 const char *parkingexten;
319 /* Allocate memory for parking data */
320 if (!(pu = ast_calloc(1, sizeof(*pu))))
321 return -1;
323 /* Lock parking lot */
324 ast_mutex_lock(&parking_lock);
325 /* Check for channel variable PARKINGEXTEN */
326 parkingexten = pbx_builtin_getvar_helper(chan, "PARKINGEXTEN");
327 if (!ast_strlen_zero(parkingexten)) {
328 if (ast_exists_extension(NULL, parking_con, parkingexten, 1, NULL)) {
329 ast_mutex_unlock(&parking_lock);
330 free(pu);
331 ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parking_con);
332 return 1; /* Continue execution if possible */
334 ast_copy_string(pu->parkingexten, parkingexten, sizeof(pu->parkingexten));
335 x = atoi(parkingexten);
336 } else {
337 /* Select parking space within range */
338 parking_range = parking_stop - parking_start+1;
339 for (i = 0; i < parking_range; i++) {
340 x = (i + parking_offset) % parking_range + parking_start;
341 cur = parkinglot;
342 while(cur) {
343 if (cur->parkingnum == x)
344 break;
345 cur = cur->next;
347 if (!cur)
348 break;
351 if (!(i < parking_range)) {
352 ast_log(LOG_WARNING, "No more parking spaces\n");
353 free(pu);
354 ast_mutex_unlock(&parking_lock);
355 return -1;
357 /* Set pointer for next parking */
358 if (parkfindnext)
359 parking_offset = x - parking_start + 1;
362 chan->appl = "Parked Call";
363 chan->data = NULL;
365 pu->chan = chan;
367 /* Put the parked channel on hold if we have two different channels */
368 if (chan != peer) {
369 ast_indicate_data(pu->chan, AST_CONTROL_HOLD,
370 S_OR(parkmohclass, NULL),
371 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
374 pu->start = ast_tvnow();
375 pu->parkingnum = x;
376 pu->parkingtime = (timeout > 0) ? timeout : parkingtime;
377 if (extout)
378 *extout = x;
380 if (peer)
381 ast_copy_string(pu->peername, peer->name, sizeof(pu->peername));
383 /* Remember what had been dialed, so that if the parking
384 expires, we try to come back to the same place */
385 ast_copy_string(pu->context, S_OR(chan->macrocontext, chan->context), sizeof(pu->context));
386 ast_copy_string(pu->exten, S_OR(chan->macroexten, chan->exten), sizeof(pu->exten));
387 pu->priority = chan->macropriority ? chan->macropriority : chan->priority;
388 pu->next = parkinglot;
389 parkinglot = pu;
391 /* If parking a channel directly, don't quiet yet get parking running on it */
392 if (peer == chan)
393 pu->notquiteyet = 1;
394 ast_mutex_unlock(&parking_lock);
395 /* Wake up the (presumably select()ing) thread */
396 pthread_kill(parking_thread, SIGURG);
397 if (option_verbose > 1)
398 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));
400 if (pu->parkingnum != -1)
401 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", x);
402 manager_event(EVENT_FLAG_CALL, "ParkedCall",
403 "Exten: %s\r\n"
404 "Channel: %s\r\n"
405 "From: %s\r\n"
406 "Timeout: %ld\r\n"
407 "CallerID: %s\r\n"
408 "CallerIDName: %s\r\n",
409 pu->parkingexten, pu->chan->name, peer ? peer->name : "",
410 (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL),
411 S_OR(pu->chan->cid.cid_num, "<unknown>"),
412 S_OR(pu->chan->cid.cid_name, "<unknown>")
415 if (peer && adsipark && ast_adsi_available(peer)) {
416 adsi_announce_park(peer, pu->parkingexten); /* Only supports parking numbers */
417 ast_adsi_unload_session(peer);
420 con = ast_context_find(parking_con);
421 if (!con)
422 con = ast_context_create(NULL, parking_con, registrar);
423 if (!con) /* Still no context? Bad */
424 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
425 /* Tell the peer channel the number of the parking space */
426 if (peer && ((pu->parkingnum != -1 && 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 */
427 /* Make sure we don't start saying digits to the channel being parked */
428 ast_set_flag(peer, AST_FLAG_MASQ_NOSTREAM);
429 ast_say_digits(peer, pu->parkingnum, "", peer->language);
430 ast_clear_flag(peer, AST_FLAG_MASQ_NOSTREAM);
432 if (con) {
433 if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, strdup(pu->parkingexten), ast_free, registrar))
434 notify_metermaids(pu->parkingexten, parking_con);
436 if (pu->notquiteyet) {
437 /* Wake up parking thread if we're really done */
438 ast_indicate_data(pu->chan, AST_CONTROL_HOLD,
439 S_OR(parkmohclass, NULL),
440 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
441 pu->notquiteyet = 0;
442 pthread_kill(parking_thread, SIGURG);
444 return 0;
447 /*! \brief Park a call
448 \note We put the user in the parking list, then wake up the parking thread to be sure it looks
449 after these channels too */
450 int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
452 return park_call_full(chan, peer, timeout, extout, NULL);
455 int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
457 struct ast_channel *chan;
458 struct ast_frame *f;
459 char *orig_chan_name = NULL;
461 /* Make a new, fake channel that we'll use to masquerade in the real one */
462 if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) {
463 ast_log(LOG_WARNING, "Unable to create parked channel\n");
464 return -1;
467 /* Make formats okay */
468 chan->readformat = rchan->readformat;
469 chan->writeformat = rchan->writeformat;
470 ast_channel_masquerade(chan, rchan);
472 /* Setup the extensions and such */
473 set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority);
475 /* Make the masq execute */
476 f = ast_read(chan);
477 if (f)
478 ast_frfree(f);
480 orig_chan_name = ast_strdupa(chan->name);
482 park_call_full(chan, peer, timeout, extout, orig_chan_name);
484 return 0;
488 #define FEATURE_RETURN_HANGUP -1
489 #define FEATURE_RETURN_SUCCESSBREAK 0
490 #define FEATURE_RETURN_PBX_KEEPALIVE AST_PBX_KEEPALIVE
491 #define FEATURE_RETURN_NO_HANGUP_PEER AST_PBX_NO_HANGUP_PEER
492 #define FEATURE_RETURN_PASSDIGITS 21
493 #define FEATURE_RETURN_STOREDIGITS 22
494 #define FEATURE_RETURN_SUCCESS 23
495 #define FEATURE_RETURN_KEEPTRYING 24
497 #define FEATURE_SENSE_CHAN (1 << 0)
498 #define FEATURE_SENSE_PEER (1 << 1)
500 /*! \brief
501 * set caller and callee according to the direction
503 static void set_peers(struct ast_channel **caller, struct ast_channel **callee,
504 struct ast_channel *peer, struct ast_channel *chan, int sense)
506 if (sense == FEATURE_SENSE_PEER) {
507 *caller = peer;
508 *callee = chan;
509 } else {
510 *callee = peer;
511 *caller = chan;
515 /*! \brief support routing for one touch call parking */
516 static int builtin_parkcall(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
518 struct ast_channel *parker;
519 struct ast_channel *parkee;
520 int res = 0;
521 struct ast_module_user *u;
523 u = ast_module_user_add(chan);
525 set_peers(&parker, &parkee, peer, chan, sense);
526 /* Setup the exten/priority to be s/1 since we don't know
527 where this call should return */
528 strcpy(chan->exten, "s");
529 chan->priority = 1;
530 if (chan->_state != AST_STATE_UP)
531 res = ast_answer(chan);
532 if (!res)
533 res = ast_safe_sleep(chan, 1000);
534 if (!res)
535 res = ast_park_call(parkee, parker, 0, NULL);
537 ast_module_user_remove(u);
539 if (!res) {
540 if (sense == FEATURE_SENSE_CHAN)
541 res = AST_PBX_NO_HANGUP_PEER;
542 else
543 res = AST_PBX_KEEPALIVE;
545 return res;
549 static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
551 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
552 int x = 0;
553 size_t len;
554 struct ast_channel *caller_chan, *callee_chan;
556 if (!monitor_ok) {
557 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
558 return -1;
561 if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) {
562 monitor_ok = 0;
563 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
564 return -1;
567 set_peers(&caller_chan, &callee_chan, peer, chan, sense);
569 if (!ast_strlen_zero(courtesytone)) {
570 if (ast_autoservice_start(callee_chan))
571 return -1;
572 if (ast_stream_and_wait(caller_chan, courtesytone, caller_chan->language, "")) {
573 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
574 ast_autoservice_stop(callee_chan);
575 return -1;
577 if (ast_autoservice_stop(callee_chan))
578 return -1;
581 if (callee_chan->monitor) {
582 if (option_verbose > 3)
583 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to stop recording call.\n", code);
584 ast_monitor_stop(callee_chan, 1);
585 return FEATURE_RETURN_SUCCESS;
588 if (caller_chan && callee_chan) {
589 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT");
590 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
592 if (!touch_format)
593 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
595 if (!touch_monitor)
596 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
598 if (touch_monitor) {
599 len = strlen(touch_monitor) + 50;
600 args = alloca(len);
601 touch_filename = alloca(len);
602 snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor);
603 snprintf(args, len, "%s|%s|m", (touch_format) ? touch_format : "wav", touch_filename);
604 } else {
605 caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name));
606 callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name));
607 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
608 args = alloca(len);
609 touch_filename = alloca(len);
610 snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id);
611 snprintf(args, len, "%s|%s|m", S_OR(touch_format, "wav"), touch_filename);
614 for( x = 0; x < strlen(args); x++) {
615 if (args[x] == '/')
616 args[x] = '-';
619 if (option_verbose > 3)
620 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call. filename: %s\n", code, args);
622 pbx_exec(callee_chan, monitor_app, args);
623 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
624 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
626 return FEATURE_RETURN_SUCCESS;
629 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");
630 return -1;
633 static int builtin_disconnect(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
635 if (option_verbose > 3)
636 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code);
637 return FEATURE_RETURN_HANGUP;
640 static int finishup(struct ast_channel *chan)
642 ast_indicate(chan, AST_CONTROL_UNHOLD);
644 return ast_autoservice_stop(chan);
647 /*! \brief Find the context for the transfer */
648 static const char *real_ctx(struct ast_channel *transferer, struct ast_channel *transferee)
650 const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT");
651 if (ast_strlen_zero(s))
652 s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT");
653 if (ast_strlen_zero(s)) /* Use the non-macro context to transfer the call XXX ? */
654 s = transferer->macrocontext;
655 if (ast_strlen_zero(s))
656 s = transferer->context;
657 return s;
660 static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
662 struct ast_channel *transferer;
663 struct ast_channel *transferee;
664 const char *transferer_real_context;
665 char xferto[256];
666 int res;
668 set_peers(&transferer, &transferee, peer, chan, sense);
669 transferer_real_context = real_ctx(transferer, transferee);
670 /* Start autoservice on chan while we talk to the originator */
671 ast_autoservice_start(transferee);
672 ast_indicate(transferee, AST_CONTROL_HOLD);
674 memset(xferto, 0, sizeof(xferto));
676 /* Transfer */
677 res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY);
678 if (res < 0) {
679 finishup(transferee);
680 return -1; /* error ? */
682 if (res > 0) /* If they've typed a digit already, handle it */
683 xferto[0] = (char) res;
685 ast_stopstream(transferer);
686 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
687 if (res < 0) { /* hangup, would be 0 for invalid and 1 for valid */
688 finishup(transferee);
689 return res;
691 if (!strcmp(xferto, ast_parking_ext())) {
692 res = finishup(transferee);
693 if (res)
694 res = -1;
695 else if (!ast_park_call(transferee, transferer, 0, NULL)) { /* success */
696 /* We return non-zero, but tell the PBX not to hang the channel when
697 the thread dies -- We have to be careful now though. We are responsible for
698 hanging up the channel, else it will never be hung up! */
700 return (transferer == peer) ? AST_PBX_KEEPALIVE : AST_PBX_NO_HANGUP_PEER;
701 } else {
702 ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name);
704 /*! \todo XXX Maybe we should have another message here instead of invalid extension XXX */
705 } else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
706 pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", transferee->name);
707 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", peer->name);
708 res=finishup(transferee);
709 if (!transferer->cdr) {
710 transferer->cdr=ast_cdr_alloc();
711 if (transferer) {
712 ast_cdr_init(transferer->cdr, transferer); /* initilize our channel's cdr */
713 ast_cdr_start(transferer->cdr);
716 if (transferer->cdr) {
717 ast_cdr_setdestchan(transferer->cdr, transferee->name);
718 ast_cdr_setapp(transferer->cdr, "BLINDTRANSFER","");
720 if (!transferee->pbx) {
721 /* Doh! Use our handy async_goto functions */
722 if (option_verbose > 2)
723 ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n"
724 ,transferee->name, xferto, transferer_real_context);
725 if (ast_async_goto(transferee, transferer_real_context, xferto, 1))
726 ast_log(LOG_WARNING, "Async goto failed :-(\n");
727 res = -1;
728 } else {
729 /* Set the channel's new extension, since it exists, using transferer context */
730 set_c_e_p(transferee, transferer_real_context, xferto, 0);
732 check_goto_on_transfer(transferer);
733 return res;
734 } else {
735 if (option_verbose > 2)
736 ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context);
738 if (ast_stream_and_wait(transferer, xferfailsound, transferer->language, AST_DIGIT_ANY) < 0 ) {
739 finishup(transferee);
740 return -1;
742 ast_stopstream(transferer);
743 res = finishup(transferee);
744 if (res) {
745 if (option_verbose > 1)
746 ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name);
747 return res;
749 return FEATURE_RETURN_SUCCESS;
752 static int check_compat(struct ast_channel *c, struct ast_channel *newchan)
754 if (ast_channel_make_compatible(c, newchan) < 0) {
755 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n",
756 c->name, newchan->name);
757 ast_hangup(newchan);
758 return -1;
760 return 0;
763 static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
765 struct ast_channel *transferer;
766 struct ast_channel *transferee;
767 const char *transferer_real_context;
768 char xferto[256] = "";
769 int res;
770 int outstate=0;
771 struct ast_channel *newchan;
772 struct ast_channel *xferchan;
773 struct ast_bridge_thread_obj *tobj;
774 struct ast_bridge_config bconfig;
775 struct ast_frame *f;
776 int l;
778 if (option_debug)
779 ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense);
780 set_peers(&transferer, &transferee, peer, chan, sense);
781 transferer_real_context = real_ctx(transferer, transferee);
782 /* Start autoservice on chan while we talk to the originator */
783 ast_autoservice_start(transferee);
784 ast_indicate(transferee, AST_CONTROL_HOLD);
786 /* Transfer */
787 res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY);
788 if (res < 0) {
789 finishup(transferee);
790 return res;
792 if (res > 0) /* If they've typed a digit already, handle it */
793 xferto[0] = (char) res;
795 /* this is specific of atxfer */
796 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
797 if (res < 0) { /* hangup, would be 0 for invalid and 1 for valid */
798 finishup(transferee);
799 return res;
801 if (res == 0) {
802 ast_log(LOG_WARNING, "Did not read data.\n");
803 finishup(transferee);
804 if (ast_stream_and_wait(transferer, "beeperr", transferer->language, ""))
805 return -1;
806 return FEATURE_RETURN_SUCCESS;
809 /* valid extension, res == 1 */
810 if (!ast_exists_extension(transferer, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
811 ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context);
812 finishup(transferee);
813 if (ast_stream_and_wait(transferer, "beeperr", transferer->language, ""))
814 return -1;
815 return FEATURE_RETURN_SUCCESS;
818 l = strlen(xferto);
819 snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context); /* append context */
820 newchan = ast_feature_request_and_dial(transferer, "Local", ast_best_codec(transferer->nativeformats),
821 xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, transferer->language);
822 ast_indicate(transferer, -1);
823 if (!newchan) {
824 finishup(transferee);
825 /* any reason besides user requested cancel and busy triggers the failed sound */
826 if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY &&
827 ast_stream_and_wait(transferer, xferfailsound, transferer->language, ""))
828 return -1;
829 return FEATURE_RETURN_SUCCESS;
832 if (check_compat(transferer, newchan)) {
833 /* we do mean transferee here, NOT transferer */
834 finishup(transferee);
835 return -1;
837 memset(&bconfig,0,sizeof(struct ast_bridge_config));
838 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
839 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
840 res = ast_bridge_call(transferer, newchan, &bconfig);
841 if (newchan->_softhangup || !transferer->_softhangup) {
842 ast_hangup(newchan);
843 if (ast_stream_and_wait(transferer, xfersound, transferer->language, ""))
844 ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
845 finishup(transferee);
846 transferer->_softhangup = 0;
847 return FEATURE_RETURN_SUCCESS;
850 if (check_compat(transferee, newchan)) {
851 finishup(transferee);
852 return -1;
855 ast_indicate(transferee, AST_CONTROL_UNHOLD);
857 if ((ast_autoservice_stop(transferee) < 0)
858 || (ast_waitfordigit(transferee, 100) < 0)
859 || (ast_waitfordigit(newchan, 100) < 0)
860 || ast_check_hangup(transferee)
861 || ast_check_hangup(newchan)) {
862 ast_hangup(newchan);
863 return -1;
866 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name);
867 if (!xferchan) {
868 ast_hangup(newchan);
869 return -1;
871 /* Make formats okay */
872 xferchan->visible_indication = transferer->visible_indication;
873 xferchan->readformat = transferee->readformat;
874 xferchan->writeformat = transferee->writeformat;
875 ast_channel_masquerade(xferchan, transferee);
876 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
877 xferchan->_state = AST_STATE_UP;
878 ast_clear_flag(xferchan, AST_FLAGS_ALL);
879 xferchan->_softhangup = 0;
881 if ((f = ast_read(xferchan)))
882 ast_frfree(f);
884 newchan->_state = AST_STATE_UP;
885 ast_clear_flag(newchan, AST_FLAGS_ALL);
886 newchan->_softhangup = 0;
888 tobj = ast_calloc(1, sizeof(struct ast_bridge_thread_obj));
889 if (!tobj) {
890 ast_hangup(xferchan);
891 ast_hangup(newchan);
892 return -1;
894 tobj->chan = newchan;
895 tobj->peer = xferchan;
896 tobj->bconfig = *config;
898 if (ast_stream_and_wait(newchan, xfersound, newchan->language, ""))
899 ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
900 ast_bridge_call_thread_launch(tobj);
901 return -1; /* XXX meaning the channel is bridged ? */
905 /* add atxfer and automon as undefined so you can only use em if you configure them */
906 #define FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0]))
908 AST_RWLOCK_DEFINE_STATIC(features_lock);
910 static struct ast_call_feature builtin_features[] =
912 { AST_FEATURE_REDIRECT, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
913 { AST_FEATURE_REDIRECT, "Attended Transfer", "atxfer", "", "", builtin_atxfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
914 { AST_FEATURE_AUTOMON, "One Touch Monitor", "automon", "", "", builtin_automonitor, AST_FEATURE_FLAG_NEEDSDTMF, "" },
915 { AST_FEATURE_DISCONNECT, "Disconnect Call", "disconnect", "*", "*", builtin_disconnect, AST_FEATURE_FLAG_NEEDSDTMF, "" },
916 { AST_FEATURE_PARKCALL, "Park Call", "parkcall", "", "", builtin_parkcall, AST_FEATURE_FLAG_NEEDSDTMF, "" },
920 static AST_LIST_HEAD_STATIC(feature_list,ast_call_feature);
922 /*! \brief register new feature into feature_list*/
923 void ast_register_feature(struct ast_call_feature *feature)
925 if (!feature) {
926 ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
927 return;
930 AST_LIST_LOCK(&feature_list);
931 AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry);
932 AST_LIST_UNLOCK(&feature_list);
934 if (option_verbose >= 2)
935 ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
938 /*! \brief unregister feature from feature_list */
939 void ast_unregister_feature(struct ast_call_feature *feature)
941 if (!feature)
942 return;
944 AST_LIST_LOCK(&feature_list);
945 AST_LIST_REMOVE(&feature_list,feature,feature_entry);
946 AST_LIST_UNLOCK(&feature_list);
947 free(feature);
950 /*! \brief Remove all features in the list */
951 static void ast_unregister_features(void)
953 struct ast_call_feature *feature;
955 AST_LIST_LOCK(&feature_list);
956 while ((feature = AST_LIST_REMOVE_HEAD(&feature_list,feature_entry)))
957 free(feature);
958 AST_LIST_UNLOCK(&feature_list);
961 /*! \brief find a feature by name */
962 static struct ast_call_feature *find_dynamic_feature(const char *name)
964 struct ast_call_feature *tmp;
966 AST_LIST_TRAVERSE(&feature_list, tmp, feature_entry) {
967 if (!strcasecmp(tmp->sname, name))
968 break;
971 return tmp;
974 /*! \brief exec an app by feature */
975 static int feature_exec_app(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
977 struct ast_app *app;
978 struct ast_call_feature *feature = data;
979 struct ast_channel *work, *idle;
980 int res;
982 if (!feature) { /* shouldn't ever happen! */
983 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
984 return -1;
987 if (sense == FEATURE_SENSE_CHAN) {
988 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
989 return FEATURE_RETURN_KEEPTRYING;
990 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
991 work = chan;
992 idle = peer;
993 } else {
994 work = peer;
995 idle = chan;
997 } else {
998 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
999 return FEATURE_RETURN_KEEPTRYING;
1000 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
1001 work = peer;
1002 idle = chan;
1003 } else {
1004 work = chan;
1005 idle = peer;
1009 if (!(app = pbx_findapp(feature->app))) {
1010 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
1011 return -2;
1014 ast_autoservice_start(idle);
1016 if (!ast_strlen_zero(feature->moh_class))
1017 ast_moh_start(idle, feature->moh_class, NULL);
1019 res = pbx_exec(work, app, feature->app_args);
1021 if (!ast_strlen_zero(feature->moh_class))
1022 ast_moh_stop(idle);
1024 ast_autoservice_stop(idle);
1026 if (res == AST_PBX_KEEPALIVE)
1027 return FEATURE_RETURN_PBX_KEEPALIVE;
1028 else if (res == AST_PBX_NO_HANGUP_PEER)
1029 return FEATURE_RETURN_NO_HANGUP_PEER;
1030 else if (res)
1031 return FEATURE_RETURN_SUCCESSBREAK;
1033 return FEATURE_RETURN_SUCCESS; /*! \todo XXX should probably return res */
1036 static void unmap_features(void)
1038 int x;
1040 ast_rwlock_wrlock(&features_lock);
1041 for (x = 0; x < FEATURES_COUNT; x++)
1042 strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
1043 ast_rwlock_unlock(&features_lock);
1046 static int remap_feature(const char *name, const char *value)
1048 int x, res = -1;
1050 ast_rwlock_wrlock(&features_lock);
1051 for (x = 0; x < FEATURES_COUNT; x++) {
1052 if (strcasecmp(builtin_features[x].sname, name))
1053 continue;
1055 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
1056 res = 0;
1057 break;
1059 ast_rwlock_unlock(&features_lock);
1061 return res;
1064 static int ast_feature_interpret(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
1066 int x;
1067 struct ast_flags features;
1068 int res = FEATURE_RETURN_PASSDIGITS;
1069 struct ast_call_feature *feature;
1070 const char *dynamic_features;
1071 char *tmp, *tok;
1073 if (sense == FEATURE_SENSE_CHAN) {
1074 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
1075 dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
1076 } else {
1077 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);
1078 dynamic_features = pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES");
1080 if (option_debug > 2)
1081 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);
1083 ast_rwlock_rdlock(&features_lock);
1084 for (x = 0; x < FEATURES_COUNT; x++) {
1085 if ((ast_test_flag(&features, builtin_features[x].feature_mask)) &&
1086 !ast_strlen_zero(builtin_features[x].exten)) {
1087 /* Feature is up for consideration */
1088 if (!strcmp(builtin_features[x].exten, code)) {
1089 res = builtin_features[x].operation(chan, peer, config, code, sense, NULL);
1090 break;
1091 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
1092 if (res == FEATURE_RETURN_PASSDIGITS)
1093 res = FEATURE_RETURN_STOREDIGITS;
1097 ast_rwlock_unlock(&features_lock);
1099 if (ast_strlen_zero(dynamic_features))
1100 return res;
1102 tmp = ast_strdupa(dynamic_features);
1104 while ((tok = strsep(&tmp, "#"))) {
1105 AST_LIST_LOCK(&feature_list);
1106 if (!(feature = find_dynamic_feature(tok))) {
1107 AST_LIST_UNLOCK(&feature_list);
1108 continue;
1111 /* Feature is up for consideration */
1112 if (!strcmp(feature->exten, code)) {
1113 if (option_verbose > 2)
1114 ast_verbose(VERBOSE_PREFIX_3 " Feature Found: %s exten: %s\n",feature->sname, tok);
1115 res = feature->operation(chan, peer, config, code, sense, feature);
1116 if (res != FEATURE_RETURN_KEEPTRYING) {
1117 AST_LIST_UNLOCK(&feature_list);
1118 break;
1120 res = FEATURE_RETURN_PASSDIGITS;
1121 } else if (!strncmp(feature->exten, code, strlen(code)))
1122 res = FEATURE_RETURN_STOREDIGITS;
1124 AST_LIST_UNLOCK(&feature_list);
1127 return res;
1130 static void set_config_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
1132 int x;
1134 ast_clear_flag(config, AST_FLAGS_ALL);
1136 ast_rwlock_rdlock(&features_lock);
1137 for (x = 0; x < FEATURES_COUNT; x++) {
1138 if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF))
1139 continue;
1141 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
1142 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
1144 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
1145 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
1147 ast_rwlock_unlock(&features_lock);
1149 if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
1150 const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
1152 if (dynamic_features) {
1153 char *tmp = ast_strdupa(dynamic_features);
1154 char *tok;
1155 struct ast_call_feature *feature;
1157 /* while we have a feature */
1158 while ((tok = strsep(&tmp, "#"))) {
1159 AST_LIST_LOCK(&feature_list);
1160 if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
1161 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
1162 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
1163 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
1164 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
1166 AST_LIST_UNLOCK(&feature_list);
1172 /*! \todo XXX Check - this is very similar to the code in channel.c */
1173 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)
1175 int state = 0;
1176 int cause = 0;
1177 int to;
1178 struct ast_channel *chan;
1179 struct ast_channel *monitor_chans[2];
1180 struct ast_channel *active_channel;
1181 int res = 0, ready = 0;
1183 if ((chan = ast_request(type, format, data, &cause))) {
1184 ast_set_callerid(chan, cid_num, cid_name, cid_num);
1185 ast_string_field_set(chan, language, language);
1186 ast_channel_inherit_variables(caller, chan);
1187 pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name);
1188 if (!chan->cdr) {
1189 chan->cdr=ast_cdr_alloc();
1190 if (chan->cdr) {
1191 ast_cdr_init(chan->cdr, chan); /* initilize our channel's cdr */
1192 ast_cdr_start(chan->cdr);
1196 if (!ast_call(chan, data, timeout)) {
1197 struct timeval started;
1198 int x, len = 0;
1199 char *disconnect_code = NULL, *dialed_code = NULL;
1201 ast_indicate(caller, AST_CONTROL_RINGING);
1202 /* support dialing of the featuremap disconnect code while performing an attended tranfer */
1203 ast_rwlock_rdlock(&features_lock);
1204 for (x = 0; x < FEATURES_COUNT; x++) {
1205 if (strcasecmp(builtin_features[x].sname, "disconnect"))
1206 continue;
1208 disconnect_code = builtin_features[x].exten;
1209 len = strlen(disconnect_code) + 1;
1210 dialed_code = alloca(len);
1211 memset(dialed_code, 0, len);
1212 break;
1214 ast_rwlock_unlock(&features_lock);
1215 x = 0;
1216 started = ast_tvnow();
1217 to = timeout;
1218 while (!ast_check_hangup(caller) && timeout && (chan->_state != AST_STATE_UP)) {
1219 struct ast_frame *f = NULL;
1221 monitor_chans[0] = caller;
1222 monitor_chans[1] = chan;
1223 active_channel = ast_waitfor_n(monitor_chans, 2, &to);
1225 /* see if the timeout has been violated */
1226 if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
1227 state = AST_CONTROL_UNHOLD;
1228 ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n");
1229 break; /*doh! timeout*/
1232 if (!active_channel)
1233 continue;
1235 if (chan && (chan == active_channel)){
1236 f = ast_read(chan);
1237 if (f == NULL) { /*doh! where'd he go?*/
1238 state = AST_CONTROL_HANGUP;
1239 res = 0;
1240 break;
1243 if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) {
1244 if (f->subclass == AST_CONTROL_RINGING) {
1245 state = f->subclass;
1246 if (option_verbose > 2)
1247 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", chan->name);
1248 ast_indicate(caller, AST_CONTROL_RINGING);
1249 } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) {
1250 state = f->subclass;
1251 if (option_verbose > 2)
1252 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", chan->name);
1253 ast_indicate(caller, AST_CONTROL_BUSY);
1254 ast_frfree(f);
1255 f = NULL;
1256 break;
1257 } else if (f->subclass == AST_CONTROL_ANSWER) {
1258 /* This is what we are hoping for */
1259 state = f->subclass;
1260 ast_frfree(f);
1261 f = NULL;
1262 ready=1;
1263 break;
1264 } else if (f->subclass != -1) {
1265 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass);
1267 /* else who cares */
1270 } else if (caller && (active_channel == caller)) {
1271 f = ast_read(caller);
1272 if (f == NULL) { /*doh! where'd he go?*/
1273 if (caller->_softhangup && !chan->_softhangup) {
1274 /* make this a blind transfer */
1275 ready = 1;
1276 break;
1278 state = AST_CONTROL_HANGUP;
1279 res = 0;
1280 break;
1283 if (f->frametype == AST_FRAME_DTMF) {
1284 dialed_code[x++] = f->subclass;
1285 dialed_code[x] = '\0';
1286 if (strlen(dialed_code) == len) {
1287 x = 0;
1288 } else if (x && strncmp(dialed_code, disconnect_code, x)) {
1289 x = 0;
1290 dialed_code[x] = '\0';
1292 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
1293 /* Caller Canceled the call */
1294 state = AST_CONTROL_UNHOLD;
1295 ast_frfree(f);
1296 f = NULL;
1297 break;
1301 if (f)
1302 ast_frfree(f);
1303 } /* end while */
1304 } else
1305 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
1306 } else {
1307 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
1308 switch(cause) {
1309 case AST_CAUSE_BUSY:
1310 state = AST_CONTROL_BUSY;
1311 break;
1312 case AST_CAUSE_CONGESTION:
1313 state = AST_CONTROL_CONGESTION;
1314 break;
1318 ast_indicate(caller, -1);
1319 if (chan && ready) {
1320 if (chan->_state == AST_STATE_UP)
1321 state = AST_CONTROL_ANSWER;
1322 res = 0;
1323 } else if(chan) {
1324 res = -1;
1325 ast_hangup(chan);
1326 chan = NULL;
1327 } else {
1328 res = -1;
1331 if (outstate)
1332 *outstate = state;
1334 if (chan && res <= 0) {
1335 if (chan->cdr || (chan->cdr = ast_cdr_alloc())) {
1336 char tmp[256];
1337 ast_cdr_init(chan->cdr, chan);
1338 snprintf(tmp, 256, "%s/%s", type, (char *)data);
1339 ast_cdr_setapp(chan->cdr,"Dial",tmp);
1340 ast_cdr_update(chan);
1341 ast_cdr_start(chan->cdr);
1342 ast_cdr_end(chan->cdr);
1343 /* If the cause wasn't handled properly */
1344 if (ast_cdr_disposition(chan->cdr,chan->hangupcause))
1345 ast_cdr_failed(chan->cdr);
1346 } else {
1347 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
1351 return chan;
1354 int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast_bridge_config *config)
1356 /* Copy voice back and forth between the two channels. Give the peer
1357 the ability to transfer calls with '#<extension' syntax. */
1358 struct ast_frame *f;
1359 struct ast_channel *who;
1360 char chan_featurecode[FEATURE_MAX_LEN + 1]="";
1361 char peer_featurecode[FEATURE_MAX_LEN + 1]="";
1362 int res;
1363 int diff;
1364 int hasfeatures=0;
1365 int hadfeatures=0;
1366 struct ast_option_header *aoh;
1367 struct ast_bridge_config backup_config;
1368 struct ast_cdr *bridge_cdr;
1370 memset(&backup_config, 0, sizeof(backup_config));
1372 config->start_time = ast_tvnow();
1374 if (chan && peer) {
1375 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
1376 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
1377 } else if (chan)
1378 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
1380 if (monitor_ok) {
1381 const char *monitor_exec;
1382 struct ast_channel *src = NULL;
1383 if (!monitor_app) {
1384 if (!(monitor_app = pbx_findapp("Monitor")))
1385 monitor_ok=0;
1387 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR")))
1388 src = chan;
1389 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
1390 src = peer;
1391 if (monitor_app && src) {
1392 char *tmp = ast_strdupa(monitor_exec);
1393 pbx_exec(src, monitor_app, tmp);
1397 set_config_flags(chan, peer, config);
1398 config->firstpass = 1;
1400 /* Answer if need be */
1401 if (ast_answer(chan))
1402 return -1;
1403 peer->appl = "Bridged Call";
1404 peer->data = chan->name;
1406 /* copy the userfield from the B-leg to A-leg if applicable */
1407 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
1408 char tmp[256];
1409 if (!ast_strlen_zero(chan->cdr->userfield)) {
1410 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield);
1411 ast_cdr_appenduserfield(chan, tmp);
1412 } else
1413 ast_cdr_setuserfield(chan, peer->cdr->userfield);
1414 /* free the peer's cdr without ast_cdr_free complaining */
1415 free(peer->cdr);
1416 peer->cdr = NULL;
1419 for (;;) {
1420 struct ast_channel *other; /* used later */
1422 res = ast_channel_bridge(chan, peer, config, &f, &who);
1424 if (config->feature_timer) {
1425 /* Update time limit for next pass */
1426 diff = ast_tvdiff_ms(ast_tvnow(), config->start_time);
1427 config->feature_timer -= diff;
1428 if (hasfeatures) {
1429 /* Running on backup config, meaning a feature might be being
1430 activated, but that's no excuse to keep things going
1431 indefinitely! */
1432 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
1433 if (option_debug)
1434 ast_log(LOG_DEBUG, "Timed out, realtime this time!\n");
1435 config->feature_timer = 0;
1436 who = chan;
1437 if (f)
1438 ast_frfree(f);
1439 f = NULL;
1440 res = 0;
1441 } else if (config->feature_timer <= 0) {
1442 /* Not *really* out of time, just out of time for
1443 digits to come in for features. */
1444 if (option_debug)
1445 ast_log(LOG_DEBUG, "Timed out for feature!\n");
1446 if (!ast_strlen_zero(peer_featurecode)) {
1447 ast_dtmf_stream(chan, peer, peer_featurecode, 0);
1448 memset(peer_featurecode, 0, sizeof(peer_featurecode));
1450 if (!ast_strlen_zero(chan_featurecode)) {
1451 ast_dtmf_stream(peer, chan, chan_featurecode, 0);
1452 memset(chan_featurecode, 0, sizeof(chan_featurecode));
1454 if (f)
1455 ast_frfree(f);
1456 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
1457 if (!hasfeatures) {
1458 /* Restore original (possibly time modified) bridge config */
1459 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
1460 memset(&backup_config, 0, sizeof(backup_config));
1462 hadfeatures = hasfeatures;
1463 /* Continue as we were */
1464 continue;
1465 } else if (!f) {
1466 /* The bridge returned without a frame and there is a feature in progress.
1467 * However, we don't think the feature has quite yet timed out, so just
1468 * go back into the bridge. */
1469 continue;
1471 } else {
1472 if (config->feature_timer <=0) {
1473 /* We ran out of time */
1474 config->feature_timer = 0;
1475 who = chan;
1476 if (f)
1477 ast_frfree(f);
1478 f = NULL;
1479 res = 0;
1483 if (res < 0) {
1484 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer))
1485 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
1486 return -1;
1489 if (!f || (f->frametype == AST_FRAME_CONTROL &&
1490 (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY ||
1491 f->subclass == AST_CONTROL_CONGESTION ) ) ) {
1492 res = -1;
1493 break;
1495 /* many things should be sent to the 'other' channel */
1496 other = (who == chan) ? peer : chan;
1497 if (f->frametype == AST_FRAME_CONTROL) {
1498 switch (f->subclass) {
1499 case AST_CONTROL_RINGING:
1500 case AST_CONTROL_FLASH:
1501 case -1:
1502 ast_indicate(other, f->subclass);
1503 break;
1504 case AST_CONTROL_HOLD:
1505 case AST_CONTROL_UNHOLD:
1506 ast_indicate_data(other, f->subclass, f->data, f->datalen);
1507 break;
1508 case AST_CONTROL_OPTION:
1509 aoh = f->data;
1510 /* Forward option Requests */
1511 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) {
1512 ast_channel_setoption(other, ntohs(aoh->option), aoh->data,
1513 f->datalen - sizeof(struct ast_option_header), 0);
1515 break;
1517 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
1518 /* eat it */
1519 } else if (f->frametype == AST_FRAME_DTMF) {
1520 char *featurecode;
1521 int sense;
1523 hadfeatures = hasfeatures;
1524 /* This cannot overrun because the longest feature is one shorter than our buffer */
1525 if (who == chan) {
1526 sense = FEATURE_SENSE_CHAN;
1527 featurecode = chan_featurecode;
1528 } else {
1529 sense = FEATURE_SENSE_PEER;
1530 featurecode = peer_featurecode;
1532 /*! append the event to featurecode. we rely on the string being zero-filled, and
1533 * not overflowing it.
1534 * \todo XXX how do we guarantee the latter ?
1536 featurecode[strlen(featurecode)] = f->subclass;
1537 /* Get rid of the frame before we start doing "stuff" with the channels */
1538 ast_frfree(f);
1539 f = NULL;
1540 config->feature_timer = backup_config.feature_timer;
1541 res = ast_feature_interpret(chan, peer, config, featurecode, sense);
1542 switch(res) {
1543 case FEATURE_RETURN_PASSDIGITS:
1544 ast_dtmf_stream(other, who, featurecode, 0);
1545 /* Fall through */
1546 case FEATURE_RETURN_SUCCESS:
1547 memset(featurecode, 0, sizeof(chan_featurecode));
1548 break;
1550 if (res >= FEATURE_RETURN_PASSDIGITS) {
1551 res = 0;
1552 } else
1553 break;
1554 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
1555 if (hadfeatures && !hasfeatures) {
1556 /* Restore backup */
1557 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
1558 memset(&backup_config, 0, sizeof(struct ast_bridge_config));
1559 } else if (hasfeatures) {
1560 if (!hadfeatures) {
1561 /* Backup configuration */
1562 memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
1563 /* Setup temporary config options */
1564 config->play_warning = 0;
1565 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
1566 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
1567 config->warning_freq = 0;
1568 config->warning_sound = NULL;
1569 config->end_sound = NULL;
1570 config->start_sound = NULL;
1571 config->firstpass = 0;
1573 config->start_time = ast_tvnow();
1574 config->feature_timer = featuredigittimeout;
1575 if (option_debug)
1576 ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer);
1579 if (f)
1580 ast_frfree(f);
1584 /* arrange the cdrs */
1585 bridge_cdr = ast_cdr_alloc();
1586 if (bridge_cdr) {
1587 if (chan->cdr && peer->cdr) { /* both of them? merge */
1588 ast_cdr_init(bridge_cdr,chan); /* seems more logicaller to use the destination as a base, but, really, it's random */
1589 ast_cdr_start(bridge_cdr); /* now is the time to start */
1591 /* absorb the channel cdr */
1592 ast_cdr_merge(bridge_cdr, chan->cdr);
1593 if (!ast_test_flag(chan->cdr, AST_CDR_FLAG_LOCKED))
1594 ast_cdr_discard(chan->cdr); /* if locked cdrs are in chan, they are taken over in the merge */
1596 /* absorb the peer cdr */
1597 ast_cdr_merge(bridge_cdr, peer->cdr);
1598 if (!ast_test_flag(peer->cdr, AST_CDR_FLAG_LOCKED))
1599 ast_cdr_discard(peer->cdr); /* if locked cdrs are in peer, they are taken over in the merge */
1601 peer->cdr = NULL;
1602 chan->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */
1603 } else if (chan->cdr) {
1604 /* take the cdr from the channel - literally */
1605 ast_cdr_init(bridge_cdr,chan);
1606 /* absorb this data */
1607 ast_cdr_merge(bridge_cdr, chan->cdr);
1608 if (!ast_test_flag(chan->cdr, AST_CDR_FLAG_LOCKED))
1609 ast_cdr_discard(chan->cdr); /* if locked cdrs are in chan, they are taken over in the merge */
1610 chan->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */
1611 } else if (peer->cdr) {
1612 /* take the cdr from the peer - literally */
1613 ast_cdr_init(bridge_cdr,peer);
1614 /* absorb this data */
1615 ast_cdr_merge(bridge_cdr, peer->cdr);
1616 if (!ast_test_flag(peer->cdr, AST_CDR_FLAG_LOCKED))
1617 ast_cdr_discard(peer->cdr); /* if locked cdrs are in chan, they are taken over in the merge */
1618 peer->cdr = NULL;
1619 peer->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */
1620 } else {
1621 /* make up a new cdr */
1622 ast_cdr_init(bridge_cdr,chan); /* eh, just pick one of them */
1623 chan->cdr = bridge_cdr; /* */
1625 if (ast_strlen_zero(bridge_cdr->dstchannel)) {
1626 if (strcmp(bridge_cdr->channel, peer->name) != 0)
1627 ast_cdr_setdestchan(bridge_cdr, peer->name);
1628 else
1629 ast_cdr_setdestchan(bridge_cdr, chan->name);
1632 return res;
1635 static void post_manager_event(const char *s, char *parkingexten, struct ast_channel *chan)
1637 manager_event(EVENT_FLAG_CALL, s,
1638 "Exten: %s\r\n"
1639 "Channel: %s\r\n"
1640 "CallerID: %s\r\n"
1641 "CallerIDName: %s\r\n\r\n",
1642 parkingexten,
1643 chan->name,
1644 S_OR(chan->cid.cid_num, "<unknown>"),
1645 S_OR(chan->cid.cid_name, "<unknown>")
1649 /*! \brief Take care of parked calls and unpark them if needed */
1650 static void *do_parking_thread(void *ignore)
1652 fd_set rfds, efds; /* results from previous select, to be preserved across loops. */
1653 FD_ZERO(&rfds);
1654 FD_ZERO(&efds);
1656 for (;;) {
1657 struct parkeduser *pu, *pl, *pt = NULL;
1658 int ms = -1; /* select timeout, uninitialized */
1659 int max = -1; /* max fd, none there yet */
1660 fd_set nrfds, nefds; /* args for the next select */
1661 FD_ZERO(&nrfds);
1662 FD_ZERO(&nefds);
1664 ast_mutex_lock(&parking_lock);
1665 pl = NULL;
1666 pu = parkinglot;
1667 /* navigate the list with prev-cur pointers to support removals */
1668 while (pu) {
1669 struct ast_channel *chan = pu->chan; /* shorthand */
1670 int tms; /* timeout for this item */
1671 int x; /* fd index in channel */
1672 struct ast_context *con;
1674 if (pu->notquiteyet) { /* Pretend this one isn't here yet */
1675 pl = pu;
1676 pu = pu->next;
1677 continue;
1679 tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
1680 if (tms > pu->parkingtime) {
1681 ast_indicate(chan, AST_CONTROL_UNHOLD);
1682 /* Get chan, exten from derived kludge */
1683 if (pu->peername[0]) {
1684 char *peername = ast_strdupa(pu->peername);
1685 char *cp = strrchr(peername, '-');
1686 if (cp)
1687 *cp = 0;
1688 con = ast_context_find(parking_con_dial);
1689 if (!con) {
1690 con = ast_context_create(NULL, parking_con_dial, registrar);
1691 if (!con)
1692 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
1694 if (con) {
1695 char returnexten[AST_MAX_EXTENSION];
1696 snprintf(returnexten, sizeof(returnexten), "%s||t", peername);
1697 ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), ast_free, registrar);
1699 set_c_e_p(chan, parking_con_dial, peername, 1);
1700 } else {
1701 /* They've been waiting too long, send them back to where they came. Theoretically they
1702 should have their original extensions and such, but we copy to be on the safe side */
1703 set_c_e_p(chan, pu->context, pu->exten, pu->priority);
1706 post_manager_event("ParkedCallTimeOut", pu->parkingexten, chan);
1708 if (option_verbose > 1)
1709 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);
1710 /* Start up the PBX, or hang them up */
1711 if (ast_pbx_start(chan)) {
1712 ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", chan->name);
1713 ast_hangup(chan);
1715 /* And take them out of the parking lot */
1716 if (pl)
1717 pl->next = pu->next;
1718 else
1719 parkinglot = pu->next;
1720 pt = pu;
1721 pu = pu->next;
1722 con = ast_context_find(parking_con);
1723 if (con) {
1724 if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL))
1725 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1726 else
1727 notify_metermaids(pt->parkingexten, parking_con);
1728 } else
1729 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1730 free(pt);
1731 } else { /* still within parking time, process descriptors */
1732 for (x = 0; x < AST_MAX_FDS; x++) {
1733 struct ast_frame *f;
1735 if (chan->fds[x] == -1 || (!FD_ISSET(chan->fds[x], &rfds) && !FD_ISSET(chan->fds[x], &efds)))
1736 continue; /* nothing on this descriptor */
1738 if (FD_ISSET(chan->fds[x], &efds))
1739 ast_set_flag(chan, AST_FLAG_EXCEPTION);
1740 else
1741 ast_clear_flag(chan, AST_FLAG_EXCEPTION);
1742 chan->fdno = x;
1744 /* See if they need servicing */
1745 f = ast_read(chan);
1746 if (!f || (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_HANGUP)) {
1747 if (f)
1748 ast_frfree(f);
1749 post_manager_event("ParkedCallGiveUp", pu->parkingexten, chan);
1751 /* There's a problem, hang them up*/
1752 if (option_verbose > 1)
1753 ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", chan->name);
1754 ast_hangup(chan);
1755 /* And take them out of the parking lot */
1756 if (pl)
1757 pl->next = pu->next;
1758 else
1759 parkinglot = pu->next;
1760 pt = pu;
1761 pu = pu->next;
1762 con = ast_context_find(parking_con);
1763 if (con) {
1764 if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL))
1765 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1766 else
1767 notify_metermaids(pt->parkingexten, parking_con);
1768 } else
1769 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1770 free(pt);
1771 break;
1772 } else {
1773 /*! \todo XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
1774 ast_frfree(f);
1775 if (pu->moh_trys < 3 && !chan->generatordata) {
1776 if (option_debug)
1777 ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source. Restarting.\n");
1778 ast_indicate_data(pu->chan, AST_CONTROL_HOLD,
1779 S_OR(parkmohclass, NULL),
1780 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
1781 pu->moh_trys++;
1783 goto std; /*! \todo XXX Ick: jumping into an else statement??? XXX */
1786 } /* end for */
1787 if (x >= AST_MAX_FDS) {
1788 std: for (x=0; x<AST_MAX_FDS; x++) { /* mark fds for next round */
1789 if (chan->fds[x] > -1) {
1790 FD_SET(chan->fds[x], &nrfds);
1791 FD_SET(chan->fds[x], &nefds);
1792 if (chan->fds[x] > max)
1793 max = chan->fds[x];
1796 /* Keep track of our shortest wait */
1797 if (tms < ms || ms < 0)
1798 ms = tms;
1799 pl = pu;
1800 pu = pu->next;
1803 } /* end while */
1804 ast_mutex_unlock(&parking_lock);
1805 rfds = nrfds;
1806 efds = nefds;
1808 struct timeval tv = ast_samp2tv(ms, 1000);
1809 /* Wait for something to happen */
1810 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
1812 pthread_testcancel();
1814 return NULL; /* Never reached */
1817 /*! \brief Park a call */
1818 static int park_call_exec(struct ast_channel *chan, void *data)
1820 /* Cache the original channel name in case we get masqueraded in the middle
1821 * of a park--it is still theoretically possible for a transfer to happen before
1822 * we get here, but it is _really_ unlikely */
1823 char *orig_chan_name = ast_strdupa(chan->name);
1824 char orig_exten[AST_MAX_EXTENSION];
1825 int orig_priority = chan->priority;
1827 /* Data is unused at the moment but could contain a parking
1828 lot context eventually */
1829 int res = 0;
1830 struct ast_module_user *u;
1832 u = ast_module_user_add(chan);
1834 ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten));
1836 /* Setup the exten/priority to be s/1 since we don't know
1837 where this call should return */
1838 strcpy(chan->exten, "s");
1839 chan->priority = 1;
1840 /* Answer if call is not up */
1841 if (chan->_state != AST_STATE_UP)
1842 res = ast_answer(chan);
1843 /* Sleep to allow VoIP streams to settle down */
1844 if (!res)
1845 res = ast_safe_sleep(chan, 1000);
1846 /* Park the call */
1847 if (!res) {
1848 res = park_call_full(chan, chan, 0, NULL, orig_chan_name);
1849 /* Continue on in the dialplan */
1850 if (res == 1) {
1851 ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten));
1852 chan->priority = orig_priority;
1853 res = 0;
1854 } else if (!res)
1855 res = AST_PBX_KEEPALIVE;
1858 ast_module_user_remove(u);
1860 return res;
1863 /*! \brief Pickup parked call */
1864 static int park_exec(struct ast_channel *chan, void *data)
1866 int res = 0;
1867 struct ast_module_user *u;
1868 struct ast_channel *peer=NULL;
1869 struct parkeduser *pu, *pl=NULL;
1870 struct ast_context *con;
1872 int park;
1873 struct ast_bridge_config config;
1875 if (!data) {
1876 ast_log(LOG_WARNING, "Parkedcall requires an argument (extension number)\n");
1877 return -1;
1880 u = ast_module_user_add(chan);
1882 park = atoi((char *)data);
1883 ast_mutex_lock(&parking_lock);
1884 pu = parkinglot;
1885 while(pu) {
1886 if (pu->parkingnum == park) {
1887 if (pl)
1888 pl->next = pu->next;
1889 else
1890 parkinglot = pu->next;
1891 break;
1893 pl = pu;
1894 pu = pu->next;
1896 ast_mutex_unlock(&parking_lock);
1897 if (pu) {
1898 peer = pu->chan;
1899 con = ast_context_find(parking_con);
1900 if (con) {
1901 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL))
1902 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1903 else
1904 notify_metermaids(pu->parkingexten, parking_con);
1905 } else
1906 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1908 manager_event(EVENT_FLAG_CALL, "UnParkedCall",
1909 "Exten: %s\r\n"
1910 "Channel: %s\r\n"
1911 "From: %s\r\n"
1912 "CallerID: %s\r\n"
1913 "CallerIDName: %s\r\n",
1914 pu->parkingexten, pu->chan->name, chan->name,
1915 S_OR(pu->chan->cid.cid_num, "<unknown>"),
1916 S_OR(pu->chan->cid.cid_name, "<unknown>")
1919 free(pu);
1921 /* JK02: it helps to answer the channel if not already up */
1922 if (chan->_state != AST_STATE_UP)
1923 ast_answer(chan);
1925 if (peer) {
1926 /* Play a courtesy to the source(s) configured to prefix the bridge connecting */
1928 if (!ast_strlen_zero(courtesytone)) {
1929 int error = 0;
1930 ast_indicate(peer, AST_CONTROL_UNHOLD);
1931 if (parkedplay == 0) {
1932 error = ast_stream_and_wait(chan, courtesytone, chan->language, "");
1933 } else if (parkedplay == 1) {
1934 error = ast_stream_and_wait(peer, courtesytone, chan->language, "");
1935 } else if (parkedplay == 2) {
1936 if (!ast_streamfile(chan, courtesytone, chan->language) &&
1937 !ast_streamfile(peer, courtesytone, chan->language)) {
1938 /*! \todo XXX we would like to wait on both! */
1939 res = ast_waitstream(chan, "");
1940 if (res >= 0)
1941 res = ast_waitstream(peer, "");
1942 if (res < 0)
1943 error = 1;
1946 if (error) {
1947 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
1948 ast_hangup(peer);
1949 ast_module_user_remove(u);
1950 return -1;
1952 } else
1953 ast_indicate(peer, AST_CONTROL_UNHOLD);
1955 res = ast_channel_make_compatible(chan, peer);
1956 if (res < 0) {
1957 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
1958 ast_hangup(peer);
1959 ast_module_user_remove(u);
1960 return -1;
1962 /* This runs sorta backwards, since we give the incoming channel control, as if it
1963 were the person called. */
1964 if (option_verbose > 2)
1965 ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
1967 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
1968 ast_cdr_setdestchan(chan->cdr, peer->name);
1969 memset(&config, 0, sizeof(struct ast_bridge_config));
1970 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
1971 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
1972 res = ast_bridge_call(chan, peer, &config);
1974 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
1975 ast_cdr_setdestchan(chan->cdr, peer->name);
1977 /* Simulate the PBX hanging up */
1978 if (res != AST_PBX_NO_HANGUP_PEER)
1979 ast_hangup(peer);
1980 ast_module_user_remove(u);
1981 return res;
1982 } else {
1983 /*! \todo XXX Play a message XXX */
1984 if (ast_stream_and_wait(chan, "pbx-invalidpark", chan->language, ""))
1985 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
1986 if (option_verbose > 2)
1987 ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
1988 res = -1;
1991 ast_module_user_remove(u);
1993 return res;
1996 static int handle_showfeatures(int fd, int argc, char *argv[])
1998 int i;
1999 struct ast_call_feature *feature;
2000 char format[] = "%-25s %-7s %-7s\n";
2002 ast_cli(fd, format, "Builtin Feature", "Default", "Current");
2003 ast_cli(fd, format, "---------------", "-------", "-------");
2005 ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */
2007 ast_rwlock_rdlock(&features_lock);
2008 for (i = 0; i < FEATURES_COUNT; i++)
2009 ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
2010 ast_rwlock_unlock(&features_lock);
2012 ast_cli(fd, "\n");
2013 ast_cli(fd, format, "Dynamic Feature", "Default", "Current");
2014 ast_cli(fd, format, "---------------", "-------", "-------");
2015 if (AST_LIST_EMPTY(&feature_list))
2016 ast_cli(fd, "(none)\n");
2017 else {
2018 AST_LIST_LOCK(&feature_list);
2019 AST_LIST_TRAVERSE(&feature_list, feature, feature_entry)
2020 ast_cli(fd, format, feature->sname, "no def", feature->exten);
2021 AST_LIST_UNLOCK(&feature_list);
2023 ast_cli(fd, "\nCall parking\n");
2024 ast_cli(fd, "------------\n");
2025 ast_cli(fd,"%-20s: %s\n", "Parking extension", parking_ext);
2026 ast_cli(fd,"%-20s: %s\n", "Parking context", parking_con);
2027 ast_cli(fd,"%-20s: %d-%d\n", "Parked call extensions", parking_start, parking_stop);
2028 ast_cli(fd,"\n");
2030 return RESULT_SUCCESS;
2033 static char showfeatures_help[] =
2034 "Usage: feature list\n"
2035 " Lists currently configured features.\n";
2037 static int handle_parkedcalls(int fd, int argc, char *argv[])
2039 struct parkeduser *cur;
2040 int numparked = 0;
2042 ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
2043 , "Context", "Extension", "Pri", "Timeout");
2045 ast_mutex_lock(&parking_lock);
2047 for (cur = parkinglot; cur; cur = cur->next) {
2048 ast_cli(fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n"
2049 ,cur->parkingexten, cur->chan->name, cur->context, cur->exten
2050 ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
2052 numparked++;
2054 ast_mutex_unlock(&parking_lock);
2055 ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : "");
2058 return RESULT_SUCCESS;
2061 static char showparked_help[] =
2062 "Usage: show parkedcalls\n"
2063 " Lists currently parked calls.\n";
2065 static struct ast_cli_entry cli_show_features_deprecated = {
2066 { "show", "features", NULL },
2067 handle_showfeatures, NULL,
2068 NULL };
2070 static struct ast_cli_entry cli_features[] = {
2071 { { "feature", "show", NULL },
2072 handle_showfeatures, "Lists configured features",
2073 showfeatures_help, NULL, &cli_show_features_deprecated },
2075 { { "show", "parkedcalls", NULL },
2076 handle_parkedcalls, "Lists parked calls",
2077 showparked_help },
2080 /*! \brief Dump lot status */
2081 static int manager_parking_status( struct mansession *s, const struct message *m)
2083 struct parkeduser *cur;
2084 const char *id = astman_get_header(m, "ActionID");
2085 char idText[256] = "";
2087 if (!ast_strlen_zero(id))
2088 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
2090 astman_send_ack(s, m, "Parked calls will follow");
2092 ast_mutex_lock(&parking_lock);
2094 for (cur = parkinglot; cur; cur = cur->next) {
2095 astman_append(s, "Event: ParkedCall\r\n"
2096 "Exten: %d\r\n"
2097 "Channel: %s\r\n"
2098 "From: %s\r\n"
2099 "Timeout: %ld\r\n"
2100 "CallerID: %s\r\n"
2101 "CallerIDName: %s\r\n"
2102 "%s"
2103 "\r\n",
2104 cur->parkingnum, cur->chan->name, cur->peername,
2105 (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
2106 S_OR(cur->chan->cid.cid_num, ""), /* XXX in other places it is <unknown> */
2107 S_OR(cur->chan->cid.cid_name, ""),
2108 idText);
2111 astman_append(s,
2112 "Event: ParkedCallsComplete\r\n"
2113 "%s"
2114 "\r\n",idText);
2116 ast_mutex_unlock(&parking_lock);
2118 return RESULT_SUCCESS;
2121 static char mandescr_park[] =
2122 "Description: Park a channel.\n"
2123 "Variables: (Names marked with * are required)\n"
2124 " *Channel: Channel name to park\n"
2125 " *Channel2: Channel to announce park info to (and return to if timeout)\n"
2126 " Timeout: Number of milliseconds to wait before callback.\n";
2128 static int manager_park(struct mansession *s, const struct message *m)
2130 const char *channel = astman_get_header(m, "Channel");
2131 const char *channel2 = astman_get_header(m, "Channel2");
2132 const char *timeout = astman_get_header(m, "Timeout");
2133 char buf[BUFSIZ];
2134 int to = 0;
2135 int res = 0;
2136 int parkExt = 0;
2137 struct ast_channel *ch1, *ch2;
2139 if (ast_strlen_zero(channel)) {
2140 astman_send_error(s, m, "Channel not specified");
2141 return 0;
2144 if (ast_strlen_zero(channel2)) {
2145 astman_send_error(s, m, "Channel2 not specified");
2146 return 0;
2149 ch1 = ast_get_channel_by_name_locked(channel);
2150 if (!ch1) {
2151 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
2152 astman_send_error(s, m, buf);
2153 return 0;
2156 ch2 = ast_get_channel_by_name_locked(channel2);
2157 if (!ch2) {
2158 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
2159 astman_send_error(s, m, buf);
2160 ast_channel_unlock(ch1);
2161 return 0;
2164 if (!ast_strlen_zero(timeout)) {
2165 sscanf(timeout, "%d", &to);
2168 res = ast_masq_park_call(ch1, ch2, to, &parkExt);
2169 if (!res) {
2170 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
2171 astman_send_ack(s, m, "Park successful");
2172 } else {
2173 astman_send_error(s, m, "Park failure");
2176 ast_channel_unlock(ch1);
2177 ast_channel_unlock(ch2);
2179 return 0;
2183 int ast_pickup_call(struct ast_channel *chan)
2185 struct ast_channel *cur = NULL;
2186 int res = -1;
2188 while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
2189 if (!cur->pbx &&
2190 (cur != chan) &&
2191 (chan->pickupgroup & cur->callgroup) &&
2192 ((cur->_state == AST_STATE_RINGING) ||
2193 (cur->_state == AST_STATE_RING))) {
2194 break;
2196 ast_channel_unlock(cur);
2198 if (cur) {
2199 if (option_debug)
2200 ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
2201 res = ast_answer(chan);
2202 if (res)
2203 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
2204 res = ast_queue_control(chan, AST_CONTROL_ANSWER);
2205 if (res)
2206 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
2207 res = ast_channel_masquerade(cur, chan);
2208 if (res)
2209 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */
2210 ast_channel_unlock(cur);
2211 } else {
2212 if (option_debug)
2213 ast_log(LOG_DEBUG, "No call pickup possible...\n");
2215 return res;
2218 /*! \brief Add parking hints for all defined parking lots */
2219 static void park_add_hints(char *context, int start, int stop)
2221 int numext;
2222 char device[AST_MAX_EXTENSION];
2223 char exten[10];
2225 for (numext = start; numext <= stop; numext++) {
2226 snprintf(exten, sizeof(exten), "%d", numext);
2227 snprintf(device, sizeof(device), "park:%s@%s", exten, context);
2228 ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
2233 static int load_config(void)
2235 int start = 0, end = 0;
2236 int res;
2237 struct ast_context *con = NULL;
2238 struct ast_config *cfg = NULL;
2239 struct ast_variable *var = NULL;
2240 char old_parking_ext[AST_MAX_EXTENSION];
2241 char old_parking_con[AST_MAX_EXTENSION] = "";
2243 if (!ast_strlen_zero(parking_con)) {
2244 strcpy(old_parking_ext, parking_ext);
2245 strcpy(old_parking_con, parking_con);
2248 /* Reset to defaults */
2249 strcpy(parking_con, "parkedcalls");
2250 strcpy(parking_con_dial, "park-dial");
2251 strcpy(parking_ext, "700");
2252 strcpy(pickup_ext, "*8");
2253 strcpy(parkmohclass, "default");
2254 courtesytone[0] = '\0';
2255 strcpy(xfersound, "beep");
2256 strcpy(xferfailsound, "pbx-invalid");
2257 parking_start = 701;
2258 parking_stop = 750;
2259 parkfindnext = 0;
2260 adsipark = 0;
2261 parkaddhints = 0;
2263 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
2264 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
2265 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
2267 cfg = ast_config_load("features.conf");
2268 if (!cfg) {
2269 ast_log(LOG_WARNING,"Could not load features.conf\n");
2270 return AST_MODULE_LOAD_DECLINE;
2272 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
2273 if (!strcasecmp(var->name, "parkext")) {
2274 ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
2275 } else if (!strcasecmp(var->name, "context")) {
2276 ast_copy_string(parking_con, var->value, sizeof(parking_con));
2277 } else if (!strcasecmp(var->name, "parkingtime")) {
2278 if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) {
2279 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
2280 parkingtime = DEFAULT_PARK_TIME;
2281 } else
2282 parkingtime = parkingtime * 1000;
2283 } else if (!strcasecmp(var->name, "parkpos")) {
2284 if (sscanf(var->value, "%d-%d", &start, &end) != 2) {
2285 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);
2286 } else {
2287 parking_start = start;
2288 parking_stop = end;
2290 } else if (!strcasecmp(var->name, "findslot")) {
2291 parkfindnext = (!strcasecmp(var->value, "next"));
2292 } else if (!strcasecmp(var->name, "parkinghints")) {
2293 parkaddhints = ast_true(var->value);
2294 } else if (!strcasecmp(var->name, "adsipark")) {
2295 adsipark = ast_true(var->value);
2296 } else if (!strcasecmp(var->name, "transferdigittimeout")) {
2297 if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
2298 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
2299 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
2300 } else
2301 transferdigittimeout = transferdigittimeout * 1000;
2302 } else if (!strcasecmp(var->name, "featuredigittimeout")) {
2303 if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
2304 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
2305 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
2307 } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) {
2308 if ((sscanf(var->value, "%d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) {
2309 ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value);
2310 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
2311 } else
2312 atxfernoanswertimeout = atxfernoanswertimeout * 1000;
2313 } else if (!strcasecmp(var->name, "courtesytone")) {
2314 ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
2315 } else if (!strcasecmp(var->name, "parkedplay")) {
2316 if (!strcasecmp(var->value, "both"))
2317 parkedplay = 2;
2318 else if (!strcasecmp(var->value, "parked"))
2319 parkedplay = 1;
2320 else
2321 parkedplay = 0;
2322 } else if (!strcasecmp(var->name, "xfersound")) {
2323 ast_copy_string(xfersound, var->value, sizeof(xfersound));
2324 } else if (!strcasecmp(var->name, "xferfailsound")) {
2325 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
2326 } else if (!strcasecmp(var->name, "pickupexten")) {
2327 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
2328 } else if (!strcasecmp(var->name, "parkedmusicclass")) {
2329 ast_copy_string(parkmohclass, var->value, sizeof(parkmohclass));
2333 unmap_features();
2334 for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) {
2335 if (remap_feature(var->name, var->value))
2336 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
2339 /* Map a key combination to an application*/
2340 ast_unregister_features();
2341 for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) {
2342 char *tmp_val = ast_strdupa(var->value);
2343 char *exten, *activateon, *activatedby, *app, *app_args, *moh_class;
2344 struct ast_call_feature *feature;
2346 /* strsep() sets the argument to NULL if match not found, and it
2347 * is safe to use it with a NULL argument, so we don't check
2348 * between calls.
2350 exten = strsep(&tmp_val,",");
2351 activatedby = strsep(&tmp_val,",");
2352 app = strsep(&tmp_val,",");
2353 app_args = strsep(&tmp_val,",");
2354 moh_class = strsep(&tmp_val,",");
2356 activateon = strsep(&activatedby, "/");
2358 /*! \todo XXX var_name or app_args ? */
2359 if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) {
2360 ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",
2361 app, exten, activateon, var->name);
2362 continue;
2365 AST_LIST_LOCK(&feature_list);
2366 if ((feature = find_dynamic_feature(var->name))) {
2367 AST_LIST_UNLOCK(&feature_list);
2368 ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name);
2369 continue;
2371 AST_LIST_UNLOCK(&feature_list);
2373 if (!(feature = ast_calloc(1, sizeof(*feature))))
2374 continue;
2376 ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN);
2377 ast_copy_string(feature->app, app, FEATURE_APP_LEN);
2378 ast_copy_string(feature->exten, exten, FEATURE_EXTEN_LEN);
2380 if (app_args)
2381 ast_copy_string(feature->app_args, app_args, FEATURE_APP_ARGS_LEN);
2383 if (moh_class)
2384 ast_copy_string(feature->moh_class, moh_class, FEATURE_MOH_LEN);
2386 ast_copy_string(feature->exten, exten, sizeof(feature->exten));
2387 feature->operation = feature_exec_app;
2388 ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF);
2390 /* Allow caller and calle to be specified for backwards compatability */
2391 if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller"))
2392 ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF);
2393 else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee"))
2394 ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER);
2395 else {
2396 ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s',"
2397 " must be 'self', or 'peer'\n", var->name);
2398 continue;
2401 if (ast_strlen_zero(activatedby))
2402 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
2403 else if (!strcasecmp(activatedby, "caller"))
2404 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER);
2405 else if (!strcasecmp(activatedby, "callee"))
2406 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE);
2407 else if (!strcasecmp(activatedby, "both"))
2408 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
2409 else {
2410 ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s',"
2411 " must be 'caller', or 'callee', or 'both'\n", var->name);
2412 continue;
2415 ast_register_feature(feature);
2417 if (option_verbose >= 1)
2418 ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, app, app_args, exten);
2420 ast_config_destroy(cfg);
2422 /* Remove the old parking extension */
2423 if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) {
2424 if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar))
2425 notify_metermaids(old_parking_ext, old_parking_con);
2426 if (option_debug)
2427 ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
2430 if (!(con = ast_context_find(parking_con)) && !(con = ast_context_create(NULL, parking_con, registrar))) {
2431 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
2432 return -1;
2434 res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar);
2435 if (parkaddhints)
2436 park_add_hints(parking_con, parking_start, parking_stop);
2437 if (!res)
2438 notify_metermaids(ast_parking_ext(), parking_con);
2439 return res;
2443 static int reload(void)
2445 return load_config();
2448 static int load_module(void)
2450 int res;
2452 memset(parking_ext, 0, sizeof(parking_ext));
2453 memset(parking_con, 0, sizeof(parking_con));
2455 if ((res = load_config()))
2456 return res;
2457 ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
2458 ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
2459 res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
2460 if (!res)
2461 res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
2462 if (!res) {
2463 ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" );
2464 ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park,
2465 "Park a channel", mandescr_park);
2468 res |= ast_devstate_prov_add("Park", metermaidstate);
2470 return res;
2474 static int unload_module(void)
2476 ast_module_user_hangup_all();
2478 ast_manager_unregister("ParkedCalls");
2479 ast_manager_unregister("Park");
2480 ast_cli_unregister_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
2481 ast_unregister_application(parkcall);
2482 ast_devstate_prov_del("Park");
2483 return ast_unregister_application(parkedcall);
2486 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Call Features Resource",
2487 .load = load_module,
2488 .unload = unload_module,
2489 .reload = reload,