Merge changes from team/russell/issue_9520
[asterisk-bristuff.git] / res / res_features.c
blob7eb1b4c4c9914f1e7ef17905caae3c977c597cef
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_channel_lock(chan); /* lock the channel before modifing cdrs */
1589 ast_cdr_init(bridge_cdr,chan); /* seems more logicaller to use the destination as a base, but, really, it's random */
1590 ast_cdr_start(bridge_cdr); /* now is the time to start */
1592 /* absorb the channel cdr */
1593 ast_cdr_merge(bridge_cdr, chan->cdr);
1594 if (!ast_test_flag(chan->cdr, AST_CDR_FLAG_LOCKED))
1595 ast_cdr_discard(chan->cdr); /* if locked cdrs are in chan, they are taken over in the merge */
1597 chan->cdr = NULL; /* remove pointer to freed memory before releasing the lock */
1599 ast_channel_unlock(chan);
1601 /* absorb the peer cdr */
1602 ast_channel_lock(peer);
1603 ast_cdr_merge(bridge_cdr, peer->cdr);
1604 if (!ast_test_flag(peer->cdr, AST_CDR_FLAG_LOCKED))
1605 ast_cdr_discard(peer->cdr); /* if locked cdrs are in peer, they are taken over in the merge */
1607 peer->cdr = NULL;
1608 ast_channel_unlock(peer);
1610 ast_channel_lock(chan);
1611 chan->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */
1612 ast_channel_unlock(chan);
1614 } else if (chan->cdr) {
1616 ast_channel_lock(chan); /* Lock before modifying CDR */
1617 /* take the cdr from the channel - literally */
1618 ast_cdr_init(bridge_cdr,chan);
1619 /* absorb this data */
1620 ast_cdr_merge(bridge_cdr, chan->cdr);
1621 if (!ast_test_flag(chan->cdr, AST_CDR_FLAG_LOCKED))
1622 ast_cdr_discard(chan->cdr); /* if locked cdrs are in chan, they are taken over in the merge */
1623 chan->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */
1624 ast_channel_unlock(chan);
1625 } else if (peer->cdr) {
1626 ast_channel_lock(peer); /* Lock before modifying CDR */
1627 /* take the cdr from the peer - literally */
1628 ast_cdr_init(bridge_cdr,peer);
1629 /* absorb this data */
1630 ast_cdr_merge(bridge_cdr, peer->cdr);
1631 if (!ast_test_flag(peer->cdr, AST_CDR_FLAG_LOCKED))
1632 ast_cdr_discard(peer->cdr); /* if locked cdrs are in chan, they are taken over in the merge */
1633 peer->cdr = NULL;
1634 peer->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */
1635 ast_channel_unlock(peer);
1636 } else {
1637 ast_channel_lock(chan); /* Lock before modifying CDR */
1638 /* make up a new cdr */
1639 ast_cdr_init(bridge_cdr,chan); /* eh, just pick one of them */
1640 chan->cdr = bridge_cdr; /* */
1641 ast_channel_unlock(chan);
1643 if (ast_strlen_zero(bridge_cdr->dstchannel)) {
1644 if (strcmp(bridge_cdr->channel, peer->name) != 0)
1645 ast_cdr_setdestchan(bridge_cdr, peer->name);
1646 else
1647 ast_cdr_setdestchan(bridge_cdr, chan->name);
1650 return res;
1653 static void post_manager_event(const char *s, char *parkingexten, struct ast_channel *chan)
1655 manager_event(EVENT_FLAG_CALL, s,
1656 "Exten: %s\r\n"
1657 "Channel: %s\r\n"
1658 "CallerID: %s\r\n"
1659 "CallerIDName: %s\r\n\r\n",
1660 parkingexten,
1661 chan->name,
1662 S_OR(chan->cid.cid_num, "<unknown>"),
1663 S_OR(chan->cid.cid_name, "<unknown>")
1667 /*! \brief Take care of parked calls and unpark them if needed */
1668 static void *do_parking_thread(void *ignore)
1670 fd_set rfds, efds; /* results from previous select, to be preserved across loops. */
1671 FD_ZERO(&rfds);
1672 FD_ZERO(&efds);
1674 for (;;) {
1675 struct parkeduser *pu, *pl, *pt = NULL;
1676 int ms = -1; /* select timeout, uninitialized */
1677 int max = -1; /* max fd, none there yet */
1678 fd_set nrfds, nefds; /* args for the next select */
1679 FD_ZERO(&nrfds);
1680 FD_ZERO(&nefds);
1682 ast_mutex_lock(&parking_lock);
1683 pl = NULL;
1684 pu = parkinglot;
1685 /* navigate the list with prev-cur pointers to support removals */
1686 while (pu) {
1687 struct ast_channel *chan = pu->chan; /* shorthand */
1688 int tms; /* timeout for this item */
1689 int x; /* fd index in channel */
1690 struct ast_context *con;
1692 if (pu->notquiteyet) { /* Pretend this one isn't here yet */
1693 pl = pu;
1694 pu = pu->next;
1695 continue;
1697 tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
1698 if (tms > pu->parkingtime) {
1699 ast_indicate(chan, AST_CONTROL_UNHOLD);
1700 /* Get chan, exten from derived kludge */
1701 if (pu->peername[0]) {
1702 char *peername = ast_strdupa(pu->peername);
1703 char *cp = strrchr(peername, '-');
1704 if (cp)
1705 *cp = 0;
1706 con = ast_context_find(parking_con_dial);
1707 if (!con) {
1708 con = ast_context_create(NULL, parking_con_dial, registrar);
1709 if (!con)
1710 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
1712 if (con) {
1713 char returnexten[AST_MAX_EXTENSION];
1714 snprintf(returnexten, sizeof(returnexten), "%s||t", peername);
1715 ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), ast_free, registrar);
1717 set_c_e_p(chan, parking_con_dial, peername, 1);
1718 } else {
1719 /* They've been waiting too long, send them back to where they came. Theoretically they
1720 should have their original extensions and such, but we copy to be on the safe side */
1721 set_c_e_p(chan, pu->context, pu->exten, pu->priority);
1724 post_manager_event("ParkedCallTimeOut", pu->parkingexten, chan);
1726 if (option_verbose > 1)
1727 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);
1728 /* Start up the PBX, or hang them up */
1729 if (ast_pbx_start(chan)) {
1730 ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", chan->name);
1731 ast_hangup(chan);
1733 /* And take them out of the parking lot */
1734 if (pl)
1735 pl->next = pu->next;
1736 else
1737 parkinglot = pu->next;
1738 pt = pu;
1739 pu = pu->next;
1740 con = ast_context_find(parking_con);
1741 if (con) {
1742 if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL))
1743 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1744 else
1745 notify_metermaids(pt->parkingexten, parking_con);
1746 } else
1747 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1748 free(pt);
1749 } else { /* still within parking time, process descriptors */
1750 for (x = 0; x < AST_MAX_FDS; x++) {
1751 struct ast_frame *f;
1753 if (chan->fds[x] == -1 || (!FD_ISSET(chan->fds[x], &rfds) && !FD_ISSET(chan->fds[x], &efds)))
1754 continue; /* nothing on this descriptor */
1756 if (FD_ISSET(chan->fds[x], &efds))
1757 ast_set_flag(chan, AST_FLAG_EXCEPTION);
1758 else
1759 ast_clear_flag(chan, AST_FLAG_EXCEPTION);
1760 chan->fdno = x;
1762 /* See if they need servicing */
1763 f = ast_read(chan);
1764 if (!f || (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_HANGUP)) {
1765 if (f)
1766 ast_frfree(f);
1767 post_manager_event("ParkedCallGiveUp", pu->parkingexten, chan);
1769 /* There's a problem, hang them up*/
1770 if (option_verbose > 1)
1771 ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", chan->name);
1772 ast_hangup(chan);
1773 /* And take them out of the parking lot */
1774 if (pl)
1775 pl->next = pu->next;
1776 else
1777 parkinglot = pu->next;
1778 pt = pu;
1779 pu = pu->next;
1780 con = ast_context_find(parking_con);
1781 if (con) {
1782 if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL))
1783 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1784 else
1785 notify_metermaids(pt->parkingexten, parking_con);
1786 } else
1787 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1788 free(pt);
1789 break;
1790 } else {
1791 /*! \todo XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
1792 ast_frfree(f);
1793 if (pu->moh_trys < 3 && !chan->generatordata) {
1794 if (option_debug)
1795 ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source. Restarting.\n");
1796 ast_indicate_data(pu->chan, AST_CONTROL_HOLD,
1797 S_OR(parkmohclass, NULL),
1798 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
1799 pu->moh_trys++;
1801 goto std; /*! \todo XXX Ick: jumping into an else statement??? XXX */
1804 } /* end for */
1805 if (x >= AST_MAX_FDS) {
1806 std: for (x=0; x<AST_MAX_FDS; x++) { /* mark fds for next round */
1807 if (chan->fds[x] > -1) {
1808 FD_SET(chan->fds[x], &nrfds);
1809 FD_SET(chan->fds[x], &nefds);
1810 if (chan->fds[x] > max)
1811 max = chan->fds[x];
1814 /* Keep track of our shortest wait */
1815 if (tms < ms || ms < 0)
1816 ms = tms;
1817 pl = pu;
1818 pu = pu->next;
1821 } /* end while */
1822 ast_mutex_unlock(&parking_lock);
1823 rfds = nrfds;
1824 efds = nefds;
1826 struct timeval tv = ast_samp2tv(ms, 1000);
1827 /* Wait for something to happen */
1828 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
1830 pthread_testcancel();
1832 return NULL; /* Never reached */
1835 /*! \brief Park a call */
1836 static int park_call_exec(struct ast_channel *chan, void *data)
1838 /* Cache the original channel name in case we get masqueraded in the middle
1839 * of a park--it is still theoretically possible for a transfer to happen before
1840 * we get here, but it is _really_ unlikely */
1841 char *orig_chan_name = ast_strdupa(chan->name);
1842 char orig_exten[AST_MAX_EXTENSION];
1843 int orig_priority = chan->priority;
1845 /* Data is unused at the moment but could contain a parking
1846 lot context eventually */
1847 int res = 0;
1848 struct ast_module_user *u;
1850 u = ast_module_user_add(chan);
1852 ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten));
1854 /* Setup the exten/priority to be s/1 since we don't know
1855 where this call should return */
1856 strcpy(chan->exten, "s");
1857 chan->priority = 1;
1858 /* Answer if call is not up */
1859 if (chan->_state != AST_STATE_UP)
1860 res = ast_answer(chan);
1861 /* Sleep to allow VoIP streams to settle down */
1862 if (!res)
1863 res = ast_safe_sleep(chan, 1000);
1864 /* Park the call */
1865 if (!res) {
1866 res = park_call_full(chan, chan, 0, NULL, orig_chan_name);
1867 /* Continue on in the dialplan */
1868 if (res == 1) {
1869 ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten));
1870 chan->priority = orig_priority;
1871 res = 0;
1872 } else if (!res)
1873 res = AST_PBX_KEEPALIVE;
1876 ast_module_user_remove(u);
1878 return res;
1881 /*! \brief Pickup parked call */
1882 static int park_exec(struct ast_channel *chan, void *data)
1884 int res = 0;
1885 struct ast_module_user *u;
1886 struct ast_channel *peer=NULL;
1887 struct parkeduser *pu, *pl=NULL;
1888 struct ast_context *con;
1890 int park;
1891 struct ast_bridge_config config;
1893 if (!data) {
1894 ast_log(LOG_WARNING, "Parkedcall requires an argument (extension number)\n");
1895 return -1;
1898 u = ast_module_user_add(chan);
1900 park = atoi((char *)data);
1901 ast_mutex_lock(&parking_lock);
1902 pu = parkinglot;
1903 while(pu) {
1904 if (pu->parkingnum == park) {
1905 if (pl)
1906 pl->next = pu->next;
1907 else
1908 parkinglot = pu->next;
1909 break;
1911 pl = pu;
1912 pu = pu->next;
1914 ast_mutex_unlock(&parking_lock);
1915 if (pu) {
1916 peer = pu->chan;
1917 con = ast_context_find(parking_con);
1918 if (con) {
1919 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL))
1920 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1921 else
1922 notify_metermaids(pu->parkingexten, parking_con);
1923 } else
1924 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1926 manager_event(EVENT_FLAG_CALL, "UnParkedCall",
1927 "Exten: %s\r\n"
1928 "Channel: %s\r\n"
1929 "From: %s\r\n"
1930 "CallerID: %s\r\n"
1931 "CallerIDName: %s\r\n",
1932 pu->parkingexten, pu->chan->name, chan->name,
1933 S_OR(pu->chan->cid.cid_num, "<unknown>"),
1934 S_OR(pu->chan->cid.cid_name, "<unknown>")
1937 free(pu);
1939 /* JK02: it helps to answer the channel if not already up */
1940 if (chan->_state != AST_STATE_UP)
1941 ast_answer(chan);
1943 if (peer) {
1944 /* Play a courtesy to the source(s) configured to prefix the bridge connecting */
1946 if (!ast_strlen_zero(courtesytone)) {
1947 int error = 0;
1948 ast_indicate(peer, AST_CONTROL_UNHOLD);
1949 if (parkedplay == 0) {
1950 error = ast_stream_and_wait(chan, courtesytone, chan->language, "");
1951 } else if (parkedplay == 1) {
1952 error = ast_stream_and_wait(peer, courtesytone, chan->language, "");
1953 } else if (parkedplay == 2) {
1954 if (!ast_streamfile(chan, courtesytone, chan->language) &&
1955 !ast_streamfile(peer, courtesytone, chan->language)) {
1956 /*! \todo XXX we would like to wait on both! */
1957 res = ast_waitstream(chan, "");
1958 if (res >= 0)
1959 res = ast_waitstream(peer, "");
1960 if (res < 0)
1961 error = 1;
1964 if (error) {
1965 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
1966 ast_hangup(peer);
1967 ast_module_user_remove(u);
1968 return -1;
1970 } else
1971 ast_indicate(peer, AST_CONTROL_UNHOLD);
1973 res = ast_channel_make_compatible(chan, peer);
1974 if (res < 0) {
1975 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
1976 ast_hangup(peer);
1977 ast_module_user_remove(u);
1978 return -1;
1980 /* This runs sorta backwards, since we give the incoming channel control, as if it
1981 were the person called. */
1982 if (option_verbose > 2)
1983 ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
1985 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
1986 ast_cdr_setdestchan(chan->cdr, peer->name);
1987 memset(&config, 0, sizeof(struct ast_bridge_config));
1988 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
1989 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
1990 res = ast_bridge_call(chan, peer, &config);
1992 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
1993 ast_cdr_setdestchan(chan->cdr, peer->name);
1995 /* Simulate the PBX hanging up */
1996 if (res != AST_PBX_NO_HANGUP_PEER)
1997 ast_hangup(peer);
1998 ast_module_user_remove(u);
1999 return res;
2000 } else {
2001 /*! \todo XXX Play a message XXX */
2002 if (ast_stream_and_wait(chan, "pbx-invalidpark", chan->language, ""))
2003 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
2004 if (option_verbose > 2)
2005 ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
2006 res = -1;
2009 ast_module_user_remove(u);
2011 return res;
2014 static int handle_showfeatures(int fd, int argc, char *argv[])
2016 int i;
2017 struct ast_call_feature *feature;
2018 char format[] = "%-25s %-7s %-7s\n";
2020 ast_cli(fd, format, "Builtin Feature", "Default", "Current");
2021 ast_cli(fd, format, "---------------", "-------", "-------");
2023 ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */
2025 ast_rwlock_rdlock(&features_lock);
2026 for (i = 0; i < FEATURES_COUNT; i++)
2027 ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
2028 ast_rwlock_unlock(&features_lock);
2030 ast_cli(fd, "\n");
2031 ast_cli(fd, format, "Dynamic Feature", "Default", "Current");
2032 ast_cli(fd, format, "---------------", "-------", "-------");
2033 if (AST_LIST_EMPTY(&feature_list))
2034 ast_cli(fd, "(none)\n");
2035 else {
2036 AST_LIST_LOCK(&feature_list);
2037 AST_LIST_TRAVERSE(&feature_list, feature, feature_entry)
2038 ast_cli(fd, format, feature->sname, "no def", feature->exten);
2039 AST_LIST_UNLOCK(&feature_list);
2041 ast_cli(fd, "\nCall parking\n");
2042 ast_cli(fd, "------------\n");
2043 ast_cli(fd,"%-20s: %s\n", "Parking extension", parking_ext);
2044 ast_cli(fd,"%-20s: %s\n", "Parking context", parking_con);
2045 ast_cli(fd,"%-20s: %d-%d\n", "Parked call extensions", parking_start, parking_stop);
2046 ast_cli(fd,"\n");
2048 return RESULT_SUCCESS;
2051 static char showfeatures_help[] =
2052 "Usage: feature list\n"
2053 " Lists currently configured features.\n";
2055 static int handle_parkedcalls(int fd, int argc, char *argv[])
2057 struct parkeduser *cur;
2058 int numparked = 0;
2060 ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
2061 , "Context", "Extension", "Pri", "Timeout");
2063 ast_mutex_lock(&parking_lock);
2065 for (cur = parkinglot; cur; cur = cur->next) {
2066 ast_cli(fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n"
2067 ,cur->parkingexten, cur->chan->name, cur->context, cur->exten
2068 ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
2070 numparked++;
2072 ast_mutex_unlock(&parking_lock);
2073 ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : "");
2076 return RESULT_SUCCESS;
2079 static char showparked_help[] =
2080 "Usage: show parkedcalls\n"
2081 " Lists currently parked calls.\n";
2083 static struct ast_cli_entry cli_show_features_deprecated = {
2084 { "show", "features", NULL },
2085 handle_showfeatures, NULL,
2086 NULL };
2088 static struct ast_cli_entry cli_features[] = {
2089 { { "feature", "show", NULL },
2090 handle_showfeatures, "Lists configured features",
2091 showfeatures_help, NULL, &cli_show_features_deprecated },
2093 { { "show", "parkedcalls", NULL },
2094 handle_parkedcalls, "Lists parked calls",
2095 showparked_help },
2098 /*! \brief Dump lot status */
2099 static int manager_parking_status( struct mansession *s, const struct message *m)
2101 struct parkeduser *cur;
2102 const char *id = astman_get_header(m, "ActionID");
2103 char idText[256] = "";
2105 if (!ast_strlen_zero(id))
2106 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
2108 astman_send_ack(s, m, "Parked calls will follow");
2110 ast_mutex_lock(&parking_lock);
2112 for (cur = parkinglot; cur; cur = cur->next) {
2113 astman_append(s, "Event: ParkedCall\r\n"
2114 "Exten: %d\r\n"
2115 "Channel: %s\r\n"
2116 "From: %s\r\n"
2117 "Timeout: %ld\r\n"
2118 "CallerID: %s\r\n"
2119 "CallerIDName: %s\r\n"
2120 "%s"
2121 "\r\n",
2122 cur->parkingnum, cur->chan->name, cur->peername,
2123 (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
2124 S_OR(cur->chan->cid.cid_num, ""), /* XXX in other places it is <unknown> */
2125 S_OR(cur->chan->cid.cid_name, ""),
2126 idText);
2129 astman_append(s,
2130 "Event: ParkedCallsComplete\r\n"
2131 "%s"
2132 "\r\n",idText);
2134 ast_mutex_unlock(&parking_lock);
2136 return RESULT_SUCCESS;
2139 static char mandescr_park[] =
2140 "Description: Park a channel.\n"
2141 "Variables: (Names marked with * are required)\n"
2142 " *Channel: Channel name to park\n"
2143 " *Channel2: Channel to announce park info to (and return to if timeout)\n"
2144 " Timeout: Number of milliseconds to wait before callback.\n";
2146 static int manager_park(struct mansession *s, const struct message *m)
2148 const char *channel = astman_get_header(m, "Channel");
2149 const char *channel2 = astman_get_header(m, "Channel2");
2150 const char *timeout = astman_get_header(m, "Timeout");
2151 char buf[BUFSIZ];
2152 int to = 0;
2153 int res = 0;
2154 int parkExt = 0;
2155 struct ast_channel *ch1, *ch2;
2157 if (ast_strlen_zero(channel)) {
2158 astman_send_error(s, m, "Channel not specified");
2159 return 0;
2162 if (ast_strlen_zero(channel2)) {
2163 astman_send_error(s, m, "Channel2 not specified");
2164 return 0;
2167 ch1 = ast_get_channel_by_name_locked(channel);
2168 if (!ch1) {
2169 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
2170 astman_send_error(s, m, buf);
2171 return 0;
2174 ch2 = ast_get_channel_by_name_locked(channel2);
2175 if (!ch2) {
2176 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
2177 astman_send_error(s, m, buf);
2178 ast_channel_unlock(ch1);
2179 return 0;
2182 if (!ast_strlen_zero(timeout)) {
2183 sscanf(timeout, "%d", &to);
2186 res = ast_masq_park_call(ch1, ch2, to, &parkExt);
2187 if (!res) {
2188 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
2189 astman_send_ack(s, m, "Park successful");
2190 } else {
2191 astman_send_error(s, m, "Park failure");
2194 ast_channel_unlock(ch1);
2195 ast_channel_unlock(ch2);
2197 return 0;
2201 int ast_pickup_call(struct ast_channel *chan)
2203 struct ast_channel *cur = NULL;
2204 int res = -1;
2206 while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
2207 if (!cur->pbx &&
2208 (cur != chan) &&
2209 (chan->pickupgroup & cur->callgroup) &&
2210 ((cur->_state == AST_STATE_RINGING) ||
2211 (cur->_state == AST_STATE_RING))) {
2212 break;
2214 ast_channel_unlock(cur);
2216 if (cur) {
2217 if (option_debug)
2218 ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
2219 res = ast_answer(chan);
2220 if (res)
2221 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
2222 res = ast_queue_control(chan, AST_CONTROL_ANSWER);
2223 if (res)
2224 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
2225 res = ast_channel_masquerade(cur, chan);
2226 if (res)
2227 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */
2228 ast_channel_unlock(cur);
2229 } else {
2230 if (option_debug)
2231 ast_log(LOG_DEBUG, "No call pickup possible...\n");
2233 return res;
2236 /*! \brief Add parking hints for all defined parking lots */
2237 static void park_add_hints(char *context, int start, int stop)
2239 int numext;
2240 char device[AST_MAX_EXTENSION];
2241 char exten[10];
2243 for (numext = start; numext <= stop; numext++) {
2244 snprintf(exten, sizeof(exten), "%d", numext);
2245 snprintf(device, sizeof(device), "park:%s@%s", exten, context);
2246 ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
2251 static int load_config(void)
2253 int start = 0, end = 0;
2254 int res;
2255 struct ast_context *con = NULL;
2256 struct ast_config *cfg = NULL;
2257 struct ast_variable *var = NULL;
2258 char old_parking_ext[AST_MAX_EXTENSION];
2259 char old_parking_con[AST_MAX_EXTENSION] = "";
2261 if (!ast_strlen_zero(parking_con)) {
2262 strcpy(old_parking_ext, parking_ext);
2263 strcpy(old_parking_con, parking_con);
2266 /* Reset to defaults */
2267 strcpy(parking_con, "parkedcalls");
2268 strcpy(parking_con_dial, "park-dial");
2269 strcpy(parking_ext, "700");
2270 strcpy(pickup_ext, "*8");
2271 strcpy(parkmohclass, "default");
2272 courtesytone[0] = '\0';
2273 strcpy(xfersound, "beep");
2274 strcpy(xferfailsound, "pbx-invalid");
2275 parking_start = 701;
2276 parking_stop = 750;
2277 parkfindnext = 0;
2278 adsipark = 0;
2279 parkaddhints = 0;
2281 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
2282 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
2283 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
2285 cfg = ast_config_load("features.conf");
2286 if (!cfg) {
2287 ast_log(LOG_WARNING,"Could not load features.conf\n");
2288 return AST_MODULE_LOAD_DECLINE;
2290 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
2291 if (!strcasecmp(var->name, "parkext")) {
2292 ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
2293 } else if (!strcasecmp(var->name, "context")) {
2294 ast_copy_string(parking_con, var->value, sizeof(parking_con));
2295 } else if (!strcasecmp(var->name, "parkingtime")) {
2296 if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) {
2297 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
2298 parkingtime = DEFAULT_PARK_TIME;
2299 } else
2300 parkingtime = parkingtime * 1000;
2301 } else if (!strcasecmp(var->name, "parkpos")) {
2302 if (sscanf(var->value, "%d-%d", &start, &end) != 2) {
2303 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);
2304 } else {
2305 parking_start = start;
2306 parking_stop = end;
2308 } else if (!strcasecmp(var->name, "findslot")) {
2309 parkfindnext = (!strcasecmp(var->value, "next"));
2310 } else if (!strcasecmp(var->name, "parkinghints")) {
2311 parkaddhints = ast_true(var->value);
2312 } else if (!strcasecmp(var->name, "adsipark")) {
2313 adsipark = ast_true(var->value);
2314 } else if (!strcasecmp(var->name, "transferdigittimeout")) {
2315 if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
2316 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
2317 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
2318 } else
2319 transferdigittimeout = transferdigittimeout * 1000;
2320 } else if (!strcasecmp(var->name, "featuredigittimeout")) {
2321 if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
2322 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
2323 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
2325 } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) {
2326 if ((sscanf(var->value, "%d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) {
2327 ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value);
2328 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
2329 } else
2330 atxfernoanswertimeout = atxfernoanswertimeout * 1000;
2331 } else if (!strcasecmp(var->name, "courtesytone")) {
2332 ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
2333 } else if (!strcasecmp(var->name, "parkedplay")) {
2334 if (!strcasecmp(var->value, "both"))
2335 parkedplay = 2;
2336 else if (!strcasecmp(var->value, "parked"))
2337 parkedplay = 1;
2338 else
2339 parkedplay = 0;
2340 } else if (!strcasecmp(var->name, "xfersound")) {
2341 ast_copy_string(xfersound, var->value, sizeof(xfersound));
2342 } else if (!strcasecmp(var->name, "xferfailsound")) {
2343 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
2344 } else if (!strcasecmp(var->name, "pickupexten")) {
2345 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
2346 } else if (!strcasecmp(var->name, "parkedmusicclass")) {
2347 ast_copy_string(parkmohclass, var->value, sizeof(parkmohclass));
2351 unmap_features();
2352 for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) {
2353 if (remap_feature(var->name, var->value))
2354 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
2357 /* Map a key combination to an application*/
2358 ast_unregister_features();
2359 for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) {
2360 char *tmp_val = ast_strdupa(var->value);
2361 char *exten, *activateon, *activatedby, *app, *app_args, *moh_class;
2362 struct ast_call_feature *feature;
2364 /* strsep() sets the argument to NULL if match not found, and it
2365 * is safe to use it with a NULL argument, so we don't check
2366 * between calls.
2368 exten = strsep(&tmp_val,",");
2369 activatedby = strsep(&tmp_val,",");
2370 app = strsep(&tmp_val,",");
2371 app_args = strsep(&tmp_val,",");
2372 moh_class = strsep(&tmp_val,",");
2374 activateon = strsep(&activatedby, "/");
2376 /*! \todo XXX var_name or app_args ? */
2377 if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) {
2378 ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",
2379 app, exten, activateon, var->name);
2380 continue;
2383 AST_LIST_LOCK(&feature_list);
2384 if ((feature = find_dynamic_feature(var->name))) {
2385 AST_LIST_UNLOCK(&feature_list);
2386 ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name);
2387 continue;
2389 AST_LIST_UNLOCK(&feature_list);
2391 if (!(feature = ast_calloc(1, sizeof(*feature))))
2392 continue;
2394 ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN);
2395 ast_copy_string(feature->app, app, FEATURE_APP_LEN);
2396 ast_copy_string(feature->exten, exten, FEATURE_EXTEN_LEN);
2398 if (app_args)
2399 ast_copy_string(feature->app_args, app_args, FEATURE_APP_ARGS_LEN);
2401 if (moh_class)
2402 ast_copy_string(feature->moh_class, moh_class, FEATURE_MOH_LEN);
2404 ast_copy_string(feature->exten, exten, sizeof(feature->exten));
2405 feature->operation = feature_exec_app;
2406 ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF);
2408 /* Allow caller and calle to be specified for backwards compatability */
2409 if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller"))
2410 ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF);
2411 else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee"))
2412 ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER);
2413 else {
2414 ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s',"
2415 " must be 'self', or 'peer'\n", var->name);
2416 continue;
2419 if (ast_strlen_zero(activatedby))
2420 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
2421 else if (!strcasecmp(activatedby, "caller"))
2422 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER);
2423 else if (!strcasecmp(activatedby, "callee"))
2424 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE);
2425 else if (!strcasecmp(activatedby, "both"))
2426 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
2427 else {
2428 ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s',"
2429 " must be 'caller', or 'callee', or 'both'\n", var->name);
2430 continue;
2433 ast_register_feature(feature);
2435 if (option_verbose >= 1)
2436 ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, app, app_args, exten);
2438 ast_config_destroy(cfg);
2440 /* Remove the old parking extension */
2441 if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) {
2442 if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar))
2443 notify_metermaids(old_parking_ext, old_parking_con);
2444 if (option_debug)
2445 ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
2448 if (!(con = ast_context_find(parking_con)) && !(con = ast_context_create(NULL, parking_con, registrar))) {
2449 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
2450 return -1;
2452 res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar);
2453 if (parkaddhints)
2454 park_add_hints(parking_con, parking_start, parking_stop);
2455 if (!res)
2456 notify_metermaids(ast_parking_ext(), parking_con);
2457 return res;
2461 static int reload(void)
2463 return load_config();
2466 static int load_module(void)
2468 int res;
2470 memset(parking_ext, 0, sizeof(parking_ext));
2471 memset(parking_con, 0, sizeof(parking_con));
2473 if ((res = load_config()))
2474 return res;
2475 ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
2476 ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
2477 res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
2478 if (!res)
2479 res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
2480 if (!res) {
2481 ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" );
2482 ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park,
2483 "Park a channel", mandescr_park);
2486 res |= ast_devstate_prov_add("Park", metermaidstate);
2488 return res;
2492 static int unload_module(void)
2494 ast_module_user_hangup_all();
2496 ast_manager_unregister("ParkedCalls");
2497 ast_manager_unregister("Park");
2498 ast_cli_unregister_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
2499 ast_unregister_application(parkcall);
2500 ast_devstate_prov_del("Park");
2501 return ast_unregister_application(parkedcall);
2504 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Call Features Resource",
2505 .load = load_module,
2506 .unload = unload_module,
2507 .reload = reload,