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