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