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: 153270 $")
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 #include "asterisk/global_datastores.h"
00066
00067 #define DEFAULT_PARK_TIME 45000
00068 #define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000
00069 #define DEFAULT_FEATURE_DIGIT_TIMEOUT 500
00070 #define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000
00071
00072 #define AST_MAX_WATCHERS 256
00073
00074 enum {
00075 AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0),
00076 AST_FEATURE_FLAG_ONPEER = (1 << 1),
00077 AST_FEATURE_FLAG_ONSELF = (1 << 2),
00078 AST_FEATURE_FLAG_BYCALLEE = (1 << 3),
00079 AST_FEATURE_FLAG_BYCALLER = (1 << 4),
00080 AST_FEATURE_FLAG_BYBOTH = (3 << 3),
00081 };
00082
00083 static char *parkedcall = "ParkedCall";
00084
00085 static int parkaddhints = 0;
00086 static int parkingtime = DEFAULT_PARK_TIME;
00087 static char parking_con[AST_MAX_EXTENSION];
00088 static char parking_con_dial[AST_MAX_EXTENSION];
00089 static char parking_ext[AST_MAX_EXTENSION];
00090 static char pickup_ext[AST_MAX_EXTENSION];
00091 static char parkmohclass[MAX_MUSICCLASS];
00092 static int parking_start;
00093 static int parking_stop;
00094
00095 static int parkedcalltransfers;
00096
00097 static char courtesytone[256];
00098 static int parkedplay = 0;
00099 static char xfersound[256];
00100 static char xferfailsound[256];
00101
00102 static int parking_offset;
00103 static int parkfindnext;
00104
00105 static int adsipark;
00106
00107 static int transferdigittimeout;
00108 static int featuredigittimeout;
00109
00110 static int atxfernoanswertimeout;
00111
00112 static char *registrar = "res_features";
00113
00114
00115 static char *synopsis = "Answer a parked call";
00116
00117 static char *descrip = "ParkedCall(exten):"
00118 "Used to connect to a parked call. This application is always\n"
00119 "registered internally and does not need to be explicitly added\n"
00120 "into the dialplan, although you should include the 'parkedcalls'\n"
00121 "context.\n";
00122
00123 static char *parkcall = PARK_APP_NAME;
00124
00125 static char *synopsis2 = "Park yourself";
00126
00127 static char *descrip2 = "Park():"
00128 "Used to park yourself (typically in combination with a supervised\n"
00129 "transfer to know the parking space). This application is always\n"
00130 "registered internally and does not need to be explicitly added\n"
00131 "into the dialplan, although you should include the 'parkedcalls'\n"
00132 "context (or the context specified in features.conf).\n\n"
00133 "If you set the PARKINGEXTEN variable to an extension in your\n"
00134 "parking context, park() will park the call on that extension, unless\n"
00135 "it already exists. In that case, execution will continue at next\n"
00136 "priority.\n" ;
00137
00138 static struct ast_app *monitor_app = NULL;
00139 static int monitor_ok = 1;
00140
00141 struct parkeduser {
00142 struct ast_channel *chan;
00143 struct timeval start;
00144 int parkingnum;
00145 char parkingexten[AST_MAX_EXTENSION];
00146 char context[AST_MAX_CONTEXT];
00147 char exten[AST_MAX_EXTENSION];
00148 int priority;
00149 int parkingtime;
00150 int notquiteyet;
00151 char peername[1024];
00152 unsigned char moh_trys;
00153 struct parkeduser *next;
00154 };
00155
00156 static struct parkeduser *parkinglot;
00157
00158 AST_MUTEX_DEFINE_STATIC(parking_lock);
00159
00160 static pthread_t parking_thread;
00161
00162 char *ast_parking_ext(void)
00163 {
00164 return parking_ext;
00165 }
00166
00167 char *ast_pickup_ext(void)
00168 {
00169 return pickup_ext;
00170 }
00171
00172 struct ast_bridge_thread_obj
00173 {
00174 struct ast_bridge_config bconfig;
00175 struct ast_channel *chan;
00176 struct ast_channel *peer;
00177 };
00178
00179
00180
00181
00182 static void set_c_e_p(struct ast_channel *chan, const char *context, const char *ext, int pri)
00183 {
00184 ast_copy_string(chan->context, context, sizeof(chan->context));
00185 ast_copy_string(chan->exten, ext, sizeof(chan->exten));
00186 chan->priority = pri;
00187 }
00188
00189 static void check_goto_on_transfer(struct ast_channel *chan)
00190 {
00191 struct ast_channel *xferchan;
00192 const char *val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR");
00193 char *x, *goto_on_transfer;
00194 struct ast_frame *f;
00195
00196 if (ast_strlen_zero(val))
00197 return;
00198
00199 goto_on_transfer = ast_strdupa(val);
00200
00201 if (!(xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, chan->name)))
00202 return;
00203
00204 for (x = goto_on_transfer; x && *x; x++) {
00205 if (*x == '^')
00206 *x = '|';
00207 }
00208
00209 xferchan->readformat = chan->readformat;
00210 xferchan->writeformat = chan->writeformat;
00211 ast_channel_masquerade(xferchan, chan);
00212 ast_parseable_goto(xferchan, goto_on_transfer);
00213 xferchan->_state = AST_STATE_UP;
00214 ast_clear_flag(xferchan, AST_FLAGS_ALL);
00215 xferchan->_softhangup = 0;
00216 if ((f = ast_read(xferchan))) {
00217 ast_frfree(f);
00218 f = NULL;
00219 ast_pbx_start(xferchan);
00220 } else {
00221 ast_hangup(xferchan);
00222 }
00223 }
00224
00225 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);
00226
00227
00228 static void *ast_bridge_call_thread(void *data)
00229 {
00230 struct ast_bridge_thread_obj *tobj = data;
00231
00232 tobj->chan->appl = "Transferred Call";
00233 tobj->chan->data = tobj->peer->name;
00234 tobj->peer->appl = "Transferred Call";
00235 tobj->peer->data = tobj->chan->name;
00236
00237 ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
00238 ast_hangup(tobj->chan);
00239 ast_hangup(tobj->peer);
00240 bzero(tobj, sizeof(*tobj));
00241 free(tobj);
00242 return NULL;
00243 }
00244
00245 static void ast_bridge_call_thread_launch(void *data)
00246 {
00247 pthread_t thread;
00248 pthread_attr_t attr;
00249 struct sched_param sched;
00250
00251 pthread_attr_init(&attr);
00252 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00253 ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data);
00254 pthread_attr_destroy(&attr);
00255 memset(&sched, 0, sizeof(sched));
00256 pthread_setschedparam(thread, SCHED_RR, &sched);
00257 }
00258
00259 static int adsi_announce_park(struct ast_channel *chan, char *parkingexten)
00260 {
00261 int res;
00262 int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
00263 char tmp[256];
00264 char *message[5] = {NULL, NULL, NULL, NULL, NULL};
00265
00266 snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten);
00267 message[0] = tmp;
00268 res = ast_adsi_load_session(chan, NULL, 0, 1);
00269 if (res == -1)
00270 return res;
00271 return ast_adsi_print(chan, message, justify, 1);
00272 }
00273
00274
00275 static void notify_metermaids(char *exten, char *context)
00276 {
00277 if (option_debug > 3)
00278 ast_log(LOG_DEBUG, "Notification of state change to metermaids %s@%s\n", exten, context);
00279
00280
00281 ast_device_state_changed("park:%s@%s", exten, context);
00282 return;
00283 }
00284
00285
00286 static int metermaidstate(const char *data)
00287 {
00288 int res = AST_DEVICE_INVALID;
00289 char *context = ast_strdupa(data);
00290 char *exten;
00291
00292 exten = strsep(&context, "@");
00293 if (!context)
00294 return res;
00295
00296 if (option_debug > 3)
00297 ast_log(LOG_DEBUG, "Checking state of exten %s in context %s\n", exten, context);
00298
00299 res = ast_exists_extension(NULL, context, exten, 1, NULL);
00300
00301 if (!res)
00302 return AST_DEVICE_NOT_INUSE;
00303 else
00304 return AST_DEVICE_INUSE;
00305 }
00306
00307 static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout, char *orig_chan_name)
00308 {
00309 struct parkeduser *pu, *cur;
00310 int i, x = -1, parking_range, parkingnum_copy;
00311 struct ast_context *con;
00312 const char *parkingexten;
00313
00314
00315 if (!(pu = ast_calloc(1, sizeof(*pu))))
00316 return -1;
00317
00318
00319 ast_mutex_lock(&parking_lock);
00320
00321 parkingexten = pbx_builtin_getvar_helper(chan, "PARKINGEXTEN");
00322 if (!ast_strlen_zero(parkingexten)) {
00323
00324
00325
00326
00327
00328
00329 if (sscanf(parkingexten, "%d", &x) != 1 || x < 0) {
00330 ast_log(LOG_WARNING, "PARKINGEXTEN does not indicate a valid parking slot: '%s'.\n", parkingexten);
00331 ast_mutex_unlock(&parking_lock);
00332 free(pu);
00333 return 1;
00334 }
00335 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", x);
00336
00337 if (ast_exists_extension(NULL, parking_con, pu->parkingexten, 1, NULL)) {
00338 ast_mutex_unlock(&parking_lock);
00339 free(pu);
00340 ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parking_con);
00341 return 1;
00342 }
00343 } else {
00344
00345 parking_range = parking_stop - parking_start+1;
00346 for (i = 0; i < parking_range; i++) {
00347 x = (i + parking_offset) % parking_range + parking_start;
00348 cur = parkinglot;
00349 while(cur) {
00350 if (cur->parkingnum == x)
00351 break;
00352 cur = cur->next;
00353 }
00354 if (!cur)
00355 break;
00356 }
00357
00358 if (!(i < parking_range)) {
00359 ast_log(LOG_WARNING, "No more parking spaces\n");
00360 free(pu);
00361 ast_mutex_unlock(&parking_lock);
00362 return -1;
00363 }
00364
00365 if (parkfindnext)
00366 parking_offset = x - parking_start + 1;
00367 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", x);
00368 }
00369
00370 chan->appl = "Parked Call";
00371 chan->data = NULL;
00372
00373 pu->chan = chan;
00374
00375
00376 if (chan != peer) {
00377 ast_indicate_data(pu->chan, AST_CONTROL_HOLD,
00378 S_OR(parkmohclass, NULL),
00379 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
00380 }
00381
00382 pu->start = ast_tvnow();
00383 pu->parkingnum = x;
00384 pu->parkingtime = (timeout > 0) ? timeout : parkingtime;
00385 if (extout)
00386 *extout = x;
00387
00388 if (peer) {
00389
00390
00391
00392
00393
00394 if (!strcasecmp(peer->tech->type, "Local")) {
00395 struct ast_channel *tmpchan, *base_peer;
00396 char other_side[AST_CHANNEL_NAME];
00397 char *c;
00398 ast_copy_string(other_side, peer->name, sizeof(other_side));
00399 if ((c = strrchr(other_side, ','))) {
00400 *++c = '1';
00401 }
00402 if ((tmpchan = ast_get_channel_by_name_locked(other_side))) {
00403 if ((base_peer = ast_bridged_channel(tmpchan))) {
00404 ast_copy_string(pu->peername, base_peer->name, sizeof(pu->peername));
00405 }
00406 ast_channel_unlock(tmpchan);
00407 }
00408 } else {
00409 ast_copy_string(pu->peername, peer->name, sizeof(pu->peername));
00410 }
00411 }
00412
00413
00414
00415 ast_copy_string(pu->context, S_OR(chan->macrocontext, chan->context), sizeof(pu->context));
00416 ast_copy_string(pu->exten, S_OR(chan->macroexten, chan->exten), sizeof(pu->exten));
00417 pu->priority = chan->macropriority ? chan->macropriority : chan->priority;
00418 pu->next = parkinglot;
00419 parkinglot = pu;
00420 parkingnum_copy = pu->parkingnum;
00421
00422 if (peer == chan)
00423 pu->notquiteyet = 1;
00424
00425 if (option_verbose > 1)
00426 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));
00427
00428 manager_event(EVENT_FLAG_CALL, "ParkedCall",
00429 "Exten: %s\r\n"
00430 "Channel: %s\r\n"
00431 "From: %s\r\n"
00432 "Timeout: %ld\r\n"
00433 "CallerID: %s\r\n"
00434 "CallerIDName: %s\r\n",
00435 pu->parkingexten, pu->chan->name, peer ? peer->name : "",
00436 (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL),
00437 S_OR(pu->chan->cid.cid_num, "<unknown>"),
00438 S_OR(pu->chan->cid.cid_name, "<unknown>")
00439 );
00440
00441 if (peer && adsipark && ast_adsi_available(peer)) {
00442 adsi_announce_park(peer, pu->parkingexten);
00443 ast_adsi_unload_session(peer);
00444 }
00445
00446 con = ast_context_find(parking_con);
00447 if (!con)
00448 con = ast_context_create(NULL, parking_con, registrar);
00449 if (!con)
00450 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
00451 if (con) {
00452 if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, strdup(pu->parkingexten), ast_free, registrar)) {
00453 notify_metermaids(pu->parkingexten, parking_con);
00454 }
00455 }
00456
00457 ast_mutex_unlock(&parking_lock);
00458
00459 pthread_kill(parking_thread, SIGURG);
00460
00461
00462 if (peer && (ast_strlen_zero(orig_chan_name) || !strcasecmp(peer->name, orig_chan_name))) {
00463
00464 ast_set_flag(peer, AST_FLAG_MASQ_NOSTREAM);
00465
00466 ast_say_digits(peer, parkingnum_copy, "", peer->language);
00467 ast_clear_flag(peer, AST_FLAG_MASQ_NOSTREAM);
00468 }
00469
00470 if (peer == chan) {
00471
00472 ast_indicate_data(pu->chan, AST_CONTROL_HOLD,
00473 S_OR(parkmohclass, NULL),
00474 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
00475 pu->notquiteyet = 0;
00476 pthread_kill(parking_thread, SIGURG);
00477 }
00478 return 0;
00479 }
00480
00481
00482
00483
00484 int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
00485 {
00486 return park_call_full(chan, peer, timeout, extout, NULL);
00487 }
00488
00489 static int masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout, int play_announcement)
00490 {
00491 struct ast_channel *chan;
00492 struct ast_frame *f;
00493 char *orig_chan_name = NULL;
00494 int park_status;
00495
00496
00497 if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) {
00498 ast_log(LOG_WARNING, "Unable to create parked channel\n");
00499 return -1;
00500 }
00501
00502
00503 chan->readformat = rchan->readformat;
00504 chan->writeformat = rchan->writeformat;
00505 ast_channel_masquerade(chan, rchan);
00506
00507
00508 set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority);
00509
00510
00511 if ((f = ast_read(chan))) {
00512 ast_frfree(f);
00513 }
00514
00515 if (!play_announcement) {
00516 orig_chan_name = ast_strdupa(chan->name);
00517 }
00518
00519 park_status = park_call_full(chan, peer, timeout, extout, orig_chan_name);
00520 if (park_status == 1) {
00521
00522 ast_hangup(chan);
00523 return -1;
00524 }
00525
00526 return 0;
00527 }
00528
00529 int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
00530 {
00531 return masq_park_call(rchan, peer, timeout, extout, 0);
00532 }
00533
00534 static int masq_park_call_announce(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
00535 {
00536 return masq_park_call(rchan, peer, timeout, extout, 1);
00537 }
00538
00539 #define FEATURE_RETURN_HANGUP -1
00540 #define FEATURE_RETURN_SUCCESSBREAK 0
00541 #define FEATURE_RETURN_PBX_KEEPALIVE AST_PBX_KEEPALIVE
00542 #define FEATURE_RETURN_NO_HANGUP_PEER AST_PBX_NO_HANGUP_PEER
00543 #define FEATURE_RETURN_NO_HANGUP_PEER_PARKED AST_PBX_NO_HANGUP_PEER_PARKED
00544 #define FEATURE_RETURN_PASSDIGITS 21
00545 #define FEATURE_RETURN_STOREDIGITS 22
00546 #define FEATURE_RETURN_SUCCESS 23
00547 #define FEATURE_RETURN_KEEPTRYING 24
00548
00549 #define FEATURE_SENSE_CHAN (1 << 0)
00550 #define FEATURE_SENSE_PEER (1 << 1)
00551
00552
00553
00554
00555 static void set_peers(struct ast_channel **caller, struct ast_channel **callee,
00556 struct ast_channel *peer, struct ast_channel *chan, int sense)
00557 {
00558 if (sense == FEATURE_SENSE_PEER) {
00559 *caller = peer;
00560 *callee = chan;
00561 } else {
00562 *callee = peer;
00563 *caller = chan;
00564 }
00565 }
00566
00567
00568 static int builtin_parkcall(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00569 {
00570 struct ast_channel *parker;
00571 struct ast_channel *parkee;
00572 int res = 0;
00573 struct ast_module_user *u;
00574
00575 u = ast_module_user_add(chan);
00576
00577 set_peers(&parker, &parkee, peer, chan, sense);
00578
00579
00580 strcpy(chan->exten, "s");
00581 chan->priority = 1;
00582 if (chan->_state != AST_STATE_UP)
00583 res = ast_answer(chan);
00584 if (!res)
00585 res = ast_safe_sleep(chan, 1000);
00586
00587 if (!res) {
00588 if (sense == FEATURE_SENSE_CHAN) {
00589 res = ast_park_call(parkee, parker, 0, NULL);
00590 if (!res) {
00591 if (sense == FEATURE_SENSE_CHAN) {
00592 res = AST_PBX_NO_HANGUP_PEER_PARKED;
00593 } else {
00594 res = AST_PBX_KEEPALIVE;
00595 }
00596 }
00597 }
00598 else if (sense == FEATURE_SENSE_PEER) {
00599 masq_park_call_announce(parkee, parker, 0, NULL);
00600 res = 0;
00601 }
00602 }
00603
00604 ast_module_user_remove(u);
00605 return res;
00606
00607 }
00608
00609 static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00610 {
00611 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
00612 int x = 0;
00613 size_t len;
00614 struct ast_channel *caller_chan, *callee_chan;
00615
00616 if (!monitor_ok) {
00617 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00618 return -1;
00619 }
00620
00621 if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) {
00622 monitor_ok = 0;
00623 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00624 return -1;
00625 }
00626
00627 set_peers(&caller_chan, &callee_chan, peer, chan, sense);
00628
00629 if (!ast_strlen_zero(courtesytone)) {
00630 if (ast_autoservice_start(callee_chan))
00631 return -1;
00632 if (ast_stream_and_wait(caller_chan, courtesytone, caller_chan->language, "")) {
00633 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
00634 ast_autoservice_stop(callee_chan);
00635 return -1;
00636 }
00637 if (ast_autoservice_stop(callee_chan))
00638 return -1;
00639 }
00640
00641 if (callee_chan->monitor) {
00642 if (option_verbose > 3)
00643 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to stop recording call.\n", code);
00644 ast_monitor_stop(callee_chan, 1);
00645 return FEATURE_RETURN_SUCCESS;
00646 }
00647
00648 if (caller_chan && callee_chan) {
00649 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT");
00650 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
00651
00652 if (!touch_format)
00653 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
00654
00655 if (!touch_monitor)
00656 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
00657
00658 if (touch_monitor) {
00659 len = strlen(touch_monitor) + 50;
00660 args = alloca(len);
00661 touch_filename = alloca(len);
00662 snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor);
00663 snprintf(args, len, "%s|%s|m", (touch_format) ? touch_format : "wav", touch_filename);
00664 } else {
00665 caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name));
00666 callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name));
00667 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
00668 args = alloca(len);
00669 touch_filename = alloca(len);
00670 snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id);
00671 snprintf(args, len, "%s|%s|m", S_OR(touch_format, "wav"), touch_filename);
00672 }
00673
00674 for( x = 0; x < strlen(args); x++) {
00675 if (args[x] == '/')
00676 args[x] = '-';
00677 }
00678
00679 if (option_verbose > 3)
00680 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call. filename: %s\n", code, args);
00681
00682 pbx_exec(callee_chan, monitor_app, args);
00683 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
00684 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
00685
00686 return FEATURE_RETURN_SUCCESS;
00687 }
00688
00689 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");
00690 return -1;
00691 }
00692
00693 static int builtin_disconnect(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00694 {
00695 if (option_verbose > 3)
00696 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code);
00697 return FEATURE_RETURN_HANGUP;
00698 }
00699
00700 static int finishup(struct ast_channel *chan)
00701 {
00702 ast_indicate(chan, AST_CONTROL_UNHOLD);
00703
00704 return ast_autoservice_stop(chan);
00705 }
00706
00707
00708 static const char *real_ctx(struct ast_channel *transferer, struct ast_channel *transferee)
00709 {
00710 const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT");
00711 if (ast_strlen_zero(s))
00712 s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT");
00713 if (ast_strlen_zero(s))
00714 s = transferer->macrocontext;
00715 if (ast_strlen_zero(s))
00716 s = transferer->context;
00717 return s;
00718 }
00719
00720 static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00721 {
00722 struct ast_channel *transferer;
00723 struct ast_channel *transferee;
00724 const char *transferer_real_context;
00725 char xferto[256];
00726 int res;
00727
00728 set_peers(&transferer, &transferee, peer, chan, sense);
00729 transferer_real_context = real_ctx(transferer, transferee);
00730
00731 ast_autoservice_start(transferee);
00732 ast_indicate(transferee, AST_CONTROL_HOLD);
00733
00734 memset(xferto, 0, sizeof(xferto));
00735
00736
00737 res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY);
00738 if (res < 0) {
00739 finishup(transferee);
00740 return -1;
00741 }
00742 if (res > 0)
00743 xferto[0] = (char) res;
00744
00745 ast_stopstream(transferer);
00746 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
00747 if (res < 0) {
00748 finishup(transferee);
00749 return res;
00750 }
00751 if (!strcmp(xferto, ast_parking_ext())) {
00752 res = finishup(transferee);
00753 if (res)
00754 res = -1;
00755 else if (!ast_park_call(transferee, transferer, 0, NULL)) {
00756
00757
00758
00759 return (transferer == peer) ? AST_PBX_KEEPALIVE : AST_PBX_NO_HANGUP_PEER_PARKED;
00760 } else {
00761 ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name);
00762 }
00763
00764 } else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
00765 pbx_builtin_setvar_helper(transferer, "BLINDTRANSFER", transferee->name);
00766 pbx_builtin_setvar_helper(transferee, "BLINDTRANSFER", transferer->name);
00767 res=finishup(transferee);
00768 if (!transferer->cdr) {
00769 transferer->cdr=ast_cdr_alloc();
00770 if (transferer) {
00771 ast_cdr_init(transferer->cdr, transferer);
00772 ast_cdr_start(transferer->cdr);
00773 }
00774 }
00775 if (transferer->cdr) {
00776 ast_cdr_setdestchan(transferer->cdr, transferee->name);
00777 ast_cdr_setapp(transferer->cdr, "BLINDTRANSFER","");
00778 }
00779 if (!transferee->pbx) {
00780
00781 if (option_verbose > 2)
00782 ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n"
00783 ,transferee->name, xferto, transferer_real_context);
00784 if (ast_async_goto(transferee, transferer_real_context, xferto, 1))
00785 ast_log(LOG_WARNING, "Async goto failed :-(\n");
00786 res = -1;
00787 } else {
00788
00789 set_c_e_p(transferee, transferer_real_context, xferto, 0);
00790 }
00791 check_goto_on_transfer(transferer);
00792 return res;
00793 } else {
00794 if (option_verbose > 2)
00795 ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context);
00796 }
00797 if (ast_stream_and_wait(transferer, xferfailsound, transferer->language, AST_DIGIT_ANY) < 0 ) {
00798 finishup(transferee);
00799 return -1;
00800 }
00801 ast_stopstream(transferer);
00802 res = finishup(transferee);
00803 if (res) {
00804 if (option_verbose > 1)
00805 ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name);
00806 return res;
00807 }
00808 return FEATURE_RETURN_SUCCESS;
00809 }
00810
00811 static int check_compat(struct ast_channel *c, struct ast_channel *newchan)
00812 {
00813 if (ast_channel_make_compatible(c, newchan) < 0) {
00814 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n",
00815 c->name, newchan->name);
00816 ast_hangup(newchan);
00817 return -1;
00818 }
00819 return 0;
00820 }
00821
00822 static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00823 {
00824 struct ast_channel *transferer;
00825 struct ast_channel *transferee;
00826 const char *transferer_real_context;
00827 char xferto[256] = "";
00828 int res;
00829 int outstate=0;
00830 struct ast_channel *newchan;
00831 struct ast_channel *xferchan;
00832 struct ast_bridge_thread_obj *tobj;
00833 struct ast_bridge_config bconfig;
00834 struct ast_frame *f;
00835 int l;
00836 struct ast_datastore *features_datastore;
00837 struct ast_dial_features *dialfeatures = NULL;
00838
00839 if (option_debug)
00840 ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense);
00841 set_peers(&transferer, &transferee, peer, chan, sense);
00842 transferer_real_context = real_ctx(transferer, transferee);
00843
00844 ast_autoservice_start(transferee);
00845 ast_indicate(transferee, AST_CONTROL_HOLD);
00846
00847
00848 res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY);
00849 if (res < 0) {
00850 finishup(transferee);
00851 return res;
00852 }
00853 if (res > 0)
00854 xferto[0] = (char) res;
00855
00856
00857 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
00858 if (res < 0) {
00859 finishup(transferee);
00860 return res;
00861 }
00862 if (res == 0) {
00863 ast_log(LOG_WARNING, "Did not read data.\n");
00864 finishup(transferee);
00865 if (ast_stream_and_wait(transferer, "beeperr", transferer->language, ""))
00866 return -1;
00867 return FEATURE_RETURN_SUCCESS;
00868 }
00869
00870
00871 if (!ast_exists_extension(transferer, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
00872 ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context);
00873 finishup(transferee);
00874 if (ast_stream_and_wait(transferer, "beeperr", transferer->language, ""))
00875 return -1;
00876 return FEATURE_RETURN_SUCCESS;
00877 }
00878
00879 l = strlen(xferto);
00880 snprintf(xferto + l, sizeof(xferto) - l, "@%s", transferer_real_context);
00881 newchan = ast_feature_request_and_dial(transferer, "Local", ast_best_codec(transferer->nativeformats),
00882 xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, transferer->language);
00883
00884
00885
00886 ast_channel_lock(transferee);
00887 if ((features_datastore = ast_channel_datastore_find(transferee, &