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