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