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