fix various other problems found by gcc 4.3
[asterisk-bristuff.git] / res / res_features.c
blobf1261b29cd4cc18d89f3bbd238128f3f566317d0
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->readformat = transferee->readformat;
873 xferchan->writeformat = transferee->writeformat;
874 ast_channel_masquerade(xferchan, transferee);
875 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
876 xferchan->_state = AST_STATE_UP;
877 ast_clear_flag(xferchan, AST_FLAGS_ALL);
878 xferchan->_softhangup = 0;
880 if ((f = ast_read(xferchan)))
881 ast_frfree(f);
883 newchan->_state = AST_STATE_UP;
884 ast_clear_flag(newchan, AST_FLAGS_ALL);
885 newchan->_softhangup = 0;
887 tobj = ast_calloc(1, sizeof(struct ast_bridge_thread_obj));
888 if (!tobj) {
889 ast_hangup(xferchan);
890 ast_hangup(newchan);
891 return -1;
893 tobj->chan = newchan;
894 tobj->peer = xferchan;
895 tobj->bconfig = *config;
897 if (ast_stream_and_wait(newchan, xfersound, newchan->language, ""))
898 ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
899 ast_bridge_call_thread_launch(tobj);
900 return -1; /* XXX meaning the channel is bridged ? */
904 /* add atxfer and automon as undefined so you can only use em if you configure them */
905 #define FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0]))
907 AST_RWLOCK_DEFINE_STATIC(features_lock);
909 static struct ast_call_feature builtin_features[] =
911 { AST_FEATURE_REDIRECT, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
912 { AST_FEATURE_REDIRECT, "Attended Transfer", "atxfer", "", "", builtin_atxfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
913 { AST_FEATURE_AUTOMON, "One Touch Monitor", "automon", "", "", builtin_automonitor, AST_FEATURE_FLAG_NEEDSDTMF, "" },
914 { AST_FEATURE_DISCONNECT, "Disconnect Call", "disconnect", "*", "*", builtin_disconnect, AST_FEATURE_FLAG_NEEDSDTMF, "" },
915 { AST_FEATURE_PARKCALL, "Park Call", "parkcall", "", "", builtin_parkcall, AST_FEATURE_FLAG_NEEDSDTMF, "" },
919 static AST_LIST_HEAD_STATIC(feature_list,ast_call_feature);
921 /*! \brief register new feature into feature_list*/
922 void ast_register_feature(struct ast_call_feature *feature)
924 if (!feature) {
925 ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
926 return;
929 AST_LIST_LOCK(&feature_list);
930 AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry);
931 AST_LIST_UNLOCK(&feature_list);
933 if (option_verbose >= 2)
934 ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
937 /*! \brief unregister feature from feature_list */
938 void ast_unregister_feature(struct ast_call_feature *feature)
940 if (!feature)
941 return;
943 AST_LIST_LOCK(&feature_list);
944 AST_LIST_REMOVE(&feature_list,feature,feature_entry);
945 AST_LIST_UNLOCK(&feature_list);
946 free(feature);
949 /*! \brief Remove all features in the list */
950 static void ast_unregister_features(void)
952 struct ast_call_feature *feature;
954 AST_LIST_LOCK(&feature_list);
955 while ((feature = AST_LIST_REMOVE_HEAD(&feature_list,feature_entry)))
956 free(feature);
957 AST_LIST_UNLOCK(&feature_list);
960 /*! \brief find a feature by name */
961 static struct ast_call_feature *find_dynamic_feature(const char *name)
963 struct ast_call_feature *tmp;
965 AST_LIST_TRAVERSE(&feature_list, tmp, feature_entry) {
966 if (!strcasecmp(tmp->sname, name))
967 break;
970 return tmp;
973 /*! \brief exec an app by feature */
974 static int feature_exec_app(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
976 struct ast_app *app;
977 struct ast_call_feature *feature = data;
978 struct ast_channel *work, *idle;
979 int res;
981 if (!feature) { /* shouldn't ever happen! */
982 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
983 return -1;
986 if (sense == FEATURE_SENSE_CHAN) {
987 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
988 return FEATURE_RETURN_KEEPTRYING;
989 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
990 work = chan;
991 idle = peer;
992 } else {
993 work = peer;
994 idle = chan;
996 } else {
997 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
998 return FEATURE_RETURN_KEEPTRYING;
999 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
1000 work = peer;
1001 idle = chan;
1002 } else {
1003 work = chan;
1004 idle = peer;
1008 if (!(app = pbx_findapp(feature->app))) {
1009 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
1010 return -2;
1013 ast_autoservice_start(idle);
1015 if (!ast_strlen_zero(feature->moh_class))
1016 ast_moh_start(idle, feature->moh_class, NULL);
1018 res = pbx_exec(work, app, feature->app_args);
1020 if (!ast_strlen_zero(feature->moh_class))
1021 ast_moh_stop(idle);
1023 ast_autoservice_stop(idle);
1025 if (res == AST_PBX_KEEPALIVE)
1026 return FEATURE_RETURN_PBX_KEEPALIVE;
1027 else if (res == AST_PBX_NO_HANGUP_PEER)
1028 return FEATURE_RETURN_NO_HANGUP_PEER;
1029 else if (res)
1030 return FEATURE_RETURN_SUCCESSBREAK;
1032 return FEATURE_RETURN_SUCCESS; /*! \todo XXX should probably return res */
1035 static void unmap_features(void)
1037 int x;
1039 ast_rwlock_wrlock(&features_lock);
1040 for (x = 0; x < FEATURES_COUNT; x++)
1041 strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
1042 ast_rwlock_unlock(&features_lock);
1045 static int remap_feature(const char *name, const char *value)
1047 int x, res = -1;
1049 ast_rwlock_wrlock(&features_lock);
1050 for (x = 0; x < FEATURES_COUNT; x++) {
1051 if (strcasecmp(builtin_features[x].sname, name))
1052 continue;
1054 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
1055 res = 0;
1056 break;
1058 ast_rwlock_unlock(&features_lock);
1060 return res;
1063 static int ast_feature_interpret(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
1065 int x;
1066 struct ast_flags features;
1067 int res = FEATURE_RETURN_PASSDIGITS;
1068 struct ast_call_feature *feature;
1069 const char *dynamic_features;
1070 char *tmp, *tok;
1072 if (sense == FEATURE_SENSE_CHAN) {
1073 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
1074 dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
1075 } else {
1076 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);
1077 dynamic_features = pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES");
1079 if (option_debug > 2)
1080 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);
1082 ast_rwlock_rdlock(&features_lock);
1083 for (x = 0; x < FEATURES_COUNT; x++) {
1084 if ((ast_test_flag(&features, builtin_features[x].feature_mask)) &&
1085 !ast_strlen_zero(builtin_features[x].exten)) {
1086 /* Feature is up for consideration */
1087 if (!strcmp(builtin_features[x].exten, code)) {
1088 res = builtin_features[x].operation(chan, peer, config, code, sense, NULL);
1089 break;
1090 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
1091 if (res == FEATURE_RETURN_PASSDIGITS)
1092 res = FEATURE_RETURN_STOREDIGITS;
1096 ast_rwlock_unlock(&features_lock);
1098 if (ast_strlen_zero(dynamic_features))
1099 return res;
1101 tmp = ast_strdupa(dynamic_features);
1103 while ((tok = strsep(&tmp, "#"))) {
1104 AST_LIST_LOCK(&feature_list);
1105 if (!(feature = find_dynamic_feature(tok))) {
1106 AST_LIST_UNLOCK(&feature_list);
1107 continue;
1110 /* Feature is up for consideration */
1111 if (!strcmp(feature->exten, code)) {
1112 if (option_verbose > 2)
1113 ast_verbose(VERBOSE_PREFIX_3 " Feature Found: %s exten: %s\n",feature->sname, tok);
1114 res = feature->operation(chan, peer, config, code, sense, feature);
1115 if (res != FEATURE_RETURN_KEEPTRYING) {
1116 AST_LIST_UNLOCK(&feature_list);
1117 break;
1119 res = FEATURE_RETURN_PASSDIGITS;
1120 } else if (!strncmp(feature->exten, code, strlen(code)))
1121 res = FEATURE_RETURN_STOREDIGITS;
1123 AST_LIST_UNLOCK(&feature_list);
1126 return res;
1129 static void set_config_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
1131 int x;
1133 ast_clear_flag(config, AST_FLAGS_ALL);
1135 ast_rwlock_rdlock(&features_lock);
1136 for (x = 0; x < FEATURES_COUNT; x++) {
1137 if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF))
1138 continue;
1140 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
1141 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
1143 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
1144 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
1146 ast_rwlock_unlock(&features_lock);
1148 if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
1149 const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
1151 if (dynamic_features) {
1152 char *tmp = ast_strdupa(dynamic_features);
1153 char *tok;
1154 struct ast_call_feature *feature;
1156 /* while we have a feature */
1157 while ((tok = strsep(&tmp, "#"))) {
1158 AST_LIST_LOCK(&feature_list);
1159 if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
1160 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
1161 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
1162 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
1163 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
1165 AST_LIST_UNLOCK(&feature_list);
1171 /*! \todo XXX Check - this is very similar to the code in channel.c */
1172 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)
1174 int state = 0;
1175 int cause = 0;
1176 int to;
1177 struct ast_channel *chan;
1178 struct ast_channel *monitor_chans[2];
1179 struct ast_channel *active_channel;
1180 int res = 0, ready = 0;
1182 if ((chan = ast_request(type, format, data, &cause))) {
1183 ast_set_callerid(chan, cid_num, cid_name, cid_num);
1184 ast_string_field_set(chan, language, language);
1185 ast_channel_inherit_variables(caller, chan);
1186 pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name);
1187 if (!chan->cdr) {
1188 chan->cdr=ast_cdr_alloc();
1189 if (chan->cdr) {
1190 ast_cdr_init(chan->cdr, chan); /* initilize our channel's cdr */
1191 ast_cdr_start(chan->cdr);
1195 if (!ast_call(chan, data, timeout)) {
1196 struct timeval started;
1197 int x, len = 0;
1198 char *disconnect_code = NULL, *dialed_code = NULL;
1200 ast_indicate(caller, AST_CONTROL_RINGING);
1201 /* support dialing of the featuremap disconnect code while performing an attended tranfer */
1202 ast_rwlock_rdlock(&features_lock);
1203 for (x = 0; x < FEATURES_COUNT; x++) {
1204 if (strcasecmp(builtin_features[x].sname, "disconnect"))
1205 continue;
1207 disconnect_code = builtin_features[x].exten;
1208 len = strlen(disconnect_code) + 1;
1209 dialed_code = alloca(len);
1210 memset(dialed_code, 0, len);
1211 break;
1213 ast_rwlock_unlock(&features_lock);
1214 x = 0;
1215 started = ast_tvnow();
1216 to = timeout;
1217 while (!ast_check_hangup(caller) && timeout && (chan->_state != AST_STATE_UP)) {
1218 struct ast_frame *f = NULL;
1220 monitor_chans[0] = caller;
1221 monitor_chans[1] = chan;
1222 active_channel = ast_waitfor_n(monitor_chans, 2, &to);
1224 /* see if the timeout has been violated */
1225 if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
1226 state = AST_CONTROL_UNHOLD;
1227 ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n");
1228 break; /*doh! timeout*/
1231 if (!active_channel)
1232 continue;
1234 if (chan && (chan == active_channel)){
1235 f = ast_read(chan);
1236 if (f == NULL) { /*doh! where'd he go?*/
1237 state = AST_CONTROL_HANGUP;
1238 res = 0;
1239 break;
1242 if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) {
1243 if (f->subclass == AST_CONTROL_RINGING) {
1244 state = f->subclass;
1245 if (option_verbose > 2)
1246 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", chan->name);
1247 ast_indicate(caller, AST_CONTROL_RINGING);
1248 } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) {
1249 state = f->subclass;
1250 if (option_verbose > 2)
1251 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", chan->name);
1252 ast_indicate(caller, AST_CONTROL_BUSY);
1253 ast_frfree(f);
1254 f = NULL;
1255 break;
1256 } else if (f->subclass == AST_CONTROL_ANSWER) {
1257 /* This is what we are hoping for */
1258 state = f->subclass;
1259 ast_frfree(f);
1260 f = NULL;
1261 ready=1;
1262 break;
1263 } else if (f->subclass != -1) {
1264 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass);
1266 /* else who cares */
1269 } else if (caller && (active_channel == caller)) {
1270 f = ast_read(caller);
1271 if (f == NULL) { /*doh! where'd he go?*/
1272 if (caller->_softhangup && !chan->_softhangup) {
1273 /* make this a blind transfer */
1274 ready = 1;
1275 break;
1277 state = AST_CONTROL_HANGUP;
1278 res = 0;
1279 break;
1282 if (f->frametype == AST_FRAME_DTMF) {
1283 dialed_code[x++] = f->subclass;
1284 dialed_code[x] = '\0';
1285 if (strlen(dialed_code) == len) {
1286 x = 0;
1287 } else if (x && strncmp(dialed_code, disconnect_code, x)) {
1288 x = 0;
1289 dialed_code[x] = '\0';
1291 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
1292 /* Caller Canceled the call */
1293 state = AST_CONTROL_UNHOLD;
1294 ast_frfree(f);
1295 f = NULL;
1296 break;
1300 if (f)
1301 ast_frfree(f);
1302 } /* end while */
1303 } else
1304 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
1305 } else {
1306 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
1307 switch(cause) {
1308 case AST_CAUSE_BUSY:
1309 state = AST_CONTROL_BUSY;
1310 break;
1311 case AST_CAUSE_CONGESTION:
1312 state = AST_CONTROL_CONGESTION;
1313 break;
1317 ast_indicate(caller, -1);
1318 if (chan && ready) {
1319 if (chan->_state == AST_STATE_UP)
1320 state = AST_CONTROL_ANSWER;
1321 res = 0;
1322 } else if(chan) {
1323 res = -1;
1324 ast_hangup(chan);
1325 chan = NULL;
1326 } else {
1327 res = -1;
1330 if (outstate)
1331 *outstate = state;
1333 if (chan && res <= 0) {
1334 if (chan->cdr || (chan->cdr = ast_cdr_alloc())) {
1335 char tmp[256];
1336 ast_cdr_init(chan->cdr, chan);
1337 snprintf(tmp, 256, "%s/%s", type, (char *)data);
1338 ast_cdr_setapp(chan->cdr,"Dial",tmp);
1339 ast_cdr_update(chan);
1340 ast_cdr_start(chan->cdr);
1341 ast_cdr_end(chan->cdr);
1342 /* If the cause wasn't handled properly */
1343 if (ast_cdr_disposition(chan->cdr,chan->hangupcause))
1344 ast_cdr_failed(chan->cdr);
1345 } else {
1346 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
1350 return chan;
1353 int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast_bridge_config *config)
1355 /* Copy voice back and forth between the two channels. Give the peer
1356 the ability to transfer calls with '#<extension' syntax. */
1357 struct ast_frame *f;
1358 struct ast_channel *who;
1359 char chan_featurecode[FEATURE_MAX_LEN + 1]="";
1360 char peer_featurecode[FEATURE_MAX_LEN + 1]="";
1361 int res;
1362 int diff;
1363 int hasfeatures=0;
1364 int hadfeatures=0;
1365 struct ast_option_header *aoh;
1366 struct ast_bridge_config backup_config;
1367 struct ast_cdr *bridge_cdr;
1369 memset(&backup_config, 0, sizeof(backup_config));
1371 config->start_time = ast_tvnow();
1373 if (chan && peer) {
1374 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
1375 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
1376 } else if (chan)
1377 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
1379 if (monitor_ok) {
1380 const char *monitor_exec;
1381 struct ast_channel *src = NULL;
1382 if (!monitor_app) {
1383 if (!(monitor_app = pbx_findapp("Monitor")))
1384 monitor_ok=0;
1386 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR")))
1387 src = chan;
1388 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
1389 src = peer;
1390 if (monitor_app && src) {
1391 char *tmp = ast_strdupa(monitor_exec);
1392 pbx_exec(src, monitor_app, tmp);
1396 set_config_flags(chan, peer, config);
1397 config->firstpass = 1;
1399 /* Answer if need be */
1400 if (ast_answer(chan))
1401 return -1;
1402 peer->appl = "Bridged Call";
1403 peer->data = chan->name;
1405 /* copy the userfield from the B-leg to A-leg if applicable */
1406 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
1407 char tmp[256];
1408 if (!ast_strlen_zero(chan->cdr->userfield)) {
1409 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield);
1410 ast_cdr_appenduserfield(chan, tmp);
1411 } else
1412 ast_cdr_setuserfield(chan, peer->cdr->userfield);
1413 /* free the peer's cdr without ast_cdr_free complaining */
1414 free(peer->cdr);
1415 peer->cdr = NULL;
1418 for (;;) {
1419 struct ast_channel *other; /* used later */
1421 res = ast_channel_bridge(chan, peer, config, &f, &who);
1423 if (config->feature_timer) {
1424 /* Update time limit for next pass */
1425 diff = ast_tvdiff_ms(ast_tvnow(), config->start_time);
1426 config->feature_timer -= diff;
1427 if (hasfeatures) {
1428 /* Running on backup config, meaning a feature might be being
1429 activated, but that's no excuse to keep things going
1430 indefinitely! */
1431 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
1432 if (option_debug)
1433 ast_log(LOG_DEBUG, "Timed out, realtime this time!\n");
1434 config->feature_timer = 0;
1435 who = chan;
1436 if (f)
1437 ast_frfree(f);
1438 f = NULL;
1439 res = 0;
1440 } else if (config->feature_timer <= 0) {
1441 /* Not *really* out of time, just out of time for
1442 digits to come in for features. */
1443 if (option_debug)
1444 ast_log(LOG_DEBUG, "Timed out for feature!\n");
1445 if (!ast_strlen_zero(peer_featurecode)) {
1446 ast_dtmf_stream(chan, peer, peer_featurecode, 0);
1447 memset(peer_featurecode, 0, sizeof(peer_featurecode));
1449 if (!ast_strlen_zero(chan_featurecode)) {
1450 ast_dtmf_stream(peer, chan, chan_featurecode, 0);
1451 memset(chan_featurecode, 0, sizeof(chan_featurecode));
1453 if (f)
1454 ast_frfree(f);
1455 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
1456 if (!hasfeatures) {
1457 /* Restore original (possibly time modified) bridge config */
1458 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
1459 memset(&backup_config, 0, sizeof(backup_config));
1461 hadfeatures = hasfeatures;
1462 /* Continue as we were */
1463 continue;
1464 } else if (!f) {
1465 /* The bridge returned without a frame and there is a feature in progress.
1466 * However, we don't think the feature has quite yet timed out, so just
1467 * go back into the bridge. */
1468 continue;
1470 } else {
1471 if (config->feature_timer <=0) {
1472 /* We ran out of time */
1473 config->feature_timer = 0;
1474 who = chan;
1475 if (f)
1476 ast_frfree(f);
1477 f = NULL;
1478 res = 0;
1482 if (res < 0) {
1483 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer))
1484 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
1485 return -1;
1488 if (!f || (f->frametype == AST_FRAME_CONTROL &&
1489 (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY ||
1490 f->subclass == AST_CONTROL_CONGESTION ) ) ) {
1491 res = -1;
1492 break;
1494 /* many things should be sent to the 'other' channel */
1495 other = (who == chan) ? peer : chan;
1496 if (f->frametype == AST_FRAME_CONTROL) {
1497 switch (f->subclass) {
1498 case AST_CONTROL_RINGING:
1499 case AST_CONTROL_FLASH:
1500 case -1:
1501 ast_indicate(other, f->subclass);
1502 break;
1503 case AST_CONTROL_HOLD:
1504 case AST_CONTROL_UNHOLD:
1505 ast_indicate_data(other, f->subclass, f->data, f->datalen);
1506 break;
1507 case AST_CONTROL_OPTION:
1508 aoh = f->data;
1509 /* Forward option Requests */
1510 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) {
1511 ast_channel_setoption(other, ntohs(aoh->option), aoh->data,
1512 f->datalen - sizeof(struct ast_option_header), 0);
1514 break;
1516 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
1517 /* eat it */
1518 } else if (f->frametype == AST_FRAME_DTMF) {
1519 char *featurecode;
1520 int sense;
1522 hadfeatures = hasfeatures;
1523 /* This cannot overrun because the longest feature is one shorter than our buffer */
1524 if (who == chan) {
1525 sense = FEATURE_SENSE_CHAN;
1526 featurecode = chan_featurecode;
1527 } else {
1528 sense = FEATURE_SENSE_PEER;
1529 featurecode = peer_featurecode;
1531 /*! append the event to featurecode. we rely on the string being zero-filled, and
1532 * not overflowing it.
1533 * \todo XXX how do we guarantee the latter ?
1535 featurecode[strlen(featurecode)] = f->subclass;
1536 /* Get rid of the frame before we start doing "stuff" with the channels */
1537 ast_frfree(f);
1538 f = NULL;
1539 config->feature_timer = backup_config.feature_timer;
1540 res = ast_feature_interpret(chan, peer, config, featurecode, sense);
1541 switch(res) {
1542 case FEATURE_RETURN_PASSDIGITS:
1543 ast_dtmf_stream(other, who, featurecode, 0);
1544 /* Fall through */
1545 case FEATURE_RETURN_SUCCESS:
1546 memset(featurecode, 0, sizeof(chan_featurecode));
1547 break;
1549 if (res >= FEATURE_RETURN_PASSDIGITS) {
1550 res = 0;
1551 } else
1552 break;
1553 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
1554 if (hadfeatures && !hasfeatures) {
1555 /* Restore backup */
1556 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
1557 memset(&backup_config, 0, sizeof(struct ast_bridge_config));
1558 } else if (hasfeatures) {
1559 if (!hadfeatures) {
1560 /* Backup configuration */
1561 memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
1562 /* Setup temporary config options */
1563 config->play_warning = 0;
1564 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
1565 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
1566 config->warning_freq = 0;
1567 config->warning_sound = NULL;
1568 config->end_sound = NULL;
1569 config->start_sound = NULL;
1570 config->firstpass = 0;
1572 config->start_time = ast_tvnow();
1573 config->feature_timer = featuredigittimeout;
1574 if (option_debug)
1575 ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer);
1578 if (f)
1579 ast_frfree(f);
1583 /* arrange the cdrs */
1584 bridge_cdr = ast_cdr_alloc();
1585 if (bridge_cdr) {
1586 if (chan->cdr && peer->cdr) { /* both of them? merge */
1587 ast_cdr_init(bridge_cdr,chan); /* seems more logicaller to use the destination as a base, but, really, it's random */
1588 ast_cdr_start(bridge_cdr); /* now is the time to start */
1590 /* absorb the channel cdr */
1591 ast_cdr_merge(bridge_cdr, chan->cdr);
1592 if (!ast_test_flag(chan->cdr, AST_CDR_FLAG_LOCKED))
1593 ast_cdr_discard(chan->cdr); /* if locked cdrs are in chan, they are taken over in the merge */
1595 /* absorb the peer cdr */
1596 ast_cdr_merge(bridge_cdr, peer->cdr);
1597 if (!ast_test_flag(peer->cdr, AST_CDR_FLAG_LOCKED))
1598 ast_cdr_discard(peer->cdr); /* if locked cdrs are in peer, they are taken over in the merge */
1600 peer->cdr = NULL;
1601 chan->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */
1602 } else if (chan->cdr) {
1603 /* take the cdr from the channel - literally */
1604 ast_cdr_init(bridge_cdr,chan);
1605 /* absorb this data */
1606 ast_cdr_merge(bridge_cdr, chan->cdr);
1607 if (!ast_test_flag(chan->cdr, AST_CDR_FLAG_LOCKED))
1608 ast_cdr_discard(chan->cdr); /* if locked cdrs are in chan, they are taken over in the merge */
1609 chan->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */
1610 } else if (peer->cdr) {
1611 /* take the cdr from the peer - literally */
1612 ast_cdr_init(bridge_cdr,peer);
1613 /* absorb this data */
1614 ast_cdr_merge(bridge_cdr, peer->cdr);
1615 if (!ast_test_flag(peer->cdr, AST_CDR_FLAG_LOCKED))
1616 ast_cdr_discard(peer->cdr); /* if locked cdrs are in chan, they are taken over in the merge */
1617 peer->cdr = NULL;
1618 peer->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */
1619 } else {
1620 /* make up a new cdr */
1621 ast_cdr_init(bridge_cdr,chan); /* eh, just pick one of them */
1622 chan->cdr = bridge_cdr; /* */
1624 if (ast_strlen_zero(bridge_cdr->dstchannel)) {
1625 if (strcmp(bridge_cdr->channel, peer->name) != 0)
1626 ast_cdr_setdestchan(bridge_cdr, peer->name);
1627 else
1628 ast_cdr_setdestchan(bridge_cdr, chan->name);
1631 return res;
1634 static void post_manager_event(const char *s, char *parkingexten, struct ast_channel *chan)
1636 manager_event(EVENT_FLAG_CALL, s,
1637 "Exten: %s\r\n"
1638 "Channel: %s\r\n"
1639 "CallerID: %s\r\n"
1640 "CallerIDName: %s\r\n\r\n",
1641 parkingexten,
1642 chan->name,
1643 S_OR(chan->cid.cid_num, "<unknown>"),
1644 S_OR(chan->cid.cid_name, "<unknown>")
1648 /*! \brief Take care of parked calls and unpark them if needed */
1649 static void *do_parking_thread(void *ignore)
1651 fd_set rfds, efds; /* results from previous select, to be preserved across loops. */
1652 FD_ZERO(&rfds);
1653 FD_ZERO(&efds);
1655 for (;;) {
1656 struct parkeduser *pu, *pl, *pt = NULL;
1657 int ms = -1; /* select timeout, uninitialized */
1658 int max = -1; /* max fd, none there yet */
1659 fd_set nrfds, nefds; /* args for the next select */
1660 FD_ZERO(&nrfds);
1661 FD_ZERO(&nefds);
1663 ast_mutex_lock(&parking_lock);
1664 pl = NULL;
1665 pu = parkinglot;
1666 /* navigate the list with prev-cur pointers to support removals */
1667 while (pu) {
1668 struct ast_channel *chan = pu->chan; /* shorthand */
1669 int tms; /* timeout for this item */
1670 int x; /* fd index in channel */
1671 struct ast_context *con;
1673 if (pu->notquiteyet) { /* Pretend this one isn't here yet */
1674 pl = pu;
1675 pu = pu->next;
1676 continue;
1678 tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
1679 if (tms > pu->parkingtime) {
1680 ast_indicate(chan, AST_CONTROL_UNHOLD);
1681 /* Get chan, exten from derived kludge */
1682 if (pu->peername[0]) {
1683 char *peername = ast_strdupa(pu->peername);
1684 char *cp = strrchr(peername, '-');
1685 if (cp)
1686 *cp = 0;
1687 con = ast_context_find(parking_con_dial);
1688 if (!con) {
1689 con = ast_context_create(NULL, parking_con_dial, registrar);
1690 if (!con)
1691 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
1693 if (con) {
1694 char returnexten[AST_MAX_EXTENSION];
1695 snprintf(returnexten, sizeof(returnexten), "%s||t", peername);
1696 ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), ast_free, registrar);
1698 set_c_e_p(chan, parking_con_dial, peername, 1);
1699 } else {
1700 /* They've been waiting too long, send them back to where they came. Theoretically they
1701 should have their original extensions and such, but we copy to be on the safe side */
1702 set_c_e_p(chan, pu->context, pu->exten, pu->priority);
1705 post_manager_event("ParkedCallTimeOut", pu->parkingexten, chan);
1707 if (option_verbose > 1)
1708 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);
1709 /* Start up the PBX, or hang them up */
1710 if (ast_pbx_start(chan)) {
1711 ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", chan->name);
1712 ast_hangup(chan);
1714 /* And take them out of the parking lot */
1715 if (pl)
1716 pl->next = pu->next;
1717 else
1718 parkinglot = pu->next;
1719 pt = pu;
1720 pu = pu->next;
1721 con = ast_context_find(parking_con);
1722 if (con) {
1723 if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL))
1724 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1725 else
1726 notify_metermaids(pt->parkingexten, parking_con);
1727 } else
1728 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1729 free(pt);
1730 } else { /* still within parking time, process descriptors */
1731 for (x = 0; x < AST_MAX_FDS; x++) {
1732 struct ast_frame *f;
1734 if (chan->fds[x] == -1 || (!FD_ISSET(chan->fds[x], &rfds) && !FD_ISSET(chan->fds[x], &efds)))
1735 continue; /* nothing on this descriptor */
1737 if (FD_ISSET(chan->fds[x], &efds))
1738 ast_set_flag(chan, AST_FLAG_EXCEPTION);
1739 else
1740 ast_clear_flag(chan, AST_FLAG_EXCEPTION);
1741 chan->fdno = x;
1743 /* See if they need servicing */
1744 f = ast_read(chan);
1745 if (!f || (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_HANGUP)) {
1746 if (f)
1747 ast_frfree(f);
1748 post_manager_event("ParkedCallGiveUp", pu->parkingexten, chan);
1750 /* There's a problem, hang them up*/
1751 if (option_verbose > 1)
1752 ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", chan->name);
1753 ast_hangup(chan);
1754 /* And take them out of the parking lot */
1755 if (pl)
1756 pl->next = pu->next;
1757 else
1758 parkinglot = pu->next;
1759 pt = pu;
1760 pu = pu->next;
1761 con = ast_context_find(parking_con);
1762 if (con) {
1763 if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL))
1764 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1765 else
1766 notify_metermaids(pt->parkingexten, parking_con);
1767 } else
1768 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1769 free(pt);
1770 break;
1771 } else {
1772 /*! \todo XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
1773 ast_frfree(f);
1774 if (pu->moh_trys < 3 && !chan->generatordata) {
1775 if (option_debug)
1776 ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source. Restarting.\n");
1777 ast_indicate_data(pu->chan, AST_CONTROL_HOLD,
1778 S_OR(parkmohclass, NULL),
1779 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
1780 pu->moh_trys++;
1782 goto std; /*! \todo XXX Ick: jumping into an else statement??? XXX */
1785 } /* end for */
1786 if (x >= AST_MAX_FDS) {
1787 std: for (x=0; x<AST_MAX_FDS; x++) { /* mark fds for next round */
1788 if (chan->fds[x] > -1) {
1789 FD_SET(chan->fds[x], &nrfds);
1790 FD_SET(chan->fds[x], &nefds);
1791 if (chan->fds[x] > max)
1792 max = chan->fds[x];
1795 /* Keep track of our shortest wait */
1796 if (tms < ms || ms < 0)
1797 ms = tms;
1798 pl = pu;
1799 pu = pu->next;
1802 } /* end while */
1803 ast_mutex_unlock(&parking_lock);
1804 rfds = nrfds;
1805 efds = nefds;
1807 struct timeval tv = ast_samp2tv(ms, 1000);
1808 /* Wait for something to happen */
1809 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
1811 pthread_testcancel();
1813 return NULL; /* Never reached */
1816 /*! \brief Park a call */
1817 static int park_call_exec(struct ast_channel *chan, void *data)
1819 /* Cache the original channel name in case we get masqueraded in the middle
1820 * of a park--it is still theoretically possible for a transfer to happen before
1821 * we get here, but it is _really_ unlikely */
1822 char *orig_chan_name = ast_strdupa(chan->name);
1823 char orig_exten[AST_MAX_EXTENSION];
1824 int orig_priority = chan->priority;
1826 /* Data is unused at the moment but could contain a parking
1827 lot context eventually */
1828 int res = 0;
1829 struct ast_module_user *u;
1831 u = ast_module_user_add(chan);
1833 ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten));
1835 /* Setup the exten/priority to be s/1 since we don't know
1836 where this call should return */
1837 strcpy(chan->exten, "s");
1838 chan->priority = 1;
1839 /* Answer if call is not up */
1840 if (chan->_state != AST_STATE_UP)
1841 res = ast_answer(chan);
1842 /* Sleep to allow VoIP streams to settle down */
1843 if (!res)
1844 res = ast_safe_sleep(chan, 1000);
1845 /* Park the call */
1846 if (!res) {
1847 res = park_call_full(chan, chan, 0, NULL, orig_chan_name);
1848 /* Continue on in the dialplan */
1849 if (res == 1) {
1850 ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten));
1851 chan->priority = orig_priority;
1852 res = 0;
1853 } else if (!res)
1854 res = AST_PBX_KEEPALIVE;
1857 ast_module_user_remove(u);
1859 return res;
1862 /*! \brief Pickup parked call */
1863 static int park_exec(struct ast_channel *chan, void *data)
1865 int res = 0;
1866 struct ast_module_user *u;
1867 struct ast_channel *peer=NULL;
1868 struct parkeduser *pu, *pl=NULL;
1869 struct ast_context *con;
1871 int park;
1872 struct ast_bridge_config config;
1874 if (!data) {
1875 ast_log(LOG_WARNING, "Parkedcall requires an argument (extension number)\n");
1876 return -1;
1879 u = ast_module_user_add(chan);
1881 park = atoi((char *)data);
1882 ast_mutex_lock(&parking_lock);
1883 pu = parkinglot;
1884 while(pu) {
1885 if (pu->parkingnum == park) {
1886 if (pl)
1887 pl->next = pu->next;
1888 else
1889 parkinglot = pu->next;
1890 break;
1892 pl = pu;
1893 pu = pu->next;
1895 ast_mutex_unlock(&parking_lock);
1896 if (pu) {
1897 peer = pu->chan;
1898 con = ast_context_find(parking_con);
1899 if (con) {
1900 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL))
1901 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1902 else
1903 notify_metermaids(pu->parkingexten, parking_con);
1904 } else
1905 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1907 manager_event(EVENT_FLAG_CALL, "UnParkedCall",
1908 "Exten: %s\r\n"
1909 "Channel: %s\r\n"
1910 "From: %s\r\n"
1911 "CallerID: %s\r\n"
1912 "CallerIDName: %s\r\n",
1913 pu->parkingexten, pu->chan->name, chan->name,
1914 S_OR(pu->chan->cid.cid_num, "<unknown>"),
1915 S_OR(pu->chan->cid.cid_name, "<unknown>")
1918 free(pu);
1920 /* JK02: it helps to answer the channel if not already up */
1921 if (chan->_state != AST_STATE_UP)
1922 ast_answer(chan);
1924 if (peer) {
1925 /* Play a courtesy to the source(s) configured to prefix the bridge connecting */
1927 if (!ast_strlen_zero(courtesytone)) {
1928 int error = 0;
1929 ast_indicate(peer, AST_CONTROL_UNHOLD);
1930 if (parkedplay == 0) {
1931 error = ast_stream_and_wait(chan, courtesytone, chan->language, "");
1932 } else if (parkedplay == 1) {
1933 error = ast_stream_and_wait(peer, courtesytone, chan->language, "");
1934 } else if (parkedplay == 2) {
1935 if (!ast_streamfile(chan, courtesytone, chan->language) &&
1936 !ast_streamfile(peer, courtesytone, chan->language)) {
1937 /*! \todo XXX we would like to wait on both! */
1938 res = ast_waitstream(chan, "");
1939 if (res >= 0)
1940 res = ast_waitstream(peer, "");
1941 if (res < 0)
1942 error = 1;
1945 if (error) {
1946 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
1947 ast_hangup(peer);
1948 ast_module_user_remove(u);
1949 return -1;
1951 } else
1952 ast_indicate(peer, AST_CONTROL_UNHOLD);
1954 res = ast_channel_make_compatible(chan, peer);
1955 if (res < 0) {
1956 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
1957 ast_hangup(peer);
1958 ast_module_user_remove(u);
1959 return -1;
1961 /* This runs sorta backwards, since we give the incoming channel control, as if it
1962 were the person called. */
1963 if (option_verbose > 2)
1964 ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
1966 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
1967 ast_cdr_setdestchan(chan->cdr, peer->name);
1968 memset(&config, 0, sizeof(struct ast_bridge_config));
1969 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
1970 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
1971 res = ast_bridge_call(chan, peer, &config);
1973 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
1974 ast_cdr_setdestchan(chan->cdr, peer->name);
1976 /* Simulate the PBX hanging up */
1977 if (res != AST_PBX_NO_HANGUP_PEER)
1978 ast_hangup(peer);
1979 ast_module_user_remove(u);
1980 return res;
1981 } else {
1982 /*! \todo XXX Play a message XXX */
1983 if (ast_stream_and_wait(chan, "pbx-invalidpark", chan->language, ""))
1984 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
1985 if (option_verbose > 2)
1986 ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
1987 res = -1;
1990 ast_module_user_remove(u);
1992 return res;
1995 static int handle_showfeatures(int fd, int argc, char *argv[])
1997 int i;
1998 struct ast_call_feature *feature;
1999 char format[] = "%-25s %-7s %-7s\n";
2001 ast_cli(fd, format, "Builtin Feature", "Default", "Current");
2002 ast_cli(fd, format, "---------------", "-------", "-------");
2004 ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */
2006 ast_rwlock_rdlock(&features_lock);
2007 for (i = 0; i < FEATURES_COUNT; i++)
2008 ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
2009 ast_rwlock_unlock(&features_lock);
2011 ast_cli(fd, "\n");
2012 ast_cli(fd, format, "Dynamic Feature", "Default", "Current");
2013 ast_cli(fd, format, "---------------", "-------", "-------");
2014 if (AST_LIST_EMPTY(&feature_list))
2015 ast_cli(fd, "(none)\n");
2016 else {
2017 AST_LIST_LOCK(&feature_list);
2018 AST_LIST_TRAVERSE(&feature_list, feature, feature_entry)
2019 ast_cli(fd, format, feature->sname, "no def", feature->exten);
2020 AST_LIST_UNLOCK(&feature_list);
2022 ast_cli(fd, "\nCall parking\n");
2023 ast_cli(fd, "------------\n");
2024 ast_cli(fd,"%-20s: %s\n", "Parking extension", parking_ext);
2025 ast_cli(fd,"%-20s: %s\n", "Parking context", parking_con);
2026 ast_cli(fd,"%-20s: %d-%d\n", "Parked call extensions", parking_start, parking_stop);
2027 ast_cli(fd,"\n");
2029 return RESULT_SUCCESS;
2032 static char showfeatures_help[] =
2033 "Usage: feature list\n"
2034 " Lists currently configured features.\n";
2036 static int handle_parkedcalls(int fd, int argc, char *argv[])
2038 struct parkeduser *cur;
2039 int numparked = 0;
2041 ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
2042 , "Context", "Extension", "Pri", "Timeout");
2044 ast_mutex_lock(&parking_lock);
2046 for (cur = parkinglot; cur; cur = cur->next) {
2047 ast_cli(fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n"
2048 ,cur->parkingexten, cur->chan->name, cur->context, cur->exten
2049 ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
2051 numparked++;
2053 ast_mutex_unlock(&parking_lock);
2054 ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : "");
2057 return RESULT_SUCCESS;
2060 static char showparked_help[] =
2061 "Usage: show parkedcalls\n"
2062 " Lists currently parked calls.\n";
2064 static struct ast_cli_entry cli_show_features_deprecated = {
2065 { "show", "features", NULL },
2066 handle_showfeatures, NULL,
2067 NULL };
2069 static struct ast_cli_entry cli_features[] = {
2070 { { "feature", "show", NULL },
2071 handle_showfeatures, "Lists configured features",
2072 showfeatures_help, NULL, &cli_show_features_deprecated },
2074 { { "show", "parkedcalls", NULL },
2075 handle_parkedcalls, "Lists parked calls",
2076 showparked_help },
2079 /*! \brief Dump lot status */
2080 static int manager_parking_status( struct mansession *s, const struct message *m)
2082 struct parkeduser *cur;
2083 const char *id = astman_get_header(m, "ActionID");
2084 char idText[256] = "";
2086 if (!ast_strlen_zero(id))
2087 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
2089 astman_send_ack(s, m, "Parked calls will follow");
2091 ast_mutex_lock(&parking_lock);
2093 for (cur = parkinglot; cur; cur = cur->next) {
2094 astman_append(s, "Event: ParkedCall\r\n"
2095 "Exten: %d\r\n"
2096 "Channel: %s\r\n"
2097 "From: %s\r\n"
2098 "Timeout: %ld\r\n"
2099 "CallerID: %s\r\n"
2100 "CallerIDName: %s\r\n"
2101 "%s"
2102 "\r\n",
2103 cur->parkingnum, cur->chan->name, cur->peername,
2104 (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
2105 S_OR(cur->chan->cid.cid_num, ""), /* XXX in other places it is <unknown> */
2106 S_OR(cur->chan->cid.cid_name, ""),
2107 idText);
2110 astman_append(s,
2111 "Event: ParkedCallsComplete\r\n"
2112 "%s"
2113 "\r\n",idText);
2115 ast_mutex_unlock(&parking_lock);
2117 return RESULT_SUCCESS;
2120 static char mandescr_park[] =
2121 "Description: Park a channel.\n"
2122 "Variables: (Names marked with * are required)\n"
2123 " *Channel: Channel name to park\n"
2124 " *Channel2: Channel to announce park info to (and return to if timeout)\n"
2125 " Timeout: Number of milliseconds to wait before callback.\n";
2127 static int manager_park(struct mansession *s, const struct message *m)
2129 const char *channel = astman_get_header(m, "Channel");
2130 const char *channel2 = astman_get_header(m, "Channel2");
2131 const char *timeout = astman_get_header(m, "Timeout");
2132 char buf[BUFSIZ];
2133 int to = 0;
2134 int res = 0;
2135 int parkExt = 0;
2136 struct ast_channel *ch1, *ch2;
2138 if (ast_strlen_zero(channel)) {
2139 astman_send_error(s, m, "Channel not specified");
2140 return 0;
2143 if (ast_strlen_zero(channel2)) {
2144 astman_send_error(s, m, "Channel2 not specified");
2145 return 0;
2148 ch1 = ast_get_channel_by_name_locked(channel);
2149 if (!ch1) {
2150 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
2151 astman_send_error(s, m, buf);
2152 return 0;
2155 ch2 = ast_get_channel_by_name_locked(channel2);
2156 if (!ch2) {
2157 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
2158 astman_send_error(s, m, buf);
2159 ast_channel_unlock(ch1);
2160 return 0;
2163 if (!ast_strlen_zero(timeout)) {
2164 sscanf(timeout, "%d", &to);
2167 res = ast_masq_park_call(ch1, ch2, to, &parkExt);
2168 if (!res) {
2169 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
2170 astman_send_ack(s, m, "Park successful");
2171 } else {
2172 astman_send_error(s, m, "Park failure");
2175 ast_channel_unlock(ch1);
2176 ast_channel_unlock(ch2);
2178 return 0;
2182 int ast_pickup_call(struct ast_channel *chan)
2184 struct ast_channel *cur = NULL;
2185 int res = -1;
2187 while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
2188 if (!cur->pbx &&
2189 (cur != chan) &&
2190 (chan->pickupgroup & cur->callgroup) &&
2191 ((cur->_state == AST_STATE_RINGING) ||
2192 (cur->_state == AST_STATE_RING))) {
2193 break;
2195 ast_channel_unlock(cur);
2197 if (cur) {
2198 if (option_debug)
2199 ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
2200 res = ast_answer(chan);
2201 if (res)
2202 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
2203 res = ast_queue_control(chan, AST_CONTROL_ANSWER);
2204 if (res)
2205 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
2206 res = ast_channel_masquerade(cur, chan);
2207 if (res)
2208 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */
2209 ast_channel_unlock(cur);
2210 } else {
2211 if (option_debug)
2212 ast_log(LOG_DEBUG, "No call pickup possible...\n");
2214 return res;
2217 /*! \brief Add parking hints for all defined parking lots */
2218 static void park_add_hints(char *context, int start, int stop)
2220 int numext;
2221 char device[AST_MAX_EXTENSION];
2222 char exten[10];
2224 for (numext = start; numext <= stop; numext++) {
2225 snprintf(exten, sizeof(exten), "%d", numext);
2226 snprintf(device, sizeof(device), "park:%s@%s", exten, context);
2227 ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
2232 static int load_config(void)
2234 int start = 0, end = 0;
2235 int res;
2236 struct ast_context *con = NULL;
2237 struct ast_config *cfg = NULL;
2238 struct ast_variable *var = NULL;
2239 char old_parking_ext[AST_MAX_EXTENSION];
2240 char old_parking_con[AST_MAX_EXTENSION] = "";
2242 if (!ast_strlen_zero(parking_con)) {
2243 strcpy(old_parking_ext, parking_ext);
2244 strcpy(old_parking_con, parking_con);
2247 /* Reset to defaults */
2248 strcpy(parking_con, "parkedcalls");
2249 strcpy(parking_con_dial, "park-dial");
2250 strcpy(parking_ext, "700");
2251 strcpy(pickup_ext, "*8");
2252 strcpy(parkmohclass, "default");
2253 courtesytone[0] = '\0';
2254 strcpy(xfersound, "beep");
2255 strcpy(xferfailsound, "pbx-invalid");
2256 parking_start = 701;
2257 parking_stop = 750;
2258 parkfindnext = 0;
2259 adsipark = 0;
2260 parkaddhints = 0;
2262 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
2263 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
2264 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
2266 cfg = ast_config_load("features.conf");
2267 if (!cfg) {
2268 ast_log(LOG_WARNING,"Could not load features.conf\n");
2269 return AST_MODULE_LOAD_DECLINE;
2271 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
2272 if (!strcasecmp(var->name, "parkext")) {
2273 ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
2274 } else if (!strcasecmp(var->name, "context")) {
2275 ast_copy_string(parking_con, var->value, sizeof(parking_con));
2276 } else if (!strcasecmp(var->name, "parkingtime")) {
2277 if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) {
2278 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
2279 parkingtime = DEFAULT_PARK_TIME;
2280 } else
2281 parkingtime = parkingtime * 1000;
2282 } else if (!strcasecmp(var->name, "parkpos")) {
2283 if (sscanf(var->value, "%d-%d", &start, &end) != 2) {
2284 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);
2285 } else {
2286 parking_start = start;
2287 parking_stop = end;
2289 } else if (!strcasecmp(var->name, "findslot")) {
2290 parkfindnext = (!strcasecmp(var->value, "next"));
2291 } else if (!strcasecmp(var->name, "parkinghints")) {
2292 parkaddhints = ast_true(var->value);
2293 } else if (!strcasecmp(var->name, "adsipark")) {
2294 adsipark = ast_true(var->value);
2295 } else if (!strcasecmp(var->name, "transferdigittimeout")) {
2296 if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
2297 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
2298 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
2299 } else
2300 transferdigittimeout = transferdigittimeout * 1000;
2301 } else if (!strcasecmp(var->name, "featuredigittimeout")) {
2302 if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
2303 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
2304 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
2306 } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) {
2307 if ((sscanf(var->value, "%d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) {
2308 ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value);
2309 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
2310 } else
2311 atxfernoanswertimeout = atxfernoanswertimeout * 1000;
2312 } else if (!strcasecmp(var->name, "courtesytone")) {
2313 ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
2314 } else if (!strcasecmp(var->name, "parkedplay")) {
2315 if (!strcasecmp(var->value, "both"))
2316 parkedplay = 2;
2317 else if (!strcasecmp(var->value, "parked"))
2318 parkedplay = 1;
2319 else
2320 parkedplay = 0;
2321 } else if (!strcasecmp(var->name, "xfersound")) {
2322 ast_copy_string(xfersound, var->value, sizeof(xfersound));
2323 } else if (!strcasecmp(var->name, "xferfailsound")) {
2324 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
2325 } else if (!strcasecmp(var->name, "pickupexten")) {
2326 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
2327 } else if (!strcasecmp(var->name, "parkedmusicclass")) {
2328 ast_copy_string(parkmohclass, var->value, sizeof(parkmohclass));
2332 unmap_features();
2333 for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) {
2334 if (remap_feature(var->name, var->value))
2335 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
2338 /* Map a key combination to an application*/
2339 ast_unregister_features();
2340 for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) {
2341 char *tmp_val = ast_strdupa(var->value);
2342 char *exten, *activateon, *activatedby, *app, *app_args, *moh_class;
2343 struct ast_call_feature *feature;
2345 /* strsep() sets the argument to NULL if match not found, and it
2346 * is safe to use it with a NULL argument, so we don't check
2347 * between calls.
2349 exten = strsep(&tmp_val,",");
2350 activatedby = strsep(&tmp_val,",");
2351 app = strsep(&tmp_val,",");
2352 app_args = strsep(&tmp_val,",");
2353 moh_class = strsep(&tmp_val,",");
2355 activateon = strsep(&activatedby, "/");
2357 /*! \todo XXX var_name or app_args ? */
2358 if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) {
2359 ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",
2360 app, exten, activateon, var->name);
2361 continue;
2364 AST_LIST_LOCK(&feature_list);
2365 if ((feature = find_dynamic_feature(var->name))) {
2366 AST_LIST_UNLOCK(&feature_list);
2367 ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name);
2368 continue;
2370 AST_LIST_UNLOCK(&feature_list);
2372 if (!(feature = ast_calloc(1, sizeof(*feature))))
2373 continue;
2375 ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN);
2376 ast_copy_string(feature->app, app, FEATURE_APP_LEN);
2377 ast_copy_string(feature->exten, exten, FEATURE_EXTEN_LEN);
2379 if (app_args)
2380 ast_copy_string(feature->app_args, app_args, FEATURE_APP_ARGS_LEN);
2382 if (moh_class)
2383 ast_copy_string(feature->moh_class, moh_class, FEATURE_MOH_LEN);
2385 ast_copy_string(feature->exten, exten, sizeof(feature->exten));
2386 feature->operation = feature_exec_app;
2387 ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF);
2389 /* Allow caller and calle to be specified for backwards compatability */
2390 if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller"))
2391 ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF);
2392 else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee"))
2393 ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER);
2394 else {
2395 ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s',"
2396 " must be 'self', or 'peer'\n", var->name);
2397 continue;
2400 if (ast_strlen_zero(activatedby))
2401 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
2402 else if (!strcasecmp(activatedby, "caller"))
2403 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER);
2404 else if (!strcasecmp(activatedby, "callee"))
2405 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE);
2406 else if (!strcasecmp(activatedby, "both"))
2407 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
2408 else {
2409 ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s',"
2410 " must be 'caller', or 'callee', or 'both'\n", var->name);
2411 continue;
2414 ast_register_feature(feature);
2416 if (option_verbose >= 1)
2417 ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, app, app_args, exten);
2419 ast_config_destroy(cfg);
2421 /* Remove the old parking extension */
2422 if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) {
2423 if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar))
2424 notify_metermaids(old_parking_ext, old_parking_con);
2425 if (option_debug)
2426 ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
2429 if (!(con = ast_context_find(parking_con)) && !(con = ast_context_create(NULL, parking_con, registrar))) {
2430 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
2431 return -1;
2433 res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar);
2434 if (parkaddhints)
2435 park_add_hints(parking_con, parking_start, parking_stop);
2436 if (!res)
2437 notify_metermaids(ast_parking_ext(), parking_con);
2438 return res;
2442 static int reload(void)
2444 return load_config();
2447 static int load_module(void)
2449 int res;
2451 memset(parking_ext, 0, sizeof(parking_ext));
2452 memset(parking_con, 0, sizeof(parking_con));
2454 if ((res = load_config()))
2455 return res;
2456 ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
2457 ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
2458 res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
2459 if (!res)
2460 res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
2461 if (!res) {
2462 ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" );
2463 ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park,
2464 "Park a channel", mandescr_park);
2467 res |= ast_devstate_prov_add("Park", metermaidstate);
2469 return res;
2473 static int unload_module(void)
2475 ast_module_user_hangup_all();
2477 ast_manager_unregister("ParkedCalls");
2478 ast_manager_unregister("Park");
2479 ast_cli_unregister_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
2480 ast_unregister_application(parkcall);
2481 ast_devstate_prov_del("Park");
2482 return ast_unregister_application(parkedcall);
2485 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Call Features Resource",
2486 .load = load_module,
2487 .unload = unload_module,
2488 .reload = reload,