use a macro instead of an inline function, so that backtraces will report the caller...
[asterisk-bristuff.git] / res / res_features.c
blob50687cb04729d75818c2a14b98690cf948c869c3
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 #include "asterisk.h"
28 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
30 #include <pthread.h>
31 #include <stdlib.h>
32 #include <errno.h>
33 #include <unistd.h>
34 #include <string.h>
35 #include <stdlib.h>
36 #include <stdio.h>
37 #include <sys/time.h>
38 #include <sys/signal.h>
39 #include <netinet/in.h>
41 #include "asterisk/lock.h"
42 #include "asterisk/file.h"
43 #include "asterisk/logger.h"
44 #include "asterisk/channel.h"
45 #include "asterisk/pbx.h"
46 #include "asterisk/options.h"
47 #include "asterisk/causes.h"
48 #include "asterisk/module.h"
49 #include "asterisk/translate.h"
50 #include "asterisk/app.h"
51 #include "asterisk/say.h"
52 #include "asterisk/features.h"
53 #include "asterisk/musiconhold.h"
54 #include "asterisk/config.h"
55 #include "asterisk/cli.h"
56 #include "asterisk/manager.h"
57 #include "asterisk/utils.h"
58 #include "asterisk/adsi.h"
59 #include "asterisk/devicestate.h"
60 #include "asterisk/monitor.h"
62 #define DEFAULT_PARK_TIME 45000
63 #define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000
64 #define DEFAULT_FEATURE_DIGIT_TIMEOUT 500
65 #define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000
67 #define AST_MAX_WATCHERS 256
69 enum {
70 AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0),
71 AST_FEATURE_FLAG_ONPEER = (1 << 1),
72 AST_FEATURE_FLAG_ONSELF = (1 << 2),
73 AST_FEATURE_FLAG_BYCALLEE = (1 << 3),
74 AST_FEATURE_FLAG_BYCALLER = (1 << 4),
75 AST_FEATURE_FLAG_BYBOTH = (3 << 3),
78 static char *parkedcall = "ParkedCall";
80 static int parkaddhints = 0; /*!< Add parking hints automatically */
81 static int parkingtime = DEFAULT_PARK_TIME; /*!< No more than 45 seconds parked before you do something with them */
82 static char parking_con[AST_MAX_EXTENSION]; /*!< Context for which parking is made accessible */
83 static char parking_con_dial[AST_MAX_EXTENSION]; /*!< Context for dialback for parking (KLUDGE) */
84 static char parking_ext[AST_MAX_EXTENSION]; /*!< Extension you type to park the call */
85 static char pickup_ext[AST_MAX_EXTENSION]; /*!< Call pickup extension */
86 static char parkmohclass[MAX_MUSICCLASS]; /*!< Music class used for parking */
87 static int parking_start; /*!< First available extension for parking */
88 static int parking_stop; /*!< Last available extension for parking */
90 static char courtesytone[256]; /*!< Courtesy tone */
91 static int parkedplay = 0; /*!< Who to play the courtesy tone to */
92 static char xfersound[256]; /*!< Call transfer sound */
93 static char xferfailsound[256]; /*!< Call transfer failure sound */
95 static int parking_offset;
96 static int parkfindnext;
98 static int adsipark;
100 static int transferdigittimeout;
101 static int featuredigittimeout;
103 static int atxfernoanswertimeout;
105 static char *registrar = "res_features"; /*!< Registrar for operations */
107 /* module and CLI command definitions */
108 static char *synopsis = "Answer a parked call";
110 static char *descrip = "ParkedCall(exten):"
111 "Used to connect to a parked call. This application is always\n"
112 "registered internally and does not need to be explicitly added\n"
113 "into the dialplan, although you should include the 'parkedcalls'\n"
114 "context.\n";
116 static char *parkcall = "Park";
118 static char *synopsis2 = "Park yourself";
120 static char *descrip2 = "Park():"
121 "Used to park yourself (typically in combination with a supervised\n"
122 "transfer to know the parking space). This application is always\n"
123 "registered internally and does not need to be explicitly added\n"
124 "into the dialplan, although you should include the 'parkedcalls'\n"
125 "context (or the context specified in features.conf).\n\n"
126 "If you set the PARKINGEXTEN variable to an extension in your\n"
127 "parking context, park() will park the call on that extension, unless\n"
128 "it already exists. In that case, execution will continue at next\n"
129 "priority.\n" ;
131 static struct ast_app *monitor_app = NULL;
132 static int monitor_ok = 1;
134 struct parkeduser {
135 struct ast_channel *chan; /*!< Parking channel */
136 struct timeval start; /*!< Time the parking started */
137 int parkingnum; /*!< Parking lot */
138 char parkingexten[AST_MAX_EXTENSION]; /*!< If set beforehand, parking extension used for this call */
139 char context[AST_MAX_CONTEXT]; /*!< Where to go if our parking time expires */
140 char exten[AST_MAX_EXTENSION];
141 int priority;
142 int parkingtime; /*!< Maximum length in parking lot before return */
143 int notquiteyet;
144 char peername[1024];
145 unsigned char moh_trys;
146 struct parkeduser *next;
149 static struct parkeduser *parkinglot;
151 AST_MUTEX_DEFINE_STATIC(parking_lock); /*!< protects all static variables above */
153 static pthread_t parking_thread;
155 char *ast_parking_ext(void)
157 return parking_ext;
160 char *ast_pickup_ext(void)
162 return pickup_ext;
165 struct ast_bridge_thread_obj
167 struct ast_bridge_config bconfig;
168 struct ast_channel *chan;
169 struct ast_channel *peer;
174 /*! \brief store context, priority and extension */
175 static void set_c_e_p(struct ast_channel *chan, const char *context, const char *ext, int pri)
177 ast_copy_string(chan->context, context, sizeof(chan->context));
178 ast_copy_string(chan->exten, ext, sizeof(chan->exten));
179 chan->priority = pri;
182 static void check_goto_on_transfer(struct ast_channel *chan)
184 struct ast_channel *xferchan;
185 const char *val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR");
186 char *x, *goto_on_transfer;
187 struct ast_frame *f;
189 if (ast_strlen_zero(val))
190 return;
192 goto_on_transfer = ast_strdupa(val);
194 if (!(xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, chan->name)))
195 return;
197 for (x = goto_on_transfer; x && *x; x++) {
198 if (*x == '^')
199 *x = '|';
201 /* Make formats okay */
202 xferchan->readformat = chan->readformat;
203 xferchan->writeformat = chan->writeformat;
204 ast_channel_masquerade(xferchan, chan);
205 ast_parseable_goto(xferchan, goto_on_transfer);
206 xferchan->_state = AST_STATE_UP;
207 ast_clear_flag(xferchan, AST_FLAGS_ALL);
208 xferchan->_softhangup = 0;
209 if ((f = ast_read(xferchan))) {
210 ast_frfree(f);
211 f = NULL;
212 ast_pbx_start(xferchan);
213 } else {
214 ast_hangup(xferchan);
218 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);
221 static void *ast_bridge_call_thread(void *data)
223 struct ast_bridge_thread_obj *tobj = data;
225 tobj->chan->appl = "Transferred Call";
226 tobj->chan->data = tobj->peer->name;
227 tobj->peer->appl = "Transferred Call";
228 tobj->peer->data = tobj->chan->name;
229 if (tobj->chan->cdr) {
230 ast_cdr_reset(tobj->chan->cdr, NULL);
231 ast_cdr_setdestchan(tobj->chan->cdr, tobj->peer->name);
233 if (tobj->peer->cdr) {
234 ast_cdr_reset(tobj->peer->cdr, NULL);
235 ast_cdr_setdestchan(tobj->peer->cdr, tobj->chan->name);
238 ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
239 ast_hangup(tobj->chan);
240 ast_hangup(tobj->peer);
241 bzero(tobj, sizeof(*tobj)); /*! \todo XXX for safety */
242 free(tobj);
243 return NULL;
246 static void ast_bridge_call_thread_launch(void *data)
248 pthread_t thread;
249 pthread_attr_t attr;
250 struct sched_param sched;
252 pthread_attr_init(&attr);
253 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
254 ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data);
255 pthread_attr_destroy(&attr);
256 memset(&sched, 0, sizeof(sched));
257 pthread_setschedparam(thread, SCHED_RR, &sched);
260 static int adsi_announce_park(struct ast_channel *chan, char *parkingexten)
262 int res;
263 int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
264 char tmp[256];
265 char *message[5] = {NULL, NULL, NULL, NULL, NULL};
267 snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten);
268 message[0] = tmp;
269 res = ast_adsi_load_session(chan, NULL, 0, 1);
270 if (res == -1)
271 return res;
272 return ast_adsi_print(chan, message, justify, 1);
275 /*! \brief Notify metermaids that we've changed an extension */
276 static void notify_metermaids(char *exten, char *context)
278 if (option_debug > 3)
279 ast_log(LOG_DEBUG, "Notification of state change to metermaids %s@%s\n", exten, context);
281 /* Send notification to devicestate subsystem */
282 ast_device_state_changed("park:%s@%s", exten, context);
283 return;
286 /*! \brief metermaids callback from devicestate.c */
287 static int metermaidstate(const char *data)
289 int res = AST_DEVICE_INVALID;
290 char *context = ast_strdupa(data);
291 char *exten;
293 exten = strsep(&context, "@");
294 if (!context)
295 return res;
297 if (option_debug > 3)
298 ast_log(LOG_DEBUG, "Checking state of exten %s in context %s\n", exten, context);
300 res = ast_exists_extension(NULL, context, exten, 1, NULL);
302 if (!res)
303 return AST_DEVICE_NOT_INUSE;
304 else
305 return AST_DEVICE_INUSE;
308 /*! \brief Park a call
309 \note We put the user in the parking list, then wake up the parking thread to be sure it looks
310 after these channels too */
311 int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
313 struct parkeduser *pu, *cur;
314 int i, x = -1, parking_range;
315 struct ast_context *con;
316 const char *parkingexten;
318 /* Allocate memory for parking data */
319 if (!(pu = ast_calloc(1, sizeof(*pu))))
320 return -1;
322 /* Lock parking lot */
323 ast_mutex_lock(&parking_lock);
324 /* Check for channel variable PARKINGEXTEN */
325 parkingexten = pbx_builtin_getvar_helper(chan, "PARKINGEXTEN");
326 if (!ast_strlen_zero(parkingexten)) {
327 if (ast_exists_extension(NULL, parking_con, parkingexten, 1, NULL)) {
328 ast_mutex_unlock(&parking_lock);
329 free(pu);
330 ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parking_con);
331 return -1; /* We failed to park this call, plain and simple so we need to error out */
333 ast_copy_string(pu->parkingexten, parkingexten, sizeof(pu->parkingexten));
334 x = atoi(parkingexten);
335 } else {
336 /* Select parking space within range */
337 parking_range = parking_stop - parking_start+1;
338 for (i = 0; i < parking_range; i++) {
339 x = (i + parking_offset) % parking_range + parking_start;
340 cur = parkinglot;
341 while(cur) {
342 if (cur->parkingnum == x)
343 break;
344 cur = cur->next;
346 if (!cur)
347 break;
350 if (!(i < parking_range)) {
351 ast_log(LOG_WARNING, "No more parking spaces\n");
352 free(pu);
353 ast_mutex_unlock(&parking_lock);
354 return -1;
356 /* Set pointer for next parking */
357 if (parkfindnext)
358 parking_offset = x - parking_start + 1;
361 chan->appl = "Parked Call";
362 chan->data = NULL;
364 pu->chan = chan;
366 /* Put the parked channel on hold if we have two different channels */
367 if (chan != peer) {
368 ast_indicate_data(pu->chan, AST_CONTROL_HOLD,
369 S_OR(parkmohclass, NULL),
370 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
373 pu->start = ast_tvnow();
374 pu->parkingnum = x;
375 pu->parkingtime = (timeout > 0) ? timeout : parkingtime;
376 if (extout)
377 *extout = x;
379 if (peer)
380 ast_copy_string(pu->peername, peer->name, sizeof(pu->peername));
382 /* Remember what had been dialed, so that if the parking
383 expires, we try to come back to the same place */
384 ast_copy_string(pu->context, S_OR(chan->macrocontext, chan->context), sizeof(pu->context));
385 ast_copy_string(pu->exten, S_OR(chan->macroexten, chan->exten), sizeof(pu->exten));
386 pu->priority = chan->macropriority ? chan->macropriority : chan->priority;
387 pu->next = parkinglot;
388 parkinglot = pu;
390 /* If parking a channel directly, don't quiet yet get parking running on it */
391 if (peer == chan)
392 pu->notquiteyet = 1;
393 ast_mutex_unlock(&parking_lock);
394 /* Wake up the (presumably select()ing) thread */
395 pthread_kill(parking_thread, SIGURG);
396 if (option_verbose > 1)
397 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));
399 if (pu->parkingnum != -1)
400 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", x);
401 manager_event(EVENT_FLAG_CALL, "ParkedCall",
402 "Exten: %s\r\n"
403 "Channel: %s\r\n"
404 "From: %s\r\n"
405 "Timeout: %ld\r\n"
406 "CallerID: %s\r\n"
407 "CallerIDName: %s\r\n",
408 pu->parkingexten, pu->chan->name, peer ? peer->name : "",
409 (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL),
410 S_OR(pu->chan->cid.cid_num, "<unknown>"),
411 S_OR(pu->chan->cid.cid_name, "<unknown>")
414 if (peer && adsipark && ast_adsi_available(peer)) {
415 adsi_announce_park(peer, pu->parkingexten); /* Only supports parking numbers */
416 ast_adsi_unload_session(peer);
419 con = ast_context_find(parking_con);
420 if (!con)
421 con = ast_context_create(NULL, parking_con, registrar);
422 if (!con) /* Still no context? Bad */
423 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
424 /* Tell the peer channel the number of the parking space */
425 if (peer && pu->parkingnum != -1) { /* Only say number if it's a number */
426 /* Make sure we don't start saying digits to the channel being parked */
427 ast_set_flag(peer, AST_FLAG_MASQ_NOSTREAM);
428 ast_say_digits(peer, pu->parkingnum, "", peer->language);
429 ast_clear_flag(peer, AST_FLAG_MASQ_NOSTREAM);
431 if (con) {
432 if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, strdup(pu->parkingexten), ast_free, registrar))
433 notify_metermaids(pu->parkingexten, parking_con);
435 if (pu->notquiteyet) {
436 /* Wake up parking thread if we're really done */
437 ast_indicate_data(pu->chan, AST_CONTROL_HOLD,
438 S_OR(parkmohclass, NULL),
439 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
440 pu->notquiteyet = 0;
441 pthread_kill(parking_thread, SIGURG);
443 return 0;
446 int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
448 struct ast_channel *chan;
449 struct ast_frame *f;
451 /* Make a new, fake channel that we'll use to masquerade in the real one */
452 if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) {
453 ast_log(LOG_WARNING, "Unable to create parked channel\n");
454 return -1;
457 /* Make formats okay */
458 chan->readformat = rchan->readformat;
459 chan->writeformat = rchan->writeformat;
460 ast_channel_masquerade(chan, rchan);
462 /* Setup the extensions and such */
463 set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority);
465 /* Make the masq execute */
466 f = ast_read(chan);
467 if (f)
468 ast_frfree(f);
470 ast_park_call(chan, peer, timeout, extout);
471 return 0;
475 #define FEATURE_RETURN_HANGUP -1
476 #define FEATURE_RETURN_SUCCESSBREAK 0
477 #define FEATURE_RETURN_PBX_KEEPALIVE AST_PBX_KEEPALIVE
478 #define FEATURE_RETURN_NO_HANGUP_PEER AST_PBX_NO_HANGUP_PEER
479 #define FEATURE_RETURN_PASSDIGITS 21
480 #define FEATURE_RETURN_STOREDIGITS 22
481 #define FEATURE_RETURN_SUCCESS 23
482 #define FEATURE_RETURN_KEEPTRYING 24
484 #define FEATURE_SENSE_CHAN (1 << 0)
485 #define FEATURE_SENSE_PEER (1 << 1)
487 /*! \brief
488 * set caller and callee according to the direction
490 static void set_peers(struct ast_channel **caller, struct ast_channel **callee,
491 struct ast_channel *peer, struct ast_channel *chan, int sense)
493 if (sense == FEATURE_SENSE_PEER) {
494 *caller = peer;
495 *callee = chan;
496 } else {
497 *callee = peer;
498 *caller = chan;
502 /*! \brief support routing for one touch call parking */
503 static int builtin_parkcall(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
505 struct ast_channel *parker;
506 struct ast_channel *parkee;
507 int res = 0;
508 struct ast_module_user *u;
510 u = ast_module_user_add(chan);
512 set_peers(&parker, &parkee, peer, chan, sense);
513 /* Setup the exten/priority to be s/1 since we don't know
514 where this call should return */
515 strcpy(chan->exten, "s");
516 chan->priority = 1;
517 if (chan->_state != AST_STATE_UP)
518 res = ast_answer(chan);
519 if (!res)
520 res = ast_safe_sleep(chan, 1000);
521 if (!res)
522 res = ast_park_call(parkee, parker, 0, NULL);
524 ast_module_user_remove(u);
526 if (!res) {
527 if (sense == FEATURE_SENSE_CHAN)
528 res = AST_PBX_NO_HANGUP_PEER;
529 else
530 res = AST_PBX_KEEPALIVE;
532 return res;
536 static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
538 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
539 int x = 0;
540 size_t len;
541 struct ast_channel *caller_chan, *callee_chan;
543 if (!monitor_ok) {
544 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
545 return -1;
548 if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) {
549 monitor_ok = 0;
550 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
551 return -1;
554 set_peers(&caller_chan, &callee_chan, peer, chan, sense);
556 if (!ast_strlen_zero(courtesytone)) {
557 if (ast_autoservice_start(callee_chan))
558 return -1;
559 if (ast_stream_and_wait(caller_chan, courtesytone, caller_chan->language, "")) {
560 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
561 ast_autoservice_stop(callee_chan);
562 return -1;
564 if (ast_autoservice_stop(callee_chan))
565 return -1;
568 if (callee_chan->monitor) {
569 if (option_verbose > 3)
570 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to stop recording call.\n", code);
571 ast_monitor_stop(callee_chan, 1);
572 return FEATURE_RETURN_SUCCESS;
575 if (caller_chan && callee_chan) {
576 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT");
577 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
579 if (!touch_format)
580 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
582 if (!touch_monitor)
583 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
585 if (touch_monitor) {
586 len = strlen(touch_monitor) + 50;
587 args = alloca(len);
588 touch_filename = alloca(len);
589 snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor);
590 snprintf(args, len, "%s|%s|m", (touch_format) ? touch_format : "wav", touch_filename);
591 } else {
592 caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name));
593 callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name));
594 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
595 args = alloca(len);
596 touch_filename = alloca(len);
597 snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id);
598 snprintf(args, len, "%s|%s|m", S_OR(touch_format, "wav"), touch_filename);
601 for( x = 0; x < strlen(args); x++) {
602 if (args[x] == '/')
603 args[x] = '-';
606 if (option_verbose > 3)
607 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call. filename: %s\n", code, args);
609 pbx_exec(callee_chan, monitor_app, args);
610 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
611 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
613 return FEATURE_RETURN_SUCCESS;
616 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");
617 return -1;
620 static int builtin_disconnect(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
622 if (option_verbose > 3)
623 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code);
624 return FEATURE_RETURN_HANGUP;
627 static int finishup(struct ast_channel *chan)
629 ast_indicate(chan, AST_CONTROL_UNHOLD);
631 return ast_autoservice_stop(chan);
634 /*! \brief Find the context for the transfer */
635 static const char *real_ctx(struct ast_channel *transferer, struct ast_channel *transferee)
637 const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT");
638 if (ast_strlen_zero(s))
639 s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT");
640 if (ast_strlen_zero(s)) /* Use the non-macro context to transfer the call XXX ? */
641 s = transferer->macrocontext;
642 if (ast_strlen_zero(s))
643 s = transferer->context;
644 return s;
647 static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
649 struct ast_channel *transferer;
650 struct ast_channel *transferee;
651 const char *transferer_real_context;
652 char xferto[256];
653 int res;
655 set_peers(&transferer, &transferee, peer, chan, sense);
656 transferer_real_context = real_ctx(transferer, transferee);
657 /* Start autoservice on chan while we talk to the originator */
658 ast_autoservice_start(transferee);
659 ast_indicate(transferee, AST_CONTROL_HOLD);
661 memset(xferto, 0, sizeof(xferto));
663 /* Transfer */
664 res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY);
665 if (res < 0) {
666 finishup(transferee);
667 return -1; /* error ? */
669 if (res > 0) /* If they've typed a digit already, handle it */
670 xferto[0] = (char) res;
672 ast_stopstream(transferer);
673 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
674 if (res < 0) { /* hangup, would be 0 for invalid and 1 for valid */
675 finishup(transferee);
676 return res;
678 if (!strcmp(xferto, ast_parking_ext())) {
679 res = finishup(transferee);
680 if (res)
681 res = -1;
682 else if (!ast_park_call(transferee, transferer, 0, NULL)) { /* success */
683 /* We return non-zero, but tell the PBX not to hang the channel when
684 the thread dies -- We have to be careful now though. We are responsible for
685 hanging up the channel, else it will never be hung up! */
687 return (transferer == peer) ? AST_PBX_KEEPALIVE : AST_PBX_NO_HANGUP_PEER;
688 } else {
689 ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name);
691 /*! \todo XXX Maybe we should have another message here instead of invalid extension XXX */
692 } else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
693 pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", transferee->name);
694 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", peer->name);
695 res=finishup(transferee);
696 if (!transferer->cdr) {
697 transferer->cdr=ast_cdr_alloc();
698 if (transferer) {
699 ast_cdr_init(transferer->cdr, transferer); /* initilize our channel's cdr */
700 ast_cdr_start(transferer->cdr);
703 if (transferer->cdr) {
704 ast_cdr_setdestchan(transferer->cdr, transferee->name);
705 ast_cdr_setapp(transferer->cdr, "BLINDTRANSFER","");
707 if (!transferee->pbx) {
708 /* Doh! Use our handy async_goto functions */
709 if (option_verbose > 2)
710 ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n"
711 ,transferee->name, xferto, transferer_real_context);
712 if (ast_async_goto(transferee, transferer_real_context, xferto, 1))
713 ast_log(LOG_WARNING, "Async goto failed :-(\n");
714 res = -1;
715 } else {
716 /* Set the channel's new extension, since it exists, using transferer context */
717 set_c_e_p(transferee, transferer_real_context, xferto, 0);
719 check_goto_on_transfer(transferer);
720 return res;
721 } else {
722 if (option_verbose > 2)
723 ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context);
725 if (ast_stream_and_wait(transferer, xferfailsound, transferer->language, AST_DIGIT_ANY) < 0 ) {
726 finishup(transferee);
727 return -1;
729 ast_stopstream(transferer);
730 res = finishup(transferee);
731 if (res) {
732 if (option_verbose > 1)
733 ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name);
734 return res;
736 return FEATURE_RETURN_SUCCESS;
739 static int check_compat(struct ast_channel *c, struct ast_channel *newchan)
741 if (ast_channel_make_compatible(c, newchan) < 0) {
742 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n",
743 c->name, newchan->name);
744 ast_hangup(newchan);
745 return -1;
747 return 0;
750 static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
752 struct ast_channel *transferer;
753 struct ast_channel *transferee;
754 const char *transferer_real_context;
755 char xferto[256] = "";
756 int res;
757 int outstate=0;
758 struct ast_channel *newchan;
759 struct ast_channel *xferchan;
760 struct ast_bridge_thread_obj *tobj;
761 struct ast_bridge_config bconfig;
762 struct ast_frame *f;
763 int l;
765 if (option_debug)
766 ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense);
767 set_peers(&transferer, &transferee, peer, chan, sense);
768 transferer_real_context = real_ctx(transferer, transferee);
769 /* Start autoservice on chan while we talk to the originator */
770 ast_autoservice_start(transferee);
771 ast_indicate(transferee, AST_CONTROL_HOLD);
773 /* Transfer */
774 res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY);
775 if (res < 0) {
776 finishup(transferee);
777 return res;
779 if (res > 0) /* If they've typed a digit already, handle it */
780 xferto[0] = (char) res;
782 /* this is specific of atxfer */
783 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
784 if (res < 0) { /* hangup, would be 0 for invalid and 1 for valid */
785 finishup(transferee);
786 return res;
788 if (res == 0) {
789 ast_log(LOG_WARNING, "Did not read data.\n");
790 finishup(transferee);
791 if (ast_stream_and_wait(transferer, "beeperr", transferer->language, ""))
792 return -1;
793 return FEATURE_RETURN_SUCCESS;
796 /* valid extension, res == 1 */
797 if (!ast_exists_extension(transferer, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
798 ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context);
799 finishup(transferee);
800 if (ast_stream_and_wait(transferer, "beeperr", transferer->language, ""))
801 return -1;
802 return FEATURE_RETURN_SUCCESS;
805 l = strlen(xferto);
806 snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context); /* append context */
807 newchan = ast_feature_request_and_dial(transferer, "Local", ast_best_codec(transferer->nativeformats),
808 xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name);
809 ast_indicate(transferer, -1);
810 if (!newchan) {
811 finishup(transferee);
812 /* any reason besides user requested cancel and busy triggers the failed sound */
813 if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY &&
814 ast_stream_and_wait(transferer, xferfailsound, transferer->language, ""))
815 return -1;
816 return FEATURE_RETURN_SUCCESS;
819 if (check_compat(transferer, newchan)) {
820 /* we do mean transferee here, NOT transferer */
821 finishup(transferee);
822 return -1;
824 memset(&bconfig,0,sizeof(struct ast_bridge_config));
825 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
826 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
827 res = ast_bridge_call(transferer, newchan, &bconfig);
828 if (newchan->_softhangup || !transferer->_softhangup) {
829 ast_hangup(newchan);
830 if (ast_stream_and_wait(transferer, xfersound, transferer->language, ""))
831 ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
832 finishup(transferee);
833 transferer->_softhangup = 0;
834 return FEATURE_RETURN_SUCCESS;
837 if (check_compat(transferee, newchan)) {
838 finishup(transferee);
839 return -1;
842 ast_indicate(transferee, AST_CONTROL_UNHOLD);
844 if ((ast_autoservice_stop(transferee) < 0)
845 || (ast_waitfordigit(transferee, 100) < 0)
846 || (ast_waitfordigit(newchan, 100) < 0)
847 || ast_check_hangup(transferee)
848 || ast_check_hangup(newchan)) {
849 ast_hangup(newchan);
850 return -1;
853 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name);
854 if (!xferchan) {
855 ast_hangup(newchan);
856 return -1;
858 /* Make formats okay */
859 xferchan->readformat = transferee->readformat;
860 xferchan->writeformat = transferee->writeformat;
861 ast_channel_masquerade(xferchan, transferee);
862 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
863 xferchan->_state = AST_STATE_UP;
864 ast_clear_flag(xferchan, AST_FLAGS_ALL);
865 xferchan->_softhangup = 0;
867 if ((f = ast_read(xferchan)))
868 ast_frfree(f);
870 newchan->_state = AST_STATE_UP;
871 ast_clear_flag(newchan, AST_FLAGS_ALL);
872 newchan->_softhangup = 0;
874 tobj = ast_calloc(1, sizeof(struct ast_bridge_thread_obj));
875 if (!tobj) {
876 ast_hangup(xferchan);
877 ast_hangup(newchan);
878 return -1;
880 tobj->chan = xferchan;
881 tobj->peer = newchan;
882 tobj->bconfig = *config;
884 if (ast_stream_and_wait(newchan, xfersound, newchan->language, ""))
885 ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
886 ast_bridge_call_thread_launch(tobj);
887 return -1; /* XXX meaning the channel is bridged ? */
891 /* add atxfer and automon as undefined so you can only use em if you configure them */
892 #define FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0]))
894 AST_RWLOCK_DEFINE_STATIC(features_lock);
896 static struct ast_call_feature builtin_features[] =
898 { AST_FEATURE_REDIRECT, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
899 { AST_FEATURE_REDIRECT, "Attended Transfer", "atxfer", "", "", builtin_atxfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
900 { AST_FEATURE_AUTOMON, "One Touch Monitor", "automon", "", "", builtin_automonitor, AST_FEATURE_FLAG_NEEDSDTMF, "" },
901 { AST_FEATURE_DISCONNECT, "Disconnect Call", "disconnect", "*", "*", builtin_disconnect, AST_FEATURE_FLAG_NEEDSDTMF, "" },
902 { AST_FEATURE_PARKCALL, "Park Call", "parkcall", "", "", builtin_parkcall, AST_FEATURE_FLAG_NEEDSDTMF, "" },
906 static AST_LIST_HEAD_STATIC(feature_list,ast_call_feature);
908 /*! \brief register new feature into feature_list*/
909 void ast_register_feature(struct ast_call_feature *feature)
911 if (!feature) {
912 ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
913 return;
916 AST_LIST_LOCK(&feature_list);
917 AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry);
918 AST_LIST_UNLOCK(&feature_list);
920 if (option_verbose >= 2)
921 ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
924 /*! \brief unregister feature from feature_list */
925 void ast_unregister_feature(struct ast_call_feature *feature)
927 if (!feature)
928 return;
930 AST_LIST_LOCK(&feature_list);
931 AST_LIST_REMOVE(&feature_list,feature,feature_entry);
932 AST_LIST_UNLOCK(&feature_list);
933 free(feature);
936 /*! \brief Remove all features in the list */
937 static void ast_unregister_features(void)
939 struct ast_call_feature *feature;
941 AST_LIST_LOCK(&feature_list);
942 while ((feature = AST_LIST_REMOVE_HEAD(&feature_list,feature_entry)))
943 free(feature);
944 AST_LIST_UNLOCK(&feature_list);
947 /*! \brief find a feature by name */
948 static struct ast_call_feature *find_dynamic_feature(const char *name)
950 struct ast_call_feature *tmp;
952 AST_LIST_TRAVERSE(&feature_list, tmp, feature_entry) {
953 if (!strcasecmp(tmp->sname, name))
954 break;
957 return tmp;
960 /*! \brief exec an app by feature */
961 static int feature_exec_app(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
963 struct ast_app *app;
964 struct ast_call_feature *feature = data;
965 struct ast_channel *work, *idle;
966 int res;
968 if (!feature) { /* shouldn't ever happen! */
969 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
970 return -1;
973 if (sense == FEATURE_SENSE_CHAN) {
974 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
975 return FEATURE_RETURN_KEEPTRYING;
976 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
977 work = chan;
978 idle = peer;
979 } else {
980 work = peer;
981 idle = chan;
983 } else {
984 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
985 return FEATURE_RETURN_KEEPTRYING;
986 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
987 work = peer;
988 idle = chan;
989 } else {
990 work = chan;
991 idle = peer;
995 if (!(app = pbx_findapp(feature->app))) {
996 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
997 return -2;
1000 ast_autoservice_start(idle);
1002 if (!ast_strlen_zero(feature->moh_class))
1003 ast_moh_start(idle, feature->moh_class, NULL);
1005 res = pbx_exec(work, app, feature->app_args);
1007 if (!ast_strlen_zero(feature->moh_class))
1008 ast_moh_stop(idle);
1010 ast_autoservice_stop(idle);
1012 if (res == AST_PBX_KEEPALIVE)
1013 return FEATURE_RETURN_PBX_KEEPALIVE;
1014 else if (res == AST_PBX_NO_HANGUP_PEER)
1015 return FEATURE_RETURN_NO_HANGUP_PEER;
1016 else if (res)
1017 return FEATURE_RETURN_SUCCESSBREAK;
1019 return FEATURE_RETURN_SUCCESS; /*! \todo XXX should probably return res */
1022 static void unmap_features(void)
1024 int x;
1026 ast_rwlock_wrlock(&features_lock);
1027 for (x = 0; x < FEATURES_COUNT; x++)
1028 strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
1029 ast_rwlock_unlock(&features_lock);
1032 static int remap_feature(const char *name, const char *value)
1034 int x, res = -1;
1036 ast_rwlock_wrlock(&features_lock);
1037 for (x = 0; x < FEATURES_COUNT; x++) {
1038 if (strcasecmp(builtin_features[x].sname, name))
1039 continue;
1041 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
1042 res = 0;
1043 break;
1045 ast_rwlock_unlock(&features_lock);
1047 return res;
1050 static int ast_feature_interpret(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
1052 int x;
1053 struct ast_flags features;
1054 int res = FEATURE_RETURN_PASSDIGITS;
1055 struct ast_call_feature *feature;
1056 const char *dynamic_features=pbx_builtin_getvar_helper(chan,"DYNAMIC_FEATURES");
1057 char *tmp, *tok;
1059 if (sense == FEATURE_SENSE_CHAN)
1060 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
1061 else
1062 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);
1063 if (option_debug > 2)
1064 ast_log(LOG_DEBUG, "Feature interpret: chan=%s, peer=%s, sense=%d, features=%d\n", chan->name, peer->name, sense, features.flags);
1066 ast_rwlock_rdlock(&features_lock);
1067 for (x = 0; x < FEATURES_COUNT; x++) {
1068 if ((ast_test_flag(&features, builtin_features[x].feature_mask)) &&
1069 !ast_strlen_zero(builtin_features[x].exten)) {
1070 /* Feature is up for consideration */
1071 if (!strcmp(builtin_features[x].exten, code)) {
1072 res = builtin_features[x].operation(chan, peer, config, code, sense, NULL);
1073 break;
1074 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
1075 if (res == FEATURE_RETURN_PASSDIGITS)
1076 res = FEATURE_RETURN_STOREDIGITS;
1080 ast_rwlock_unlock(&features_lock);
1082 if (ast_strlen_zero(dynamic_features))
1083 return res;
1085 tmp = ast_strdupa(dynamic_features);
1087 while ((tok = strsep(&tmp, "#"))) {
1088 AST_LIST_LOCK(&feature_list);
1089 if (!(feature = find_dynamic_feature(tok))) {
1090 AST_LIST_UNLOCK(&feature_list);
1091 continue;
1094 /* Feature is up for consideration */
1095 if (!strcmp(feature->exten, code)) {
1096 if (option_verbose > 2)
1097 ast_verbose(VERBOSE_PREFIX_3 " Feature Found: %s exten: %s\n",feature->sname, tok);
1098 res = feature->operation(chan, peer, config, code, sense, feature);
1099 if (res != FEATURE_RETURN_KEEPTRYING) {
1100 AST_LIST_UNLOCK(&feature_list);
1101 break;
1103 res = FEATURE_RETURN_PASSDIGITS;
1104 } else if (!strncmp(feature->exten, code, strlen(code)))
1105 res = FEATURE_RETURN_STOREDIGITS;
1107 AST_LIST_UNLOCK(&feature_list);
1110 return res;
1113 static void set_config_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
1115 int x;
1117 ast_clear_flag(config, AST_FLAGS_ALL);
1119 ast_rwlock_rdlock(&features_lock);
1120 for (x = 0; x < FEATURES_COUNT; x++) {
1121 if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF))
1122 continue;
1124 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
1125 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
1127 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
1128 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
1130 ast_rwlock_unlock(&features_lock);
1132 if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
1133 const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
1135 if (dynamic_features) {
1136 char *tmp = ast_strdupa(dynamic_features);
1137 char *tok;
1138 struct ast_call_feature *feature;
1140 /* while we have a feature */
1141 while ((tok = strsep(&tmp, "#"))) {
1142 AST_LIST_LOCK(&feature_list);
1143 if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
1144 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
1145 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
1146 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
1147 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
1149 AST_LIST_UNLOCK(&feature_list);
1155 /*! \todo XXX Check - this is very similar to the code in channel.c */
1156 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)
1158 int state = 0;
1159 int cause = 0;
1160 int to;
1161 struct ast_channel *chan;
1162 struct ast_channel *monitor_chans[2];
1163 struct ast_channel *active_channel;
1164 int res = 0, ready = 0;
1166 if ((chan = ast_request(type, format, data, &cause))) {
1167 ast_set_callerid(chan, cid_num, cid_name, cid_num);
1168 ast_channel_inherit_variables(caller, chan);
1169 pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name);
1170 if (!chan->cdr) {
1171 chan->cdr=ast_cdr_alloc();
1172 if (chan->cdr) {
1173 ast_cdr_init(chan->cdr, chan); /* initilize our channel's cdr */
1174 ast_cdr_start(chan->cdr);
1178 if (!ast_call(chan, data, timeout)) {
1179 struct timeval started;
1180 int x, len = 0;
1181 char *disconnect_code = NULL, *dialed_code = NULL;
1183 ast_indicate(caller, AST_CONTROL_RINGING);
1184 /* support dialing of the featuremap disconnect code while performing an attended tranfer */
1185 ast_rwlock_rdlock(&features_lock);
1186 for (x = 0; x < FEATURES_COUNT; x++) {
1187 if (strcasecmp(builtin_features[x].sname, "disconnect"))
1188 continue;
1190 disconnect_code = builtin_features[x].exten;
1191 len = strlen(disconnect_code) + 1;
1192 dialed_code = alloca(len);
1193 memset(dialed_code, 0, len);
1194 break;
1196 ast_rwlock_unlock(&features_lock);
1197 x = 0;
1198 started = ast_tvnow();
1199 to = timeout;
1200 while (!ast_check_hangup(caller) && timeout && (chan->_state != AST_STATE_UP)) {
1201 struct ast_frame *f = NULL;
1203 monitor_chans[0] = caller;
1204 monitor_chans[1] = chan;
1205 active_channel = ast_waitfor_n(monitor_chans, 2, &to);
1207 /* see if the timeout has been violated */
1208 if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
1209 state = AST_CONTROL_UNHOLD;
1210 ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n");
1211 break; /*doh! timeout*/
1214 if (!active_channel)
1215 continue;
1217 if (chan && (chan == active_channel)){
1218 f = ast_read(chan);
1219 if (f == NULL) { /*doh! where'd he go?*/
1220 state = AST_CONTROL_HANGUP;
1221 res = 0;
1222 break;
1225 if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) {
1226 if (f->subclass == AST_CONTROL_RINGING) {
1227 state = f->subclass;
1228 if (option_verbose > 2)
1229 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", chan->name);
1230 ast_indicate(caller, AST_CONTROL_RINGING);
1231 } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) {
1232 state = f->subclass;
1233 if (option_verbose > 2)
1234 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", chan->name);
1235 ast_indicate(caller, AST_CONTROL_BUSY);
1236 ast_frfree(f);
1237 f = NULL;
1238 break;
1239 } else if (f->subclass == AST_CONTROL_ANSWER) {
1240 /* This is what we are hoping for */
1241 state = f->subclass;
1242 ast_frfree(f);
1243 f = NULL;
1244 ready=1;
1245 break;
1246 } else if (f->subclass != -1) {
1247 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass);
1249 /* else who cares */
1252 } else if (caller && (active_channel == caller)) {
1253 f = ast_read(caller);
1254 if (f == NULL) { /*doh! where'd he go?*/
1255 if (caller->_softhangup && !chan->_softhangup) {
1256 /* make this a blind transfer */
1257 ready = 1;
1258 break;
1260 state = AST_CONTROL_HANGUP;
1261 res = 0;
1262 break;
1265 if (f->frametype == AST_FRAME_DTMF) {
1266 dialed_code[x++] = f->subclass;
1267 dialed_code[x] = '\0';
1268 if (strlen(dialed_code) == len) {
1269 x = 0;
1270 } else if (x && strncmp(dialed_code, disconnect_code, x)) {
1271 x = 0;
1272 dialed_code[x] = '\0';
1274 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
1275 /* Caller Canceled the call */
1276 state = AST_CONTROL_UNHOLD;
1277 ast_frfree(f);
1278 f = NULL;
1279 break;
1283 if (f)
1284 ast_frfree(f);
1285 } /* end while */
1286 } else
1287 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
1288 } else {
1289 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
1290 switch(cause) {
1291 case AST_CAUSE_BUSY:
1292 state = AST_CONTROL_BUSY;
1293 break;
1294 case AST_CAUSE_CONGESTION:
1295 state = AST_CONTROL_CONGESTION;
1296 break;
1300 ast_indicate(caller, -1);
1301 if (chan && ready) {
1302 if (chan->_state == AST_STATE_UP)
1303 state = AST_CONTROL_ANSWER;
1304 res = 0;
1305 } else if(chan) {
1306 res = -1;
1307 ast_hangup(chan);
1308 chan = NULL;
1309 } else {
1310 res = -1;
1313 if (outstate)
1314 *outstate = state;
1316 if (chan && res <= 0) {
1317 if (chan->cdr || (chan->cdr = ast_cdr_alloc())) {
1318 char tmp[256];
1319 ast_cdr_init(chan->cdr, chan);
1320 snprintf(tmp, 256, "%s/%s", type, (char *)data);
1321 ast_cdr_setapp(chan->cdr,"Dial",tmp);
1322 ast_cdr_update(chan);
1323 ast_cdr_start(chan->cdr);
1324 ast_cdr_end(chan->cdr);
1325 /* If the cause wasn't handled properly */
1326 if (ast_cdr_disposition(chan->cdr,chan->hangupcause))
1327 ast_cdr_failed(chan->cdr);
1328 } else {
1329 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
1333 return chan;
1336 int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast_bridge_config *config)
1338 /* Copy voice back and forth between the two channels. Give the peer
1339 the ability to transfer calls with '#<extension' syntax. */
1340 struct ast_frame *f;
1341 struct ast_channel *who;
1342 char chan_featurecode[FEATURE_MAX_LEN + 1]="";
1343 char peer_featurecode[FEATURE_MAX_LEN + 1]="";
1344 int res;
1345 int diff;
1346 int hasfeatures=0;
1347 int hadfeatures=0;
1348 struct ast_option_header *aoh;
1349 struct ast_bridge_config backup_config;
1350 struct ast_cdr *bridge_cdr;
1352 memset(&backup_config, 0, sizeof(backup_config));
1354 config->start_time = ast_tvnow();
1356 if (chan && peer) {
1357 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
1358 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
1359 } else if (chan)
1360 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
1362 if (monitor_ok) {
1363 const char *monitor_exec;
1364 struct ast_channel *src = NULL;
1365 if (!monitor_app) {
1366 if (!(monitor_app = pbx_findapp("Monitor")))
1367 monitor_ok=0;
1369 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR")))
1370 src = chan;
1371 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
1372 src = peer;
1373 if (monitor_app && src) {
1374 char *tmp = ast_strdupa(monitor_exec);
1375 pbx_exec(src, monitor_app, tmp);
1379 set_config_flags(chan, peer, config);
1380 config->firstpass = 1;
1382 /* Answer if need be */
1383 if (ast_answer(chan))
1384 return -1;
1385 peer->appl = "Bridged Call";
1386 peer->data = chan->name;
1388 /* copy the userfield from the B-leg to A-leg if applicable */
1389 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
1390 char tmp[256];
1391 if (!ast_strlen_zero(chan->cdr->userfield)) {
1392 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield);
1393 ast_cdr_appenduserfield(chan, tmp);
1394 } else
1395 ast_cdr_setuserfield(chan, peer->cdr->userfield);
1396 /* free the peer's cdr without ast_cdr_free complaining */
1397 free(peer->cdr);
1398 peer->cdr = NULL;
1401 for (;;) {
1402 struct ast_channel *other; /* used later */
1404 res = ast_channel_bridge(chan, peer, config, &f, &who);
1406 if (config->feature_timer) {
1407 /* Update time limit for next pass */
1408 diff = ast_tvdiff_ms(ast_tvnow(), config->start_time);
1409 config->feature_timer -= diff;
1410 if (hasfeatures) {
1411 /* Running on backup config, meaning a feature might be being
1412 activated, but that's no excuse to keep things going
1413 indefinitely! */
1414 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
1415 if (option_debug)
1416 ast_log(LOG_DEBUG, "Timed out, realtime this time!\n");
1417 config->feature_timer = 0;
1418 who = chan;
1419 if (f)
1420 ast_frfree(f);
1421 f = NULL;
1422 res = 0;
1423 } else if (config->feature_timer <= 0) {
1424 /* Not *really* out of time, just out of time for
1425 digits to come in for features. */
1426 if (option_debug)
1427 ast_log(LOG_DEBUG, "Timed out for feature!\n");
1428 if (!ast_strlen_zero(peer_featurecode)) {
1429 ast_dtmf_stream(chan, peer, peer_featurecode, 0);
1430 memset(peer_featurecode, 0, sizeof(peer_featurecode));
1432 if (!ast_strlen_zero(chan_featurecode)) {
1433 ast_dtmf_stream(peer, chan, chan_featurecode, 0);
1434 memset(chan_featurecode, 0, sizeof(chan_featurecode));
1436 if (f)
1437 ast_frfree(f);
1438 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
1439 if (!hasfeatures) {
1440 /* Restore original (possibly time modified) bridge config */
1441 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
1442 memset(&backup_config, 0, sizeof(backup_config));
1444 hadfeatures = hasfeatures;
1445 /* Continue as we were */
1446 continue;
1447 } else if (!f) {
1448 /* The bridge returned without a frame and there is a feature in progress.
1449 * However, we don't think the feature has quite yet timed out, so just
1450 * go back into the bridge. */
1451 continue;
1453 } else {
1454 if (config->feature_timer <=0) {
1455 /* We ran out of time */
1456 config->feature_timer = 0;
1457 who = chan;
1458 if (f)
1459 ast_frfree(f);
1460 f = NULL;
1461 res = 0;
1465 if (res < 0) {
1466 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE))
1467 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s, res = %d\n", chan->name, peer->name, res);
1468 return -1;
1471 if (!f || (f->frametype == AST_FRAME_CONTROL &&
1472 (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY ||
1473 f->subclass == AST_CONTROL_CONGESTION ) ) ) {
1474 res = -1;
1475 break;
1477 /* many things should be sent to the 'other' channel */
1478 other = (who == chan) ? peer : chan;
1479 if (f->frametype == AST_FRAME_CONTROL) {
1480 switch (f->subclass) {
1481 case AST_CONTROL_RINGING:
1482 case AST_CONTROL_FLASH:
1483 case -1:
1484 ast_indicate(other, f->subclass);
1485 break;
1486 case AST_CONTROL_HOLD:
1487 case AST_CONTROL_UNHOLD:
1488 ast_indicate_data(other, f->subclass, f->data, f->datalen);
1489 break;
1490 case AST_CONTROL_OPTION:
1491 aoh = f->data;
1492 /* Forward option Requests */
1493 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) {
1494 ast_channel_setoption(other, ntohs(aoh->option), aoh->data,
1495 f->datalen - sizeof(struct ast_option_header), 0);
1497 break;
1499 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
1500 /* eat it */
1501 } else if (f->frametype == AST_FRAME_DTMF) {
1502 char *featurecode;
1503 int sense;
1505 hadfeatures = hasfeatures;
1506 /* This cannot overrun because the longest feature is one shorter than our buffer */
1507 if (who == chan) {
1508 sense = FEATURE_SENSE_CHAN;
1509 featurecode = chan_featurecode;
1510 } else {
1511 sense = FEATURE_SENSE_PEER;
1512 featurecode = peer_featurecode;
1514 /*! append the event to featurecode. we rely on the string being zero-filled, and
1515 * not overflowing it.
1516 * \todo XXX how do we guarantee the latter ?
1518 featurecode[strlen(featurecode)] = f->subclass;
1519 /* Get rid of the frame before we start doing "stuff" with the channels */
1520 ast_frfree(f);
1521 f = NULL;
1522 config->feature_timer = backup_config.feature_timer;
1523 res = ast_feature_interpret(chan, peer, config, featurecode, sense);
1524 switch(res) {
1525 case FEATURE_RETURN_PASSDIGITS:
1526 ast_dtmf_stream(other, who, featurecode, 0);
1527 /* Fall through */
1528 case FEATURE_RETURN_SUCCESS:
1529 memset(featurecode, 0, sizeof(chan_featurecode));
1530 break;
1532 if (res >= FEATURE_RETURN_PASSDIGITS) {
1533 res = 0;
1534 } else
1535 break;
1536 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
1537 if (hadfeatures && !hasfeatures) {
1538 /* Restore backup */
1539 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
1540 memset(&backup_config, 0, sizeof(struct ast_bridge_config));
1541 } else if (hasfeatures) {
1542 if (!hadfeatures) {
1543 /* Backup configuration */
1544 memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
1545 /* Setup temporary config options */
1546 config->play_warning = 0;
1547 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
1548 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
1549 config->warning_freq = 0;
1550 config->warning_sound = NULL;
1551 config->end_sound = NULL;
1552 config->start_sound = NULL;
1553 config->firstpass = 0;
1555 config->start_time = ast_tvnow();
1556 config->feature_timer = featuredigittimeout;
1557 if (option_debug)
1558 ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer);
1561 if (f)
1562 ast_frfree(f);
1566 /* arrange the cdrs */
1567 bridge_cdr = ast_cdr_alloc();
1568 if (bridge_cdr) {
1569 if (chan->cdr && peer->cdr) { /* both of them? merge */
1570 ast_cdr_init(bridge_cdr,chan); /* seems more logicaller to use the destination as a base, but, really, it's random */
1571 ast_cdr_start(bridge_cdr); /* now is the time to start */
1573 /* absorb the channel cdr */
1574 ast_cdr_merge(bridge_cdr, chan->cdr);
1575 if (!ast_test_flag(chan->cdr, AST_CDR_FLAG_LOCKED))
1576 ast_cdr_discard(chan->cdr); /* if locked cdrs are in chan, they are taken over in the merge */
1578 /* absorb the peer cdr */
1579 ast_cdr_merge(bridge_cdr, peer->cdr);
1580 if (!ast_test_flag(peer->cdr, AST_CDR_FLAG_LOCKED))
1581 ast_cdr_discard(peer->cdr); /* if locked cdrs are in peer, they are taken over in the merge */
1583 peer->cdr = NULL;
1584 chan->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */
1585 } else if (chan->cdr) {
1586 /* take the cdr from the channel - literally */
1587 ast_cdr_init(bridge_cdr,chan);
1588 /* absorb this data */
1589 ast_cdr_merge(bridge_cdr, chan->cdr);
1590 if (!ast_test_flag(chan->cdr, AST_CDR_FLAG_LOCKED))
1591 ast_cdr_discard(chan->cdr); /* if locked cdrs are in chan, they are taken over in the merge */
1592 chan->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */
1593 } else if (peer->cdr) {
1594 /* take the cdr from the peer - literally */
1595 ast_cdr_init(bridge_cdr,peer);
1596 /* absorb this data */
1597 ast_cdr_merge(bridge_cdr, peer->cdr);
1598 if (!ast_test_flag(peer->cdr, AST_CDR_FLAG_LOCKED))
1599 ast_cdr_discard(peer->cdr); /* if locked cdrs are in chan, they are taken over in the merge */
1600 peer->cdr = NULL;
1601 peer->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */
1602 } else {
1603 /* make up a new cdr */
1604 ast_cdr_init(bridge_cdr,chan); /* eh, just pick one of them */
1605 chan->cdr = bridge_cdr; /* */
1607 if (ast_strlen_zero(bridge_cdr->dstchannel)) {
1608 if (strcmp(bridge_cdr->channel, peer->name) != 0)
1609 ast_cdr_setdestchan(bridge_cdr, peer->name);
1610 else
1611 ast_cdr_setdestchan(bridge_cdr, chan->name);
1614 return res;
1617 static void post_manager_event(const char *s, char *parkingexten, struct ast_channel *chan)
1619 manager_event(EVENT_FLAG_CALL, s,
1620 "Exten: %s\r\n"
1621 "Channel: %s\r\n"
1622 "CallerID: %s\r\n"
1623 "CallerIDName: %s\r\n\r\n",
1624 parkingexten,
1625 chan->name,
1626 S_OR(chan->cid.cid_num, "<unknown>"),
1627 S_OR(chan->cid.cid_name, "<unknown>")
1631 /*! \brief Take care of parked calls and unpark them if needed */
1632 static void *do_parking_thread(void *ignore)
1634 fd_set rfds, efds; /* results from previous select, to be preserved across loops. */
1635 FD_ZERO(&rfds);
1636 FD_ZERO(&efds);
1638 for (;;) {
1639 struct parkeduser *pu, *pl, *pt = NULL;
1640 int ms = -1; /* select timeout, uninitialized */
1641 int max = -1; /* max fd, none there yet */
1642 fd_set nrfds, nefds; /* args for the next select */
1643 FD_ZERO(&nrfds);
1644 FD_ZERO(&nefds);
1646 ast_mutex_lock(&parking_lock);
1647 pl = NULL;
1648 pu = parkinglot;
1649 /* navigate the list with prev-cur pointers to support removals */
1650 while (pu) {
1651 struct ast_channel *chan = pu->chan; /* shorthand */
1652 int tms; /* timeout for this item */
1653 int x; /* fd index in channel */
1654 struct ast_context *con;
1656 if (pu->notquiteyet) { /* Pretend this one isn't here yet */
1657 pl = pu;
1658 pu = pu->next;
1659 continue;
1661 tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
1662 if (tms > pu->parkingtime) {
1663 ast_indicate(chan, AST_CONTROL_UNHOLD);
1664 /* Get chan, exten from derived kludge */
1665 if (pu->peername[0]) {
1666 char *peername = ast_strdupa(pu->peername);
1667 char *cp = strrchr(peername, '-');
1668 if (cp)
1669 *cp = 0;
1670 con = ast_context_find(parking_con_dial);
1671 if (!con) {
1672 con = ast_context_create(NULL, parking_con_dial, registrar);
1673 if (!con)
1674 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
1676 if (con) {
1677 char returnexten[AST_MAX_EXTENSION];
1678 snprintf(returnexten, sizeof(returnexten), "%s||t", peername);
1679 ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), ast_free, registrar);
1681 set_c_e_p(chan, parking_con_dial, peername, 1);
1682 } else {
1683 /* They've been waiting too long, send them back to where they came. Theoretically they
1684 should have their original extensions and such, but we copy to be on the safe side */
1685 set_c_e_p(chan, pu->context, pu->exten, pu->priority);
1688 post_manager_event("ParkedCallTimeOut", pu->parkingexten, chan);
1690 if (option_verbose > 1)
1691 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);
1692 /* Start up the PBX, or hang them up */
1693 if (ast_pbx_start(chan)) {
1694 ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", chan->name);
1695 ast_hangup(chan);
1697 /* And take them out of the parking lot */
1698 if (pl)
1699 pl->next = pu->next;
1700 else
1701 parkinglot = pu->next;
1702 pt = pu;
1703 pu = pu->next;
1704 con = ast_context_find(parking_con);
1705 if (con) {
1706 if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL))
1707 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1708 else
1709 notify_metermaids(pt->parkingexten, parking_con);
1710 } else
1711 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1712 free(pt);
1713 } else { /* still within parking time, process descriptors */
1714 for (x = 0; x < AST_MAX_FDS; x++) {
1715 struct ast_frame *f;
1717 if (chan->fds[x] == -1 || (!FD_ISSET(chan->fds[x], &rfds) && !FD_ISSET(chan->fds[x], &efds)))
1718 continue; /* nothing on this descriptor */
1720 if (FD_ISSET(chan->fds[x], &efds))
1721 ast_set_flag(chan, AST_FLAG_EXCEPTION);
1722 else
1723 ast_clear_flag(chan, AST_FLAG_EXCEPTION);
1724 chan->fdno = x;
1726 /* See if they need servicing */
1727 f = ast_read(chan);
1728 if (!f || (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_HANGUP)) {
1729 if (f)
1730 ast_frfree(f);
1731 post_manager_event("ParkedCallGiveUp", pu->parkingexten, chan);
1733 /* There's a problem, hang them up*/
1734 if (option_verbose > 1)
1735 ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", chan->name);
1736 ast_hangup(chan);
1737 /* And take them out of the parking lot */
1738 if (pl)
1739 pl->next = pu->next;
1740 else
1741 parkinglot = pu->next;
1742 pt = pu;
1743 pu = pu->next;
1744 con = ast_context_find(parking_con);
1745 if (con) {
1746 if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL))
1747 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1748 else
1749 notify_metermaids(pt->parkingexten, parking_con);
1750 } else
1751 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1752 free(pt);
1753 break;
1754 } else {
1755 /*! \todo XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
1756 ast_frfree(f);
1757 if (pu->moh_trys < 3 && !chan->generatordata) {
1758 if (option_debug)
1759 ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source. Restarting.\n");
1760 ast_indicate_data(pu->chan, AST_CONTROL_HOLD,
1761 S_OR(parkmohclass, NULL),
1762 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
1763 pu->moh_trys++;
1765 goto std; /*! \todo XXX Ick: jumping into an else statement??? XXX */
1768 } /* end for */
1769 if (x >= AST_MAX_FDS) {
1770 std: for (x=0; x<AST_MAX_FDS; x++) { /* mark fds for next round */
1771 if (chan->fds[x] > -1) {
1772 FD_SET(chan->fds[x], &nrfds);
1773 FD_SET(chan->fds[x], &nefds);
1774 if (chan->fds[x] > max)
1775 max = chan->fds[x];
1778 /* Keep track of our shortest wait */
1779 if (tms < ms || ms < 0)
1780 ms = tms;
1781 pl = pu;
1782 pu = pu->next;
1785 } /* end while */
1786 ast_mutex_unlock(&parking_lock);
1787 rfds = nrfds;
1788 efds = nefds;
1790 struct timeval tv = ast_samp2tv(ms, 1000);
1791 /* Wait for something to happen */
1792 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
1794 pthread_testcancel();
1796 return NULL; /* Never reached */
1799 /*! \brief Park a call */
1800 static int park_call_exec(struct ast_channel *chan, void *data)
1802 /* Data is unused at the moment but could contain a parking
1803 lot context eventually */
1804 int res = 0;
1805 struct ast_module_user *u;
1807 u = ast_module_user_add(chan);
1809 /* Setup the exten/priority to be s/1 since we don't know
1810 where this call should return */
1811 strcpy(chan->exten, "s");
1812 chan->priority = 1;
1813 /* Answer if call is not up */
1814 if (chan->_state != AST_STATE_UP)
1815 res = ast_answer(chan);
1816 /* Sleep to allow VoIP streams to settle down */
1817 if (!res)
1818 res = ast_safe_sleep(chan, 1000);
1819 /* Park the call */
1820 if (!res)
1821 res = ast_park_call(chan, chan, 0, NULL);
1823 ast_module_user_remove(u);
1825 return !res ? AST_PBX_KEEPALIVE : res;
1828 /*! \brief Pickup parked call */
1829 static int park_exec(struct ast_channel *chan, void *data)
1831 int res = 0;
1832 struct ast_module_user *u;
1833 struct ast_channel *peer=NULL;
1834 struct parkeduser *pu, *pl=NULL;
1835 struct ast_context *con;
1837 int park;
1838 struct ast_bridge_config config;
1840 if (!data) {
1841 ast_log(LOG_WARNING, "Parkedcall requires an argument (extension number)\n");
1842 return -1;
1845 u = ast_module_user_add(chan);
1847 park = atoi((char *)data);
1848 ast_mutex_lock(&parking_lock);
1849 pu = parkinglot;
1850 while(pu) {
1851 if (pu->parkingnum == park) {
1852 if (pl)
1853 pl->next = pu->next;
1854 else
1855 parkinglot = pu->next;
1856 break;
1858 pl = pu;
1859 pu = pu->next;
1861 ast_mutex_unlock(&parking_lock);
1862 if (pu) {
1863 peer = pu->chan;
1864 con = ast_context_find(parking_con);
1865 if (con) {
1866 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL))
1867 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1868 else
1869 notify_metermaids(pu->parkingexten, parking_con);
1870 } else
1871 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1873 manager_event(EVENT_FLAG_CALL, "UnParkedCall",
1874 "Exten: %s\r\n"
1875 "Channel: %s\r\n"
1876 "From: %s\r\n"
1877 "CallerID: %s\r\n"
1878 "CallerIDName: %s\r\n",
1879 pu->parkingexten, pu->chan->name, chan->name,
1880 S_OR(pu->chan->cid.cid_num, "<unknown>"),
1881 S_OR(pu->chan->cid.cid_name, "<unknown>")
1884 free(pu);
1886 /* JK02: it helps to answer the channel if not already up */
1887 if (chan->_state != AST_STATE_UP)
1888 ast_answer(chan);
1890 if (peer) {
1891 /* Play a courtesy to the source(s) configured to prefix the bridge connecting */
1893 if (!ast_strlen_zero(courtesytone)) {
1894 int error = 0;
1895 ast_indicate(peer, AST_CONTROL_UNHOLD);
1896 if (parkedplay == 0) {
1897 error = ast_stream_and_wait(chan, courtesytone, chan->language, "");
1898 } else if (parkedplay == 1) {
1899 error = ast_stream_and_wait(peer, courtesytone, chan->language, "");
1900 } else if (parkedplay == 2) {
1901 if (!ast_streamfile(chan, courtesytone, chan->language) &&
1902 !ast_streamfile(peer, courtesytone, chan->language)) {
1903 /*! \todo XXX we would like to wait on both! */
1904 res = ast_waitstream(chan, "");
1905 if (res >= 0)
1906 res = ast_waitstream(peer, "");
1907 if (res < 0)
1908 error = 1;
1911 if (error) {
1912 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
1913 ast_hangup(peer);
1914 return -1;
1916 } else
1917 ast_indicate(peer, AST_CONTROL_UNHOLD);
1919 res = ast_channel_make_compatible(chan, peer);
1920 if (res < 0) {
1921 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
1922 ast_hangup(peer);
1923 return -1;
1925 /* This runs sorta backwards, since we give the incoming channel control, as if it
1926 were the person called. */
1927 if (option_verbose > 2)
1928 ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
1930 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
1931 ast_cdr_setdestchan(chan->cdr, peer->name);
1932 memset(&config, 0, sizeof(struct ast_bridge_config));
1933 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
1934 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
1935 res = ast_bridge_call(chan, peer, &config);
1937 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
1938 ast_cdr_setdestchan(chan->cdr, peer->name);
1940 /* Simulate the PBX hanging up */
1941 if (res != AST_PBX_NO_HANGUP_PEER)
1942 ast_hangup(peer);
1943 return res;
1944 } else {
1945 /*! \todo XXX Play a message XXX */
1946 if (ast_stream_and_wait(chan, "pbx-invalidpark", chan->language, ""))
1947 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
1948 if (option_verbose > 2)
1949 ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
1950 res = -1;
1953 ast_module_user_remove(u);
1955 return res;
1958 static int handle_showfeatures(int fd, int argc, char *argv[])
1960 int i;
1961 struct ast_call_feature *feature;
1962 char format[] = "%-25s %-7s %-7s\n";
1964 ast_cli(fd, format, "Builtin Feature", "Default", "Current");
1965 ast_cli(fd, format, "---------------", "-------", "-------");
1967 ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */
1969 ast_rwlock_rdlock(&features_lock);
1970 for (i = 0; i < FEATURES_COUNT; i++)
1971 ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
1972 ast_rwlock_unlock(&features_lock);
1974 ast_cli(fd, "\n");
1975 ast_cli(fd, format, "Dynamic Feature", "Default", "Current");
1976 ast_cli(fd, format, "---------------", "-------", "-------");
1977 if (AST_LIST_EMPTY(&feature_list))
1978 ast_cli(fd, "(none)\n");
1979 else {
1980 AST_LIST_LOCK(&feature_list);
1981 AST_LIST_TRAVERSE(&feature_list, feature, feature_entry)
1982 ast_cli(fd, format, feature->sname, "no def", feature->exten);
1983 AST_LIST_UNLOCK(&feature_list);
1985 ast_cli(fd, "\nCall parking\n");
1986 ast_cli(fd, "------------\n");
1987 ast_cli(fd,"%-20s: %s\n", "Parking extension", parking_ext);
1988 ast_cli(fd,"%-20s: %s\n", "Parking context", parking_con);
1989 ast_cli(fd,"%-20s: %d-%d\n", "Parked call extensions", parking_start, parking_stop);
1990 ast_cli(fd,"\n");
1992 return RESULT_SUCCESS;
1995 static char showfeatures_help[] =
1996 "Usage: feature list\n"
1997 " Lists currently configured features.\n";
1999 static int handle_parkedcalls(int fd, int argc, char *argv[])
2001 struct parkeduser *cur;
2002 int numparked = 0;
2004 ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
2005 , "Context", "Extension", "Pri", "Timeout");
2007 ast_mutex_lock(&parking_lock);
2009 for (cur = parkinglot; cur; cur = cur->next) {
2010 ast_cli(fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n"
2011 ,cur->parkingexten, cur->chan->name, cur->context, cur->exten
2012 ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
2014 numparked++;
2016 ast_mutex_unlock(&parking_lock);
2017 ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : "");
2020 return RESULT_SUCCESS;
2023 static char showparked_help[] =
2024 "Usage: show parkedcalls\n"
2025 " Lists currently parked calls.\n";
2027 static struct ast_cli_entry cli_show_features_deprecated = {
2028 { "show", "features", NULL },
2029 handle_showfeatures, NULL,
2030 NULL };
2032 static struct ast_cli_entry cli_features[] = {
2033 { { "feature", "show", NULL },
2034 handle_showfeatures, "Lists configured features",
2035 showfeatures_help, NULL, &cli_show_features_deprecated },
2037 { { "show", "parkedcalls", NULL },
2038 handle_parkedcalls, "Lists parked calls",
2039 showparked_help },
2042 /*! \brief Dump lot status */
2043 static int manager_parking_status( struct mansession *s, const struct message *m)
2045 struct parkeduser *cur;
2046 const char *id = astman_get_header(m, "ActionID");
2047 char idText[256] = "";
2049 if (!ast_strlen_zero(id))
2050 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
2052 astman_send_ack(s, m, "Parked calls will follow");
2054 ast_mutex_lock(&parking_lock);
2056 for (cur = parkinglot; cur; cur = cur->next) {
2057 astman_append(s, "Event: ParkedCall\r\n"
2058 "Exten: %d\r\n"
2059 "Channel: %s\r\n"
2060 "From: %s\r\n"
2061 "Timeout: %ld\r\n"
2062 "CallerID: %s\r\n"
2063 "CallerIDName: %s\r\n"
2064 "%s"
2065 "\r\n",
2066 cur->parkingnum, cur->chan->name, cur->peername,
2067 (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
2068 S_OR(cur->chan->cid.cid_num, ""), /* XXX in other places it is <unknown> */
2069 S_OR(cur->chan->cid.cid_name, ""),
2070 idText);
2073 astman_append(s,
2074 "Event: ParkedCallsComplete\r\n"
2075 "%s"
2076 "\r\n",idText);
2078 ast_mutex_unlock(&parking_lock);
2080 return RESULT_SUCCESS;
2083 static char mandescr_park[] =
2084 "Description: Park a channel.\n"
2085 "Variables: (Names marked with * are required)\n"
2086 " *Channel: Channel name to park\n"
2087 " *Channel2: Channel to announce park info to (and return to if timeout)\n"
2088 " Timeout: Number of milliseconds to wait before callback.\n";
2090 static int manager_park(struct mansession *s, const struct message *m)
2092 const char *channel = astman_get_header(m, "Channel");
2093 const char *channel2 = astman_get_header(m, "Channel2");
2094 const char *timeout = astman_get_header(m, "Timeout");
2095 char buf[BUFSIZ];
2096 int to = 0;
2097 int res = 0;
2098 int parkExt = 0;
2099 struct ast_channel *ch1, *ch2;
2101 if (ast_strlen_zero(channel)) {
2102 astman_send_error(s, m, "Channel not specified");
2103 return 0;
2106 if (ast_strlen_zero(channel2)) {
2107 astman_send_error(s, m, "Channel2 not specified");
2108 return 0;
2111 ch1 = ast_get_channel_by_name_locked(channel);
2112 if (!ch1) {
2113 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
2114 astman_send_error(s, m, buf);
2115 return 0;
2118 ch2 = ast_get_channel_by_name_locked(channel2);
2119 if (!ch2) {
2120 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
2121 astman_send_error(s, m, buf);
2122 ast_channel_unlock(ch1);
2123 return 0;
2126 if (!ast_strlen_zero(timeout)) {
2127 sscanf(timeout, "%d", &to);
2130 res = ast_masq_park_call(ch1, ch2, to, &parkExt);
2131 if (!res) {
2132 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
2133 astman_send_ack(s, m, "Park successful");
2134 } else {
2135 astman_send_error(s, m, "Park failure");
2138 ast_channel_unlock(ch1);
2139 ast_channel_unlock(ch2);
2141 return 0;
2145 int ast_pickup_call(struct ast_channel *chan)
2147 struct ast_channel *cur = NULL;
2148 int res = -1;
2150 while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
2151 if (!cur->pbx &&
2152 (cur != chan) &&
2153 (chan->pickupgroup & cur->callgroup) &&
2154 ((cur->_state == AST_STATE_RINGING) ||
2155 (cur->_state == AST_STATE_RING))) {
2156 break;
2158 ast_channel_unlock(cur);
2160 if (cur) {
2161 if (option_debug)
2162 ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
2163 res = ast_answer(chan);
2164 if (res)
2165 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
2166 res = ast_queue_control(chan, AST_CONTROL_ANSWER);
2167 if (res)
2168 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
2169 res = ast_channel_masquerade(cur, chan);
2170 if (res)
2171 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */
2172 ast_channel_unlock(cur);
2173 } else {
2174 if (option_debug)
2175 ast_log(LOG_DEBUG, "No call pickup possible...\n");
2177 return res;
2180 /*! \brief Add parking hints for all defined parking lots */
2181 static void park_add_hints(char *context, int start, int stop)
2183 int numext;
2184 char device[AST_MAX_EXTENSION];
2185 char exten[10];
2187 for (numext = start; numext <= stop; numext++) {
2188 snprintf(exten, sizeof(exten), "%d", numext);
2189 snprintf(device, sizeof(device), "park:%s@%s", exten, context);
2190 ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
2195 static int load_config(void)
2197 int start = 0, end = 0;
2198 int res;
2199 struct ast_context *con = NULL;
2200 struct ast_config *cfg = NULL;
2201 struct ast_variable *var = NULL;
2202 char old_parking_ext[AST_MAX_EXTENSION];
2203 char old_parking_con[AST_MAX_EXTENSION] = "";
2205 if (!ast_strlen_zero(parking_con)) {
2206 strcpy(old_parking_ext, parking_ext);
2207 strcpy(old_parking_con, parking_con);
2210 /* Reset to defaults */
2211 strcpy(parking_con, "parkedcalls");
2212 strcpy(parking_con_dial, "park-dial");
2213 strcpy(parking_ext, "700");
2214 strcpy(pickup_ext, "*8");
2215 strcpy(parkmohclass, "default");
2216 courtesytone[0] = '\0';
2217 strcpy(xfersound, "beep");
2218 strcpy(xferfailsound, "pbx-invalid");
2219 parking_start = 701;
2220 parking_stop = 750;
2221 parkfindnext = 0;
2222 adsipark = 0;
2223 parkaddhints = 0;
2225 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
2226 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
2227 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
2229 cfg = ast_config_load("features.conf");
2230 if (!cfg) {
2231 ast_log(LOG_WARNING,"Could not load features.conf\n");
2232 return AST_MODULE_LOAD_DECLINE;
2234 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
2235 if (!strcasecmp(var->name, "parkext")) {
2236 ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
2237 } else if (!strcasecmp(var->name, "context")) {
2238 ast_copy_string(parking_con, var->value, sizeof(parking_con));
2239 } else if (!strcasecmp(var->name, "parkingtime")) {
2240 if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) {
2241 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
2242 parkingtime = DEFAULT_PARK_TIME;
2243 } else
2244 parkingtime = parkingtime * 1000;
2245 } else if (!strcasecmp(var->name, "parkpos")) {
2246 if (sscanf(var->value, "%d-%d", &start, &end) != 2) {
2247 ast_log(LOG_WARNING, "Format for parking positions is a-b, where a and b are numbers at line %d of parking.conf\n", var->lineno);
2248 } else {
2249 parking_start = start;
2250 parking_stop = end;
2252 } else if (!strcasecmp(var->name, "findslot")) {
2253 parkfindnext = (!strcasecmp(var->value, "next"));
2254 } else if (!strcasecmp(var->name, "parkinghints")) {
2255 parkaddhints = ast_true(var->value);
2256 } else if (!strcasecmp(var->name, "adsipark")) {
2257 adsipark = ast_true(var->value);
2258 } else if (!strcasecmp(var->name, "transferdigittimeout")) {
2259 if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
2260 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
2261 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
2262 } else
2263 transferdigittimeout = transferdigittimeout * 1000;
2264 } else if (!strcasecmp(var->name, "featuredigittimeout")) {
2265 if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
2266 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
2267 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
2269 } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) {
2270 if ((sscanf(var->value, "%d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) {
2271 ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value);
2272 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
2273 } else
2274 atxfernoanswertimeout = atxfernoanswertimeout * 1000;
2275 } else if (!strcasecmp(var->name, "courtesytone")) {
2276 ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
2277 } else if (!strcasecmp(var->name, "parkedplay")) {
2278 if (!strcasecmp(var->value, "both"))
2279 parkedplay = 2;
2280 else if (!strcasecmp(var->value, "parked"))
2281 parkedplay = 1;
2282 else
2283 parkedplay = 0;
2284 } else if (!strcasecmp(var->name, "xfersound")) {
2285 ast_copy_string(xfersound, var->value, sizeof(xfersound));
2286 } else if (!strcasecmp(var->name, "xferfailsound")) {
2287 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
2288 } else if (!strcasecmp(var->name, "pickupexten")) {
2289 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
2290 } else if (!strcasecmp(var->name, "parkedmusicclass")) {
2291 ast_copy_string(parkmohclass, var->value, sizeof(parkmohclass));
2295 unmap_features();
2296 for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) {
2297 if (remap_feature(var->name, var->value))
2298 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
2301 /* Map a key combination to an application*/
2302 ast_unregister_features();
2303 for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) {
2304 char *tmp_val = ast_strdupa(var->value);
2305 char *exten, *activateon, *activatedby, *app, *app_args, *moh_class;
2306 struct ast_call_feature *feature;
2308 /* strsep() sets the argument to NULL if match not found, and it
2309 * is safe to use it with a NULL argument, so we don't check
2310 * between calls.
2312 exten = strsep(&tmp_val,",");
2313 activatedby = strsep(&tmp_val,",");
2314 app = strsep(&tmp_val,",");
2315 app_args = strsep(&tmp_val,",");
2316 moh_class = strsep(&tmp_val,",");
2318 activateon = strsep(&activatedby, "/");
2320 /*! \todo XXX var_name or app_args ? */
2321 if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) {
2322 ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",
2323 app, exten, activateon, var->name);
2324 continue;
2327 AST_LIST_LOCK(&feature_list);
2328 if ((feature = find_dynamic_feature(var->name))) {
2329 AST_LIST_UNLOCK(&feature_list);
2330 ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name);
2331 continue;
2333 AST_LIST_UNLOCK(&feature_list);
2335 if (!(feature = ast_calloc(1, sizeof(*feature))))
2336 continue;
2338 ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN);
2339 ast_copy_string(feature->app, app, FEATURE_APP_LEN);
2340 ast_copy_string(feature->exten, exten, FEATURE_EXTEN_LEN);
2342 if (app_args)
2343 ast_copy_string(feature->app_args, app_args, FEATURE_APP_ARGS_LEN);
2345 if (moh_class)
2346 ast_copy_string(feature->moh_class, moh_class, FEATURE_MOH_LEN);
2348 ast_copy_string(feature->exten, exten, sizeof(feature->exten));
2349 feature->operation = feature_exec_app;
2350 ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF);
2352 /* Allow caller and calle to be specified for backwards compatability */
2353 if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller"))
2354 ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF);
2355 else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee"))
2356 ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER);
2357 else {
2358 ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s',"
2359 " must be 'self', or 'peer'\n", var->name);
2360 continue;
2363 if (ast_strlen_zero(activatedby))
2364 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
2365 else if (!strcasecmp(activatedby, "caller"))
2366 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER);
2367 else if (!strcasecmp(activatedby, "callee"))
2368 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE);
2369 else if (!strcasecmp(activatedby, "both"))
2370 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
2371 else {
2372 ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s',"
2373 " must be 'caller', or 'callee', or 'both'\n", var->name);
2374 continue;
2377 ast_register_feature(feature);
2379 if (option_verbose >= 1)
2380 ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, app, app_args, exten);
2382 ast_config_destroy(cfg);
2384 /* Remove the old parking extension */
2385 if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) {
2386 if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar))
2387 notify_metermaids(old_parking_ext, old_parking_con);
2388 if (option_debug)
2389 ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
2392 if (!(con = ast_context_find(parking_con)) && !(con = ast_context_create(NULL, parking_con, registrar))) {
2393 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
2394 return -1;
2396 res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar);
2397 if (parkaddhints)
2398 park_add_hints(parking_con, parking_start, parking_stop);
2399 if (!res)
2400 notify_metermaids(ast_parking_ext(), parking_con);
2401 return res;
2405 static int reload(void)
2407 return load_config();
2410 static int load_module(void)
2412 int res;
2414 memset(parking_ext, 0, sizeof(parking_ext));
2415 memset(parking_con, 0, sizeof(parking_con));
2417 if ((res = load_config()))
2418 return res;
2419 ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
2420 ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
2421 res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
2422 if (!res)
2423 res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
2424 if (!res) {
2425 ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" );
2426 ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park,
2427 "Park a channel", mandescr_park);
2430 res |= ast_devstate_prov_add("Park", metermaidstate);
2432 return res;
2436 static int unload_module(void)
2438 ast_module_user_hangup_all();
2440 ast_manager_unregister("ParkedCalls");
2441 ast_manager_unregister("Park");
2442 ast_cli_unregister_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
2443 ast_unregister_application(parkcall);
2444 ast_devstate_prov_del("Park");
2445 return ast_unregister_application(parkedcall);
2448 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Call Features Resource",
2449 .load = load_module,
2450 .unload = unload_module,
2451 .reload = reload,