00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include "asterisk.h"
00031
00032 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
00033
00034 #include <pthread.h>
00035 #include <stdlib.h>
00036 #include <errno.h>
00037 #include <unistd.h>
00038 #include <string.h>
00039 #include <stdlib.h>
00040 #include <stdio.h>
00041 #include <sys/time.h>
00042 #include <sys/signal.h>
00043 #include <netinet/in.h>
00044
00045 #include "asterisk/lock.h"
00046 #include "asterisk/file.h"
00047 #include "asterisk/logger.h"
00048 #include "asterisk/channel.h"
00049 #include "asterisk/pbx.h"
00050 #include "asterisk/options.h"
00051 #include "asterisk/causes.h"
00052 #include "asterisk/module.h"
00053 #include "asterisk/translate.h"
00054 #include "asterisk/app.h"
00055 #include "asterisk/say.h"
00056 #include "asterisk/features.h"
00057 #include "asterisk/musiconhold.h"
00058 #include "asterisk/config.h"
00059 #include "asterisk/cli.h"
00060 #include "asterisk/manager.h"
00061 #include "asterisk/utils.h"
00062 #include "asterisk/adsi.h"
00063 #include "asterisk/devicestate.h"
00064 #include "asterisk/monitor.h"
00065
00066 #define DEFAULT_PARK_TIME 45000
00067 #define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000
00068 #define DEFAULT_FEATURE_DIGIT_TIMEOUT 500
00069 #define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000
00070
00071 #define AST_MAX_WATCHERS 256
00072
00073 enum {
00074 AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0),
00075 AST_FEATURE_FLAG_ONPEER = (1 << 1),
00076 AST_FEATURE_FLAG_ONSELF = (1 << 2),
00077 AST_FEATURE_FLAG_BYCALLEE = (1 << 3),
00078 AST_FEATURE_FLAG_BYCALLER = (1 << 4),
00079 AST_FEATURE_FLAG_BYBOTH = (3 << 3),
00080 };
00081
00082 static char *parkedcall = "ParkedCall";
00083
00084 static int parkaddhints = 0;
00085 static int parkingtime = DEFAULT_PARK_TIME;
00086 static char parking_con[AST_MAX_EXTENSION];
00087 static char parking_con_dial[AST_MAX_EXTENSION];
00088 static char parking_ext[AST_MAX_EXTENSION];
00089 static char pickup_ext[AST_MAX_EXTENSION];
00090 static char parkmohclass[MAX_MUSICCLASS];
00091 static int parking_start;
00092 static int parking_stop;
00093
00094 static char courtesytone[256];
00095 static int parkedplay = 0;
00096 static char xfersound[256];
00097 static char xferfailsound[256];
00098
00099 static int parking_offset;
00100 static int parkfindnext;
00101
00102 static int adsipark;
00103
00104 static int transferdigittimeout;
00105 static int featuredigittimeout;
00106
00107 static int atxfernoanswertimeout;
00108
00109 static char *registrar = "res_features";
00110
00111
00112 static char *synopsis = "Answer a parked call";
00113
00114 static char *descrip = "ParkedCall(exten):"
00115 "Used to connect to a parked call. This application is always\n"
00116 "registered internally and does not need to be explicitly added\n"
00117 "into the dialplan, although you should include the 'parkedcalls'\n"
00118 "context.\n";
00119
00120 static char *parkcall = "Park";
00121
00122 static char *synopsis2 = "Park yourself";
00123
00124 static char *descrip2 = "Park():"
00125 "Used to park yourself (typically in combination with a supervised\n"
00126 "transfer to know the parking space). This application is always\n"
00127 "registered internally and does not need to be explicitly added\n"
00128 "into the dialplan, although you should include the 'parkedcalls'\n"
00129 "context (or the context specified in features.conf).\n\n"
00130 "If you set the PARKINGEXTEN variable to an extension in your\n"
00131 "parking context, park() will park the call on that extension, unless\n"
00132 "it already exists. In that case, execution will continue at next\n"
00133 "priority.\n" ;
00134
00135 static struct ast_app *monitor_app = NULL;
00136 static int monitor_ok = 1;
00137
00138 struct parkeduser {
00139 struct ast_channel *chan;
00140 struct timeval start;
00141 int parkingnum;
00142 char parkingexten[AST_MAX_EXTENSION];
00143 char context[AST_MAX_CONTEXT];
00144 char exten[AST_MAX_EXTENSION];
00145 int priority;
00146 int parkingtime;
00147 int notquiteyet;
00148 char peername[1024];
00149 unsigned char moh_trys;
00150 struct parkeduser *next;
00151 };
00152
00153 static struct parkeduser *parkinglot;
00154
00155 AST_MUTEX_DEFINE_STATIC(parking_lock);
00156
00157 static pthread_t parking_thread;
00158
00159 char *ast_parking_ext(void)
00160 {
00161 return parking_ext;
00162 }
00163
00164 char *ast_pickup_ext(void)
00165 {
00166 return pickup_ext;
00167 }
00168
00169 struct ast_bridge_thread_obj
00170 {
00171 struct ast_bridge_config bconfig;
00172 struct ast_channel *chan;
00173 struct ast_channel *peer;
00174 unsigned int return_to_pbx:1;
00175 };
00176
00177
00178
00179
00180 static void set_c_e_p(struct ast_channel *chan, const char *context, const char *ext, int pri)
00181 {
00182 ast_copy_string(chan->context, context, sizeof(chan->context));
00183 ast_copy_string(chan->exten, ext, sizeof(chan->exten));
00184 chan->priority = pri;
00185 }
00186
00187 static void check_goto_on_transfer(struct ast_channel *chan)
00188 {
00189 struct ast_channel *xferchan;
00190 const char *val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR");
00191 char *x, *goto_on_transfer;
00192 struct ast_frame *f;
00193
00194 if (ast_strlen_zero(val))
00195 return;
00196
00197 goto_on_transfer = ast_strdupa(val);
00198
00199 if (!(xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, chan->name)))
00200 return;
00201
00202 for (x = goto_on_transfer; x && *x; x++) {
00203 if (*x == '^')
00204 *x = '|';
00205 }
00206
00207 xferchan->readformat = chan->readformat;
00208 xferchan->writeformat = chan->writeformat;
00209 ast_channel_masquerade(xferchan, chan);
00210 ast_parseable_goto(xferchan, goto_on_transfer);
00211 xferchan->_state = AST_STATE_UP;
00212 ast_clear_flag(xferchan, AST_FLAGS_ALL);
00213 xferchan->_softhangup = 0;
00214 if ((f = ast_read(xferchan))) {
00215 ast_frfree(f);
00216 f = NULL;
00217 ast_pbx_start(xferchan);
00218 } else {
00219 ast_hangup(xferchan);
00220 }
00221 }
00222
00223 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);
00224
00225
00226 static void *ast_bridge_call_thread(void *data)
00227 {
00228 struct ast_bridge_thread_obj *tobj = data;
00229 int res;
00230
00231 tobj->chan->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge";
00232 tobj->chan->data = tobj->peer->name;
00233 tobj->peer->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge";
00234 tobj->peer->data = tobj->chan->name;
00235
00236 if (tobj->chan->cdr) {
00237 ast_cdr_reset(tobj->chan->cdr, NULL);
00238 ast_cdr_setdestchan(tobj->chan->cdr, tobj->peer->name);
00239 }
00240 if (tobj->peer->cdr) {
00241 ast_cdr_reset(tobj->peer->cdr, NULL);
00242 ast_cdr_setdestchan(tobj->peer->cdr, tobj->chan->name);
00243 }
00244
00245 ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
00246
00247 if (tobj->return_to_pbx) {
00248 if (!ast_check_hangup(tobj->peer)) {
00249 ast_log(LOG_VERBOSE, "putting peer %s into PBX again\n", tobj->peer->name);
00250 res = ast_pbx_start(tobj->peer);
00251 if (res != AST_PBX_SUCCESS)
00252 ast_log(LOG_WARNING, "FAILED continuing PBX on peer %s\n", tobj->peer->name);
00253 } else
00254 ast_hangup(tobj->peer);
00255 if (!ast_check_hangup(tobj->chan)) {
00256 ast_log(LOG_VERBOSE, "putting chan %s into PBX again\n", tobj->chan->name);
00257 res = ast_pbx_start(tobj->chan);
00258 if (res != AST_PBX_SUCCESS)
00259 ast_log(LOG_WARNING, "FAILED continuing PBX on chan %s\n", tobj->chan->name);
00260 } else
00261 ast_hangup(tobj->chan);
00262 } else {
00263 ast_hangup(tobj->chan);
00264 ast_hangup(tobj->peer);
00265 }
00266
00267 free(tobj);
00268
00269 return NULL;
00270 }
00271
00272 static void ast_bridge_call_thread_launch(void *data)
00273 {
00274 pthread_t thread;
00275 pthread_attr_t attr;
00276 struct sched_param sched;
00277
00278 pthread_attr_init(&attr);
00279 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00280 ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data);
00281 pthread_attr_destroy(&attr);
00282 memset(&sched, 0, sizeof(sched));
00283 pthread_setschedparam(thread, SCHED_RR, &sched);
00284 }
00285
00286 static int adsi_announce_park(struct ast_channel *chan, char *parkingexten)
00287 {
00288 int res;
00289 int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
00290 char tmp[256];
00291 char *message[5] = {NULL, NULL, NULL, NULL, NULL};
00292
00293 snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten);
00294 message[0] = tmp;
00295 res = ast_adsi_load_session(chan, NULL, 0, 1);
00296 if (res == -1)
00297 return res;
00298 return ast_adsi_print(chan, message, justify, 1);
00299 }
00300
00301
00302 static void notify_metermaids(char *exten, char *context)
00303 {
00304 if (option_debug > 3)
00305 ast_log(LOG_DEBUG, "Notification of state change to metermaids %s@%s\n", exten, context);
00306
00307
00308 ast_device_state_changed("park:%s@%s", exten, context);
00309 return;
00310 }
00311
00312
00313 static int metermaidstate(const char *data)
00314 {
00315 int res = AST_DEVICE_INVALID;
00316 char *context = ast_strdupa(data);
00317 char *exten;
00318
00319 exten = strsep(&context, "@");
00320 if (!context)
00321 return res;
00322
00323 if (option_debug > 3)
00324 ast_log(LOG_DEBUG, "Checking state of exten %s in context %s\n", exten, context);
00325
00326 res = ast_exists_extension(NULL, context, exten, 1, NULL);
00327
00328 if (!res)
00329 return AST_DEVICE_NOT_INUSE;
00330 else
00331 return AST_DEVICE_INUSE;
00332 }
00333
00334 static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout, char *orig_chan_name)
00335 {
00336 struct parkeduser *pu, *cur;
00337 int i, x = -1, parking_range;
00338 struct ast_context *con;
00339 const char *parkingexten;
00340
00341
00342 if (!(pu = ast_calloc(1, sizeof(*pu))))
00343 return -1;
00344
00345
00346 ast_mutex_lock(&parking_lock);
00347
00348 parkingexten = pbx_builtin_getvar_helper(chan, "PARKINGEXTEN");
00349 if (!ast_strlen_zero(parkingexten)) {
00350 if (ast_exists_extension(NULL, parking_con, parkingexten, 1, NULL)) {
00351 ast_mutex_unlock(&parking_lock);
00352 free(pu);
00353 ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parking_con);
00354 return 1;
00355 }
00356 ast_copy_string(pu->parkingexten, parkingexten, sizeof(pu->parkingexten));
00357 x = atoi(parkingexten);
00358 } else {
00359
00360 parking_range = parking_stop - parking_start+1;
00361 for (i = 0; i < parking_range; i++) {
00362 x = (i + parking_offset) % parking_range + parking_start;
00363 cur = parkinglot;
00364 while(cur) {
00365 if (cur->parkingnum == x)
00366 break;
00367 cur = cur->next;
00368 }
00369 if (!cur)
00370 break;
00371 }
00372
00373 if (!(i < parking_range)) {
00374 ast_log(LOG_WARNING, "No more parking spaces\n");
00375 free(pu);
00376 ast_mutex_unlock(&parking_lock);
00377 return -1;
00378 }
00379
00380 if (parkfindnext)
00381 parking_offset = x - parking_start + 1;
00382 }
00383
00384 chan->appl = "Parked Call";
00385 chan->data = NULL;
00386
00387 pu->chan = chan;
00388
00389
00390 if (chan != peer) {
00391 ast_indicate_data(pu->chan, AST_CONTROL_HOLD,
00392 S_OR(parkmohclass, NULL),
00393 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
00394 }
00395
00396 pu->start = ast_tvnow();
00397 pu->parkingnum = x;
00398 pu->parkingtime = (timeout > 0) ? timeout : parkingtime;
00399 if (extout)
00400 *extout = x;
00401
00402 if (peer)
00403 ast_copy_string(pu->peername, peer->name, sizeof(pu->peername));
00404
00405
00406
00407 ast_copy_string(pu->context, S_OR(chan->macrocontext, chan->context), sizeof(pu->context));
00408 ast_copy_string(pu->exten, S_OR(chan->macroexten, chan->exten), sizeof(pu->exten));
00409 pu->priority = chan->macropriority ? chan->macropriority : chan->priority;
00410 pu->next = parkinglot;
00411 parkinglot = pu;
00412
00413
00414 if (peer == chan)
00415 pu->notquiteyet = 1;
00416 ast_mutex_unlock(&parking_lock);
00417
00418 pthread_kill(parking_thread, SIGURG);
00419 if (option_verbose > 1)
00420 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));
00421
00422 if (pu->parkingnum != -1)
00423 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", x);
00424 manager_event(EVENT_FLAG_CALL, "ParkedCall",
00425 "Exten: %s\r\n"
00426 "Channel: %s\r\n"
00427 "From: %s\r\n"
00428 "Timeout: %ld\r\n"
00429 "CallerID: %s\r\n"
00430 "CallerIDName: %s\r\n",
00431 pu->parkingexten, pu->chan->name, peer ? peer->name : "",
00432 (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL),
00433 S_OR(pu->chan->cid.cid_num, "<unknown>"),
00434 S_OR(pu->chan->cid.cid_name, "<unknown>")
00435 );
00436
00437 if (peer && adsipark && ast_adsi_available(peer)) {
00438 adsi_announce_park(peer, pu->parkingexten);
00439 ast_adsi_unload_session(peer);
00440 }
00441
00442 con = ast_context_find(parking_con);
00443 if (!con)
00444 con = ast_context_create(NULL, parking_con, registrar);
00445 if (!con)
00446 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
00447
00448 if (peer && ((pu->parkingnum != -1 && ast_strlen_zero(orig_chan_name)) || !strcasecmp(peer->name, orig_chan_name))) {
00449
00450 ast_set_flag(peer, AST_FLAG_MASQ_NOSTREAM);
00451 ast_say_digits(peer, pu->parkingnum, "", peer->language);
00452 ast_clear_flag(peer, AST_FLAG_MASQ_NOSTREAM);
00453 }
00454 if (con) {
00455 if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, strdup(pu->parkingexten), ast_free, registrar))
00456 notify_metermaids(pu->parkingexten, parking_con);
00457 }
00458 if (pu->notquiteyet) {
00459
00460 ast_indicate_data(pu->chan, AST_CONTROL_HOLD,
00461 S_OR(parkmohclass, NULL),
00462 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
00463 pu->notquiteyet = 0;
00464 pthread_kill(parking_thread, SIGURG);
00465 }
00466 return 0;
00467 }
00468
00469
00470
00471
00472 int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
00473 {
00474 return park_call_full(chan, peer, timeout, extout, NULL);
00475 }
00476
00477 int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
00478 {
00479 struct ast_channel *chan;
00480 struct ast_frame *f;
00481 char *orig_chan_name = NULL;
00482
00483
00484 if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) {
00485 ast_log(LOG_WARNING, "Unable to create parked channel\n");
00486 return -1;
00487 }
00488
00489
00490 chan->readformat = rchan->readformat;
00491 chan->writeformat = rchan->writeformat;
00492 ast_channel_masquerade(chan, rchan);
00493
00494
00495 set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority);
00496
00497
00498 f = ast_read(chan);
00499 if (f)
00500 ast_frfree(f);
00501
00502 orig_chan_name = ast_strdupa(chan->name);
00503
00504 park_call_full(chan, peer, timeout, extout, orig_chan_name);
00505
00506 return 0;
00507 }
00508
00509
00510 #define FEATURE_RETURN_HANGUP -1
00511 #define FEATURE_RETURN_SUCCESSBREAK 0
00512 #define FEATURE_RETURN_PBX_KEEPALIVE AST_PBX_KEEPALIVE
00513 #define FEATURE_RETURN_NO_HANGUP_PEER AST_PBX_NO_HANGUP_PEER
00514 #define FEATURE_RETURN_PASSDIGITS 21
00515 #define FEATURE_RETURN_STOREDIGITS 22
00516 #define FEATURE_RETURN_SUCCESS 23
00517 #define FEATURE_RETURN_KEEPTRYING 24
00518
00519 #define FEATURE_SENSE_CHAN (1 << 0)
00520 #define FEATURE_SENSE_PEER (1 << 1)
00521
00522
00523
00524
00525 static void set_peers(struct ast_channel **caller, struct ast_channel **callee,
00526 struct ast_channel *peer, struct ast_channel *chan, int sense)
00527 {
00528 if (sense == FEATURE_SENSE_PEER) {
00529 *caller = peer;
00530 *callee = chan;
00531 } else {
00532 *callee = peer;
00533 *caller = chan;
00534 }
00535 }
00536
00537
00538 static int builtin_parkcall(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00539 {
00540 struct ast_channel *parker;
00541 struct ast_channel *parkee;
00542 int res = 0;
00543 struct ast_module_user *u;
00544
00545 u = ast_module_user_add(chan);
00546
00547 set_peers(&parker, &parkee, peer, chan, sense);
00548
00549
00550 strcpy(chan->exten, "s");
00551 chan->priority = 1;
00552 if (chan->_state != AST_STATE_UP)
00553 res = ast_answer(chan);
00554 if (!res)
00555 res = ast_safe_sleep(chan, 1000);
00556 if (!res)
00557 res = ast_park_call(parkee, parker, 0, NULL);
00558
00559 ast_module_user_remove(u);
00560
00561 if (!res) {
00562 if (sense == FEATURE_SENSE_CHAN)
00563 res = AST_PBX_NO_HANGUP_PEER;
00564 else
00565 res = AST_PBX_KEEPALIVE;
00566 }
00567 return res;
00568
00569 }
00570
00571 static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00572 {
00573 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
00574 int x = 0;
00575 size_t len;
00576 struct ast_channel *caller_chan, *callee_chan;
00577
00578 if (!monitor_ok) {
00579 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00580 return -1;
00581 }
00582
00583 if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) {
00584 monitor_ok = 0;
00585 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00586 return -1;
00587 }
00588
00589 set_peers(&caller_chan, &callee_chan, peer, chan, sense);
00590
00591 if (!ast_strlen_zero(courtesytone)) {
00592 if (ast_autoservice_start(callee_chan))
00593 return -1;
00594 if (ast_stream_and_wait(caller_chan, courtesytone, caller_chan->language, "")) {
00595 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
00596 ast_autoservice_stop(callee_chan);
00597 return -1;
00598 }
00599 if (ast_autoservice_stop(callee_chan))
00600 return -1;
00601 }
00602
00603 if (callee_chan->monitor) {
00604 if (option_verbose > 3)
00605 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to stop recording call.\n", code);
00606 ast_monitor_stop(callee_chan, 1);
00607 return FEATURE_RETURN_SUCCESS;
00608 }
00609
00610 if (caller_chan && callee_chan) {
00611 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT");
00612 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
00613
00614 if (!touch_format)
00615 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
00616
00617 if (!touch_monitor)
00618 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
00619
00620 if (touch_monitor) {
00621 len = strlen(touch_monitor) + 50;
00622 args = alloca(len);
00623 touch_filename = alloca(len);
00624 snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor);
00625 snprintf(args, len, "%s|%s|m", (touch_format) ? touch_format : "wav", touch_filename);
00626 } else {
00627 caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name));
00628 callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name));
00629 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
00630 args = alloca(len);
00631 touch_filename = alloca(len);
00632 snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id);
00633 snprintf(args, len, "%s|%s|m", S_OR(touch_format, "wav"), touch_filename);
00634 }
00635
00636 for(x = 0; x < strlen(args); x++) {
00637 if (args[x] == '/')
00638 args[x] = '-';
00639 }
00640
00641 if (option_verbose > 3)
00642 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call. filename: %s\n", code, args);
00643
00644 pbx_exec(callee_chan, monitor_app, args);
00645 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
00646 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
00647
00648 return FEATURE_RETURN_SUCCESS;
00649 }
00650
00651 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");
00652 return -1;
00653 }
00654
00655 static int builtin_disconnect(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00656 {
00657 if (option_verbose > 3)
00658 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code);
00659 return FEATURE_RETURN_HANGUP;
00660 }
00661
00662 static int finishup(struct ast_channel *chan)
00663 {
00664 ast_indicate(chan, AST_CONTROL_UNHOLD);
00665
00666 return ast_autoservice_stop(chan);
00667 }
00668
00669
00670 static const char *real_ctx(struct ast_channel *transferer, struct ast_channel *transferee)
00671 {
00672 const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT");
00673 if (ast_strlen_zero(s))
00674 s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT");
00675 if (ast_strlen_zero(s))
00676 s = transferer->macrocontext;
00677 if (ast_strlen_zero(s))
00678 s = transferer->context;
00679 return s;
00680 }
00681
00682 static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00683 {
00684 struct ast_channel *transferer;
00685 struct ast_channel *transferee;
00686 const char *transferer_real_context;
00687 char xferto[256];
00688 int res;
00689
00690 set_peers(&transferer, &transferee, peer, chan, sense);
00691 transferer_real_context = real_ctx(transferer, transferee);
00692
00693 ast_autoservice_start(transferee);
00694 ast_indicate(transferee, AST_CONTROL_HOLD);
00695
00696 memset(xferto, 0, sizeof(xferto));
00697
00698
00699 res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY);
00700 if (res < 0) {
00701 finishup(transferee);
00702 return -1;
00703 }
00704 if (res > 0)
00705 xferto[0] = (char) res;
00706
00707 ast_stopstream(transferer);
00708 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
00709 if (res < 0) {
00710 finishup(transferee);
00711 return res;
00712 }
00713 if (!strcmp(xferto, ast_parking_ext())) {
00714 res = finishup(transferee);
00715 if (res)
00716 res = -1;
00717 else if (!ast_park_call(transferee, transferer, 0, NULL)) {
00718
00719
00720
00721
00722 return (transferer == peer) ? AST_PBX_KEEPALIVE : AST_PBX_NO_HANGUP_PEER;
00723 } else {
00724 ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name);
00725 }
00726
00727 } else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
00728 pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", transferee->name);
00729 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", peer->name);
00730 res=finishup(transferee);
00731 if (!transferer->cdr) {
00732 transferer->cdr=ast_cdr_alloc();
00733 if (transferer) {
00734 ast_cdr_init(transferer->cdr, transferer);
00735 ast_cdr_start(transferer->cdr);
00736 }
00737 }
00738 if (transferer->cdr) {
00739 ast_cdr_setdestchan(transferer->cdr, transferee->name);
00740 ast_cdr_setapp(transferer->cdr, "BLINDTRANSFER","");
00741 }
00742 if (!transferee->pbx) {
00743
00744 if (option_verbose > 2)
00745 ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n"
00746 ,transferee->name, xferto, transferer_real_context);
00747 if (ast_async_goto(transferee, transferer_real_context, xferto, 1))
00748 ast_log(LOG_WARNING, "Async goto failed :-(\n");
00749 res = -1;
00750 } else {
00751
00752 set_c_e_p(transferee, transferer_real_context, xferto, 0);
00753 }
00754 check_goto_on_transfer(transferer);
00755 return res;
00756 } else {
00757 if (option_verbose > 2)
00758 ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context);
00759 }
00760 if (ast_stream_and_wait(transferer, xferfailsound, transferer->language, AST_DIGIT_ANY) < 0) {
00761 finishup(transferee);
00762 return -1;
00763 }
00764 ast_stopstream(transferer);
00765 res = finishup(transferee);
00766 if (res) {
00767 if (option_verbose > 1)
00768 ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name);
00769 return res;
00770 }
00771 return FEATURE_RETURN_SUCCESS;
00772 }
00773
00774 static int check_compat(struct ast_channel *c, struct ast_channel *newchan)
00775 {
00776 if (ast_channel_make_compatible(c, newchan) < 0) {
00777 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n",
00778 c->name, newchan->name);
00779 ast_hangup(newchan);
00780 return -1;
00781 }
00782 return 0;
00783 }
00784
00785 static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00786 {
00787 struct ast_channel *transferer;
00788 struct ast_channel *transferee;
00789 const char *transferer_real_context;
00790 char xferto[256] = "";
00791 int res;
00792 int outstate=0;
00793 struct ast_channel *newchan;
00794 struct ast_channel *xferchan;
00795 struct ast_bridge_thread_obj *tobj;
00796 struct ast_bridge_config bconfig;
00797 struct ast_frame *f;
00798 int l;
00799
00800 if (option_debug)
00801 ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense);
00802 set_peers(&transferer, &transferee, peer, chan, sense);
00803 transferer_real_context = real_ctx(transferer, transferee);
00804
00805 ast_autoservice_start(transferee);
00806 ast_indicate(transferee, AST_CONTROL_HOLD);
00807
00808
00809 res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY);
00810 if (res < 0) {
00811 finishup(transferee);
00812 return res;
00813 }
00814 if (res > 0)
00815 xferto[0] = (char) res;
00816
00817
00818 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
00819 if (res < 0) {
00820 finishup(transferee);
00821 return res;
00822 }
00823 if (res == 0) {
00824 ast_log(LOG_WARNING, "Did not read data.\n");
00825 finishup(transferee);
00826 if (ast_stream_and_wait(transferer, "beeperr", transferer->language, ""))
00827 return -1;
00828 return FEATURE_RETURN_SUCCESS;
00829 }
00830
00831
00832 if (!ast_exists_extension(transferer, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
00833 ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context);
00834 finishup(transferee);
00835 if (ast_stream_and_wait(transferer, "beeperr", transferer->language, ""))
00836 return -1;
00837 return FEATURE_RETURN_SUCCESS;
00838 }
00839
00840 l = strlen(xferto);
00841 snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context);
00842 newchan = ast_feature_request_and_dial(transferer, "Local", ast_best_codec(transferer->nativeformats),
00843 xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, transferer->language);
00844 ast_indicate(transferer, -1);
00845 if (!newchan) {
00846 finishup(transferee);
00847
00848 if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY &&
00849 ast_stream_and_wait(transferer, xferfailsound, transferer->language, ""))
00850 return -1;
00851 return FEATURE_RETURN_SUCCESS;
00852 }
00853
00854 if (check_compat(transferer, newchan)) {
00855
00856 finishup(transferee);
00857 return -1;
00858 }
00859 memset(&bconfig,0,sizeof(struct ast_bridge_config));
00860 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
00861 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
00862 res = ast_bridge_call(transferer, newchan, &bconfig);
00863 if (newchan->_softhangup || !transferer->_softhangup) {
00864 ast_hangup(newchan);
00865 if (ast_stream_and_wait(transferer, xfersound, transferer->language, ""))
00866 ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
00867 finishup(transferee);
00868 transferer->_softhangup = 0;
00869 return FEATURE_RETURN_SUCCESS;
00870 }
00871
00872 if (check_compat(transferee, newchan)) {
00873 finishup(transferee);
00874 return -1;
00875 }
00876
00877 ast_indicate(transferee, AST_CONTROL_UNHOLD);
00878
00879 if ((ast_autoservice_stop(transferee) < 0)
00880 || (ast_waitfordigit(transferee, 100) < 0)
00881 || (ast_waitfordigit(newchan, 100) < 0)
00882 || ast_check_hangup(transferee)
00883 || ast_check_hangup(newchan)) {
00884 ast_hangup(newchan);
00885 return -1;
00886 }
00887
00888 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name);
00889 if (!xferchan) {
00890 ast_hangup(newchan);
00891 return -1;
00892 }
00893
00894 xferchan->visible_indication = transferer->visible_indication;
00895 xferchan->readformat = transferee->readformat;
00896 xferchan->writeformat = transferee->writeformat;
00897 ast_channel_masquerade(xferchan, transferee);
00898 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
00899 xferchan->_state = AST_STATE_UP;
00900 ast_clear_flag(xferchan, AST_FLAGS_ALL);
00901 xferchan->_softhangup = 0;
00902
00903 if ((f = ast_read(xferchan)))
00904 ast_frfree(f);
00905
00906 newchan->_state = AST_STATE_UP;
00907 ast_clear_flag(newchan, AST_FLAGS_ALL);
00908 newchan->_softhangup = 0;
00909
00910 tobj = ast_calloc(1, sizeof(struct ast_bridge_thread_obj));
00911 if (!tobj) {
00912 ast_hangup(xferchan);
00913 ast_hangup(newchan);
00914 return -1;
00915 }
00916 tobj->chan = newchan;
00917 tobj->peer = xferchan;
00918 tobj->bconfig = *config;
00919
00920 if (ast_stream_and_wait(newchan, xfersound, newchan->language, ""))
00921 ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
00922 ast_bridge_call_thread_launch(tobj);
00923 return -1;
00924 }
00925
00926
00927
00928 #define FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0]))
00929
00930 AST_RWLOCK_DEFINE_STATIC(features_lock);
00931
00932 static struct ast_call_feature builtin_features[] =
00933 {
00934 { AST_FEATURE_REDIRECT, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
00935 { AST_FEATURE_REDIRECT, "Attended Transfer", "atxfer", "", "", builtin_atxfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
00936 { AST_FEATURE_AUTOMON, "One Touch Monitor", "automon", "", "", builtin_automonitor, AST_FEATURE_FLAG_NEEDSDTMF, "" },
00937 { AST_FEATURE_DISCONNECT, "Disconnect Call", "disconnect", "*", "*", builtin_disconnect, AST_FEATURE_FLAG_NEEDSDTMF, "" },
00938 { AST_FEATURE_PARKCALL, "Park Call", "parkcall", "", "", builtin_parkcall, AST_FEATURE_FLAG_NEEDSDTMF, "" },
00939 };
00940
00941
00942 static AST_LIST_HEAD_STATIC(feature_list,ast_call_feature);
00943
00944
00945 void ast_register_feature(struct ast_call_feature *feature)
00946 {
00947 if (!feature) {
00948 ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
00949 return;
00950 }
00951
00952 AST_LIST_LOCK(&feature_list);
00953 AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry);
00954 AST_LIST_UNLOCK(&feature_list);
00955
00956 if (option_verbose >= 2)
00957 ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
00958 }
00959
00960
00961 void ast_unregister_feature(struct ast_call_feature *feature)
00962 {
00963 if (!feature)
00964 return;
00965
00966 AST_LIST_LOCK(&feature_list);
00967 AST_LIST_REMOVE(&feature_list,feature,feature_entry);
00968 AST_LIST_UNLOCK(&feature_list);
00969 free(feature);
00970 }
00971
00972
00973 static void ast_unregister_features(void)
00974 {
00975 struct ast_call_feature *feature;
00976
00977 AST_LIST_LOCK(&feature_list);
00978 while ((feature = AST_LIST_REMOVE_HEAD(&feature_list,feature_entry)))
00979 free(feature);
00980 AST_LIST_UNLOCK(&feature_list);
00981 }
00982
00983
00984 static struct ast_call_feature *find_dynamic_feature(const char *name)
00985 {
00986 struct ast_call_feature *tmp;
00987
00988 AST_LIST_TRAVERSE(&feature_list, tmp, feature_entry) {
00989 if (!strcasecmp(tmp->sname, name))
00990 break;
00991 }
00992
00993 return tmp;
00994 }
00995
00996
00997 static int feature_exec_app(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00998 {
00999 struct ast_app *app;
01000 struct ast_call_feature *feature = data;
01001 struct ast_channel *work, *idle;
01002 int res;
01003
01004 if (!feature) {
01005 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
01006 return -1;
01007 }
01008
01009 if (sense == FEATURE_SENSE_CHAN) {
01010 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
01011 return FEATURE_RETURN_KEEPTRYING;
01012 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
01013 work = chan;
01014 idle = peer;
01015 } else {
01016 work = peer;
01017 idle = chan;
01018 }
01019 } else {
01020 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
01021 return FEATURE_RETURN_KEEPTRYING;
01022 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
01023 work = peer;
01024 idle = chan;
01025 } else {
01026 work = chan;
01027 idle = peer;
01028 }
01029 }
01030
01031 if (!(app = pbx_findapp(feature->app))) {
01032 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
01033 return -2;
01034 }
01035
01036 ast_autoservice_start(idle);
01037
01038 if (!ast_strlen_zero(feature->moh_class))
01039 ast_moh_start(idle, feature->moh_class, NULL);
01040
01041 res = pbx_exec(work, app, feature->app_args);
01042
01043 if (!ast_strlen_zero(feature->moh_class))
01044 ast_moh_stop(idle);
01045
01046 ast_autoservice_stop(idle);
01047
01048 if (res == AST_PBX_KEEPALIVE)
01049 return FEATURE_RETURN_PBX_KEEPALIVE;
01050 else if (res == AST_PBX_NO_HANGUP_PEER)
01051 return FEATURE_RETURN_NO_HANGUP_PEER;
01052 else if (res)
01053 return FEATURE_RETURN_SUCCESSBREAK;
01054
01055 return FEATURE_RETURN_SUCCESS;
01056 }
01057
01058 static void unmap_features(void)
01059 {
01060 int x;
01061
01062 ast_rwlock_wrlock(&features_lock);
01063 for (x = 0; x < FEATURES_COUNT; x++)
01064 strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
01065 ast_rwlock_unlock(&features_lock);
01066 }
01067
01068 static int remap_feature(const char *name, const char *value)
01069 {
01070 int x, res = -1;
01071
01072 ast_rwlock_wrlock(&features_lock);
01073 for (x = 0; x < FEATURES_COUNT; x++) {
01074 if (strcasecmp(builtin_features[x].sname, name))
01075 continue;
01076
01077 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
01078 res = 0;
01079 break;
01080 }
01081 ast_rwlock_unlock(&features_lock);
01082
01083 return res;
01084 }
01085
01086 static int ast_feature_interpret(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
01087 {
01088 int x;
01089 struct ast_flags features;
01090 int res = FEATURE_RETURN_PASSDIGITS;
01091 struct ast_call_feature *feature;
01092 const char *dynamic_features;
01093 char *tmp, *tok;
01094
01095 if (sense == FEATURE_SENSE_CHAN) {
01096 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
01097 dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
01098 } else {
01099 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);
01100 dynamic_features = pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES");
01101 }
01102 if (option_debug > 2)
01103 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);
01104
01105 ast_rwlock_rdlock(&features_lock);
01106 for (x = 0; x < FEATURES_COUNT; x++) {
01107 if ((ast_test_flag(&features, builtin_features[x].feature_mask)) &&
01108 !ast_strlen_zero(builtin_features[x].exten)) {
01109
01110 if (!strcmp(builtin_features[x].exten, code)) {
01111 res = builtin_features[x].operation(chan, peer, config, code, sense, NULL);
01112 break;
01113 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
01114 if (res == FEATURE_RETURN_PASSDIGITS)
01115 res = FEATURE_RETURN_STOREDIGITS;
01116 }
01117 }
01118 }
01119 ast_rwlock_unlock(&features_lock);
01120
01121 if (ast_strlen_zero(dynamic_features))
01122 return res;
01123
01124 tmp = ast_strdupa(dynamic_features);
01125
01126 while ((tok = strsep(&tmp, "#"))) {
01127 AST_LIST_LOCK(&feature_list);
01128 if (!(feature = find_dynamic_feature(tok))) {
01129 AST_LIST_UNLOCK(&feature_list);
01130 continue;
01131 }
01132
01133
01134 if (!strcmp(feature->exten, code)) {
01135 if (option_verbose > 2)
01136 ast_verbose(VERBOSE_PREFIX_3 " Feature Found: %s exten: %s\n",feature->sname, tok);
01137 res = feature->operation(chan, peer, config, code, sense, feature);
01138 if (res != FEATURE_RETURN_KEEPTRYING) {
01139 AST_LIST_UNLOCK(&feature_list);
01140 break;
01141 }
01142 res = FEATURE_RETURN_PASSDIGITS;
01143 } else if (!strncmp(feature->exten, code, strlen(code)))
01144 res = FEATURE_RETURN_STOREDIGITS;
01145
01146 AST_LIST_UNLOCK(&feature_list);
01147 }
01148
01149 return res;
01150 }
01151
01152 static void set_config_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
01153 {
01154 int x;
01155
01156 ast_clear_flag(config, AST_FLAGS_ALL);
01157
01158 ast_rwlock_rdlock(&features_lock);
01159 for (x = 0; x < FEATURES_COUNT; x++) {
01160 if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF))
01161 continue;
01162
01163 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
01164 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01165
01166 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
01167 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01168 }
01169 ast_rwlock_unlock(&features_lock);
01170
01171 if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
01172 const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
01173
01174 if (dynamic_features) {
01175 char *tmp = ast_strdupa(dynamic_features);
01176 char *tok;
01177 struct ast_call_feature *feature;
01178
01179
01180 while ((tok = strsep(&tmp, "#"))) {
01181 AST_LIST_LOCK(&feature_list);
01182 if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
01183 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
01184 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01185 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
01186 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01187 }
01188 AST_LIST_UNLOCK(&feature_list);
01189 }
01190 }
01191 }
01192 }
01193
01194
01195 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)
01196 {
01197 int state = 0;
01198 int cause = 0;
01199 int to;
01200 struct ast_channel *chan;
01201 struct ast_channel *monitor_chans[2];
01202 struct ast_channel *active_channel;
01203 int res = 0, ready = 0;
01204
01205 if ((chan = ast_request(type, format, data, &cause))) {
01206 ast_set_callerid(chan, cid_num, cid_name, cid_num);
01207 ast_string_field_set(chan, language, language);
01208 ast_channel_inherit_variables(caller, chan);
01209 pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name);
01210 if (!chan->cdr) {
01211 chan->cdr=ast_cdr_alloc();
01212 if (chan->cdr) {
01213 ast_cdr_init(chan->cdr, chan);
01214 ast_cdr_start(chan->cdr);
01215 }
01216 }
01217
01218 if (!ast_call(chan, data, timeout)) {
01219 struct timeval started;
01220 int x, len = 0;
01221 char *disconnect_code = NULL, *dialed_code = NULL;
01222
01223 ast_indicate(caller, AST_CONTROL_RINGING);
01224
01225 ast_rwlock_rdlock(&features_lock);
01226 for (x = 0; x < FEATURES_COUNT; x++) {
01227 if (strcasecmp(builtin_features[x].sname, "disconnect"))
01228 continue;
01229
01230 disconnect_code = builtin_features[x].exten;
01231 len = strlen(disconnect_code) + 1;
01232 dialed_code = alloca(len);
01233 memset(dialed_code, 0, len);
01234 break;
01235 }
01236 ast_rwlock_unlock(&features_lock);
01237 x = 0;
01238 started = ast_tvnow();
01239 to = timeout;
01240 while (!ast_check_hangup(caller) && timeout && (chan->_state != AST_STATE_UP)) {
01241 struct ast_frame *f = NULL;
01242
01243 monitor_chans[0] = caller;
01244 monitor_chans[1] = chan;
01245 active_channel = ast_waitfor_n(monitor_chans, 2, &to);
01246
01247
01248 if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
01249 state = AST_CONTROL_UNHOLD;
01250 ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n");
01251 break;
01252 }
01253
01254 if (!active_channel)
01255 continue;
01256
01257 if (chan && (chan == active_channel)){
01258 f = ast_read(chan);
01259 if (f == NULL) {
01260 state = AST_CONTROL_HANGUP;
01261 res = 0;
01262 break;
01263 }
01264
01265 if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) {
01266 if (f->subclass == AST_CONTROL_RINGING) {
01267 state = f->subclass;
01268 if (option_verbose > 2)
01269 ast_verbose(VERBOSE_PREFIX_3 "%s is ringing\n", chan->name);
01270 ast_indicate(caller, AST_CONTROL_RINGING);
01271 } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) {
01272 state = f->subclass;
01273 if (option_verbose > 2)
01274 ast_verbose(VERBOSE_PREFIX_3 "%s is busy\n", chan->name);
01275 ast_indicate(caller, AST_CONTROL_BUSY);
01276 ast_frfree(f);
01277 f = NULL;
01278 break;
01279 } else if (f->subclass == AST_CONTROL_ANSWER) {
01280
01281 state = f->subclass;
01282 ast_frfree(f);
01283 f = NULL;
01284 ready=1;
01285 break;
01286 } else if (f->subclass != -1) {
01287 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass);
01288 }
01289
01290 }
01291
01292 } else if (caller && (active_channel == caller)) {
01293 f = ast_read(caller);
01294 if (f == NULL) {
01295 if (caller->_softhangup && !chan->_softhangup) {
01296
01297 ready = 1;
01298 break;
01299 }
01300 state = AST_CONTROL_HANGUP;
01301 res = 0;
01302 break;
01303 }
01304
01305 if (f->frametype == AST_FRAME_DTMF) {
01306 dialed_code[x++] = f->subclass;
01307 dialed_code[x] = '\0';
01308 if (strlen(dialed_code) == len) {
01309 x = 0;
01310 } else if (x && strncmp(dialed_code, disconnect_code, x)) {
01311 x = 0;
01312 dialed_code[x] = '\0';
01313 }
01314 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
01315
01316 state = AST_CONTROL_UNHOLD;
01317 ast_frfree(f);
01318 f = NULL;
01319 break;
01320 }
01321 }
01322 }
01323 if (f)
01324 ast_frfree(f);
01325 }
01326 } else
01327 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
01328 } else {
01329 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
01330 switch(cause) {
01331 case AST_CAUSE_BUSY:
01332 state = AST_CONTROL_BUSY;
01333 break;
01334 case AST_CAUSE_CONGESTION:
01335 state = AST_CONTROL_CONGESTION;
01336 break;
01337 }
01338 }
01339
01340 ast_indicate(caller, -1);
01341 if (chan && ready) {
01342 if (chan->_state == AST_STATE_UP)
01343 state = AST_CONTROL_ANSWER;
01344 res = 0;
01345 } else if(chan) {
01346 res = -1;
01347 ast_hangup(chan);
01348 chan = NULL;
01349 } else {
01350 res = -1;
01351 }
01352
01353 if (outstate)
01354 *outstate = state;
01355
01356 if (chan && res <= 0) {
01357 if (chan->cdr || (chan->cdr = ast_cdr_alloc())) {
01358 char tmp[256];
01359 ast_cdr_init(chan->cdr, chan);
01360 snprintf(tmp, 256, "%s/%s", type, (char *)data);
01361 ast_cdr_setapp(chan->cdr,"Dial",tmp);
01362 ast_cdr_update(chan);
01363 ast_cdr_start(chan->cdr);
01364 ast_cdr_end(chan->cdr);
01365
01366 if (ast_cdr_disposition(chan->cdr,chan->hangupcause))
01367 ast_cdr_failed(chan->cdr);
01368 } else {
01369 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
01370 }
01371 }
01372
01373 return chan;
01374 }
01375
01376 int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast_bridge_config *config)
01377 {
01378
01379
01380 struct ast_frame *f;
01381 struct ast_channel *who;
01382 char chan_featurecode[FEATURE_MAX_LEN + 1]="";
01383 char peer_featurecode[FEATURE_MAX_LEN + 1]="";
01384 int res;
01385 int diff;
01386 int hasfeatures=0;
01387 int hadfeatures=0;
01388 struct ast_option_header *aoh;
01389 struct ast_bridge_config backup_config;
01390 struct ast_cdr *bridge_cdr;
01391
01392 memset(&backup_config, 0, sizeof(backup_config));
01393
01394 config->start_time = ast_tvnow();
01395
01396 if (chan && peer) {
01397 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
01398 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
01399 } else if (chan)
01400 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
01401
01402 if (monitor_ok) {
01403 const char *monitor_exec;
01404 struct ast_channel *src = NULL;
01405 if (!monitor_app) {
01406 if (!(monitor_app = pbx_findapp("Monitor")))
01407 monitor_ok=0;
01408 }
01409 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR")))
01410 src = chan;
01411 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
01412 src = peer;
01413 if (monitor_app && src) {
01414 char *tmp = ast_strdupa(monitor_exec);
01415 pbx_exec(src, monitor_app, tmp);
01416 }
01417 }
01418
01419 set_config_flags(chan, peer, config);
01420 config->firstpass = 1;
01421
01422
01423 if (ast_answer(chan))
01424 return -1;
01425 peer->appl = "Bridged Call";
01426 peer->data = chan->name;
01427
01428
01429 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
01430 char tmp[256];
01431 if (!ast_strlen_zero(chan->cdr->userfield)) {
01432 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield);
01433 ast_cdr_appenduserfield(chan, tmp);
01434 } else
01435 ast_cdr_setuserfield(chan, peer->cdr->userfield);
01436
01437 free(peer->cdr);
01438 peer->cdr = NULL;
01439 }
01440
01441 for (;;) {
01442 struct ast_channel *other;
01443
01444 res = ast_channel_bridge(chan, peer, config, &f, &who);
01445
01446 if (config->feature_timer) {
01447
01448 diff = ast_tvdiff_ms(ast_tvnow(), config->start_time);
01449 config->feature_timer -= diff;
01450 if (hasfeatures) {
01451
01452
01453
01454 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
01455 if (option_debug)
01456 ast_log(LOG_DEBUG, "Timed out, realtime this time!\n");
01457 config->feature_timer = 0;
01458 who = chan;
01459 if (f)
01460 ast_frfree(f);
01461 f = NULL;
01462 res = 0;
01463 } else if (config->feature_timer <= 0) {
01464
01465
01466 if (option_debug)
01467 ast_log(LOG_DEBUG, "Timed out for feature!\n");
01468 if (!ast_strlen_zero(peer_featurecode)) {
01469 ast_dtmf_stream(chan, peer, peer_featurecode, 0);
01470 memset(peer_featurecode, 0, sizeof(peer_featurecode));
01471 }
01472 if (!ast_strlen_zero(chan_featurecode)) {
01473 ast_dtmf_stream(peer, chan, chan_featurecode, 0);
01474 memset(chan_featurecode, 0, sizeof(chan_featurecode));
01475 }
01476 if (f)
01477 ast_frfree(f);
01478 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01479 if (!hasfeatures) {
01480
01481 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01482 memset(&backup_config, 0, sizeof(backup_config));
01483 }
01484 hadfeatures = hasfeatures;
01485
01486 continue;
01487 } else if (!f) {
01488
01489
01490
01491 continue;
01492 }
01493 } else {
01494 if (config->feature_timer <=0) {
01495
01496 config->feature_timer = 0;
01497 who = chan;
01498 if (f)
01499 ast_frfree(f);
01500 f = NULL;
01501 res = 0;
01502 }
01503 }
01504 }
01505 if (res < 0) {
01506 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer))
01507 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
01508 return -1;
01509 }
01510
01511 if (!f || (f->frametype == AST_FRAME_CONTROL &&
01512 (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY ||
01513 f->subclass == AST_CONTROL_CONGESTION))) {
01514 res = -1;
01515 break;
01516 }
01517
01518 other = (who == chan) ? peer : chan;
01519 if (f->frametype == AST_FRAME_CONTROL) {
01520 switch (f->subclass) {
01521 case AST_CONTROL_RINGING:
01522 case AST_CONTROL_FLASH:
01523 case -1:
01524 ast_indicate(other, f->subclass);
01525 break;
01526 case AST_CONTROL_HOLD:
01527 case AST_CONTROL_UNHOLD:
01528 ast_indicate_data(other, f->subclass, f->data, f->datalen);
01529 break;
01530 case AST_CONTROL_OPTION:
01531 aoh = f->data;
01532
01533 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) {
01534 ast_channel_setoption(other, ntohs(aoh->option), aoh->data,
01535 f->datalen - sizeof(struct ast_option_header), 0);
01536 }
01537 break;
01538 }
01539 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
01540
01541 } else if (f->frametype == AST_FRAME_DTMF) {
01542 char *featurecode;
01543 int sense;
01544
01545 hadfeatures = hasfeatures;
01546
01547 if (who == chan) {
01548 sense = FEATURE_SENSE_CHAN;
01549 featurecode = chan_featurecode;
01550 } else {
01551 sense = FEATURE_SENSE_PEER;
01552 featurecode = peer_featurecode;
01553 }
01554
01555
01556
01557
01558 featurecode[strlen(featurecode)] = f->subclass;
01559
01560 ast_frfree(f);
01561 f = NULL;
01562 config->feature_timer = backup_config.feature_timer;
01563 res = ast_feature_interpret(chan, peer, config, featurecode, sense);
01564 switch(res) {
01565 case FEATURE_RETURN_PASSDIGITS:
01566 ast_dtmf_stream(other, who, featurecode, 0);
01567
01568 case FEATURE_RETURN_SUCCESS:
01569 memset(featurecode, 0, sizeof(chan_featurecode));
01570 break;
01571 }
01572 if (res >= FEATURE_RETURN_PASSDIGITS) {
01573 res = 0;
01574 } else
01575 break;
01576 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01577 if (hadfeatures && !hasfeatures) {
01578
01579 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01580 memset(&backup_config, 0, sizeof(struct ast_bridge_config));
01581 } else if (hasfeatures) {
01582 if (!hadfeatures) {
01583
01584 memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
01585
01586 config->play_warning = 0;
01587 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
01588 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
01589 config->warning_freq = 0;
01590 config->warning_sound = NULL;
01591 config->end_sound = NULL;
01592 config->start_sound = NULL;
01593 config->firstpass = 0;
01594 }
01595 config->start_time = ast_tvnow();
01596 config->feature_timer = featuredigittimeout;
01597 if (option_debug)
01598 ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer);
01599 }
01600 }
01601 if (f)
01602 ast_frfree(f);
01603
01604 }
01605
01606
01607 bridge_cdr = ast_cdr_alloc();
01608 if (bridge_cdr) {
01609 if (chan->cdr && peer->cdr) {
01610 ast_cdr_init(bridge_cdr,chan);
01611 ast_cdr_start(bridge_cdr);
01612
01613
01614 ast_cdr_merge(bridge_cdr, chan->cdr);
01615 if (!ast_test_flag(chan->cdr, AST_CDR_FLAG_LOCKED))
01616 ast_cdr_discard(chan->cdr);
01617
01618
01619 ast_cdr_merge(bridge_cdr, peer->cdr);
01620 if (!ast_test_flag(peer->cdr, AST_CDR_FLAG_LOCKED))
01621 ast_cdr_discard(peer->cdr);
01622
01623 peer->cdr = NULL;
01624 chan->cdr = bridge_cdr;
01625 } else if (chan->cdr) {
01626
01627 ast_cdr_init(bridge_cdr,chan);
01628
01629 ast_cdr_merge(bridge_cdr, chan->cdr);
01630 if (!ast_test_flag(chan->cdr, AST_CDR_FLAG_LOCKED))
01631 ast_cdr_discard(chan->cdr);
01632 chan->cdr = bridge_cdr;
01633 } else if (peer->cdr) {
01634
01635 ast_cdr_init(bridge_cdr,peer);
01636
01637 ast_cdr_merge(bridge_cdr, peer->cdr);
01638 if (!ast_test_flag(peer->cdr, AST_CDR_FLAG_LOCKED))
01639 ast_cdr_discard(peer->cdr);
01640 peer->cdr = NULL;
01641 peer->cdr = bridge_cdr;
01642 } else {
01643
01644 ast_cdr_init(bridge_cdr,chan);
01645 chan->cdr = bridge_cdr;
01646 }
01647 if (ast_strlen_zero(bridge_cdr->dstchannel)) {
01648 if (strcmp(bridge_cdr->channel, peer->name) != 0)
01649 ast_cdr_setdestchan(bridge_cdr, peer->name);
01650 else
01651 ast_cdr_setdestchan(bridge_cdr, chan->name);
01652 }
01653 }
01654 return res;
01655 }
01656
01657 static void post_manager_event(const char *s, char *parkingexten, struct ast_channel *chan)
01658 {
01659 manager_event(EVENT_FLAG_CALL, s,
01660 "Exten: %s\r\n"
01661 "Channel: %s\r\n"
01662 "CallerID: %s\r\n"
01663 "CallerIDName: %s\r\n\r\n",
01664 parkingexten,
01665 chan->name,
01666 S_OR(chan->cid.cid_num, "<unknown>"),
01667 S_OR(chan->cid.cid_name, "<unknown>")
01668 );
01669 }
01670
01671
01672 static void *do_parking_thread(void *ignore)
01673 {
01674 fd_set rfds, efds;
01675 FD_ZERO(&rfds);
01676 FD_ZERO(&efds);
01677
01678 for (;;) {
01679 struct parkeduser *pu, *pl, *pt = NULL;
01680 int ms = -1;
01681 int max = -1;
01682 fd_set nrfds, nefds;
01683 FD_ZERO(&nrfds);
01684 FD_ZERO(&nefds);
01685
01686 ast_mutex_lock(&parking_lock);
01687 pl = NULL;
01688 pu = parkinglot;
01689
01690 while (pu) {
01691 struct ast_channel *chan = pu->chan;
01692 int tms;
01693 int x;
01694 struct ast_context *con;
01695
01696 if (pu->notquiteyet) {
01697 pl = pu;
01698 pu = pu->next;
01699 continue;
01700 }
01701 tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
01702 if (tms > pu->parkingtime) {
01703 ast_indicate(chan, AST_CONTROL_UNHOLD);
01704
01705 if (pu->peername[0]) {
01706 char *peername = ast_strdupa(pu->peername);
01707 char *cp = strrchr(peername, '-');
01708 if (cp)
01709 *cp = 0;
01710 con = ast_context_find(parking_con_dial);
01711 if (!con) {
01712 con = ast_context_create(NULL, parking_con_dial, registrar);
01713 if (!con)
01714 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
01715 }
01716 if (con) {
01717 char returnexten[AST_MAX_EXTENSION];
01718 snprintf(returnexten, sizeof(returnexten), "%s||t", peername);
01719 ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), ast_free, registrar);
01720 }
01721 set_c_e_p(chan, parking_con_dial, peername, 1);
01722 } else {
01723
01724
01725 set_c_e_p(chan, pu->context, pu->exten, pu->priority);
01726 }
01727
01728 post_manager_event("ParkedCallTimeOut", pu->parkingexten, chan);
01729
01730 if (option_verbose > 1)
01731 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);
01732
01733 if (ast_pbx_start(chan)) {
01734 ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", chan->name);
01735 ast_hangup(chan);
01736 }
01737
01738 if (pl)
01739 pl->next = pu->next;
01740 else
01741 parkinglot = pu->next;
01742 pt = pu;
01743 pu = pu->next;
01744 con = ast_context_find(parking_con);
01745 if (con) {
01746 if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL))
01747 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01748 else
01749 notify_metermaids(pt->parkingexten, parking_con);
01750 } else
01751 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01752 free(pt);
01753 } else {
01754 for (x = 0; x < AST_MAX_FDS; x++) {
01755 struct ast_frame *f;
01756
01757 if (chan->fds[x] == -1 || (!FD_ISSET(chan->fds[x], &rfds) && !FD_ISSET(chan->fds[x], &efds)))
01758 continue;
01759
01760 if (FD_ISSET(chan->fds[x], &efds))
01761 ast_set_flag(chan, AST_FLAG_EXCEPTION);
01762 else
01763 ast_clear_flag(chan, AST_FLAG_EXCEPTION);
01764 chan->fdno = x;
01765
01766
01767 f = ast_read(chan);
01768 if (!f || (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_HANGUP)) {
01769 if (f)
01770 ast_frfree(f);
01771 post_manager_event("ParkedCallGiveUp", pu->parkingexten, chan);
01772
01773
01774 if (option_verbose > 1)
01775 ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", chan->name);
01776 ast_hangup(chan);
01777
01778 if (pl)
01779 pl->next = pu->next;
01780 else
01781 parkinglot = pu->next;
01782 pt = pu;
01783 pu = pu->next;
01784 con = ast_context_find(parking_con);
01785 if (con) {
01786 if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL))
01787 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01788 else
01789 notify_metermaids(pt->parkingexten, parking_con);
01790 } else
01791 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01792 free(pt);
01793 break;
01794 } else {
01795
01796 ast_frfree(f);
01797 if (pu->moh_trys < 3 && !chan->generatordata) {
01798 if (option_debug)
01799 ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source. Restarting.\n");
01800 ast_indicate_data(pu->chan, AST_CONTROL_HOLD,
01801 S_OR(parkmohclass, NULL),
01802 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
01803 pu->moh_trys++;
01804 }
01805 goto std;
01806 }
01807
01808 }
01809 if (x >= AST_MAX_FDS) {
01810 std: for (x=0; x<AST_MAX_FDS; x++) {
01811 if (chan->fds[x] > -1) {
01812 FD_SET(chan->fds[x], &nrfds);
01813 FD_SET(chan->fds[x], &nefds);
01814 if (chan->fds[x] > max)
01815 max = chan->fds[x];
01816 }
01817 }
01818
01819 if (tms < ms || ms < 0)
01820 ms = tms;
01821 pl = pu;
01822 pu = pu->next;
01823 }
01824 }
01825 }
01826 ast_mutex_unlock(&parking_lock);
01827 rfds = nrfds;
01828 efds = nefds;
01829 {
01830 struct timeval tv = ast_samp2tv(ms, 1000);
01831
01832 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
01833 }
01834 pthread_testcancel();
01835 }
01836 return NULL;
01837 }
01838
01839
01840 static int park_call_exec(struct ast_channel *chan, void *data)
01841 {
01842
01843
01844
01845 char *orig_chan_name = ast_strdupa(chan->name);
01846 char orig_exten[AST_MAX_EXTENSION];
01847 int orig_priority = chan->priority;
01848
01849
01850
01851 int res = 0;
01852 struct ast_module_user *u;
01853
01854 u = ast_module_user_add(chan);
01855
01856 ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten));
01857
01858
01859
01860 strcpy(chan->exten, "s");
01861 chan->priority = 1;
01862
01863 if (chan->_state != AST_STATE_UP)
01864 res = ast_answer(chan);
01865
01866 if (!res)
01867 res = ast_safe_sleep(chan, 1000);
01868
01869 if (!res) {
01870 res = park_call_full(chan, chan, 0, NULL, orig_chan_name);
01871
01872 if (res == 1) {
01873 ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten));
01874 chan->priority = orig_priority;
01875 res = 0;
01876 } else if (!res)
01877 res = AST_PBX_KEEPALIVE;
01878 }
01879
01880 ast_module_user_remove(u);
01881
01882 return res;
01883 }
01884
01885
01886 static int park_exec(struct ast_channel *chan, void *data)
01887 {
01888 int res = 0;
01889 struct ast_module_user *u;
01890 struct ast_channel *peer=NULL;
01891 struct parkeduser *pu, *pl=NULL;
01892 struct ast_context *con;
01893
01894 int park;
01895 struct ast_bridge_config config;
01896
01897 if (!data) {
01898 ast_log(LOG_WARNING, "Parkedcall requires an argument (extension number)\n");
01899 return -1;
01900 }
01901
01902 u = ast_module_user_add(chan);
01903
01904 park = atoi((char *)data);
01905 ast_mutex_lock(&parking_lock);
01906 pu = parkinglot;
01907 while(pu) {
01908 if (pu->parkingnum == park) {
01909 if (pl)
01910 pl->next = pu->next;
01911 else
01912 parkinglot = pu->next;
01913 break;
01914 }
01915 pl = pu;
01916 pu = pu->next;
01917 }
01918 ast_mutex_unlock(&parking_lock);
01919 if (pu) {
01920 peer = pu->chan;
01921 con = ast_context_find(parking_con);
01922 if (con) {
01923 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL))
01924 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01925 else
01926 notify_metermaids(pu->parkingexten, parking_con);
01927 } else
01928 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01929
01930 manager_event(EVENT_FLAG_CALL, "UnParkedCall",
01931 "Exten: %s\r\n"
01932 "Channel: %s\r\n"
01933 "From: %s\r\n"
01934 "CallerID: %s\r\n"
01935 "CallerIDName: %s\r\n",
01936 pu->parkingexten, pu->chan->name, chan->name,
01937 S_OR(pu->chan->cid.cid_num, "<unknown>"),
01938 S_OR(pu->chan->cid.cid_name, "<unknown>")
01939 );
01940
01941 free(pu);
01942 }
01943
01944 if (chan->_state != AST_STATE_UP)
01945 ast_answer(chan);
01946
01947 if (peer) {
01948
01949
01950 if (!ast_strlen_zero(courtesytone)) {
01951 int error = 0;
01952 ast_indicate(peer, AST_CONTROL_UNHOLD);
01953 if (parkedplay == 0) {
01954 error = ast_stream_and_wait(chan, courtesytone, chan->language, "");
01955 } else if (parkedplay == 1) {
01956 error = ast_stream_and_wait(peer, courtesytone, chan->language, "");
01957 } else if (parkedplay == 2) {
01958 if (!ast_streamfile(chan, courtesytone, chan->language) &&
01959 !ast_streamfile(peer, courtesytone, chan->language)) {
01960
01961 res = ast_waitstream(chan, "");
01962 if (res >= 0)
01963 res = ast_waitstream(peer, "");
01964 if (res < 0)
01965 error = 1;
01966 }
01967 }
01968 if (error) {
01969 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
01970 ast_hangup(peer);
01971 ast_module_user_remove(u);
01972 return -1;
01973 }
01974 } else
01975 ast_indicate(peer, AST_CONTROL_UNHOLD);
01976
01977 res = ast_channel_make_compatible(chan, peer);
01978 if (res < 0) {
01979 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
01980 ast_hangup(peer);
01981 ast_module_user_remove(u);
01982 return -1;
01983 }
01984
01985
01986 if (option_verbose > 2)
01987 ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
01988
01989 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
01990 ast_cdr_setdestchan(chan->cdr, peer->name);
01991 memset(&config, 0, sizeof(struct ast_bridge_config));
01992 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
01993 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
01994 res = ast_bridge_call(chan, peer, &config);
01995
01996 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
01997 ast_cdr_setdestchan(chan->cdr, peer->name);
01998
01999
02000 if (res != AST_PBX_NO_HANGUP_PEER)
02001 ast_hangup(peer);
02002 ast_module_user_remove(u);
02003 return res;
02004 } else {
02005
02006 if (ast_stream_and_wait(chan, "pbx-invalidpark", chan->language, ""))
02007 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
02008 if (option_verbose > 2)
02009 ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
02010 res = -1;
02011 }
02012
02013 ast_module_user_remove(u);
02014
02015 return res;
02016 }
02017
02018 static int handle_showfeatures(int fd, int argc, char *argv[])
02019 {
02020 int i;
02021 struct ast_call_feature *feature;
02022 char format[] = "%-25s %-7s %-7s\n";
02023
02024 ast_cli(fd, format, "Builtin Feature", "Default", "Current");
02025 ast_cli(fd, format, "---------------", "-------", "-------");
02026
02027 ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext());
02028
02029 ast_rwlock_rdlock(&features_lock);
02030 for (i = 0; i < FEATURES_COUNT; i++)
02031 ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
02032 ast_rwlock_unlock(&features_lock);
02033
02034 ast_cli(fd, "\n");
02035 ast_cli(fd, format, "Dynamic Feature", "Default", "Current");
02036 ast_cli(fd, format, "---------------", "-------", "-------");
02037 if (AST_LIST_EMPTY(&feature_list))
02038 ast_cli(fd, "(none)\n");
02039 else {
02040 AST_LIST_LOCK(&feature_list);
02041 AST_LIST_TRAVERSE(&feature_list, feature, feature_entry)
02042 ast_cli(fd, format, feature->sname, "no def", feature->exten);
02043 AST_LIST_UNLOCK(&feature_list);
02044 }
02045 ast_cli(fd, "\nCall parking\n");
02046 ast_cli(fd, "------------\n");
02047 ast_cli(fd,"%-20s: %s\n", "Parking extension", parking_ext);
02048 ast_cli(fd,"%-20s: %s\n", "Parking context", parking_con);
02049 ast_cli(fd,"%-20s: %d-%d\n", "Parked call extensions", parking_start, parking_stop);
02050 ast_cli(fd,"\n");
02051
02052 return RESULT_SUCCESS;
02053 }
02054
02055 static char mandescr_bridge[] =
02056 "Description: Bridge together two channels already in the PBX\n"
02057 "Variables: ( Headers marked with * are required )\n"
02058 " *Channel1: Channel to Bridge to Channel2\n"
02059 " *Channel2: Channel to Bridge to Channel1\n"
02060 " Tone: (Yes|No) Play courtesy tone to Channel 2\n"
02061 "\n";
02062
02063 static void do_bridge_masquerade(struct ast_channel *chan, struct ast_channel *tmpchan)
02064 {
02065 ast_moh_stop(chan);
02066 ast_mutex_lock(&chan->lock);
02067 ast_setstate(tmpchan, chan->_state);
02068 tmpchan->readformat = chan->readformat;
02069 tmpchan->writeformat = chan->writeformat;
02070 ast_channel_masquerade(tmpchan, chan);
02071 ast_mutex_lock(&tmpchan->lock);
02072 ast_do_masquerade(tmpchan);
02073
02074 ast_explicit_goto(tmpchan, chan->context, chan->exten, chan->priority + 1);
02075 ast_mutex_unlock(&tmpchan->lock);
02076 ast_mutex_unlock(&chan->lock);
02077 }
02078
02079 static int action_bridge(struct mansession *s, const struct message *m)
02080 {
02081 const char *channela = astman_get_header(m, "Channel1");
02082 const char *channelb = astman_get_header(m, "Channel2");
02083 const char *playtone = astman_get_header(m, "Tone");
02084 struct ast_channel *chana = NULL, *chanb = NULL;
02085 struct ast_channel *tmpchana = NULL, *tmpchanb = NULL;
02086 struct ast_bridge_thread_obj *tobj = NULL;
02087
02088
02089 if (!ast_strlen_zero(channela) && !ast_strlen_zero(channelb)) {
02090 chana = ast_get_channel_by_name_prefix_locked(channela, strlen(channela));
02091 chanb = ast_get_channel_by_name_prefix_locked(channelb, strlen(channelb));
02092 if (chana)
02093 ast_mutex_unlock(&chana->lock);
02094 if (chanb)
02095 ast_mutex_unlock(&chanb->lock);
02096
02097
02098 if (!chana) {
02099 char buf[256];
02100 snprintf(buf, sizeof(buf), "Channel1 does not exists: %s", channela);
02101 astman_send_error(s, m, buf);
02102 return 0;
02103 }
02104 if (!chanb) {
02105 char buf[256];
02106 snprintf(buf, sizeof(buf), "Channel2 does not exists: %s", channelb);
02107 astman_send_error(s, m, buf);
02108 return 0;
02109 }
02110 } else {
02111 astman_send_error(s, m, "Missing channel parameter in request");
02112 return 0;
02113 }
02114
02115
02116 if (chana->_state != AST_STATE_UP)
02117 ast_answer(chana);
02118 if (chanb->_state != AST_STATE_UP)
02119 ast_answer(chanb);
02120
02121
02122 if (!(tmpchana = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
02123 NULL, NULL, 0, "Bridge/%s", chana->name))) {
02124 astman_send_error(s, m, "Unable to create temporary channel!");
02125 return 1;
02126 }
02127
02128 if (!(tmpchanb = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
02129 NULL, NULL, 0, "Bridge/%s", chanb->name))) {
02130 astman_send_error(s, m, "Unable to create temporary channels!");
02131 ast_channel_free(tmpchana);
02132 return 1;
02133 }
02134
02135 do_bridge_masquerade(chana, tmpchana);
02136 do_bridge_masquerade(chanb, tmpchanb);
02137
02138
02139 if (ast_channel_make_compatible(tmpchana, tmpchanb)) {
02140 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for manager bridge\n", tmpchana->name, tmpchanb->name);
02141 astman_send_error(s, m, "Could not make channels compatible for manager bridge");
02142 ast_hangup(tmpchana);
02143 ast_hangup(tmpchanb);
02144 return 1;
02145 }
02146
02147
02148 if (!(tobj = ast_calloc(1, sizeof(*tobj)))) {
02149 ast_log(LOG_WARNING, "Unable to spawn a new bridge thread on %s and %s: %s\n", tmpchana->name, tmpchanb->name, strerror(errno));
02150 astman_send_error(s, m, "Unable to spawn a new bridge thread");
02151 ast_hangup(tmpchana);
02152 ast_hangup(tmpchanb);
02153 return 1;
02154 }
02155
02156 tobj->chan = tmpchana;
02157 tobj->peer = tmpchanb;
02158 tobj->return_to_pbx = 1;
02159
02160 if (ast_true(playtone)) {
02161 if (!ast_strlen_zero(xfersound) && !ast_streamfile(tmpchanb, xfersound, tmpchanb->language)) {
02162 if (ast_waitstream(tmpchanb, "") < 0)
02163 ast_log(LOG_WARNING, "Failed to play a courtesy tone on chan %s\n", tmpchanb->name);
02164 }
02165 }
02166
02167 ast_bridge_call_thread_launch(tobj);
02168
02169 astman_send_ack(s, m, "Launched bridge thread with success");
02170
02171 return 0;
02172 }
02173
02174 static char showfeatures_help[] =
02175 "Usage: feature list\n"
02176 " Lists currently configured features.\n";
02177
02178 static int handle_parkedcalls(int fd, int argc, char *argv[])
02179 {
02180 struct parkeduser *cur;
02181 int numparked = 0;
02182
02183 ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
02184 , "Context", "Extension", "Pri", "Timeout");
02185
02186 ast_mutex_lock(&parking_lock);
02187
02188 for (cur = parkinglot; cur; cur = cur->next) {
02189 ast_cli(fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n"
02190 ,cur->parkingexten, cur->chan->name, cur->context, cur->exten
02191 ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
02192
02193 numparked++;
02194 }
02195 ast_mutex_unlock(&parking_lock);
02196 ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : "");
02197
02198
02199 return RESULT_SUCCESS;
02200 }
02201
02202 static char showparked_help[] =
02203 "Usage: show parkedcalls\n"
02204 " Lists currently parked calls.\n";
02205
02206 static struct ast_cli_entry cli_show_features_deprecated = {
02207 { "show", "features", NULL },
02208 handle_showfeatures, NULL,
02209 NULL };
02210
02211 static struct ast_cli_entry cli_features[] = {
02212 { { "feature", "show", NULL },
02213 handle_showfeatures, "Lists configured features",
02214 showfeatures_help, NULL, &cli_show_features_deprecated },
02215
02216 { { "show", "parkedcalls", NULL },
02217 handle_parkedcalls, "Lists parked calls",
02218 showparked_help },
02219 };
02220
02221
02222 static int manager_parking_status(struct mansession *s, const struct message *m)
02223 {
02224 struct parkeduser *cur;
02225 const char *id = astman_get_header(m, "ActionID");
02226 char idText[256] = "";
02227
02228 if (!ast_strlen_zero(id))
02229 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
02230
02231 astman_send_ack(s, m, "Parked calls will follow");
02232
02233 ast_mutex_lock(&parking_lock);
02234
02235 for (cur = parkinglot; cur; cur = cur->next) {
02236 astman_append(s, "Event: ParkedCall\r\n"
02237 "Exten: %d\r\n"
02238 "Channel: %s\r\n"
02239 "From: %s\r\n"
02240 "Timeout: %ld\r\n"
02241 "CallerID: %s\r\n"
02242 "CallerIDName: %s\r\n"
02243 "%s"
02244 "\r\n",
02245 cur->parkingnum, cur->chan->name, cur->peername,
02246 (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
02247 S_OR(cur->chan->cid.cid_num, ""),
02248 S_OR(cur->chan->cid.cid_name, ""),
02249 idText);
02250 }
02251
02252 astman_append(s,
02253 "Event: ParkedCallsComplete\r\n"
02254 "%s"
02255 "\r\n",idText);
02256
02257 ast_mutex_unlock(&parking_lock);
02258
02259 return RESULT_SUCCESS;
02260 }
02261
02262 static char mandescr_park[] =
02263 "Description: Park a channel.\n"
02264 "Variables: (Names marked with * are required)\n"
02265 " *Channel: Channel name to park\n"
02266 " *Channel2: Channel to announce park info to (and return to if timeout)\n"
02267 " Timeout: Number of milliseconds to wait before callback.\n";
02268
02269 static int manager_park(struct mansession *s, const struct message *m)
02270 {
02271 const char *channel = astman_get_header(m, "Channel");
02272 const char *channel2 = astman_get_header(m, "Channel2");
02273 const char *timeout = astman_get_header(m, "Timeout");
02274 char buf[BUFSIZ];
02275 int to = 0;
02276 int res = 0;
02277 int parkExt = 0;
02278 struct ast_channel *ch1, *ch2;
02279
02280 if (ast_strlen_zero(channel)) {
02281 astman_send_error(s, m, "Channel not specified");
02282 return 0;
02283 }
02284
02285 if (ast_strlen_zero(channel2)) {
02286 astman_send_error(s, m, "Channel2 not specified");
02287 return 0;
02288 }
02289
02290 ch1 = ast_get_channel_by_name_locked(channel);
02291 if (!ch1) {
02292 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
02293 astman_send_error(s, m, buf);
02294 return 0;
02295 }
02296
02297 ch2 = ast_get_channel_by_name_locked(channel2);
02298 if (!ch2) {
02299 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
02300 astman_send_error(s, m, buf);
02301 ast_channel_unlock(ch1);
02302 return 0;
02303 }
02304
02305 if (!ast_strlen_zero(timeout)) {
02306 sscanf(timeout, "%d", &to);
02307 }
02308
02309 res = ast_masq_park_call(ch1, ch2, to, &parkExt);
02310 if (!res) {
02311 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
02312 astman_send_ack(s, m, "Park successful");
02313 } else {
02314 astman_send_error(s, m, "Park failure");
02315 }
02316
02317 ast_channel_unlock(ch1);
02318 ast_channel_unlock(ch2);
02319
02320 return 0;
02321 }
02322
02323
02324 int ast_pickup_call(struct ast_channel *chan)
02325 {
02326 struct ast_channel *cur = NULL;
02327 int res = -1;
02328
02329 while ((cur = ast_channel_walk_locked(cur)) != NULL) {
02330 if (!cur->pbx &&
02331 (cur != chan) &&
02332 (chan->pickupgroup & cur->callgroup) &&
02333 ((cur->_state == AST_STATE_RINGING) ||
02334 (cur->_state == AST_STATE_RING))) {
02335 break;
02336 }
02337 ast_channel_unlock(cur);
02338 }
02339 if (cur) {
02340 if (option_debug)
02341 ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
02342 res = ast_answer(chan);
02343 if (res)
02344 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
02345 res = ast_queue_control(chan, AST_CONTROL_ANSWER);
02346 if (res)
02347 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
02348 res = ast_channel_masquerade(cur, chan);
02349 if (res)
02350 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);
02351 ast_channel_unlock(cur);
02352 } else {
02353 if (option_debug)
02354 ast_log(LOG_DEBUG, "No call pickup possible...\n");
02355 }
02356 return res;
02357 }
02358
02359
02360 static void park_add_hints(char *context, int start, int stop)
02361 {
02362 int numext;
02363 char device[AST_MAX_EXTENSION];
02364 char exten[10];
02365
02366 for (numext = start; numext <= stop; numext++) {
02367 snprintf(exten, sizeof(exten), "%d", numext);
02368 snprintf(device, sizeof(device), "park:%s@%s", exten, context);
02369 ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
02370 }
02371 }
02372
02373
02374 static int load_config(void)
02375 {
02376 int start = 0, end = 0;
02377 int res;
02378 struct ast_context *con = NULL;
02379 struct ast_config *cfg = NULL;
02380 struct ast_variable *var = NULL;
02381 char old_parking_ext[AST_MAX_EXTENSION];
02382 char old_parking_con[AST_MAX_EXTENSION] = "";
02383
02384 if (!ast_strlen_zero(parking_con)) {
02385 strcpy(old_parking_ext, parking_ext);
02386 strcpy(old_parking_con, parking_con);
02387 }
02388
02389
02390 strcpy(parking_con, "parkedcalls");
02391 strcpy(parking_con_dial, "park-dial");
02392 strcpy(parking_ext, "700");
02393 strcpy(pickup_ext, "*8");
02394 strcpy(parkmohclass, "default");
02395 courtesytone[0] = '\0';
02396 strcpy(xfersound, "beep");
02397 strcpy(xferfailsound, "pbx-invalid");
02398 parking_start = 701;
02399 parking_stop = 750;
02400 parkfindnext = 0;
02401 adsipark = 0;
02402 parkaddhints = 0;
02403
02404 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
02405 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
02406 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
02407
02408 cfg = ast_config_load("features.conf");
02409 if (!cfg) {
02410 ast_log(LOG_WARNING,"Could not load features.conf\n");
02411 return AST_MODULE_LOAD_DECLINE;
02412 }
02413 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
02414 if (!strcasecmp(var->name, "parkext")) {
02415 ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
02416 } else if (!strcasecmp(var->name, "context")) {
02417 ast_copy_string(parking_con, var->value, sizeof(parking_con));
02418 } else if (!strcasecmp(var->name, "parkingtime")) {
02419 if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) {
02420 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
02421 parkingtime = DEFAULT_PARK_TIME;
02422 } else
02423 parkingtime = parkingtime * 1000;
02424 } else if (!strcasecmp(var->name, "parkpos")) {
02425 if (sscanf(var->value, "%d-%d", &start, &end) != 2) {
02426 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);
02427 } else {
02428 parking_start = start;
02429 parking_stop = end;
02430 }
02431 } else if (!strcasecmp(var->name, "findslot")) {
02432 parkfindnext = (!strcasecmp(var->value, "next"));
02433 } else if (!strcasecmp(var->name, "parkinghints")) {
02434 parkaddhints = ast_true(var->value);
02435 } else if (!strcasecmp(var->name, "adsipark")) {
02436 adsipark = ast_true(var->value);
02437 } else if (!strcasecmp(var->name, "transferdigittimeout")) {
02438 if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
02439 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
02440 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
02441 } else
02442 transferdigittimeout = transferdigittimeout * 1000;
02443 } else if (!strcasecmp(var->name, "featuredigittimeout")) {
02444 if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
02445 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
02446 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
02447 }
02448 } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) {
02449 if ((sscanf(var->value, "%d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) {
02450 ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value);
02451 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
02452 } else
02453 atxfernoanswertimeout = atxfernoanswertimeout * 1000;
02454 } else if (!strcasecmp(var->name, "courtesytone")) {
02455 ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
02456 } else if (!strcasecmp(var->name, "parkedplay")) {
02457 if (!strcasecmp(var->value, "both"))
02458 parkedplay = 2;
02459 else if (!strcasecmp(var->value, "parked"))
02460 parkedplay = 1;
02461 else
02462 parkedplay = 0;
02463 } else if (!strcasecmp(var->name, "xfersound")) {
02464 ast_copy_string(xfersound, var->value, sizeof(xfersound));
02465 } else if (!strcasecmp(var->name, "xferfailsound")) {
02466 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
02467 } else if (!strcasecmp(var->name, "pickupexten")) {
02468 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
02469 } else if (!strcasecmp(var->name, "parkedmusicclass")) {
02470 ast_copy_string(parkmohclass, var->value, sizeof(parkmohclass));
02471 }
02472 }
02473
02474 unmap_features();
02475 for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) {
02476 if (remap_feature(var->name, var->value))
02477 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
02478 }
02479
02480
02481 ast_unregister_features();
02482 for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) {
02483 char *tmp_val = ast_strdupa(var->value);
02484 char *exten, *activateon, *activatedby, *app, *app_args, *moh_class;
02485 struct ast_call_feature *feature;
02486
02487
02488
02489
02490
02491 exten = strsep(&tmp_val,",");
02492 activatedby = strsep(&tmp_val,",");
02493 app = strsep(&tmp_val,",");
02494 app_args = strsep(&tmp_val,",");
02495 moh_class = strsep(&tmp_val,",");
02496
02497 activateon = strsep(&activatedby, "/");
02498
02499
02500 if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) {
02501 ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",
02502 app, exten, activateon, var->name);
02503 continue;
02504 }
02505
02506 AST_LIST_LOCK(&feature_list);
02507 if ((feature = find_dynamic_feature(var->name))) {
02508 AST_LIST_UNLOCK(&feature_list);
02509 ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name);
02510 continue;
02511 }
02512 AST_LIST_UNLOCK(&feature_list);
02513
02514 if (!(feature = ast_calloc(1, sizeof(*feature))))
02515 continue;
02516
02517 ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN);
02518 ast_copy_string(feature->app, app, FEATURE_APP_LEN);
02519 ast_copy_string(feature->exten, exten, FEATURE_EXTEN_LEN);
02520
02521 if (app_args)
02522 ast_copy_string(feature->app_args, app_args, FEATURE_APP_ARGS_LEN);
02523
02524 if (moh_class)
02525 ast_copy_string(feature->moh_class, moh_class, FEATURE_MOH_LEN);
02526
02527 ast_copy_string(feature->exten, exten, sizeof(feature->exten));
02528 feature->operation = feature_exec_app;
02529 ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF);
02530
02531
02532 if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller"))
02533 ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF);
02534 else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee"))
02535 ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER);
02536 else {
02537 ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s',"
02538 " must be 'self', or 'peer'\n", var->name);
02539 continue;
02540 }
02541
02542 if (ast_strlen_zero(activatedby))
02543 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
02544 else if (!strcasecmp(activatedby, "caller"))
02545 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER);
02546 else if (!strcasecmp(activatedby, "callee"))
02547 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE);
02548 else if (!strcasecmp(activatedby, "both"))
02549 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
02550 else {
02551 ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s',"
02552 " must be 'caller', or 'callee', or 'both'\n", var->name);
02553 continue;
02554 }
02555
02556 ast_register_feature(feature);
02557
02558 if (option_verbose >= 1)
02559 ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, app, app_args, exten);
02560 }
02561 ast_config_destroy(cfg);
02562
02563
02564 if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) {
02565 if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar))
02566 notify_metermaids(old_parking_ext, old_parking_con);
02567 if (option_debug)
02568 ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
02569 }
02570
02571 if (!(con = ast_context_find(parking_con)) && !(con = ast_context_create(NULL, parking_con, registrar))) {
02572 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
02573 return -1;
02574 }
02575 res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar);
02576 if (parkaddhints)
02577 park_add_hints(parking_con, parking_start, parking_stop);
02578 if (!res)
02579 notify_metermaids(ast_parking_ext(), parking_con);
02580 return res;
02581
02582 }
02583
02584 static char *app_bridge = "Bridge";
02585 static char *bridge_synopsis = "Bridge two channels";
02586 static char *bridge_descrip =
02587 "Usage: Bridge(channel[|options])\n"
02588 " Allows the ability to bridge two channels via the dialplan.\n"
02589 "The current channel is bridged to the specified 'channel'.\n"
02590 "The following options are supported:\n"
02591 " p - Play a courtesy tone to 'channel'.\n"
02592 "BRIDGERESULT dial plan variable will contain SUCCESS, FAILURE, LOOP, NONEXISTENT or INCOMPATIBLE.\n";
02593
02594 enum {
02595 BRIDGE_OPT_PLAYTONE = (1 << 0),
02596 };
02597
02598 AST_APP_OPTIONS(bridge_exec_options, BEGIN_OPTIONS
02599 AST_APP_OPTION('p', BRIDGE_OPT_PLAYTONE)
02600 END_OPTIONS );
02601
02602 static int bridge_exec(struct ast_channel *chan, void *data)
02603 {
02604 struct ast_module_user *u;
02605 struct ast_channel *current_dest_chan, *final_dest_chan;
02606 char *tmp_data = NULL;
02607 struct ast_flags opts = { 0, };
02608 struct ast_bridge_config bconfig = { { 0, }, };
02609
02610 AST_DECLARE_APP_ARGS(args,
02611 AST_APP_ARG(dest_chan);
02612 AST_APP_ARG(options);
02613 );
02614
02615 if (ast_strlen_zero(data)) {
02616 ast_log(LOG_WARNING, "Bridge require at least 1 argument specifying the other end of the bridge\n");
02617 return -1;
02618 }
02619
02620 u = ast_module_user_add(chan);
02621
02622 tmp_data = ast_strdupa(data);
02623 AST_STANDARD_APP_ARGS(args, tmp_data);
02624 if (!ast_strlen_zero(args.options))
02625 ast_app_parse_options(bridge_exec_options, &opts, NULL, args.options);
02626
02627
02628 if (!strncmp(chan->name, args.dest_chan,
02629 strlen(chan->name) < strlen(args.dest_chan) ?
02630 strlen(chan->name) : strlen(args.dest_chan))) {
02631 ast_log(LOG_WARNING, "Unable to bridge channel %s with itself\n", chan->name);
02632 manager_event(EVENT_FLAG_CALL, "BridgeExec",
02633 "Response: Failed\r\n"
02634 "Reason: Unable to bridge channel to itself\r\n"
02635 "Channel1: %s\r\n"
02636 "Channel2: %s\r\n",
02637 chan->name, args.dest_chan);
02638 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "LOOP");
02639 ast_module_user_remove(u);
02640 return 0;
02641 }
02642
02643
02644 if (!(current_dest_chan = ast_get_channel_by_name_prefix_locked(args.dest_chan,
02645 strlen(args.dest_chan)))) {
02646 ast_log(LOG_WARNING, "Bridge failed because channel %s does not exists or we "
02647 "cannot get its lock\n", args.dest_chan);
02648 manager_event(EVENT_FLAG_CALL, "BridgeExec",
02649 "Response: Failed\r\n"
02650 "Reason: Cannot grab end point\r\n"
02651 "Channel1: %s\r\n"
02652 "Channel2: %s\r\n", chan->name, args.dest_chan);
02653 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "NONEXISTENT");
02654 ast_module_user_remove(u);
02655 return 0;
02656 }
02657 ast_mutex_unlock(¤t_dest_chan->lock);
02658
02659
02660 if (current_dest_chan->_state != AST_STATE_UP)
02661 ast_answer(current_dest_chan);
02662
02663
02664 if (!(final_dest_chan = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
02665 NULL, NULL, 0, "Bridge/%s", current_dest_chan->name))) {
02666 ast_log(LOG_WARNING, "Cannot create placeholder channel for chan %s\n", args.dest_chan);
02667 manager_event(EVENT_FLAG_CALL, "BridgeExec",
02668 "Response: Failed\r\n"
02669 "Reason: cannot create placeholder\r\n"
02670 "Channel1: %s\r\n"
02671 "Channel2: %s\r\n", chan->name, args.dest_chan);
02672 }
02673 do_bridge_masquerade(current_dest_chan, final_dest_chan);
02674
02675
02676
02677 if (ast_channel_make_compatible(chan, final_dest_chan) < 0) {
02678 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, final_dest_chan->name);
02679 manager_event(EVENT_FLAG_CALL, "BridgeExec",
02680 "Response: Failed\r\n"
02681 "Reason: Could not make channels compatible for bridge\r\n"
02682 "Channel1: %s\r\n"
02683 "Channel2: %s\r\n", chan->name, final_dest_chan->name);
02684 ast_hangup(final_dest_chan);
02685 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "INCOMPATIBLE");
02686 ast_module_user_remove(u);
02687 return 0;
02688 }
02689
02690
02691 manager_event(EVENT_FLAG_CALL, "BridgeExec",
02692 "Response: Success\r\n"
02693 "Channel1: %s\r\n"
02694 "Channel2: %s\r\n", chan->name, final_dest_chan->name);
02695
02696
02697 if (ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE) && !ast_strlen_zero(xfersound)) {
02698 if (!ast_streamfile(final_dest_chan, xfersound, final_dest_chan->language)) {
02699 if (ast_waitstream(final_dest_chan, "") < 0)
02700 ast_log(LOG_WARNING, "Failed to play courtesy tone on %s\n", final_dest_chan->name);
02701 }
02702 }
02703
02704
02705 ast_bridge_call(chan, final_dest_chan, &bconfig);
02706
02707
02708 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "SUCCESS");
02709 if (!ast_check_hangup(final_dest_chan)) {
02710 if (option_debug) {
02711 ast_log(LOG_DEBUG, "starting new PBX in %s,%s,%d for chan %s\n",
02712 final_dest_chan->context, final_dest_chan->exten,
02713 final_dest_chan->priority, final_dest_chan->name);
02714 }
02715
02716 if (ast_pbx_start(final_dest_chan) != AST_PBX_SUCCESS) {
02717 ast_log(LOG_WARNING, "FAILED continuing PBX on dest chan %s\n", final_dest_chan->name);
02718 ast_hangup(final_dest_chan);
02719 } else if (option_debug)
02720 ast_log(LOG_DEBUG, "SUCCESS continuing PBX on chan %s\n", final_dest_chan->name);
02721 } else {
02722 if (option_debug)
02723 ast_log(LOG_DEBUG, "hangup chan %s since the other endpoint has hung up\n", final_dest_chan->name);
02724 ast_hangup(final_dest_chan);
02725 }
02726
02727 ast_module_user_remove(u);
02728
02729 return 0;
02730 }
02731
02732 static int reload(void)
02733 {
02734 return load_config();
02735 }
02736
02737 static int load_module(void)
02738 {
02739 int res;
02740
02741 ast_register_application(app_bridge, bridge_exec, bridge_synopsis, bridge_descrip);
02742
02743 memset(parking_ext, 0, sizeof(parking_ext));
02744 memset(parking_con, 0, sizeof(parking_con));
02745
02746 if ((res = load_config()))
02747 return res;
02748 ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
02749 ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
02750 res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
02751 if (!res)
02752 res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
02753 if (!res) {
02754 ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls");
02755 ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park,
02756 "Park a channel", mandescr_park);
02757 ast_manager_register2("Bridge", EVENT_FLAG_COMMAND, action_bridge, "Bridge two channels already in the PBX", mandescr_bridge);
02758 }
02759
02760 res |= ast_devstate_prov_add("Park", metermaidstate);
02761
02762 return res;
02763 }
02764
02765
02766 static int unload_module(void)
02767 {
02768 ast_module_user_hangup_all();
02769
02770 ast_manager_unregister("ParkedCalls");
02771 ast_manager_unregister("Bridge");
02772 ast_manager_unregister("Park");
02773 ast_cli_unregister_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
02774 ast_unregister_application(parkcall);
02775 ast_unregister_application(app_bridge);
02776 ast_devstate_prov_del("Park");
02777 return ast_unregister_application(parkedcall);
02778 }
02779
02780 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Call Features Resource",
02781 .load = load_module,
02782 .unload = unload_module,
02783 .reload = reload,
02784 );