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