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: 201830 $")
00029
00030 #include "asterisk/_private.h"
00031
00032 #include <pthread.h>
00033 #include <sys/time.h>
00034 #include <sys/signal.h>
00035 #include <netinet/in.h>
00036
00037 #include "asterisk/lock.h"
00038 #include "asterisk/file.h"
00039 #include "asterisk/channel.h"
00040 #include "asterisk/pbx.h"
00041 #include "asterisk/causes.h"
00042 #include "asterisk/module.h"
00043 #include "asterisk/translate.h"
00044 #include "asterisk/app.h"
00045 #include "asterisk/say.h"
00046 #include "asterisk/features.h"
00047 #include "asterisk/musiconhold.h"
00048 #include "asterisk/config.h"
00049 #include "asterisk/cli.h"
00050 #include "asterisk/manager.h"
00051 #include "asterisk/utils.h"
00052 #include "asterisk/adsi.h"
00053 #include "asterisk/devicestate.h"
00054 #include "asterisk/monitor.h"
00055 #include "asterisk/audiohook.h"
00056 #include "asterisk/global_datastores.h"
00057
00058 #define DEFAULT_PARK_TIME 45000
00059 #define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000
00060 #define DEFAULT_FEATURE_DIGIT_TIMEOUT 1000
00061 #define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000
00062 #define DEFAULT_ATXFER_DROP_CALL 0
00063 #define DEFAULT_ATXFER_LOOP_DELAY 10000
00064 #define DEFAULT_ATXFER_CALLBACK_RETRIES 2
00065
00066 #define AST_MAX_WATCHERS 256
00067 #define MAX_DIAL_FEATURE_OPTIONS 30
00068
00069 #define FEATURE_RETURN_HANGUP -1
00070 #define FEATURE_RETURN_SUCCESSBREAK 0
00071 #define FEATURE_RETURN_PASSDIGITS 21
00072 #define FEATURE_RETURN_STOREDIGITS 22
00073 #define FEATURE_RETURN_SUCCESS 23
00074 #define FEATURE_RETURN_KEEPTRYING 24
00075 #define FEATURE_RETURN_PARKFAILED 25
00076
00077 enum {
00078 AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0),
00079 AST_FEATURE_FLAG_ONPEER = (1 << 1),
00080 AST_FEATURE_FLAG_ONSELF = (1 << 2),
00081 AST_FEATURE_FLAG_BYCALLEE = (1 << 3),
00082 AST_FEATURE_FLAG_BYCALLER = (1 << 4),
00083 AST_FEATURE_FLAG_BYBOTH = (3 << 3),
00084 };
00085
00086 struct feature_group_exten {
00087 AST_LIST_ENTRY(feature_group_exten) entry;
00088 AST_DECLARE_STRING_FIELDS(
00089 AST_STRING_FIELD(exten);
00090 );
00091 struct ast_call_feature *feature;
00092 };
00093
00094 struct feature_group {
00095 AST_LIST_ENTRY(feature_group) entry;
00096 AST_DECLARE_STRING_FIELDS(
00097 AST_STRING_FIELD(gname);
00098 );
00099 AST_LIST_HEAD_NOLOCK(, feature_group_exten) features;
00100 };
00101
00102 static AST_RWLIST_HEAD_STATIC(feature_groups, feature_group);
00103
00104 static char *parkedcall = "ParkedCall";
00105
00106 static int parkaddhints = 0;
00107 static int parkedcalltransfers = 0;
00108 static int parkedcallreparking = 0;
00109 static int parkedcallhangup = 0;
00110 static int parkedcallrecording = 0;
00111 static int parkingtime = DEFAULT_PARK_TIME;
00112 static char parking_con[AST_MAX_EXTENSION];
00113 static char parking_con_dial[AST_MAX_EXTENSION];
00114 static char parking_ext[AST_MAX_EXTENSION];
00115 static char pickup_ext[AST_MAX_EXTENSION];
00116 static char parkmohclass[MAX_MUSICCLASS];
00117 static int parking_start;
00118 static int parking_stop;
00119
00120 static char courtesytone[256];
00121 static int parkedplay = 0;
00122 static char xfersound[256];
00123 static char xferfailsound[256];
00124
00125 static int parking_offset;
00126 static int parkfindnext;
00127
00128 static int adsipark;
00129
00130 static int transferdigittimeout;
00131 static int featuredigittimeout;
00132 static int comebacktoorigin = 1;
00133
00134 static int atxfernoanswertimeout;
00135 static unsigned int atxferdropcall;
00136 static unsigned int atxferloopdelay;
00137 static unsigned int atxfercallbackretries;
00138
00139 static char *registrar = "features";
00140
00141
00142 static char *synopsis = "Answer a parked call";
00143
00144 static char *descrip = "ParkedCall(exten): "
00145 "Used to connect to a parked call. This application is always\n"
00146 "registered internally and does not need to be explicitly added\n"
00147 "into the dialplan, although you should include the 'parkedcalls'\n"
00148 "context. If no extension is provided, then the first available\n"
00149 "parked call will be acquired.\n";
00150
00151 static char *parkcall = "Park";
00152
00153 static char *synopsis2 = "Park yourself";
00154
00155 static char *descrip2 = "Park(): "
00156 "Used to park yourself (typically in combination with a supervised\n"
00157 "transfer to know the parking space). This application is always\n"
00158 "registered internally and does not need to be explicitly added\n"
00159 "into the dialplan, although you should include the 'parkedcalls'\n"
00160 "context (or the context specified in features.conf).\n\n"
00161 "If you set the PARKINGEXTEN variable to an extension in your\n"
00162 "parking context, Park() will park the call on that extension, unless\n"
00163 "it already exists. In that case, execution will continue at next\n"
00164 "priority.\n" ;
00165
00166 static struct ast_app *monitor_app = NULL;
00167 static int monitor_ok = 1;
00168
00169 static struct ast_app *mixmonitor_app = NULL;
00170 static int mixmonitor_ok = 1;
00171
00172 static struct ast_app *stopmixmonitor_app = NULL;
00173 static int stopmixmonitor_ok = 1;
00174
00175 struct parkeduser {
00176 struct ast_channel *chan;
00177 struct timeval start;
00178 int parkingnum;
00179 char parkingexten[AST_MAX_EXTENSION];
00180 char context[AST_MAX_CONTEXT];
00181 char exten[AST_MAX_EXTENSION];
00182 int priority;
00183 int parkingtime;
00184 int notquiteyet;
00185 char peername[1024];
00186 unsigned char moh_trys;
00187 AST_LIST_ENTRY(parkeduser) list;
00188 };
00189 struct ast_dial_features {
00190 struct ast_flags features_caller;
00191 struct ast_flags features_callee;
00192 int is_caller;
00193 };
00194
00195 static AST_LIST_HEAD_STATIC(parkinglot, parkeduser);
00196
00197 static void *dial_features_duplicate(void *data)
00198 {
00199 struct ast_dial_features *df = data, *df_copy;
00200
00201 if (!(df_copy = ast_calloc(1, sizeof(*df)))) {
00202 return NULL;
00203 }
00204
00205 memcpy(df_copy, df, sizeof(*df));
00206
00207 return df_copy;
00208 }
00209
00210 static void dial_features_destroy(void *data)
00211 {
00212 struct ast_dial_features *df = data;
00213 if (df) {
00214 ast_free(df);
00215 }
00216 }
00217
00218 const struct ast_datastore_info dial_features_info = {
00219 .type = "dial-features",
00220 .destroy = dial_features_destroy,
00221 .duplicate = dial_features_duplicate,
00222 };
00223
00224 static pthread_t parking_thread;
00225
00226 const char *ast_parking_ext(void)
00227 {
00228 return parking_ext;
00229 }
00230
00231 const char *ast_pickup_ext(void)
00232 {
00233 return pickup_ext;
00234 }
00235
00236 struct ast_bridge_thread_obj
00237 {
00238 struct ast_bridge_config bconfig;
00239 struct ast_channel *chan;
00240 struct ast_channel *peer;
00241 unsigned int return_to_pbx:1;
00242 };
00243
00244
00245
00246
00247
00248
00249
00250 static void set_c_e_p(struct ast_channel *chan, const char *context, const char *ext, int pri)
00251 {
00252 ast_copy_string(chan->context, context, sizeof(chan->context));
00253 ast_copy_string(chan->exten, ext, sizeof(chan->exten));
00254 chan->priority = pri;
00255 }
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265 static void check_goto_on_transfer(struct ast_channel *chan)
00266 {
00267 struct ast_channel *xferchan;
00268 const char *val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR");
00269 char *x, *goto_on_transfer;
00270 struct ast_frame *f;
00271
00272 if (ast_strlen_zero(val))
00273 return;
00274
00275 goto_on_transfer = ast_strdupa(val);
00276
00277 if (!(xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "%s", chan->name)))
00278 return;
00279
00280 for (x = goto_on_transfer; x && *x; x++) {
00281 if (*x == '^')
00282 *x = '|';
00283 }
00284
00285 xferchan->readformat = chan->readformat;
00286 xferchan->writeformat = chan->writeformat;
00287 ast_channel_masquerade(xferchan, chan);
00288 ast_parseable_goto(xferchan, goto_on_transfer);
00289 xferchan->_state = AST_STATE_UP;
00290 ast_clear_flag(xferchan, AST_FLAGS_ALL);
00291 xferchan->_softhangup = 0;
00292 if ((f = ast_read(xferchan))) {
00293 ast_frfree(f);
00294 f = NULL;
00295 ast_pbx_start(xferchan);
00296 } else {
00297 ast_hangup(xferchan);
00298 }
00299 }
00300
00301 static struct ast_channel *ast_feature_request_and_dial(struct ast_channel *caller, struct ast_channel *transferee, const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name, int igncallerstate, const char *language);
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311 static void *ast_bridge_call_thread(void *data)
00312 {
00313 struct ast_bridge_thread_obj *tobj = data;
00314 int res;
00315
00316 tobj->chan->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge";
00317 tobj->chan->data = tobj->peer->name;
00318 tobj->peer->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge";
00319 tobj->peer->data = tobj->chan->name;
00320
00321 ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
00322
00323 if (tobj->return_to_pbx) {
00324 if (!ast_check_hangup(tobj->peer)) {
00325 ast_log(LOG_VERBOSE, "putting peer %s into PBX again\n", tobj->peer->name);
00326 res = ast_pbx_start(tobj->peer);
00327 if (res != AST_PBX_SUCCESS)
00328 ast_log(LOG_WARNING, "FAILED continuing PBX on peer %s\n", tobj->peer->name);
00329 } else
00330 ast_hangup(tobj->peer);
00331 if (!ast_check_hangup(tobj->chan)) {
00332 ast_log(LOG_VERBOSE, "putting chan %s into PBX again\n", tobj->chan->name);
00333 res = ast_pbx_start(tobj->chan);
00334 if (res != AST_PBX_SUCCESS)
00335 ast_log(LOG_WARNING, "FAILED continuing PBX on chan %s\n", tobj->chan->name);
00336 } else
00337 ast_hangup(tobj->chan);
00338 } else {
00339 ast_hangup(tobj->chan);
00340 ast_hangup(tobj->peer);
00341 }
00342
00343 ast_free(tobj);
00344
00345 return NULL;
00346 }
00347
00348
00349
00350
00351
00352
00353
00354 static void ast_bridge_call_thread_launch(void *data)
00355 {
00356 pthread_t thread;
00357 pthread_attr_t attr;
00358 struct sched_param sched;
00359
00360 pthread_attr_init(&attr);
00361 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00362 ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data);
00363 pthread_attr_destroy(&attr);
00364 memset(&sched, 0, sizeof(sched));
00365 pthread_setschedparam(thread, SCHED_RR, &sched);
00366 }
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376 static int adsi_announce_park(struct ast_channel *chan, char *parkingexten)
00377 {
00378 int res;
00379 int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
00380 char tmp[256];
00381 char *message[5] = {NULL, NULL, NULL, NULL, NULL};
00382
00383 snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten);
00384 message[0] = tmp;
00385 res = ast_adsi_load_session(chan, NULL, 0, 1);
00386 if (res == -1)
00387 return res;
00388 return ast_adsi_print(chan, message, justify, 1);
00389 }
00390
00391
00392 static void notify_metermaids(const char *exten, char *context, enum ast_device_state state)
00393 {
00394 ast_debug(4, "Notification of state change to metermaids %s@%s\n to state '%s'",
00395 exten, context, devstate2str(state));
00396
00397 ast_devstate_changed(state, "park:%s@%s", exten, context);
00398 }
00399
00400
00401 static enum ast_device_state metermaidstate(const char *data)
00402 {
00403 char *context;
00404 char *exten;
00405
00406 context = ast_strdupa(data);
00407
00408 exten = strsep(&context, "@");
00409 if (!context)
00410 return AST_DEVICE_INVALID;
00411
00412 ast_debug(4, "Checking state of exten %s in context %s\n", exten, context);
00413
00414 if (!ast_exists_extension(NULL, context, exten, 1, NULL))
00415 return AST_DEVICE_NOT_INUSE;
00416
00417 return AST_DEVICE_INUSE;
00418 }
00419
00420 static struct parkeduser *park_space_reserve(struct ast_channel *chan)
00421 {
00422 struct parkeduser *pu, *cur;
00423 int i, parking_space = -1, parking_range;
00424 const char *parkingexten;
00425
00426
00427 if (!(pu = ast_calloc(1, sizeof(*pu))))
00428 return NULL;
00429
00430
00431 AST_LIST_LOCK(&parkinglot);
00432
00433 parkingexten = pbx_builtin_getvar_helper(chan, "PARKINGEXTEN");
00434 if (!ast_strlen_zero(parkingexten)) {
00435
00436
00437
00438
00439
00440
00441 if (sscanf(parkingexten, "%d", &parking_space) != 1 || parking_space < 0) {
00442 AST_LIST_UNLOCK(&parkinglot);
00443 ast_free(pu);
00444 ast_log(LOG_WARNING, "PARKINGEXTEN does not indicate a valid parking slot: '%s'.\n", parkingexten);
00445 return NULL;
00446 }
00447 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space);
00448
00449 if (ast_exists_extension(NULL, parking_con, pu->parkingexten, 1, NULL)) {
00450 AST_LIST_UNLOCK(&parkinglot);
00451 ast_free(pu);
00452 ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parking_con);
00453 return NULL;
00454 }
00455 } else {
00456
00457 parking_range = parking_stop - parking_start+1;
00458 for (i = 0; i < parking_range; i++) {
00459 parking_space = (i + parking_offset) % parking_range + parking_start;
00460 AST_LIST_TRAVERSE(&parkinglot, cur, list) {
00461 if (cur->parkingnum == parking_space)
00462 break;
00463 }
00464 if (!cur)
00465 break;
00466 }
00467
00468 if (!(i < parking_range)) {
00469 ast_log(LOG_WARNING, "No more parking spaces\n");
00470 ast_free(pu);
00471 AST_LIST_UNLOCK(&parkinglot);
00472 return NULL;
00473 }
00474
00475 if (parkfindnext)
00476 parking_offset = parking_space - parking_start + 1;
00477 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space);
00478 }
00479
00480 pu->notquiteyet = 1;
00481 pu->parkingnum = parking_space;
00482 AST_LIST_INSERT_TAIL(&parkinglot, pu, list);
00483 AST_LIST_UNLOCK(&parkinglot);
00484
00485 return pu;
00486 }
00487
00488
00489 static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout, const char *orig_chan_name, struct parkeduser *pu)
00490 {
00491 struct ast_context *con;
00492 const char *event_from;
00493
00494
00495 if (pu == NULL)
00496 pu = park_space_reserve(chan);
00497 if (pu == NULL)
00498 return 1;
00499
00500 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", pu->parkingnum);
00501
00502 chan->appl = "Parked Call";
00503 chan->data = NULL;
00504
00505 pu->chan = chan;
00506
00507
00508 if (chan != peer) {
00509 ast_indicate_data(pu->chan, AST_CONTROL_HOLD,
00510 S_OR(parkmohclass, NULL),
00511 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
00512 }
00513
00514 pu->start = ast_tvnow();
00515 pu->parkingtime = (timeout > 0) ? timeout : parkingtime;
00516 if (extout)
00517 *extout = pu->parkingnum;
00518
00519 if (peer) {
00520
00521
00522
00523
00524
00525 if (!strcasecmp(peer->tech->type, "Local")) {
00526 struct ast_channel *tmpchan, *base_peer;
00527 char other_side[AST_CHANNEL_NAME];
00528 char *c;
00529 ast_copy_string(other_side, S_OR(orig_chan_name, peer->name), sizeof(other_side));
00530 if ((c = strrchr(other_side, ';'))) {
00531 *++c = '1';
00532 }
00533 if ((tmpchan = ast_get_channel_by_name_locked(other_side))) {
00534 if ((base_peer = ast_bridged_channel(tmpchan))) {
00535 ast_copy_string(pu->peername, base_peer->name, sizeof(pu->peername));
00536 }
00537 ast_channel_unlock(tmpchan);
00538 }
00539 } else {
00540 ast_copy_string(pu->peername, S_OR(orig_chan_name, peer->name), sizeof(pu->peername));
00541 }
00542 }
00543
00544
00545
00546 ast_copy_string(pu->context, S_OR(chan->macrocontext, chan->context), sizeof(pu->context));
00547 ast_copy_string(pu->exten, S_OR(chan->macroexten, chan->exten), sizeof(pu->exten));
00548 pu->priority = chan->macropriority ? chan->macropriority : chan->priority;
00549
00550
00551
00552 if (peer != chan)
00553 pu->notquiteyet = 0;
00554
00555
00556 pthread_kill(parking_thread, SIGURG);
00557 ast_verb(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));
00558
00559 if (peer) {
00560 event_from = peer->name;
00561 } else {
00562 event_from = pbx_builtin_getvar_helper(chan, "BLINDTRANSFER");
00563 }
00564
00565 manager_event(EVENT_FLAG_CALL, "ParkedCall",
00566 "Exten: %s\r\n"
00567 "Channel: %s\r\n"
00568 "From: %s\r\n"
00569 "Timeout: %ld\r\n"
00570 "CallerIDNum: %s\r\n"
00571 "CallerIDName: %s\r\n"
00572 "Uniqueid: %s\r\n",
00573 pu->parkingexten, pu->chan->name, event_from ? event_from : "",
00574 (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL),
00575 S_OR(pu->chan->cid.cid_num, "<unknown>"),
00576 S_OR(pu->chan->cid.cid_name, "<unknown>"),
00577 pu->chan->uniqueid
00578 );
00579
00580 if (peer && adsipark && ast_adsi_available(peer)) {
00581 adsi_announce_park(peer, pu->parkingexten);
00582 ast_adsi_unload_session(peer);
00583 }
00584
00585 con = ast_context_find_or_create(NULL, NULL, parking_con, registrar);
00586 if (!con)
00587 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
00588 if (con) {
00589 if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, ast_strdup(pu->parkingexten), ast_free_ptr, registrar))
00590 notify_metermaids(pu->parkingexten, parking_con, AST_DEVICE_INUSE);
00591 }
00592
00593 if (peer && (ast_strlen_zero(orig_chan_name) || !strcasecmp(peer->name, orig_chan_name))) {
00594
00595 ast_set_flag(peer, AST_FLAG_MASQ_NOSTREAM);
00596 ast_say_digits(peer, pu->parkingnum, "", peer->language);
00597 ast_clear_flag(peer, AST_FLAG_MASQ_NOSTREAM);
00598 }
00599 if (pu->notquiteyet) {
00600
00601 ast_indicate_data(pu->chan, AST_CONTROL_HOLD,
00602 S_OR(parkmohclass, NULL),
00603 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
00604 pu->notquiteyet = 0;
00605 pthread_kill(parking_thread, SIGURG);
00606 }
00607 return 0;
00608 }
00609
00610
00611 int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
00612 {
00613 return park_call_full(chan, peer, timeout, extout, NULL, NULL);
00614 }
00615
00616 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)
00617 {
00618 struct ast_channel *chan;
00619 struct ast_frame *f;
00620 struct parkeduser *pu;
00621 int park_status;
00622
00623 if ((pu = park_space_reserve(rchan)) == NULL) {
00624 if (peer)
00625 ast_stream_and_wait(peer, "beeperr", "");
00626 return FEATURE_RETURN_PARKFAILED;
00627 }
00628
00629
00630 if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) {
00631 ast_log(LOG_WARNING, "Unable to create parked channel\n");
00632 return -1;
00633 }
00634
00635
00636 chan->readformat = rchan->readformat;
00637 chan->writeformat = rchan->writeformat;
00638 ast_channel_masquerade(chan, rchan);
00639
00640
00641 set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority);
00642
00643
00644 if ((f = ast_read(chan)))
00645 ast_frfree(f);
00646
00647 if (peer == rchan) {
00648 peer = chan;
00649 }
00650
00651 if (!play_announcement && !orig_chan_name) {
00652 orig_chan_name = ast_strdupa(chan->name);
00653 }
00654
00655 park_status = park_call_full(chan, peer, timeout, extout, orig_chan_name, pu);
00656 if (park_status == 1) {
00657
00658 ast_hangup(chan);
00659 return -1;
00660 }
00661 return 0;
00662 }
00663
00664
00665 int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
00666 {
00667 return masq_park_call(rchan, peer, timeout, extout, 0, NULL);
00668 }
00669
00670 static int masq_park_call_announce(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout, const char *orig_chan_name)
00671 {
00672 return masq_park_call(rchan, peer, timeout, extout, 1, orig_chan_name);
00673 }
00674
00675
00676
00677
00678
00679
00680
00681 static void set_peers(struct ast_channel **caller, struct ast_channel **callee,
00682 struct ast_channel *peer, struct ast_channel *chan, int sense)
00683 {
00684 if (sense == FEATURE_SENSE_PEER) {
00685 *caller = peer;
00686 *callee = chan;
00687 } else {
00688 *callee = peer;
00689 *caller = chan;
00690 }
00691 }
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705 static int builtin_parkcall(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00706 {
00707 struct ast_channel *parker;
00708 struct ast_channel *parkee;
00709 int res = 0;
00710
00711 set_peers(&parker, &parkee, peer, chan, sense);
00712
00713
00714
00715
00716
00717
00718
00719
00720 if (chan->_state != AST_STATE_UP)
00721 res = ast_answer(chan);
00722 if (!res)
00723 res = ast_safe_sleep(chan, 1000);
00724
00725 if (!res) {
00726 res = masq_park_call_announce(parkee, parker, 0, NULL, NULL);
00727
00728 }
00729 return res;
00730 }
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746 static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00747 {
00748 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
00749 int x = 0;
00750 size_t len;
00751 struct ast_channel *caller_chan, *callee_chan;
00752
00753 if (!monitor_ok) {
00754 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00755 return -1;
00756 }
00757
00758 if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) {
00759 monitor_ok = 0;
00760 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00761 return -1;
00762 }
00763
00764 set_peers(&caller_chan, &callee_chan, peer, chan, sense);
00765
00766 if (!ast_strlen_zero(courtesytone)) {
00767 if (ast_autoservice_start(callee_chan))
00768 return -1;
00769 if (ast_stream_and_wait(caller_chan, courtesytone, "")) {
00770 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
00771 ast_autoservice_stop(callee_chan);
00772 return -1;
00773 }
00774 if (ast_autoservice_stop(callee_chan))
00775 return -1;
00776 }
00777
00778 if (callee_chan->monitor) {
00779 ast_verb(4, "User hit '%s' to stop recording call.\n", code);
00780 callee_chan->monitor->stop(callee_chan, 1);
00781 return FEATURE_RETURN_SUCCESS;
00782 }
00783
00784 if (caller_chan && callee_chan) {
00785 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT");
00786 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
00787 const char *touch_monitor_prefix = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_PREFIX");
00788
00789 if (!touch_format)
00790 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
00791
00792 if (!touch_monitor)
00793 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
00794
00795 if (!touch_monitor_prefix)
00796 touch_monitor_prefix = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_PREFIX");
00797
00798 if (touch_monitor) {
00799 len = strlen(touch_monitor) + 50;
00800 args = alloca(len);
00801 touch_filename = alloca(len);
00802 snprintf(touch_filename, len, "%s-%ld-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), touch_monitor);
00803 snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename);
00804 } else {
00805 caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name));
00806 callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name));
00807 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
00808 args = alloca(len);
00809 touch_filename = alloca(len);
00810 snprintf(touch_filename, len, "%s-%ld-%s-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), caller_chan_id, callee_chan_id);
00811 snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename);
00812 }
00813
00814 for(x = 0; x < strlen(args); x++) {
00815 if (args[x] == '/')
00816 args[x] = '-';
00817 }
00818
00819 ast_verb(4, "User hit '%s' to record call. filename: %s\n", code, args);
00820
00821 pbx_exec(callee_chan, monitor_app, args);
00822 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
00823 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
00824
00825 return FEATURE_RETURN_SUCCESS;
00826 }
00827
00828 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");
00829 return -1;
00830 }
00831
00832 static int builtin_automixmonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00833 {
00834 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
00835 int x = 0;
00836 size_t len;
00837 struct ast_channel *caller_chan, *callee_chan;
00838 const char *mixmonitor_spy_type = "MixMonitor";
00839 int count = 0;
00840
00841 if (!mixmonitor_ok) {
00842 ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n");
00843 return -1;
00844 }
00845
00846 if (!(mixmonitor_app = pbx_findapp("MixMonitor"))) {
00847 mixmonitor_ok = 0;
00848 ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n");
00849 return -1;
00850 }
00851
00852 set_peers(&caller_chan, &callee_chan, peer, chan, sense);
00853
00854 if (!ast_strlen_zero(courtesytone)) {
00855 if (ast_autoservice_start(callee_chan))
00856 return -1;
00857 if (ast_stream_and_wait(caller_chan, courtesytone, "")) {
00858 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
00859 ast_autoservice_stop(callee_chan);
00860 return -1;
00861 }
00862 if (ast_autoservice_stop(callee_chan))
00863 return -1;
00864 }
00865
00866 ast_channel_lock(callee_chan);
00867 count = ast_channel_audiohook_count_by_source(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY);
00868 ast_channel_unlock(callee_chan);
00869
00870
00871 if (count > 0) {
00872
00873 ast_verb(3, "User hit '%s' to stop recording call.\n", code);
00874
00875
00876 ast_channel_lock(callee_chan);
00877 count = ast_channel_audiohook_count_by_source_running(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY);
00878 ast_channel_unlock(callee_chan);
00879 if (count > 0) {
00880 if (!stopmixmonitor_ok) {
00881 ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n");
00882 return -1;
00883 }
00884 if (!(stopmixmonitor_app = pbx_findapp("StopMixMonitor"))) {
00885 stopmixmonitor_ok = 0;
00886 ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n");
00887 return -1;
00888 } else {
00889 pbx_exec(callee_chan, stopmixmonitor_app, "");
00890 return FEATURE_RETURN_SUCCESS;
00891 }
00892 }
00893
00894 ast_log(LOG_WARNING,"Stopped MixMonitors are attached to the channel.\n");
00895 }
00896
00897 if (caller_chan && callee_chan) {
00898 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR_FORMAT");
00899 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR");
00900
00901 if (!touch_format)
00902 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR_FORMAT");
00903
00904 if (!touch_monitor)
00905 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR");
00906
00907 if (touch_monitor) {
00908 len = strlen(touch_monitor) + 50;
00909 args = alloca(len);
00910 touch_filename = alloca(len);
00911 snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor);
00912 snprintf(args, len, "%s.%s,b", touch_filename, (touch_format) ? touch_format : "wav");
00913 } else {
00914 caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name));
00915 callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name));
00916 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
00917 args = alloca(len);
00918 touch_filename = alloca(len);
00919 snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id);
00920 snprintf(args, len, "%s.%s,b", touch_filename, S_OR(touch_format, "wav"));
00921 }
00922
00923 for( x = 0; x < strlen(args); x++) {
00924 if (args[x] == '/')
00925 args[x] = '-';
00926 }
00927
00928 ast_verb(3, "User hit '%s' to record call. filename: %s\n", code, touch_filename);
00929
00930 pbx_exec(callee_chan, mixmonitor_app, args);
00931 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename);
00932 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename);
00933 return FEATURE_RETURN_SUCCESS;
00934
00935 }
00936
00937 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");
00938 return -1;
00939
00940 }
00941
00942 static int builtin_disconnect(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00943 {
00944 ast_verb(4, "User hit '%s' to disconnect call.\n", code);
00945 return FEATURE_RETURN_HANGUP;
00946 }
00947
00948 static int finishup(struct ast_channel *chan)
00949 {
00950 ast_indicate(chan, AST_CONTROL_UNHOLD);
00951
00952 return ast_autoservice_stop(chan);
00953 }
00954
00955
00956
00957
00958
00959
00960
00961
00962
00963 static const char *real_ctx(struct ast_channel *transferer, struct ast_channel *transferee)
00964 {
00965 const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT");
00966 if (ast_strlen_zero(s)) {
00967 s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT");
00968 }
00969 if (ast_strlen_zero(s)) {
00970 s = transferer->macrocontext;
00971 }
00972 if (ast_strlen_zero(s)) {
00973 s = transferer->context;
00974 }
00975 return s;
00976 }
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986
00987
00988
00989
00990
00991
00992 static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00993 {
00994 struct ast_channel *transferer;
00995 struct ast_channel *transferee;
00996 const char *transferer_real_context;
00997 char xferto[256];
00998 int res;
00999 int parkstatus = 0;
01000
01001 set_peers(&transferer, &transferee, peer, chan, sense);
01002 transferer_real_context = real_ctx(transferer, transferee);
01003
01004 ast_autoservice_start(transferee);
01005 ast_indicate(transferee, AST_CONTROL_HOLD);
01006
01007 memset(xferto, 0, sizeof(xferto));
01008
01009
01010 res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY);
01011 if (res < 0) {
01012 finishup(transferee);
01013 return -1;
01014 }
01015 if (res > 0)
01016 xferto[0] = (char) res;
01017
01018 ast_stopstream(transferer);
01019 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
01020 if (res < 0) {
01021 finishup(transferee);
01022 return res;
01023 }
01024 if (!strcmp(xferto, ast_parking_ext())) {
01025 res = finishup(transferee);
01026 if (res)
01027 res = -1;
01028 else if (!(parkstatus = masq_park_call_announce(transferee, transferer, 0, NULL, NULL))) {
01029
01030
01031
01032
01033 return 0;
01034 } else {
01035 ast_log(LOG_WARNING, "Unable to park call %s, parkstatus = %d\n", transferee->name, parkstatus);
01036 }
01037
01038 } else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
01039 pbx_builtin_setvar_helper(transferer, "BLINDTRANSFER", transferee->name);
01040 pbx_builtin_setvar_helper(transferee, "BLINDTRANSFER", transferer->name);
01041 res=finishup(transferee);
01042 if (!transferer->cdr) {
01043 transferer->cdr=ast_cdr_alloc();
01044 if (transferer->cdr) {
01045 ast_cdr_init(transferer->cdr, transferer);
01046 ast_cdr_start(transferer->cdr);
01047 }
01048 }
01049 if (transferer->cdr) {
01050 struct ast_cdr *swap = transferer->cdr;
01051 ast_log(LOG_DEBUG,"transferer=%s; transferee=%s; lastapp=%s; lastdata=%s; chan=%s; dstchan=%s\n",
01052 transferer->name, transferee->name, transferer->cdr->lastapp, transferer->cdr->lastdata,
01053 transferer->cdr->channel, transferer->cdr->dstchannel);
01054 ast_log(LOG_DEBUG,"TRANSFEREE; lastapp=%s; lastdata=%s, chan=%s; dstchan=%s\n",
01055 transferee->cdr->lastapp, transferee->cdr->lastdata, transferee->cdr->channel, transferee->cdr->dstchannel);
01056 ast_log(LOG_DEBUG,"transferer_real_context=%s; xferto=%s\n", transferer_real_context, xferto);
01057
01058 transferer->cdr = transferee->cdr;
01059 transferee->cdr = swap;
01060 }
01061 if (!transferee->pbx) {
01062
01063 ast_verb(3, "Transferring %s to '%s' (context %s) priority 1\n"
01064 ,transferee->name, xferto, transferer_real_context);
01065 if (ast_async_goto(transferee, transferer_real_context, xferto, 1))
01066 ast_log(LOG_WARNING, "Async goto failed :-(\n");
01067 } else {
01068
01069 ast_set_flag(transferee, AST_FLAG_BRIDGE_HANGUP_DONT);
01070 ast_log(LOG_DEBUG,"ABOUT TO AST_ASYNC_GOTO, have a pbx... set HANGUP_DONT on chan=%s\n", transferee->name);
01071 set_c_e_p(transferee, transferer_real_context, xferto, 0);
01072 }
01073 check_goto_on_transfer(transferer);
01074 return res;
01075 } else {
01076 ast_verb(3, "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context);
01077 }
01078 if (parkstatus != FEATURE_RETURN_PARKFAILED && ast_stream_and_wait(transferer, xferfailsound, AST_DIGIT_ANY) < 0) {
01079 finishup(transferee);
01080 return -1;
01081 }
01082 ast_stopstream(transferer);
01083 res = finishup(transferee);
01084 if (res) {
01085 ast_verb(2, "Hungup during autoservice stop on '%s'\n", transferee->name);
01086 return res;
01087 }
01088 return FEATURE_RETURN_SUCCESS;
01089 }
01090
01091
01092
01093
01094
01095
01096
01097
01098 static int check_compat(struct ast_channel *c, struct ast_channel *newchan)
01099 {
01100 if (ast_channel_make_compatible(c, newchan) < 0) {
01101 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n",
01102 c->name, newchan->name);
01103 ast_hangup(newchan);
01104 return -1;
01105 }
01106 return 0;
01107 }
01108
01109
01110
01111
01112
01113
01114
01115
01116
01117
01118
01119
01120
01121
01122
01123
01124 static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
01125 {
01126 struct ast_channel *transferer;
01127 struct ast_channel *transferee;
01128 const char *transferer_real_context;
01129 char xferto[256] = "";
01130 int res;
01131 int outstate=0;
01132 struct ast_channel *newchan;
01133 struct ast_channel *xferchan;
01134 struct ast_bridge_thread_obj *tobj;
01135 struct ast_bridge_config bconfig;
01136 struct ast_frame *f;
01137 int l;
01138 struct ast_datastore *features_datastore;
01139 struct ast_dial_features *dialfeatures = NULL;
01140
01141 ast_debug(1, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense);
01142 set_peers(&transferer, &transferee, peer, chan, sense);
01143 transferer_real_context = real_ctx(transferer, transferee);
01144
01145 ast_autoservice_start(transferee);
01146 ast_indicate(transferee, AST_CONTROL_HOLD);
01147
01148
01149 res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY);
01150 if (res < 0) {
01151 finishup(transferee);
01152 return res;
01153 }
01154 if (res > 0)
01155 xferto[0] = (char) res;
01156
01157
01158 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
01159 if (res < 0) {
01160 finishup(transferee);
01161 return res;
01162 }
01163 if (res == 0) {
01164 ast_log(LOG_WARNING, "Did not read data.\n");
01165 finishup(transferee);
01166 if (ast_stream_and_wait(transferer, "beeperr", ""))
01167 return -1;
01168 return FEATURE_RETURN_SUCCESS;
01169 }
01170
01171
01172 if (!ast_exists_extension(transferer, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
01173 ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context);
01174 finishup(transferee);
01175 if (ast_stream_and_wait(transferer, "beeperr", ""))
01176 return -1;
01177 return FEATURE_RETURN_SUCCESS;
01178 }
01179
01180
01181
01182 if (!strcmp(xferto, ast_parking_ext())) {
01183 finishup(transferee);
01184 return builtin_parkcall(chan, peer, config, code, sense, data);
01185 }
01186
01187 l = strlen(xferto);
01188 snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context);
01189 newchan = ast_feature_request_and_dial(transferer, transferee, "Local", ast_best_codec(transferer->nativeformats),
01190 xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, 1, transferer->language);
01191
01192 if (!ast_check_hangup(transferer)) {
01193
01194 ast_indicate(transferer, -1);
01195 if (!newchan) {
01196 finishup(transferee);
01197
01198 if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY &&
01199 ast_stream_and_wait(transferer, xferfailsound, ""))
01200 return -1;
01201 if (ast_stream_and_wait(transferer, xfersound, ""))
01202 ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
01203 return FEATURE_RETURN_SUCCESS;
01204 }
01205
01206 if (check_compat(transferer, newchan)) {
01207
01208 finishup(transferee);
01209 return -1;
01210 }
01211 memset(&bconfig,0,sizeof(struct ast_bridge_config));
01212 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
01213 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
01214 res = ast_bridge_call(transferer, newchan, &bconfig);
01215 if (ast_check_hangup(newchan) || !ast_check_hangup(transferer)) {
01216 ast_hangup(newchan);
01217 if (ast_stream_and_wait(transferer, xfersound, ""))
01218 ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
01219 finishup(transferee);
01220 transferer->_softhangup = 0;
01221 return FEATURE_RETURN_SUCCESS;
01222 }
01223 if (check_compat(transferee, newchan)) {
01224 finishup(transferee);
01225 return -1;
01226 }
01227 ast_indicate(transferee, AST_CONTROL_UNHOLD);
01228
01229 if ((ast_autoservice_stop(transferee) < 0)
01230 || (ast_waitfordigit(transferee, 100) < 0)
01231 || (ast_waitfordigit(newchan, 100) < 0)
01232 || ast_check_hangup(transferee)
01233 || ast_check_hangup(newchan)) {
01234 ast_hangup(newchan);
01235 return -1;
01236 }
01237 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name);
01238 if (!xferchan) {
01239 ast_hangup(newchan);
01240 return -1;
01241 }
01242
01243 xferchan->visible_indication = transferer->visible_indication;
01244 xferchan->readformat = transferee->readformat;
01245 xferchan->writeformat = transferee->writeformat;
01246 ast_channel_masquerade(xferchan, transferee);
01247 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
01248 xferchan->_state = AST_STATE_UP;
01249 ast_clear_flag(xferchan, AST_FLAGS_ALL);
01250 xferchan->_softhangup = 0;
01251 if ((f = ast_read(xferchan)))
01252 ast_frfree(f);
01253 newchan->_state = AST_STATE_UP;
01254 ast_clear_flag(newchan, AST_FLAGS_ALL);
01255 newchan->_softhangup = 0;
01256 if (!(tobj = ast_calloc(1, sizeof(*tobj)))) {
01257 ast_hangup(xferchan);
01258 ast_hangup(newchan);
01259 return -1;
01260 }
01261
01262 ast_channel_lock(newchan);
01263 if ((features_datastore = ast_channel_datastore_find(newchan, &dial_features_info, NULL))) {
01264 dialfeatures = features_datastore->data;
01265 }
01266 ast_channel_unlock(newchan);
01267
01268 if (dialfeatures) {
01269
01270
01271 ast_copy_flags(&(config->features_callee), &(dialfeatures->features_caller), AST_FLAGS_ALL);
01272 dialfeatures = NULL;
01273 }
01274
01275 ast_channel_lock(xferchan);
01276 if ((features_datastore = ast_channel_datastore_find(xferchan, &dial_features_info, NULL))) {
01277 dialfeatures = features_datastore->data;
01278 }
01279 ast_channel_unlock(xferchan);
01280
01281 if (dialfeatures) {
01282 ast_copy_flags(&(config->features_caller), &(dialfeatures->features_caller), AST_FLAGS_ALL);
01283 }
01284
01285 tobj->chan = newchan;
01286 tobj->peer = xferchan;
01287 tobj->bconfig = *config;
01288
01289 if (tobj->bconfig.end_bridge_callback_data_fixup) {
01290 tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan);
01291 }
01292
01293 if (ast_stream_and_wait(newchan, xfersound, ""))
01294 ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
01295 ast_bridge_call_thread_launch(tobj);
01296 return -1;
01297 } else if (!ast_check_hangup(transferee)) {
01298
01299 if (ast_autoservice_stop(transferee) < 0) {
01300 ast_hangup(newchan);
01301 return -1;
01302 }
01303
01304 if (!newchan) {
01305 unsigned int tries = 0;
01306 char *transferer_tech, *transferer_name = ast_strdupa(transferer->name);
01307
01308 transferer_tech = strsep(&transferer_name, "/");
01309 transferer_name = strsep(&transferer_name, "-");
01310
01311 if (ast_strlen_zero(transferer_name) || ast_strlen_zero(transferer_tech)) {
01312 ast_log(LOG_WARNING, "Transferer has invalid channel name: '%s'\n", transferer->name);
01313 if (ast_stream_and_wait(transferee, "beeperr", ""))
01314 return -1;
01315 return FEATURE_RETURN_SUCCESS;
01316 }
01317
01318 ast_log(LOG_NOTICE, "We're trying to call %s/%s\n", transferer_tech, transferer_name);
01319 newchan = ast_feature_request_and_dial(transferee, NULL, transferer_tech, ast_best_codec(transferee->nativeformats),
01320 transferer_name, atxfernoanswertimeout, &outstate, transferee->cid.cid_num, transferee->cid.cid_name, 0, transferer->language);
01321 while (!newchan && !atxferdropcall && tries < atxfercallbackretries) {
01322
01323 ast_autoservice_start(transferee);
01324 ast_indicate(transferee, AST_CONTROL_HOLD);
01325
01326 newchan = ast_feature_request_and_dial(transferer, transferee, "Local", ast_best_codec(transferer->nativeformats),
01327 xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, 1, transferer->language);
01328 if (ast_autoservice_stop(transferee) < 0) {
01329 if (newchan)
01330 ast_hangup(newchan);
01331 return -1;
01332 }
01333 if (!newchan) {
01334
01335 ast_debug(1, "Sleeping for %d ms before callback.\n", atxferloopdelay);
01336 ast_safe_sleep(transferee, atxferloopdelay);
01337 ast_debug(1, "Trying to callback...\n");
01338 newchan = ast_feature_request_and_dial(transferee, NULL, transferer_tech, ast_best_codec(transferee->nativeformats),
01339 transferer_name, atxfernoanswertimeout, &outstate, transferee->cid.cid_num, transferee->cid.cid_name, 0, transferer->language);
01340 }
01341 tries++;
01342 }
01343 }
01344 if (!newchan)
01345 return -1;
01346
01347
01348 if (check_compat(transferee, newchan)) {
01349 finishup(transferee);
01350 return -1;
01351 }
01352 ast_indicate(transferee, AST_CONTROL_UNHOLD);
01353
01354 if ((ast_waitfordigit(transferee, 100) < 0)
01355 || (ast_waitfordigit(newchan, 100) < 0)
01356 || ast_check_hangup(transferee)
01357 || ast_check_hangup(newchan)) {
01358 ast_hangup(newchan);
01359 return -1;
01360 }
01361
01362 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name);
01363 if (!xferchan) {
01364 ast_hangup(newchan);
01365 return -1;
01366 }
01367
01368 xferchan->visible_indication = transferer->visible_indication;
01369 xferchan->readformat = transferee->readformat;
01370 xferchan->writeformat = transferee->writeformat;
01371 ast_channel_masquerade(xferchan, transferee);
01372 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
01373 xferchan->_state = AST_STATE_UP;
01374 ast_clear_flag(xferchan, AST_FLAGS_ALL);
01375 xferchan->_softhangup = 0;
01376 if ((f = ast_read(xferchan)))
01377 ast_frfree(f);
01378 newchan->_state = AST_STATE_UP;
01379 ast_clear_flag(newchan, AST_FLAGS_ALL);
01380 newchan->_softhangup = 0;
01381 if (!(tobj = ast_calloc(1, sizeof(*tobj)))) {
01382 ast_hangup(xferchan);
01383 ast_hangup(newchan);
01384 return -1;
01385 }
01386 tobj->chan = newchan;
01387 tobj->peer = xferchan;
01388 tobj->bconfig = *config;
01389
01390 if (tobj->bconfig.end_bridge_callback_data_fixup) {
01391 tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan);
01392 }
01393
01394 if (ast_stream_and_wait(newchan, xfersound, ""))
01395 ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
01396 ast_bridge_call_thread_launch(tobj);
01397 return -1;
01398 } else {
01399
01400 finishup(transferee);
01401 return -1;
01402 }
01403 }
01404
01405
01406 #define FEATURES_COUNT ARRAY_LEN(builtin_features)
01407
01408 AST_RWLOCK_DEFINE_STATIC(features_lock);
01409
01410 static struct ast_call_feature builtin_features[] =
01411 {
01412 { AST_FEATURE_REDIRECT, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
01413 { AST_FEATURE_REDIRECT, "Attended Transfer", "atxfer", "", "", builtin_atxfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
01414 { AST_FEATURE_AUTOMON, "One Touch Monitor", "automon", "", "", builtin_automonitor, AST_FEATURE_FLAG_NEEDSDTMF, "" },
01415 { AST_FEATURE_DISCONNECT, "Disconnect Call", "disconnect", "*", "*", builtin_disconnect, AST_FEATURE_FLAG_NEEDSDTMF, "" },
01416 { AST_FEATURE_PARKCALL, "Park Call", "parkcall", "", "", builtin_parkcall, AST_FEATURE_FLAG_NEEDSDTMF, "" },
01417 { AST_FEATURE_AUTOMIXMON, "One Touch MixMonitor", "automixmon", "", "", builtin_automixmonitor, AST_FEATURE_FLAG_NEEDSDTMF, "" },
01418 };
01419
01420
01421 static AST_RWLIST_HEAD_STATIC(feature_list, ast_call_feature);
01422
01423
01424 void ast_register_feature(struct ast_call_feature *feature)
01425 {
01426 if (!feature) {
01427 ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
01428 return;
01429 }
01430
01431 AST_RWLIST_WRLOCK(&feature_list);
01432 AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry);
01433 AST_RWLIST_UNLOCK(&feature_list);
01434
01435 ast_verb(2, "Registered Feature '%s'\n",feature->sname);
01436 }
01437
01438
01439
01440
01441
01442
01443
01444
01445 static struct feature_group* register_group(const char *fgname)
01446 {
01447 struct feature_group *fg;
01448
01449 if (!fgname) {
01450 ast_log(LOG_NOTICE, "You didn't pass a new group name!\n");
01451 return NULL;
01452 }
01453
01454 if (!(fg = ast_calloc(1, sizeof(*fg))))
01455 return NULL;
01456
01457 if (ast_string_field_init(fg, 128)) {
01458 ast_free(fg);
01459 return NULL;
01460 }
01461
01462 ast_string_field_set(fg, gname, fgname);
01463
01464 AST_LIST_INSERT_HEAD(&feature_groups, fg, entry);
01465
01466 ast_verb(2, "Registered group '%s'\n", fg->gname);
01467
01468 return fg;
01469 }
01470
01471
01472
01473
01474
01475
01476
01477
01478
01479
01480 static void register_group_feature(struct feature_group *fg, const char *exten, struct ast_call_feature *feature)
01481 {
01482 struct feature_group_exten *fge;
01483
01484 if (!fg) {
01485 ast_log(LOG_NOTICE, "You didn't pass a group!\n");
01486 return;
01487 }
01488
01489 if (!feature) {
01490 ast_log(LOG_NOTICE, "You didn't pass a feature!\n");
01491 return;
01492 }
01493
01494 if (!(fge = ast_calloc(1, sizeof(*fge))))
01495 return;
01496
01497 if (ast_string_field_init(fge, 128)) {
01498 ast_free(fge);
01499 return;
01500 }
01501
01502 ast_string_field_set(fge, exten, S_OR(exten, feature->exten));
01503
01504 fge->feature = feature;
01505
01506 AST_LIST_INSERT_HEAD(&fg->features, fge, entry);
01507
01508 ast_verb(2, "Registered feature '%s' for group '%s' at exten '%s'\n",
01509 feature->sname, fg->gname, exten);
01510 }
01511
01512 void ast_unregister_feature(struct ast_call_feature *feature)
01513 {
01514 if (!feature) {
01515 return;
01516 }
01517
01518 AST_RWLIST_WRLOCK(&feature_list);
01519 AST_RWLIST_REMOVE(&feature_list, feature, feature_entry);
01520 AST_RWLIST_UNLOCK(&feature_list);
01521
01522 ast_free(feature);
01523 }
01524
01525
01526 static void ast_unregister_features(void)
01527 {
01528 struct ast_call_feature *feature;
01529
01530 AST_RWLIST_WRLOCK(&feature_list);
01531 while ((feature = AST_RWLIST_REMOVE_HEAD(&feature_list, feature_entry))) {
01532 ast_free(feature);
01533 }
01534 AST_RWLIST_UNLOCK(&feature_list);
01535 }
01536
01537
01538 static struct ast_call_feature *find_dynamic_feature(const char *name)
01539 {
01540 struct ast_call_feature *tmp;
01541
01542 AST_RWLIST_TRAVERSE(&feature_list, tmp, feature_entry) {
01543 if (!strcasecmp(tmp->sname, name)) {
01544 break;
01545 }
01546 }
01547
01548 return tmp;
01549 }
01550
01551
01552 static void ast_unregister_groups(void)
01553 {
01554 struct feature_group *fg;
01555 struct feature_group_exten *fge;
01556
01557 AST_RWLIST_WRLOCK(&feature_groups);
01558 while ((fg = AST_LIST_REMOVE_HEAD(&feature_groups, entry))) {
01559 while ((fge = AST_LIST_REMOVE_HEAD(&fg->features, entry))) {
01560 ast_string_field_free_memory(fge);
01561 ast_free(fge);
01562 }
01563
01564 ast_string_field_free_memory(fg);
01565 ast_free(fg);
01566 }
01567 AST_RWLIST_UNLOCK(&feature_groups);
01568 }
01569
01570
01571
01572
01573
01574
01575
01576 static struct feature_group *find_group(const char *name) {
01577 struct feature_group *fg = NULL;
01578
01579 AST_LIST_TRAVERSE(&feature_groups, fg, entry) {
01580 if (!strcasecmp(fg->gname, name))
01581 break;
01582 }
01583
01584 return fg;
01585 }
01586
01587 void ast_rdlock_call_features(void)
01588 {
01589 ast_rwlock_rdlock(&features_lock);
01590 }
01591
01592 void ast_unlock_call_features(void)
01593 {
01594 ast_rwlock_unlock(&features_lock);
01595 }
01596
01597 struct ast_call_feature *ast_find_call_feature(const char *name)
01598 {
01599 int x;
01600 for (x = 0; x < FEATURES_COUNT; x++) {
01601 if (!strcasecmp(name, builtin_features[x].sname))
01602 return &builtin_features[x];
01603 }
01604 return NULL;
01605 }
01606
01607
01608
01609
01610
01611
01612
01613
01614
01615 static int feature_exec_app(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
01616 {
01617 struct ast_app *app;
01618 struct ast_call_feature *feature = data;
01619 struct ast_channel *work, *idle;
01620 int res;
01621
01622 if (!feature) {
01623 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
01624 return -1;
01625 }
01626
01627 if (sense == FEATURE_SENSE_CHAN) {
01628 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
01629 return FEATURE_RETURN_KEEPTRYING;
01630 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
01631 work = chan;
01632 idle = peer;
01633 } else {
01634 work = peer;
01635 idle = chan;
01636 }
01637 } else {
01638 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
01639 return FEATURE_RETURN_KEEPTRYING;
01640 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
01641 work = peer;
01642 idle = chan;
01643 } else {
01644 work = chan;
01645 idle = peer;
01646 }
01647 }
01648
01649 if (!(app = pbx_findapp(feature->app))) {
01650 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
01651 return -2;
01652 }
01653
01654 ast_autoservice_start(idle);
01655
01656 if (!ast_strlen_zero(feature->moh_class))
01657 ast_moh_start(idle, feature->moh_class, NULL);
01658
01659 res = pbx_exec(work, app, feature->app_args);
01660
01661 if (!ast_strlen_zero(feature->moh_class))
01662 ast_moh_stop(idle);
01663
01664 ast_autoservice_stop(idle);
01665
01666 if (res) {
01667 return FEATURE_RETURN_SUCCESSBREAK;
01668 }
01669 return FEATURE_RETURN_SUCCESS;
01670 }
01671
01672 static void unmap_features(void)
01673 {
01674 int x;
01675
01676 ast_rwlock_wrlock(&features_lock);
01677 for (x = 0; x < FEATURES_COUNT; x++)
01678 strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
01679 ast_rwlock_unlock(&features_lock);
01680 }
01681
01682 static int remap_feature(const char *name, const char *value)
01683 {
01684 int x, res = -1;
01685
01686 ast_rwlock_wrlock(&features_lock);
01687 for (x = 0; x < FEATURES_COUNT; x++) {
01688 if (strcasecmp(builtin_features[x].sname, name))
01689 continue;
01690
01691 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
01692 res = 0;
01693 break;
01694 }
01695 ast_rwlock_unlock(&features_lock);
01696
01697 return res;
01698 }
01699
01700
01701
01702
01703
01704
01705
01706
01707
01708
01709
01710 static int feature_interpret_helper(struct ast_channel *chan, struct ast_channel *peer,
01711 struct ast_bridge_config *config, char *code, int sense, char *dynamic_features_buf,
01712 struct ast_flags *features, int operation, struct ast_call_feature *feature)
01713 {
01714 int x;
01715 struct feature_group *fg = NULL;
01716 struct feature_group_exten *fge;
01717 struct ast_call_feature *tmpfeature;
01718 char *tmp, *tok;
01719 int res = AST_FEATURE_RETURN_PASSDIGITS;
01720 int feature_detected = 0;
01721
01722 if (!(peer && chan && config) && operation) {
01723 return -1;
01724 }
01725
01726 ast_rwlock_rdlock(&features_lock);
01727 for (x = 0; x < FEATURES_COUNT; x++) {
01728 if ((ast_test_flag(features, builtin_features[x].feature_mask)) &&
01729 !ast_strlen_zero(builtin_features[x].exten)) {
01730
01731 if (!strcmp(builtin_features[x].exten, code)) {
01732 ast_debug(3, "Feature detected: fname=%s sname=%s exten=%s\n", builtin_features[x].fname, builtin_features[x].sname, builtin_features[x].exten);
01733 if (operation) {
01734 res = builtin_features[x].operation(chan, peer, config, code, sense, NULL);
01735 }
01736 memcpy(feature, &builtin_features[x], sizeof(feature));
01737 feature_detected = 1;
01738 break;
01739 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
01740 if (res == AST_FEATURE_RETURN_PASSDIGITS)
01741 res = AST_FEATURE_RETURN_STOREDIGITS;
01742 }
01743 }
01744 }
01745 ast_rwlock_unlock(&features_lock);
01746
01747 if (ast_strlen_zero(dynamic_features_buf) || feature_detected) {
01748 return res;
01749 }
01750
01751 tmp = dynamic_features_buf;
01752
01753 while ((tok = strsep(&tmp, "#"))) {
01754 AST_RWLIST_RDLOCK(&feature_groups);
01755
01756 fg = find_group(tok);
01757
01758 if (fg) {
01759 AST_LIST_TRAVERSE(&fg->features, fge, entry) {
01760 if (strcasecmp(fge->exten, code))
01761 continue;
01762 if (operation) {
01763 res = fge->feature->operation(chan, peer, config, code, sense, fge->feature);
01764 }
01765 memcpy(feature, fge->feature, sizeof(feature));
01766 if (res != AST_FEATURE_RETURN_KEEPTRYING) {
01767 AST_RWLIST_UNLOCK(&feature_groups);
01768 break;
01769 }
01770 res = AST_FEATURE_RETURN_PASSDIGITS;
01771 }
01772 if (fge)
01773 break;
01774 }
01775
01776 AST_RWLIST_UNLOCK(&feature_groups);
01777
01778 AST_RWLIST_RDLOCK(&feature_list);
01779
01780 if (!(tmpfeature = find_dynamic_feature(tok))) {
01781 AST_RWLIST_UNLOCK(&feature_list);
01782 continue;
01783 }
01784
01785
01786 if (!strcmp(tmpfeature->exten, code)) {
01787 ast_verb(3, " Feature Found: %s exten: %s\n",tmpfeature->sname, tok);
01788 if (operation) {
01789 res = tmpfeature->operation(chan, peer, config, code, sense, tmpfeature);
01790 }
01791 memcpy(feature, tmpfeature, sizeof(feature));
01792 if (res != AST_FEATURE_RETURN_KEEPTRYING) {
01793 AST_RWLIST_UNLOCK(&feature_list);
01794 break;
01795 }
01796 res = AST_FEATURE_RETURN_PASSDIGITS;
01797 } else if (!strncmp(tmpfeature->exten, code, strlen(code)))
01798 res = AST_FEATURE_RETURN_STOREDIGITS;
01799
01800 AST_RWLIST_UNLOCK(&feature_list);
01801 }
01802
01803 return res;
01804 }
01805
01806
01807
01808
01809
01810
01811
01812
01813 static int ast_feature_interpret(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) {
01814
01815 char dynamic_features_buf[128];
01816 const char *peer_dynamic_features, *chan_dynamic_features;
01817 struct ast_flags features;
01818 struct ast_call_feature feature;
01819 if (sense == FEATURE_SENSE_CHAN) {
01820 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
01821 }
01822 else {
01823 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);
01824 }
01825
01826 ast_channel_lock(peer);
01827 peer_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES"),""));
01828 ast_channel_unlock(peer);
01829
01830 ast_channel_lock(chan);
01831 chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),""));
01832 ast_channel_unlock(chan);
01833
01834 snprintf(dynamic_features_buf, sizeof(dynamic_features_buf), "%s%s%s", S_OR(chan_dynamic_features, ""), chan_dynamic_features && peer_dynamic_features ? "#" : "", S_OR(peer_dynamic_features,""));
01835
01836 ast_debug(3, "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_buf);
01837
01838 return feature_interpret_helper(chan, peer, config, code, sense, dynamic_features_buf, &features, 1, &feature);
01839 }
01840
01841
01842 int ast_feature_detect(struct ast_channel *chan, struct ast_flags *features, char *code, struct ast_call_feature *feature) {
01843
01844 return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, 0, feature);
01845 }
01846
01847 static void set_config_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
01848 {
01849 int x;
01850
01851 ast_clear_flag(config, AST_FLAGS_ALL);
01852
01853 ast_rwlock_rdlock(&features_lock);
01854 for (x = 0; x < FEATURES_COUNT; x++) {
01855 if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF))
01856 continue;
01857
01858 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
01859 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01860
01861 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
01862 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01863 }
01864 ast_rwlock_unlock(&features_lock);
01865
01866 if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
01867 const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
01868
01869 if (dynamic_features) {
01870 char *tmp = ast_strdupa(dynamic_features);
01871 char *tok;
01872 struct ast_call_feature *feature;
01873
01874
01875 while ((tok = strsep(&tmp, "#"))) {
01876 AST_RWLIST_RDLOCK(&feature_list);
01877 if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
01878 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
01879 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01880 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
01881 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01882 }
01883 AST_RWLIST_UNLOCK(&feature_list);
01884 }
01885 }
01886 }
01887 }
01888
01889
01890
01891
01892
01893
01894
01895
01896
01897
01898
01899
01900 static struct ast_channel *ast_feature_request_and_dial(struct ast_channel *caller, struct ast_channel *transferee, const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name, int igncallerstate, const char *language)
01901 {
01902 int state = 0;
01903 int cause = 0;
01904 int to;
01905 struct ast_channel *chan;
01906 struct ast_channel *monitor_chans[2];
01907 struct ast_channel *active_channel;
01908 int res = 0, ready = 0;
01909
01910 if ((chan = ast_request(type, format, data, &cause))) {
01911 ast_set_callerid(chan, cid_num, cid_name, cid_num);
01912 ast_string_field_set(chan, language, language);
01913 ast_channel_inherit_variables(caller, chan);
01914 pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name);
01915
01916 if (!ast_call(chan, data, timeout)) {
01917 struct timeval started;
01918 int x, len = 0;
01919 char *disconnect_code = NULL, *dialed_code = NULL;
01920
01921 ast_indicate(caller, AST_CONTROL_RINGING);
01922
01923 ast_rwlock_rdlock(&features_lock);
01924 for (x = 0; x < FEATURES_COUNT; x++) {
01925 if (strcasecmp(builtin_features[x].sname, "disconnect"))
01926 continue;
01927
01928 disconnect_code = builtin_features[x].exten;
01929 len = strlen(disconnect_code) + 1;
01930 dialed_code = alloca(len);
01931 memset(dialed_code, 0, len);
01932 break;
01933 }
01934 ast_rwlock_unlock(&features_lock);
01935 x = 0;
01936 started = ast_tvnow();
01937 to = timeout;
01938
01939 ast_poll_channel_add(caller, chan);
01940
01941 while (!((transferee && ast_check_hangup(transferee)) && (!igncallerstate && ast_check_hangup(caller))) && timeout && (chan->_state != AST_STATE_UP)) {
01942 struct ast_frame *f = NULL;
01943
01944 monitor_chans[0] = caller;
01945 monitor_chans[1] = chan;
01946 active_channel = ast_waitfor_n(monitor_chans, 2, &to);
01947
01948
01949 if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
01950 state = AST_CONTROL_UNHOLD;
01951 ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n");
01952 break;
01953 }
01954
01955 if (!active_channel)
01956 continue;
01957
01958 if (chan && (chan == active_channel)) {
01959 if (!ast_strlen_zero(chan->call_forward)) {
01960 if (!(chan = ast_call_forward(caller, chan, &to, format, NULL, outstate))) {
01961 return NULL;
01962 }
01963 continue;
01964 }
01965 f = ast_read(chan);
01966 if (f == NULL) {
01967 state = AST_CONTROL_HANGUP;
01968 res = 0;
01969 break;
01970 }
01971
01972 if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) {
01973 if (f->subclass == AST_CONTROL_RINGING) {
01974 state = f->subclass;
01975 ast_verb(3, "%s is ringing\n", chan->name);
01976 ast_indicate(caller, AST_CONTROL_RINGING);
01977 } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) {
01978 state = f->subclass;
01979 ast_verb(3, "%s is busy\n", chan->name);
01980 ast_indicate(caller, AST_CONTROL_BUSY);
01981 ast_frfree(f);
01982 f = NULL;
01983 break;
01984 } else if (f->subclass == AST_CONTROL_ANSWER) {
01985
01986 state = f->subclass;
01987 ast_frfree(f);
01988 f = NULL;
01989 ready=1;
01990 break;
01991 } else if (f->subclass != -1) {
01992 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass);
01993 }
01994
01995 }
01996
01997 } else if (caller && (active_channel == caller)) {
01998 f = ast_read(caller);
01999 if (f == NULL) {
02000 if (!igncallerstate) {
02001 if (ast_check_hangup(caller) && !ast_check_hangup(chan)) {
02002
02003 ready = 1;
02004 break;
02005 }
02006 state = AST_CONTROL_HANGUP;
02007 res = 0;
02008 break;
02009 }
02010 } else {
02011
02012 if (f->frametype == AST_FRAME_DTMF) {
02013 dialed_code[x++] = f->subclass;
02014 dialed_code[x] = '\0';
02015 if (strlen(dialed_code) == len) {
02016 x = 0;
02017 } else if (x && strncmp(dialed_code, disconnect_code, x)) {
02018 x = 0;
02019 dialed_code[x] = '\0';
02020 }
02021 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
02022
02023 state = AST_CONTROL_UNHOLD;
02024 ast_frfree(f);
02025 f = NULL;
02026 break;
02027 }
02028 }
02029 }
02030 }
02031 if (f)
02032 ast_frfree(f);
02033 }
02034
02035 ast_poll_channel_del(caller, chan);
02036
02037 } else
02038 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
02039 } else {
02040 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
02041 switch(cause) {
02042 case AST_CAUSE_BUSY:
02043 state = AST_CONTROL_BUSY;
02044 break;
02045 case AST_CAUSE_CONGESTION:
02046 state = AST_CONTROL_CONGESTION;
02047 break;
02048 }
02049 }
02050
02051 ast_indicate(caller, -1);
02052 if (chan && ready) {
02053 if (chan->_state == AST_STATE_UP)
02054 state = AST_CONTROL_ANSWER;
02055 res = 0;
02056 } else if(chan) {
02057 res = -1;
02058 ast_hangup(chan);
02059 chan = NULL;
02060 } else {
02061 res = -1;
02062 }
02063
02064 if (outstate)
02065 *outstate = state;
02066
02067 return chan;
02068 }
02069
02070
02071
02072
02073 static struct ast_cdr *pick_unlocked_cdr(struct ast_cdr *cdr)
02074 {
02075 struct ast_cdr *cdr_orig = cdr;
02076 while (cdr) {
02077 if (!ast_test_flag(cdr,AST_CDR_FLAG_LOCKED))
02078 return cdr;
02079 cdr = cdr->next;
02080 }
02081 return cdr_orig;
02082 }
02083
02084 static void set_bridge_features_on_config(struct ast_bridge_config *config, const char *features)
02085 {
02086 const char *feature;
02087
02088 if (ast_strlen_zero(features)) {
02089 return;
02090 }
02091
02092 for (feature = features; *feature; feature++) {
02093 switch (*feature) {
02094 case 'T' :
02095 case 't' :
02096 ast_set_flag(&(config->features_caller), AST_FEATURE_REDIRECT);
02097 break;
02098 case 'K' :
02099 case 'k' :
02100 ast_set_flag(&(config->features_caller), AST_FEATURE_PARKCALL);
02101 break;
02102 case 'H' :
02103 case 'h' :
02104 ast_set_flag(&(config->features_caller), AST_FEATURE_DISCONNECT);
02105 break;
02106 case 'W' :
02107 case 'w' :
02108 ast_set_flag(&(config->features_caller), AST_FEATURE_AUTOMON);
02109 break;
02110 default :
02111 ast_log(LOG_WARNING, "Skipping unknown feature code '%c'\n", *feature);
02112 }
02113 }
02114 }
02115
02116 static void add_features_datastores(struct ast_channel *caller, struct ast_channel *callee, struct ast_bridge_config *config)
02117 {
02118 struct ast_datastore *ds_callee_features = NULL, *ds_caller_features = NULL;
02119 struct ast_dial_features *callee_features = NULL, *caller_features = NULL;
02120
02121 ast_channel_lock(caller);
02122 ds_caller_features = ast_channel_datastore_find(caller, &dial_features_info, NULL);
02123 ast_channel_unlock(caller);
02124 if (!ds_caller_features) {
02125 if (!(ds_caller_features = ast_channel_datastore_alloc(&dial_features_info, NULL))) {
02126 ast_log(LOG_WARNING, "Unable to create channel datastore for caller features. Aborting!\n");
02127 return;
02128 }
02129 if (!(caller_features = ast_calloc(1, sizeof(*caller_features)))) {
02130 ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n");
02131 ast_channel_datastore_free(ds_caller_features);
02132 return;
02133 }
02134 ds_caller_features->inheritance = DATASTORE_INHERIT_FOREVER;
02135 caller_features->is_caller = 1;
02136 ast_copy_flags(&(caller_features->features_callee), &(config->features_callee), AST_FLAGS_ALL);
02137 ast_copy_flags(&(caller_features->features_caller), &(config->features_caller), AST_FLAGS_ALL);
02138 ds_caller_features->data = caller_features;
02139 ast_channel_lock(caller);
02140 ast_channel_datastore_add(caller, ds_caller_features);
02141 ast_channel_unlock(caller);
02142 } else {
02143
02144
02145 return;
02146 }
02147
02148 ast_channel_lock(callee);
02149 ds_callee_features = ast_channel_datastore_find(callee, &dial_features_info, NULL);
02150 ast_channel_unlock(callee);
02151 if (!ds_callee_features) {
02152 if (!(ds_callee_features = ast_channel_datastore_alloc(&dial_features_info, NULL))) {
02153 ast_log(LOG_WARNING, "Unable to create channel datastore for callee features. Aborting!\n");
02154 return;
02155 }
02156 if (!(callee_features = ast_calloc(1, sizeof(*callee_features)))) {
02157 ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n");
02158 ast_channel_datastore_free(ds_callee_features);
02159 return;
02160 }
02161 ds_callee_features->inheritance = DATASTORE_INHERIT_FOREVER;
02162 callee_features->is_caller = 0;
02163 ast_copy_flags(&(callee_features->features_callee), &(config->features_caller), AST_FLAGS_ALL);
02164 ast_copy_flags(&(callee_features->features_caller), &(config->features_callee), AST_FLAGS_ALL);
02165 ds_callee_features->data = callee_features;
02166 ast_channel_lock(callee);
02167 ast_channel_datastore_add(callee, ds_callee_features);
02168 ast_channel_unlock(callee);
02169 }
02170
02171 return;
02172 }
02173
02174
02175
02176
02177
02178
02179
02180
02181
02182
02183 int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast_bridge_config *config)
02184 {
02185
02186
02187 struct ast_frame *f;
02188 struct ast_channel *who;
02189 char chan_featurecode[FEATURE_MAX_LEN + 1]="";
02190 char peer_featurecode[FEATURE_MAX_LEN + 1]="";
02191 char orig_channame[AST_MAX_EXTENSION];
02192 char orig_peername[AST_MAX_EXTENSION];
02193 int res;
02194 int diff;
02195 int hasfeatures=0;
02196 int hadfeatures=0;
02197 int autoloopflag;
02198 struct ast_option_header *aoh;
02199 struct ast_bridge_config backup_config;
02200 struct ast_cdr *bridge_cdr = NULL;
02201 struct ast_cdr *orig_peer_cdr = NULL;
02202 struct ast_cdr *chan_cdr = pick_unlocked_cdr(chan->cdr);
02203 struct ast_cdr *peer_cdr = pick_unlocked_cdr(peer->cdr);
02204 struct ast_cdr *new_chan_cdr = NULL;
02205 struct ast_cdr *new_peer_cdr = NULL;
02206
02207 memset(&backup_config, 0, sizeof(backup_config));
02208
02209 config->start_time = ast_tvnow();
02210
02211 if (chan && peer) {
02212 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
02213 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
02214 } else if (chan) {
02215 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
02216 }
02217
02218 set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES"));
02219 add_features_datastores(chan, peer, config);
02220
02221
02222
02223
02224 if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) {
02225 ast_indicate(peer, AST_CONTROL_RINGING);
02226 }
02227
02228 if (monitor_ok) {
02229 const char *monitor_exec;
02230 struct ast_channel *src = NULL;
02231 if (!monitor_app) {
02232 if (!(monitor_app = pbx_findapp("Monitor")))
02233 monitor_ok=0;
02234 }
02235 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR")))
02236 src = chan;
02237 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
02238 src = peer;
02239 if (monitor_app && src) {
02240 char *tmp = ast_strdupa(monitor_exec);
02241 pbx_exec(src, monitor_app, tmp);
02242 }
02243 }
02244
02245 set_config_flags(chan, peer, config);
02246 config->firstpass = 1;
02247
02248
02249 if (chan->_state != AST_STATE_UP) {
02250 if (ast_raw_answer(chan, 1)) {
02251 return -1;
02252 }
02253 }
02254
02255 ast_copy_string(orig_channame,chan->name,sizeof(orig_channame));
02256 ast_copy_string(orig_peername,peer->name,sizeof(orig_peername));
02257 orig_peer_cdr = peer_cdr;
02258
02259 if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) {
02260
02261 if (chan_cdr) {
02262 ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN);
02263 ast_cdr_update(chan);
02264 bridge_cdr = ast_cdr_dup(chan_cdr);
02265 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp));
02266 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata));
02267 } else {
02268
02269 bridge_cdr = ast_cdr_alloc();
02270 ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel));
02271 ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel));
02272 ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid));
02273 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp));
02274 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata));
02275 ast_cdr_setcid(bridge_cdr, chan);
02276 bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ? AST_CDR_ANSWERED : AST_CDR_NULL;
02277 bridge_cdr->amaflags = chan->amaflags ? chan->amaflags : ast_default_amaflags;
02278 ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode));
02279
02280 ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst));
02281 ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext));
02282 if (peer_cdr) {
02283 bridge_cdr->start = peer_cdr->start;
02284 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield));
02285 } else {
02286 ast_cdr_start(bridge_cdr);
02287 }
02288 }
02289 ast_debug(4,"bridge answer set, chan answer set\n");
02290
02291
02292
02293
02294
02295
02296 if (peer_cdr && !ast_tvzero(peer_cdr->answer)) {
02297 bridge_cdr->answer = peer_cdr->answer;
02298 bridge_cdr->disposition = peer_cdr->disposition;
02299 if (chan_cdr) {
02300 chan_cdr->answer = peer_cdr->answer;
02301 chan_cdr->disposition = peer_cdr->disposition;
02302 }
02303 } else {
02304 ast_cdr_answer(bridge_cdr);
02305 if (chan_cdr) {
02306 ast_cdr_answer(chan_cdr);
02307 }
02308 }
02309 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT) && (chan_cdr || peer_cdr)) {
02310 if (chan_cdr) {
02311 ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED);
02312 }
02313 if (peer_cdr) {
02314 ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED);
02315 }
02316 }
02317 }
02318 for (;;) {
02319 struct ast_channel *other;
02320
02321 res = ast_channel_bridge(chan, peer, config, &f, &who);
02322
02323
02324
02325
02326
02327
02328
02329
02330 if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) {
02331
02332 diff = ast_tvdiff_ms(ast_tvnow(), config->start_time);
02333 if (res == AST_BRIDGE_RETRY) {
02334
02335
02336
02337 config->feature_timer = -1;
02338 } else {
02339 config->feature_timer -= diff;
02340 }
02341
02342 if (hasfeatures) {
02343
02344
02345
02346 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
02347 ast_debug(1, "Timed out, realtime this time!\n");
02348 config->feature_timer = 0;
02349 who = chan;
02350 if (f)
02351 ast_frfree(f);
02352 f = NULL;
02353 res = 0;
02354 } else if (config->feature_timer <= 0) {
02355
02356
02357 ast_debug(1, "Timed out for feature!\n");
02358 if (!ast_strlen_zero(peer_featurecode)) {
02359 ast_dtmf_stream(chan, peer, peer_featurecode, 0, 0);
02360 memset(peer_featurecode, 0, sizeof(peer_featurecode));
02361 }
02362 if (!ast_strlen_zero(chan_featurecode)) {
02363 ast_dtmf_stream(peer, chan, chan_featurecode, 0, 0);
02364 memset(chan_featurecode, 0, sizeof(chan_featurecode));
02365 }
02366 if (f)
02367 ast_frfree(f);
02368 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
02369 if (!hasfeatures) {
02370
02371 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
02372 memset(&backup_config, 0, sizeof(backup_config));
02373 }
02374 hadfeatures = hasfeatures;
02375
02376 continue;
02377 } else if (!f) {
02378
02379
02380
02381 continue;
02382 }
02383 } else {
02384 if (config->feature_timer <=0) {
02385
02386 config->feature_timer = 0;
02387 who = chan;
02388 if (f)
02389 ast_frfree(f);
02390 f = NULL;
02391 res = 0;
02392 }
02393 }
02394 }
02395 if (res < 0) {
02396 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer))
02397 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
02398 goto before_you_go;
02399 }
02400
02401 if (!f || (f->frametype == AST_FRAME_CONTROL &&
02402 (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY ||
02403 f->subclass == AST_CONTROL_CONGESTION))) {
02404 res = -1;
02405 break;
02406 }
02407
02408 other = (who == chan) ? peer : chan;
02409 if (f->frametype == AST_FRAME_CONTROL) {
02410 switch (f->subclass) {
02411 case AST_CONTROL_RINGING:
02412 case AST_CONTROL_FLASH:
02413 case -1:
02414 ast_indicate(other, f->subclass);
02415 break;
02416 case AST_CONTROL_HOLD:
02417 case AST_CONTROL_UNHOLD:
02418 ast_indicate_data(other, f->subclass, f->data, f->datalen);
02419 break;
02420 case AST_CONTROL_OPTION:
02421 aoh = f->data;
02422
02423 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) {
02424 ast_channel_setoption(other, ntohs(aoh->option), aoh->data,
02425 f->datalen - sizeof(struct ast_option_header), 0);
02426 }
02427 break;
02428 }
02429 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
02430
02431 } else if (f->frametype == AST_FRAME_DTMF) {
02432 char *featurecode;
02433 int sense;
02434
02435 hadfeatures = hasfeatures;
02436
02437 if (who == chan) {
02438 sense = FEATURE_SENSE_CHAN;
02439 featurecode = chan_featurecode;
02440 } else {
02441 sense = FEATURE_SENSE_PEER;
02442 featurecode = peer_featurecode;
02443 }
02444
02445
02446
02447
02448 featurecode[strlen(featurecode)] = f->subclass;
02449
02450 ast_frfree(f);
02451 f = NULL;
02452 config->feature_timer = backup_config.feature_timer;
02453 res = ast_feature_interpret(chan, peer, config, featurecode, sense);
02454 switch(res) {
02455 case FEATURE_RETURN_PASSDIGITS:
02456 ast_dtmf_stream(other, who, featurecode, 0, 0);
02457
02458 case FEATURE_RETURN_SUCCESS:
02459 memset(featurecode, 0, sizeof(chan_featurecode));
02460 break;
02461 }
02462 if (res >= FEATURE_RETURN_PASSDIGITS) {
02463 res = 0;
02464 } else
02465 break;
02466 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
02467 if (hadfeatures && !hasfeatures) {
02468
02469 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
02470 memset(&backup_config, 0, sizeof(struct ast_bridge_config));
02471 } else if (hasfeatures) {
02472 if (!hadfeatures) {
02473
02474 memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
02475
02476 config->play_warning = 0;
02477 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
02478 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
02479 config->warning_freq = 0;
02480 config->warning_sound = NULL;
02481 config->end_sound = NULL;
02482 config->start_sound = NULL;
02483 config->firstpass = 0;
02484 }
02485 config->start_time = ast_tvnow();
02486 config->feature_timer = featuredigittimeout;
02487 ast_debug(1, "Set time limit to %ld\n", config->feature_timer);
02488 }
02489 }
02490 if (f)
02491 ast_frfree(f);
02492
02493 }
02494 before_you_go:
02495
02496 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) {
02497 ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT);
02498 if (bridge_cdr) {
02499 ast_cdr_discard(bridge_cdr);
02500
02501 }
02502 return res;
02503 }
02504
02505 if (config->end_bridge_callback) {
02506 config->end_bridge_callback(config->end_bridge_callback_data);
02507 }
02508
02509 if (!ast_test_flag(&(config->features_caller),AST_FEATURE_NO_H_EXTEN) &&
02510 ast_exists_extension(chan, chan->context, "h", 1, chan->cid.cid_num)) {
02511 struct ast_cdr *swapper = NULL;
02512 char savelastapp[AST_MAX_EXTENSION];
02513 char savelastdata[AST_MAX_EXTENSION];
02514 char save_exten[AST_MAX_EXTENSION];
02515 int save_prio;
02516 int found = 0;
02517 int spawn_error = 0;
02518
02519 autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP);
02520 ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP);
02521 if (bridge_cdr && ast_opt_end_cdr_before_h_exten) {
02522 ast_cdr_end(bridge_cdr);
02523 }
02524
02525
02526 ast_channel_lock(chan);
02527 if (bridge_cdr) {
02528 swapper = chan->cdr;
02529 ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp));
02530 ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata));
02531 chan->cdr = bridge_cdr;
02532 }
02533 ast_copy_string(save_exten, chan->exten, sizeof(save_exten));
02534 save_prio = chan->priority;
02535 ast_copy_string(chan->exten, "h", sizeof(chan->exten));
02536 chan->priority = 1;
02537 ast_channel_unlock(chan);
02538 while ((spawn_error = ast_spawn_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num, &found, 1)) == 0) {
02539 chan->priority++;
02540 }
02541 if (found && spawn_error) {
02542
02543 ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name);
02544 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name);
02545 }
02546
02547 ast_channel_lock(chan);
02548 ast_copy_string(chan->exten, save_exten, sizeof(chan->exten));
02549 chan->priority = save_prio;
02550 if (bridge_cdr) {
02551 if (chan->cdr == bridge_cdr) {
02552 chan->cdr = swapper;
02553 } else {
02554 bridge_cdr = NULL;
02555 }
02556 }
02557 if (chan->priority != 1 || !spawn_error) {
02558 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN);
02559 }
02560 ast_channel_unlock(chan);
02561
02562 if (bridge_cdr) {
02563 ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp));
02564 ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata));
02565 }
02566 ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP);
02567 }
02568
02569
02570 new_chan_cdr = pick_unlocked_cdr(chan->cdr);
02571 if (bridge_cdr && new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED))
02572 ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED);
02573
02574
02575 if (bridge_cdr) {
02576 ast_cdr_end(bridge_cdr);
02577 ast_cdr_detach(bridge_cdr);
02578 }
02579
02580
02581
02582
02583
02584
02585
02586
02587
02588
02589
02590
02591
02592
02593
02594
02595
02596
02597
02598
02599
02600
02601
02602
02603
02604 if (new_chan_cdr) {
02605 struct ast_channel *chan_ptr = NULL;
02606
02607 if (strcasecmp(orig_channame, chan->name) != 0) {
02608
02609 chan_ptr = ast_get_channel_by_name_locked(orig_channame);
02610 if (chan_ptr) {
02611 if (!ast_bridged_channel(chan_ptr)) {
02612 struct ast_cdr *cur;
02613 for (cur = chan_ptr->cdr; cur; cur = cur->next) {
02614 if (cur == chan_cdr) {
02615 break;
02616 }
02617 }
02618 if (cur)
02619 ast_cdr_specialized_reset(chan_cdr,0);
02620 }
02621 ast_channel_unlock(chan_ptr);
02622 }
02623
02624 ast_cdr_specialized_reset(new_chan_cdr,0);
02625 } else {
02626 ast_cdr_specialized_reset(chan_cdr,0);
02627 }
02628 }
02629
02630 {
02631 struct ast_channel *chan_ptr = NULL;
02632 new_peer_cdr = pick_unlocked_cdr(peer->cdr);
02633 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))
02634 ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED);
02635 if (strcasecmp(orig_peername, peer->name) != 0) {
02636
02637 chan_ptr = ast_get_channel_by_name_locked(orig_peername);
02638 if (chan_ptr) {
02639 if (!ast_bridged_channel(chan_ptr)) {
02640 struct ast_cdr *cur;
02641 for (cur = chan_ptr->cdr; cur; cur = cur->next) {
02642 if (cur == peer_cdr) {
02643 break;
02644 }
02645 }
02646 if (cur)
02647 ast_cdr_specialized_reset(peer_cdr,0);
02648 }
02649 ast_channel_unlock(chan_ptr);
02650 }
02651
02652 ast_cdr_specialized_reset(new_peer_cdr,0);
02653 } else {
02654 ast_cdr_specialized_reset(peer_cdr,0);
02655 }
02656 }
02657
02658 return res;
02659 }
02660
02661
02662 static void post_manager_event(const char *s, struct parkeduser *pu)
02663 {
02664 manager_event(EVENT_FLAG_CALL, s,
02665 "Exten: %s\r\n"
02666 "Channel: %s\r\n"
02667 "CallerIDNum: %s\r\n"
02668 "CallerIDName: %s\r\n\r\n",
02669 pu->parkingexten,
02670 pu->chan->name,
02671 S_OR(pu->chan->cid.cid_num, "<unknown>"),
02672 S_OR(pu->chan->cid.cid_name, "<unknown>")
02673 );
02674 }
02675
02676 static char *callback_dialoptions(struct ast_flags *features_callee, struct ast_flags *features_caller, char *options, size_t len)
02677 {
02678 int i = 0;
02679 enum {
02680 OPT_CALLEE_REDIRECT = 't',
02681 OPT_CALLER_REDIRECT = 'T',
02682 OPT_CALLEE_AUTOMON = 'w',
02683 OPT_CALLER_AUTOMON = 'W',
02684 OPT_CALLEE_DISCONNECT = 'h',
02685 OPT_CALLER_DISCONNECT = 'H',
02686 OPT_CALLEE_PARKCALL = 'k',
02687 OPT_CALLER_PARKCALL = 'K',
02688 };
02689
02690 memset(options, 0, len);
02691 if (ast_test_flag(features_caller, AST_FEATURE_REDIRECT) && i < len) {
02692 options[i++] = OPT_CALLER_REDIRECT;
02693 }
02694 if (ast_test_flag(features_caller, AST_FEATURE_AUTOMON) && i < len) {
02695 options[i++] = OPT_CALLER_AUTOMON;
02696 }
02697 if (ast_test_flag(features_caller, AST_FEATURE_DISCONNECT) && i < len) {
02698 options[i++] = OPT_CALLER_DISCONNECT;
02699 }
02700 if (ast_test_flag(features_caller, AST_FEATURE_PARKCALL) && i < len) {
02701 options[i++] = OPT_CALLER_PARKCALL;
02702 }
02703
02704 if (ast_test_flag(features_callee, AST_FEATURE_REDIRECT) && i < len) {
02705 options[i++] = OPT_CALLEE_REDIRECT;
02706 }
02707 if (ast_test_flag(features_callee, AST_FEATURE_AUTOMON) && i < len) {
02708 options[i++] = OPT_CALLEE_AUTOMON;
02709 }
02710 if (ast_test_flag(features_callee, AST_FEATURE_DISCONNECT) && i < len) {
02711 options[i++] = OPT_CALLEE_DISCONNECT;
02712 }
02713 if (ast_test_flag(features_callee, AST_FEATURE_PARKCALL) && i < len) {
02714 options[i++] = OPT_CALLEE_PARKCALL;
02715 }
02716
02717 return options;
02718 }
02719
02720
02721
02722
02723
02724
02725
02726
02727
02728 static void *do_parking_thread(void *ignore)
02729 {
02730 char parkingslot[AST_MAX_EXTENSION];
02731 fd_set rfds, efds;
02732
02733 FD_ZERO(&rfds);
02734 FD_ZERO(&efds);
02735
02736 for (;;) {
02737 struct parkeduser *pu;
02738 int ms = -1;
02739 int max = -1;
02740 fd_set nrfds, nefds;
02741 FD_ZERO(&nrfds);
02742 FD_ZERO(&nefds);
02743
02744 AST_LIST_LOCK(&parkinglot);
02745 AST_LIST_TRAVERSE_SAFE_BEGIN(&parkinglot, pu, list) {
02746 struct ast_channel *chan = pu->chan;
02747 int tms;
02748 int x;
02749 struct ast_context *con;
02750
02751 if (pu->notquiteyet)
02752 continue;
02753 tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
02754 if (tms > pu->parkingtime) {
02755 ast_indicate(chan, AST_CONTROL_UNHOLD);
02756
02757 if (pu->peername[0]) {
02758 char *peername = ast_strdupa(pu->peername);
02759 char *cp = strrchr(peername, '-');
02760 char peername_flat[AST_MAX_EXTENSION];
02761 int i;
02762
02763 if (cp)
02764 *cp = 0;
02765 ast_copy_string(peername_flat,peername,sizeof(peername_flat));
02766 for(i=0; peername_flat[i] && i < AST_MAX_EXTENSION; i++) {
02767 if (peername_flat[i] == '/')
02768 peername_flat[i]= '0';
02769 }
02770 con = ast_context_find_or_create(NULL, NULL, parking_con_dial, registrar);
02771 if (!con)
02772 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
02773 if (con) {
02774 char returnexten[AST_MAX_EXTENSION];
02775 struct ast_datastore *features_datastore;
02776 struct ast_dial_features *dialfeatures = NULL;
02777
02778 ast_channel_lock(chan);
02779
02780 if ((features_datastore = ast_channel_datastore_find(chan, &dial_features_info, NULL)))
02781 dialfeatures = features_datastore->data;
02782
02783 ast_channel_unlock(chan);
02784
02785 if (!strncmp(peername, "Parked/", 7)) {
02786 peername += 7;
02787 }
02788
02789 if (dialfeatures) {
02790 char buf[MAX_DIAL_FEATURE_OPTIONS] = {0,};
02791 snprintf(returnexten, sizeof(returnexten), "%s,30,%s", peername, callback_dialoptions(&(dialfeatures->features_callee), &(dialfeatures->features_caller), buf, sizeof(buf)));
02792 } else {
02793 snprintf(returnexten, sizeof(returnexten), "%s,30,t", peername);
02794 }
02795 ast_add_extension2(con, 1, peername_flat, 1, NULL, NULL, "Dial", ast_strdup(returnexten), ast_free_ptr, registrar);
02796 }
02797 if (comebacktoorigin) {
02798 set_c_e_p(chan, parking_con_dial, peername_flat, 1);
02799 } else {
02800 ast_log(LOG_WARNING, "now going to parkedcallstimeout,s,1 | ps is %d\n",pu->parkingnum);
02801 snprintf(parkingslot, sizeof(parkingslot), "%d", pu->parkingnum);
02802 pbx_builtin_setvar_helper(pu->chan, "PARKINGSLOT", parkingslot);
02803 set_c_e_p(chan, "parkedcallstimeout", peername_flat, 1);
02804 }
02805 } else {
02806
02807
02808 set_c_e_p(chan, pu->context, pu->exten, pu->priority);
02809 }
02810
02811 post_manager_event("ParkedCallTimeOut", pu);
02812
02813 ast_verb(2, "Timeout for %s parked on %d. Returning to %s,%s,%d\n", chan->name, pu->parkingnum, chan->context, chan->exten, chan->priority);
02814
02815 if (ast_pbx_start(chan)) {
02816 ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", chan->name);
02817 ast_hangup(chan);
02818 }
02819
02820 AST_LIST_REMOVE_CURRENT(list);
02821 con = ast_context_find(parking_con);
02822 if (con) {
02823 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0))
02824 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
02825 else
02826 notify_metermaids(pu->parkingexten, parking_con, AST_DEVICE_NOT_INUSE);
02827 } else
02828 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
02829 ast_free(pu);
02830 } else {
02831 for (x = 0; x < AST_MAX_FDS; x++) {
02832 struct ast_frame *f;
02833
02834 if (chan->fds[x] == -1 || (!FD_ISSET(chan->fds[x], &rfds) && !FD_ISSET(chan->fds[x], &efds)))
02835 continue;
02836
02837 if (FD_ISSET(chan->fds[x], &efds))
02838 ast_set_flag(chan, AST_FLAG_EXCEPTION);
02839 else
02840 ast_clear_flag(chan, AST_FLAG_EXCEPTION);
02841 chan->fdno = x;
02842
02843
02844 f = ast_read(chan);
02845 if (!f || (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_HANGUP)) {
02846 if (f)
02847 ast_frfree(f);
02848 post_manager_event("ParkedCallGiveUp", pu);
02849
02850
02851 ast_verb(2, "%s got tired of being parked\n", chan->name);
02852 ast_hangup(chan);
02853
02854 AST_LIST_REMOVE_CURRENT(list);
02855 con = ast_context_find(parking_con);
02856 if (con) {
02857 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0))
02858 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
02859 else
02860 notify_metermaids(pu->parkingexten, parking_con, AST_DEVICE_NOT_INUSE);
02861 } else
02862 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
02863 ast_free(pu);
02864 break;
02865 } else {
02866
02867 ast_frfree(f);
02868 if (pu->moh_trys < 3 && !chan->generatordata) {
02869 ast_debug(1, "MOH on parked call stopped by outside source. Restarting.\n");
02870 ast_indicate_data(chan, AST_CONTROL_HOLD,
02871 S_OR(parkmohclass, NULL),
02872 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
02873 pu->moh_trys++;
02874 }
02875 goto std;
02876 }
02877
02878 }
02879 if (x >= AST_MAX_FDS) {
02880 std: for (x=0; x<AST_MAX_FDS; x++) {
02881 if (chan->fds[x] > -1) {
02882 FD_SET(chan->fds[x], &nrfds);
02883 FD_SET(chan->fds[x], &nefds);
02884 if (chan->fds[x] > max)
02885 max = chan->fds[x];
02886 }
02887 }
02888
02889 if (tms < ms || ms < 0)
02890 ms = tms;
02891 }
02892 }
02893 }
02894 AST_LIST_TRAVERSE_SAFE_END
02895 AST_LIST_UNLOCK(&parkinglot);
02896 rfds = nrfds;
02897 efds = nefds;
02898 {
02899 struct timeval tv = ast_samp2tv(ms, 1000);
02900
02901 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
02902 }
02903 pthread_testcancel();
02904 }
02905 return NULL;
02906 }
02907
02908
02909 static int park_call_exec(struct ast_channel *chan, void *data)
02910 {
02911 char *orig_chan_name = ast_strdupa(chan->name);
02912 char orig_exten[AST_MAX_EXTENSION];
02913 int orig_priority = chan->priority;
02914
02915
02916
02917 int res = 0;
02918
02919 ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten));
02920
02921
02922
02923 strcpy(chan->exten, "s");
02924 chan->priority = 1;
02925
02926 if (chan->_state != AST_STATE_UP)
02927 res = ast_answer(chan);
02928
02929 if (!res)
02930 res = ast_safe_sleep(chan, 1000);
02931
02932 if (!res) {
02933 res = masq_park_call_announce(chan, chan, 0, NULL, orig_chan_name);
02934
02935 if (res == 1) {
02936 ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten));
02937 chan->priority = orig_priority;
02938 res = 0;
02939 } else if (!res) {
02940 res = 1;
02941 }
02942 }
02943
02944 return res;
02945 }
02946
02947
02948 static int park_exec(struct ast_channel *chan, void *data)
02949 {
02950 int res = 0;
02951 struct ast_channel *peer=NULL;
02952 struct parkeduser *pu;
02953 struct ast_context *con;
02954 int park = 0;
02955 struct ast_bridge_config config;
02956
02957 if (data)
02958 park = atoi((char *)data);
02959
02960 AST_LIST_LOCK(&parkinglot);
02961 AST_LIST_TRAVERSE_SAFE_BEGIN(&parkinglot, pu, list) {
02962 if (!data || pu->parkingnum == park) {
02963 AST_LIST_REMOVE_CURRENT(list);
02964 break;
02965 }
02966 }
02967 AST_LIST_TRAVERSE_SAFE_END
02968 AST_LIST_UNLOCK(&parkinglot);
02969
02970 if (pu) {
02971 peer = pu->chan;
02972 con = ast_context_find(parking_con);
02973 if (con) {
02974 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0))
02975 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
02976 else
02977 notify_metermaids(pu->parkingexten, parking_con, AST_DEVICE_NOT_INUSE);
02978 } else
02979 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
02980
02981 manager_event(EVENT_FLAG_CALL, "UnParkedCall",
02982 "Exten: %s\r\n"
02983 "Channel: %s\r\n"
02984 "From: %s\r\n"
02985 "CallerIDNum: %s\r\n"
02986 "CallerIDName: %s\r\n",
02987 pu->parkingexten, pu->chan->name, chan->name,
02988 S_OR(pu->chan->cid.cid_num, "<unknown>"),
02989 S_OR(pu->chan->cid.cid_name, "<unknown>")
02990 );
02991
02992 ast_free(pu);
02993 }
02994
02995 if (chan->_state != AST_STATE_UP)
02996 ast_answer(chan);
02997
02998 if (peer) {
02999 struct ast_datastore *features_datastore;
03000 struct ast_dial_features *dialfeatures = NULL;
03001
03002
03003
03004 if (!ast_strlen_zero(courtesytone)) {
03005 int error = 0;
03006 ast_indicate(peer, AST_CONTROL_UNHOLD);
03007 if (parkedplay == 0) {
03008 error = ast_stream_and_wait(chan, courtesytone, "");
03009 } else if (parkedplay == 1) {
03010 error = ast_stream_and_wait(peer, courtesytone, "");
03011 } else if (parkedplay == 2) {
03012 if (!ast_streamfile(chan, courtesytone, chan->language) &&
03013 !ast_streamfile(peer, courtesytone, chan->language)) {
03014
03015 res = ast_waitstream(chan, "");
03016 if (res >= 0)
03017 res = ast_waitstream(peer, "");
03018 if (res < 0)
03019 error = 1;
03020 }
03021 }
03022 if (error) {
03023 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
03024 ast_hangup(peer);
03025 return -1;
03026 }
03027 } else
03028 ast_indicate(peer, AST_CONTROL_UNHOLD);
03029
03030 res = ast_channel_make_compatible(chan, peer);
03031 if (res < 0) {
03032 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
03033 ast_hangup(peer);
03034 return -1;
03035 }
03036
03037
03038 ast_verb(3, "Channel %s connected to parked call %d\n", chan->name, park);
03039
03040 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
03041 ast_cdr_setdestchan(chan->cdr, peer->name);
03042 memset(&config, 0, sizeof(struct ast_bridge_config));
03043
03044
03045 ast_channel_lock(peer);
03046 if ((features_datastore = ast_channel_datastore_find(peer, &dial_features_info, NULL))) {
03047 dialfeatures = features_datastore->data;
03048 }
03049 ast_channel_unlock(peer);
03050
03051 if (dialfeatures) {
03052 ast_copy_flags(&(config.features_callee), dialfeatures->is_caller ? &(dialfeatures->features_caller) : &(dialfeatures->features_callee), AST_FLAGS_ALL);
03053 }
03054
03055 if ((parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
03056 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
03057 }
03058 if ((parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
03059 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
03060 }
03061 if ((parkedcallreparking == AST_FEATURE_FLAG_BYCALLEE) || (parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
03062 ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL);
03063 }
03064 if ((parkedcallreparking == AST_FEATURE_FLAG_BYCALLER) || (parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
03065 ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL);
03066 }
03067 if ((parkedcallhangup == AST_FEATURE_FLAG_BYCALLEE) || (parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
03068 ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT);
03069 }
03070 if ((parkedcallhangup == AST_FEATURE_FLAG_BYCALLER) || (parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
03071 ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT);
03072 }
03073 if ((parkedcallrecording == AST_FEATURE_FLAG_BYCALLEE) || (parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
03074 ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
03075 }
03076 if ((parkedcallrecording == AST_FEATURE_FLAG_BYCALLER) || (parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
03077 ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
03078 }
03079
03080 res = ast_bridge_call(chan, peer, &config);
03081
03082 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
03083 ast_cdr_setdestchan(chan->cdr, peer->name);
03084
03085
03086 ast_hangup(peer);
03087 return -1;
03088 } else {
03089
03090 if (ast_stream_and_wait(chan, "pbx-invalidpark", ""))
03091 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
03092 ast_verb(3, "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
03093 res = -1;
03094 }
03095
03096 return -1;
03097 }
03098
03099
03100
03101
03102
03103
03104
03105 static void park_add_hints(char *context, int start, int stop)
03106 {
03107 int numext;
03108 char device[AST_MAX_EXTENSION];
03109 char exten[10];
03110
03111 for (numext = start; numext <= stop; numext++) {
03112 snprintf(exten, sizeof(exten), "%d", numext);
03113 snprintf(device, sizeof(device), "park:%s@%s", exten, context);
03114 ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
03115 }
03116 }
03117
03118 static int load_config(void)
03119 {
03120 int start = 0, end = 0;
03121 int res;
03122 int i;
03123 struct ast_context *con = NULL;
03124 struct ast_config *cfg = NULL;
03125 struct ast_variable *var = NULL;
03126 struct feature_group *fg = NULL;
03127 struct ast_flags config_flags = { 0 };
03128 char old_parking_ext[AST_MAX_EXTENSION];
03129 char old_parking_con[AST_MAX_EXTENSION] = "";
03130 char *ctg;
03131 static const char *categories[] = {
03132
03133
03134
03135 "general",
03136 "featuremap",
03137 "applicationmap"
03138 };
03139
03140 if (!ast_strlen_zero(parking_con)) {
03141 strcpy(old_parking_ext, parking_ext);
03142 strcpy(old_parking_con, parking_con);
03143 }
03144
03145
03146 strcpy(parking_con, "parkedcalls");
03147 strcpy(parking_con_dial, "park-dial");
03148 strcpy(parking_ext, "700");
03149 strcpy(pickup_ext, "*8");
03150 strcpy(parkmohclass, "default");
03151 courtesytone[0] = '\0';
03152 strcpy(xfersound, "beep");
03153 strcpy(xferfailsound, "pbx-invalid");
03154 parking_start = 701;
03155 parking_stop = 750;
03156 parkfindnext = 0;
03157 adsipark = 0;
03158 comebacktoorigin = 1;
03159 parkaddhints = 0;
03160 parkedcalltransfers = 0;
03161 parkedcallreparking = 0;
03162 parkedcallrecording = 0;
03163 parkedcallhangup = 0;
03164
03165 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
03166 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
03167 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
03168 atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY;
03169 atxferdropcall = DEFAULT_ATXFER_DROP_CALL;
03170 atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES;
03171
03172 cfg = ast_config_load("features.conf", config_flags);
03173 if (!cfg) {
03174 ast_log(LOG_WARNING,"Could not load features.conf\n");
03175 return 0;
03176 }
03177 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
03178 if (!strcasecmp(var->name, "parkext")) {
03179 ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
03180 } else if (!strcasecmp(var->name, "context")) {
03181 ast_copy_string(parking_con, var->value, sizeof(parking_con));
03182 } else if (!strcasecmp(var->name, "parkingtime")) {
03183 if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) {
03184 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
03185 parkingtime = DEFAULT_PARK_TIME;
03186 } else
03187 parkingtime = parkingtime * 1000;
03188 } else if (!strcasecmp(var->name, "parkpos")) {
03189 if (sscanf(var->value, "%d-%d", &start, &end) != 2) {
03190 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);
03191 } else {
03192 parking_start = start;
03193 parking_stop = end;
03194 }
03195 } else if (!strcasecmp(var->name, "findslot")) {
03196 parkfindnext = (!strcasecmp(var->value, "next"));
03197 } else if (!strcasecmp(var->name, "parkinghints")) {
03198 parkaddhints = ast_true(var->value);
03199 } else if (!strcasecmp(var->name, "parkedcalltransfers")) {
03200 if (!strcasecmp(var->value, "both"))
03201 parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH;
03202 else if (!strcasecmp(var->value, "caller"))
03203 parkedcalltransfers = AST_FEATURE_FLAG_BYCALLER;
03204 else if (!strcasecmp(var->value, "callee"))
03205 parkedcalltransfers = AST_FEATURE_FLAG_BYCALLEE;
03206 } else if (!strcasecmp(var->name, "parkedcallreparking")) {
03207 if (!strcasecmp(var->value, "both"))
03208 parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH;
03209 else if (!strcasecmp(var->value, "caller"))
03210 parkedcalltransfers = AST_FEATURE_FLAG_BYCALLER;
03211 else if (!strcasecmp(var->value, "callee"))
03212 parkedcalltransfers = AST_FEATURE_FLAG_BYCALLEE;
03213 } else if (!strcasecmp(var->name, "parkedcallhangup")) {
03214 if (!strcasecmp(var->value, "both"))
03215 parkedcallhangup = AST_FEATURE_FLAG_BYBOTH;
03216 else if (!strcasecmp(var->value, "caller"))
03217 parkedcallhangup = AST_FEATURE_FLAG_BYCALLER;
03218 else if (!strcasecmp(var->value, "callee"))
03219 parkedcallhangup = AST_FEATURE_FLAG_BYCALLEE;
03220 } else if (!strcasecmp(var->name, "parkedcallrecording")) {
03221 if (!strcasecmp(var->value, "both"))
03222 parkedcallrecording = AST_FEATURE_FLAG_BYBOTH;
03223 else if (!strcasecmp(var->value, "caller"))
03224 parkedcallrecording = AST_FEATURE_FLAG_BYCALLER;
03225 else if (!strcasecmp(var->value, "callee"))
03226 parkedcallrecording = AST_FEATURE_FLAG_BYCALLEE;
03227 } else if (!strcasecmp(var->name, "adsipark")) {
03228 adsipark = ast_true(var->value);
03229 } else if (!strcasecmp(var->name, "transferdigittimeout")) {
03230 if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
03231 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
03232 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
03233 } else
03234 transferdigittimeout = transferdigittimeout * 1000;
03235 } else if (!strcasecmp(var->name, "featuredigittimeout")) {
03236 if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
03237 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
03238 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
03239 }
03240 } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) {
03241 if ((sscanf(var->value, "%d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) {
03242 ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value);
03243 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
03244 } else
03245 atxfernoanswertimeout = atxfernoanswertimeout * 1000;
03246 } else if (!strcasecmp(var->name, "atxferloopdelay")) {
03247 if ((sscanf(var->value, "%u", &atxferloopdelay) != 1)) {
03248 ast_log(LOG_WARNING, "%s is not a valid atxferloopdelay\n", var->value);
03249 atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY;
03250 } else
03251 atxferloopdelay *= 1000;
03252 } else if (!strcasecmp(var->name, "atxferdropcall")) {
03253 atxferdropcall = ast_true(var->value);
03254 } else if (!strcasecmp(var->name, "atxfercallbackretries")) {
03255 if ((sscanf(var->value, "%u", &atxferloopdelay) != 1)) {
03256 ast_log(LOG_WARNING, "%s is not a valid atxfercallbackretries\n", var->value);
03257 atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES;
03258 }
03259 } else if (!strcasecmp(var->name, "courtesytone")) {
03260 ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
03261 } else if (!strcasecmp(var->name, "parkedplay")) {
03262 if (!strcasecmp(var->value, "both"))
03263 parkedplay = 2;
03264 else if (!strcasecmp(var->value, "parked"))
03265 parkedplay = 1;
03266 else
03267 parkedplay = 0;
03268 } else if (!strcasecmp(var->name, "xfersound")) {
03269 ast_copy_string(xfersound, var->value, sizeof(xfersound));
03270 } else if (!strcasecmp(var->name, "xferfailsound")) {
03271 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
03272 } else if (!strcasecmp(var->name, "pickupexten")) {
03273 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
03274 } else if (!strcasecmp(var->name, "comebacktoorigin")) {
03275 comebacktoorigin = ast_true(var->value);
03276 } else if (!strcasecmp(var->name, "parkedmusicclass")) {
03277 ast_copy_string(parkmohclass, var->value, sizeof(parkmohclass));
03278 }
03279 }
03280
03281 unmap_features();
03282 for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) {
03283 if (remap_feature(var->name, var->value))
03284 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
03285 }
03286
03287
03288 ast_unregister_features();
03289 for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) {
03290 char *tmp_val = ast_strdupa(var->value);
03291 char *exten, *activateon, *activatedby, *app, *app_args, *moh_class;
03292 struct ast_call_feature *feature;
03293
03294
03295
03296
03297
03298 exten = strsep(&tmp_val,",");
03299 activatedby = strsep(&tmp_val,",");
03300 app = strsep(&tmp_val,",");
03301 app_args = strsep(&tmp_val,",");
03302 moh_class = strsep(&tmp_val,",");
03303
03304 activateon = strsep(&activatedby, "/");
03305
03306
03307 if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) {
03308 ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",
03309 app, exten, activateon, var->name);
03310 continue;
03311 }
03312
03313 AST_RWLIST_RDLOCK(&feature_list);
03314 if ((feature = find_dynamic_feature(var->name))) {
03315 AST_RWLIST_UNLOCK(&feature_list);
03316 ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name);
03317 continue;
03318 }
03319 AST_RWLIST_UNLOCK(&feature_list);
03320
03321 if (!(feature = ast_calloc(1, sizeof(*feature))))
03322 continue;
03323
03324 ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN);
03325 ast_copy_string(feature->app, app, FEATURE_APP_LEN);
03326 ast_copy_string(feature->exten, exten, FEATURE_EXTEN_LEN);
03327
03328 if (app_args)
03329 ast_copy_string(feature->app_args, app_args, FEATURE_APP_ARGS_LEN);
03330
03331 if (moh_class)
03332 ast_copy_string(feature->moh_class, moh_class, FEATURE_MOH_LEN);
03333
03334 ast_copy_string(feature->exten, exten, sizeof(feature->exten));
03335 feature->operation = feature_exec_app;
03336 ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF);
03337
03338
03339 if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller"))
03340 ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF);
03341 else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee"))
03342 ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER);
03343 else {
03344 ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s',"
03345 " must be 'self', or 'peer'\n", var->name);
03346 continue;
03347 }
03348
03349 if (ast_strlen_zero(activatedby))
03350 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
03351 else if (!strcasecmp(activatedby, "caller"))
03352 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER);
03353 else if (!strcasecmp(activatedby, "callee"))
03354 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE);
03355 else if (!strcasecmp(activatedby, "both"))
03356 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
03357 else {
03358 ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s',"
03359 " must be 'caller', or 'callee', or 'both'\n", var->name);
03360 continue;
03361 }
03362
03363 ast_register_feature(feature);
03364
03365 ast_verb(2, "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, app, app_args, exten);
03366 }
03367
03368 ast_unregister_groups();
03369 AST_RWLIST_WRLOCK(&feature_groups);
03370
03371 ctg = NULL;
03372 while ((ctg = ast_category_browse(cfg, ctg))) {
03373 for (i = 0; i < ARRAY_LEN(categories); i++) {
03374 if (!strcasecmp(categories[i], ctg))
03375 break;
03376 }
03377
03378 if (i < ARRAY_LEN(categories))
03379 continue;
03380
03381 if (!(fg = register_group(ctg)))
03382 continue;
03383
03384 for (var = ast_variable_browse(cfg, ctg); var; var = var->next) {
03385 struct ast_call_feature *feature;
03386
03387 AST_RWLIST_RDLOCK(&feature_list);
03388 if (!(feature = find_dynamic_feature(var->name)) &&
03389 !(feature = ast_find_call_feature(var->name))) {
03390 AST_RWLIST_UNLOCK(&feature_list);
03391 ast_log(LOG_WARNING, "Feature '%s' was not found.\n", var->name);
03392 continue;
03393 }
03394 AST_RWLIST_UNLOCK(&feature_list);
03395
03396 register_group_feature(fg, var->value, feature);
03397 }
03398 }
03399
03400 AST_RWLIST_UNLOCK(&feature_groups);
03401
03402 ast_config_destroy(cfg);
03403
03404
03405 if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) {
03406 if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar, 0))
03407 notify_metermaids(old_parking_ext, old_parking_con, AST_DEVICE_NOT_INUSE);
03408 ast_debug(1, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
03409 }
03410
03411 if (!(con = ast_context_find_or_create(NULL, NULL, parking_con, registrar))) {
03412 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
03413 return -1;
03414 }
03415 res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar);
03416 if (parkaddhints)
03417 park_add_hints(parking_con, parking_start, parking_stop);
03418 if (!res)
03419 notify_metermaids(ast_parking_ext(), parking_con, AST_DEVICE_INUSE);
03420 return res;
03421
03422 }
03423
03424
03425
03426
03427
03428
03429
03430
03431
03432
03433 static char *handle_feature_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
03434 {
03435 int i;
03436 struct ast_call_feature *feature;
03437 #define HFS_FORMAT "%-25s %-7s %-7s\n"
03438
03439 switch (cmd) {
03440
03441 case CLI_INIT:
03442 e->command = "features show";
03443 e->usage =
03444 "Usage: features show\n"
03445 " Lists configured features\n";
03446 return NULL;
03447 case CLI_GENERATE:
03448 return NULL;
03449 }
03450
03451 ast_cli(a->fd, HFS_FORMAT, "Builtin Feature", "Default", "Current");
03452 ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
03453
03454 ast_cli(a->fd, HFS_FORMAT, "Pickup", "*8", ast_pickup_ext());
03455
03456 ast_rwlock_rdlock(&features_lock);
03457 for (i = 0; i < FEATURES_COUNT; i++)
03458 ast_cli(a->fd, HFS_FORMAT, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
03459 ast_rwlock_unlock(&features_lock);
03460
03461 ast_cli(a->fd, "\n");
03462 ast_cli(a->fd, HFS_FORMAT, "Dynamic Feature", "Default", "Current");
03463 ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
03464 if (AST_RWLIST_EMPTY(&feature_list)) {
03465 ast_cli(a->fd, "(none)\n");
03466 } else {
03467 AST_RWLIST_RDLOCK(&feature_list);
03468 AST_RWLIST_TRAVERSE(&feature_list, feature, feature_entry) {
03469 ast_cli(a->fd, HFS_FORMAT, feature->sname, "no def", feature->exten);
03470 }
03471 AST_RWLIST_UNLOCK(&feature_list);
03472 }
03473 ast_cli(a->fd, "\nCall parking\n");
03474 ast_cli(a->fd, "------------\n");
03475 ast_cli(a->fd,"%-20s: %s\n", "Parking extension", parking_ext);
03476 ast_cli(a->fd,"%-20s: %s\n", "Parking context", parking_con);
03477 ast_cli(a->fd,"%-20s: %d-%d\n", "Parked call extensions", parking_start, parking_stop);
03478 ast_cli(a->fd,"\n");
03479
03480 return CLI_SUCCESS;
03481 }
03482
03483 int ast_features_reload(void)
03484 {
03485 load_config();
03486
03487 return RESULT_SUCCESS;
03488 }
03489
03490 static char *handle_features_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
03491 {
03492 switch (cmd) {
03493 case CLI_INIT:
03494 e->command = "features reload";
03495 e->usage =
03496 "Usage: features reload\n"
03497 " Reloads configured call features from features.conf\n";
03498 return NULL;
03499 case CLI_GENERATE:
03500 return NULL;
03501 }
03502 load_config();
03503
03504 return CLI_SUCCESS;
03505 }
03506
03507 static char mandescr_bridge[] =
03508 "Description: Bridge together two channels already in the PBX\n"
03509 "Variables: ( Headers marked with * are required )\n"
03510 " *Channel1: Channel to Bridge to Channel2\n"
03511 " *Channel2: Channel to Bridge to Channel1\n"
03512 " Tone: (Yes|No) Play courtesy tone to Channel 2\n"
03513 "\n";
03514
03515
03516
03517
03518
03519
03520
03521
03522
03523 static void do_bridge_masquerade(struct ast_channel *chan, struct ast_channel *tmpchan)
03524 {
03525 ast_moh_stop(chan);
03526 ast_channel_lock(chan);
03527 ast_setstate(tmpchan, chan->_state);
03528 tmpchan->readformat = chan->readformat;
03529 tmpchan->writeformat = chan->writeformat;
03530 ast_channel_masquerade(tmpchan, chan);
03531 ast_channel_lock(tmpchan);
03532 ast_do_masquerade(tmpchan);
03533
03534 ast_explicit_goto(tmpchan, chan->context, chan->exten, chan->priority + 1);
03535 ast_channel_unlock(tmpchan);
03536 ast_channel_unlock(chan);
03537 }
03538
03539
03540
03541
03542
03543
03544
03545
03546
03547
03548
03549
03550
03551
03552
03553 static int action_bridge(struct mansession *s, const struct message *m)
03554 {
03555 const char *channela = astman_get_header(m, "Channel1");
03556 const char *channelb = astman_get_header(m, "Channel2");
03557 const char *playtone = astman_get_header(m, "Tone");
03558 struct ast_channel *chana = NULL, *chanb = NULL;
03559 struct ast_channel *tmpchana = NULL, *tmpchanb = NULL;
03560 struct ast_bridge_thread_obj *tobj = NULL;
03561
03562
03563 if (ast_strlen_zero(channela) || ast_strlen_zero(channelb)) {
03564 astman_send_error(s, m, "Missing channel parameter in request");
03565 return 0;
03566 }
03567
03568
03569
03570
03571
03572
03573 chana = ast_get_channel_by_name_prefix_locked(channela, strlen(channela));
03574
03575
03576 if (!chana) {
03577 char buf[256];
03578 snprintf(buf, sizeof(buf), "Channel1 does not exists: %s", channela);
03579 astman_send_error(s, m, buf);
03580 return 0;
03581 }
03582
03583
03584 if (chana->_state != AST_STATE_UP)
03585 ast_answer(chana);
03586
03587
03588 if (!(tmpchana = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
03589 NULL, NULL, 0, "Bridge/%s", chana->name))) {
03590 astman_send_error(s, m, "Unable to create temporary channel!");
03591 ast_channel_unlock(chana);
03592 return 1;
03593 }
03594
03595 do_bridge_masquerade(chana, tmpchana);
03596 ast_channel_unlock(chana);
03597 chana = NULL;
03598
03599
03600 chanb = ast_get_channel_by_name_prefix_locked(channelb, strlen(channelb));
03601
03602 if (!chanb) {
03603 char buf[256];
03604 snprintf(buf, sizeof(buf), "Channel2 does not exists: %s", channelb);
03605 ast_hangup(tmpchana);
03606 astman_send_error(s, m, buf);
03607 return 0;
03608 }
03609
03610
03611 if (chanb->_state != AST_STATE_UP)
03612 ast_answer(chanb);
03613
03614
03615 if (!(tmpchanb = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
03616 NULL, NULL, 0, "Bridge/%s", chanb->name))) {
03617 astman_send_error(s, m, "Unable to create temporary channels!");
03618 ast_hangup(tmpchana);
03619 ast_channel_unlock(chanb);
03620 return 1;
03621 }
03622 do_bridge_masquerade(chanb, tmpchanb);
03623 ast_channel_unlock(chanb);
03624 chanb = NULL;
03625
03626
03627 if (ast_channel_make_compatible(tmpchana, tmpchanb)) {
03628 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for manager bridge\n", tmpchana->name, tmpchanb->name);
03629 astman_send_error(s, m, "Could not make channels compatible for manager bridge");
03630 ast_hangup(tmpchana);
03631 ast_hangup(tmpchanb);
03632 return 1;
03633 }
03634
03635
03636 if (!(tobj = ast_calloc(1, sizeof(*tobj)))) {
03637 ast_log(LOG_WARNING, "Unable to spawn a new bridge thread on %s and %s: %s\n", tmpchana->name, tmpchanb->name, strerror(errno));
03638 astman_send_error(s, m, "Unable to spawn a new bridge thread");
03639 ast_hangup(tmpchana);
03640 ast_hangup(tmpchanb);
03641 return 1;
03642 }
03643
03644 tobj->chan = tmpchana;
03645 tobj->peer = tmpchanb;
03646 tobj->return_to_pbx = 1;
03647
03648 if (ast_true(playtone)) {
03649 if (!ast_strlen_zero(xfersound) && !ast_streamfile(tmpchanb, xfersound, tmpchanb->language)) {
03650 if (ast_waitstream(tmpchanb, "") < 0)
03651 ast_log(LOG_WARNING, "Failed to play a courtesy tone on chan %s\n", tmpchanb->name);
03652 }
03653 }
03654
03655 ast_bridge_call_thread_launch(tobj);
03656
03657 astman_send_ack(s, m, "Launched bridge thread with success");
03658
03659 return 0;
03660 }
03661
03662
03663
03664
03665
03666
03667
03668
03669
03670
03671
03672
03673 static char *handle_parkedcalls(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
03674 {
03675 struct parkeduser *cur;
03676 int numparked = 0;
03677
03678 switch (cmd) {
03679 case CLI_INIT:
03680 e->command = "parkedcalls show";
03681 e->usage =
03682 "Usage: parkedcalls show\n"
03683 " List currently parked calls\n";
03684 return NULL;
03685 case CLI_GENERATE:
03686 return NULL;
03687 }
03688
03689 if (a->argc > e->args)
03690 return CLI_SHOWUSAGE;
03691
03692 ast_cli(a->fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
03693 , "Context", "Extension", "Pri", "Timeout");
03694
03695 AST_LIST_LOCK(&parkinglot);
03696 AST_LIST_TRAVERSE(&parkinglot, cur, list) {
03697 ast_cli(a->fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n"
03698 ,cur->parkingexten, cur->chan->name, cur->context, cur->exten
03699 ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
03700
03701 numparked++;
03702 }
03703 AST_LIST_UNLOCK(&parkinglot);
03704 ast_cli(a->fd, "%d parked call%s.\n", numparked, ESS(numparked));
03705
03706
03707 return CLI_SUCCESS;
03708 }
03709
03710 static char *handle_parkedcalls_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
03711 {
03712 char *res = handle_parkedcalls(e, cmd, a);
03713 if (cmd == CLI_INIT)
03714 e->command = "show parkedcalls";
03715 return res;
03716 }
03717
03718 static struct ast_cli_entry cli_show_parkedcalls_deprecated = AST_CLI_DEFINE(handle_parkedcalls_deprecated, "List currently parked calls.");
03719
03720 static struct ast_cli_entry cli_features[] = {
03721 AST_CLI_DEFINE(handle_feature_show, "Lists configured features"),
03722 AST_CLI_DEFINE(handle_features_reload, "Reloads configured features"),
03723 AST_CLI_DEFINE(handle_parkedcalls, "List currently parked calls", .deprecate_cmd = &cli_show_parkedcalls_deprecated),
03724 };
03725
03726
03727
03728
03729
03730
03731
03732
03733
03734 static int manager_parking_status(struct mansession *s, const struct message *m)
03735 {
03736 struct parkeduser *cur;
03737 const char *id = astman_get_header(m, "ActionID");
03738 char idText[256] = "";
03739
03740 if (!ast_strlen_zero(id))
03741 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
03742
03743 astman_send_ack(s, m, "Parked calls will follow");
03744
03745 AST_LIST_LOCK(&parkinglot);
03746
03747 AST_LIST_TRAVERSE(&parkinglot, cur, list) {
03748 astman_append(s, "Event: ParkedCall\r\n"
03749 "Exten: %d\r\n"
03750 "Channel: %s\r\n"
03751 "From: %s\r\n"
03752 "Timeout: %ld\r\n"
03753 "CallerIDNum: %s\r\n"
03754 "CallerIDName: %s\r\n"
03755 "%s"
03756 "\r\n",
03757 cur->parkingnum, cur->chan->name, cur->peername,
03758 (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
03759 S_OR(cur->chan->cid.cid_num, ""),
03760 S_OR(cur->chan->cid.cid_name, ""),
03761 idText);
03762 }
03763
03764 astman_append(s,
03765 "Event: ParkedCallsComplete\r\n"
03766 "%s"
03767 "\r\n",idText);
03768
03769 AST_LIST_UNLOCK(&parkinglot);
03770
03771 return RESULT_SUCCESS;
03772 }
03773
03774 static char mandescr_park[] =
03775 "Description: Park a channel.\n"
03776 "Variables: (Names marked with * are required)\n"
03777 " *Channel: Channel name to park\n"
03778 " *Channel2: Channel to announce park info to (and return to if timeout)\n"
03779 " Timeout: Number of milliseconds to wait before callback.\n";
03780
03781
03782
03783
03784
03785
03786
03787
03788
03789 static int manager_park(struct mansession *s, const struct message *m)
03790 {
03791 const char *channel = astman_get_header(m, "Channel");
03792 const char *channel2 = astman_get_header(m, "Channel2");
03793 const char *timeout = astman_get_header(m, "Timeout");
03794 char buf[BUFSIZ];
03795 int to = 0;
03796 int res = 0;
03797 int parkExt = 0;
03798 struct ast_channel *ch1, *ch2;
03799
03800 if (ast_strlen_zero(channel)) {
03801 astman_send_error(s, m, "Channel not specified");
03802 return 0;
03803 }
03804
03805 if (ast_strlen_zero(channel2)) {
03806 astman_send_error(s, m, "Channel2 not specified");
03807 return 0;
03808 }
03809
03810 ch1 = ast_get_channel_by_name_locked(channel);
03811 if (!ch1) {
03812 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
03813 astman_send_error(s, m, buf);
03814 return 0;
03815 }
03816
03817 ch2 = ast_get_channel_by_name_locked(channel2);
03818 if (!ch2) {
03819 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
03820 astman_send_error(s, m, buf);
03821 ast_channel_unlock(ch1);
03822 return 0;
03823 }
03824
03825 if (!ast_strlen_zero(timeout)) {
03826 sscanf(timeout, "%d", &to);
03827 }
03828
03829 res = ast_masq_park_call(ch1, ch2, to, &parkExt);
03830 if (!res) {
03831 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
03832 astman_send_ack(s, m, "Park successful");
03833 } else {
03834 astman_send_error(s, m, "Park failure");
03835 }
03836
03837 ast_channel_unlock(ch1);
03838 ast_channel_unlock(ch2);
03839
03840 return 0;
03841 }
03842
03843
03844
03845
03846
03847
03848
03849
03850
03851 int ast_pickup_call(struct ast_channel *chan)
03852 {
03853 struct ast_channel *cur = NULL;
03854 int res = -1;
03855
03856 while ((cur = ast_channel_walk_locked(cur)) != NULL) {
03857 if (!cur->pbx &&
03858 (cur != chan) &&
03859 (chan->pickupgroup & cur->callgroup) &&
03860 ((cur->_state == AST_STATE_RINGING) ||
03861 (cur->_state == AST_STATE_RING))) {
03862 break;
03863 }
03864 ast_channel_unlock(cur);
03865 }
03866 if (cur) {
03867 ast_debug(1, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
03868 res = ast_answer(chan);
03869 if (res)
03870 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
03871 res = ast_queue_control(chan, AST_CONTROL_ANSWER);
03872 if (res)
03873 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
03874 res = ast_channel_masquerade(cur, chan);
03875 if (res)
03876 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);
03877 ast_channel_unlock(cur);
03878 } else {
03879 ast_debug(1, "No call pickup possible...\n");
03880 }
03881 return res;
03882 }
03883
03884 static char *app_bridge = "Bridge";
03885 static char *bridge_synopsis = "Bridge two channels";
03886 static char *bridge_descrip =
03887 "Usage: Bridge(channel[,options])\n"
03888 " Allows the ability to bridge two channels via the dialplan.\n"
03889 "The current channel is bridged to the specified 'channel'.\n"
03890 " Options:\n"
03891 " p - Play a courtesy tone to 'channel'.\n"
03892 "This application sets the following channel variable upon completion:\n"
03893 " BRIDGERESULT The result of the bridge attempt as a text string, one of\n"
03894 " SUCCESS | FAILURE | LOOP | NONEXISTENT | INCOMPATIBLE\n";
03895
03896 enum {
03897 BRIDGE_OPT_PLAYTONE = (1 << 0),
03898 };
03899
03900 AST_APP_OPTIONS(bridge_exec_options, BEGIN_OPTIONS
03901 AST_APP_OPTION('p', BRIDGE_OPT_PLAYTONE)
03902 END_OPTIONS );
03903
03904
03905
03906
03907
03908
03909
03910
03911
03912
03913 static int bridge_exec(struct ast_channel *chan, void *data)
03914 {
03915 struct ast_channel *current_dest_chan, *final_dest_chan;
03916 char *tmp_data = NULL;
03917 struct ast_flags opts = { 0, };
03918 struct ast_bridge_config bconfig = { { 0, }, };
03919
03920 AST_DECLARE_APP_ARGS(args,
03921 AST_APP_ARG(dest_chan);
03922 AST_APP_ARG(options);
03923 );
03924
03925 if (ast_strlen_zero(data)) {
03926 ast_log(LOG_WARNING, "Bridge require at least 1 argument specifying the other end of the bridge\n");
03927 return -1;
03928 }
03929
03930 tmp_data = ast_strdupa(data);
03931 AST_STANDARD_APP_ARGS(args, tmp_data);
03932 if (!ast_strlen_zero(args.options))
03933 ast_app_parse_options(bridge_exec_options, &opts, NULL, args.options);
03934
03935
03936 if (!strncmp(chan->name, args.dest_chan,
03937 strlen(chan->name) < strlen(args.dest_chan) ?
03938 strlen(chan->name) : strlen(args.dest_chan))) {
03939 ast_log(LOG_WARNING, "Unable to bridge channel %s with itself\n", chan->name);
03940 manager_event(EVENT_FLAG_CALL, "BridgeExec",
03941 "Response: Failed\r\n"
03942 "Reason: Unable to bridge channel to itself\r\n"
03943 "Channel1: %s\r\n"
03944 "Channel2: %s\r\n",
03945 chan->name, args.dest_chan);
03946 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "LOOP");
03947 return 0;
03948 }
03949
03950
03951 if (!(current_dest_chan = ast_get_channel_by_name_prefix_locked(args.dest_chan,
03952 strlen(args.dest_chan)))) {
03953 ast_log(LOG_WARNING, "Bridge failed because channel %s does not exists or we "
03954 "cannot get its lock\n", args.dest_chan);
03955 manager_event(EVENT_FLAG_CALL, "BridgeExec",
03956 "Response: Failed\r\n"
03957 "Reason: Cannot grab end point\r\n"
03958 "Channel1: %s\r\n"
03959 "Channel2: %s\r\n", chan->name, args.dest_chan);
03960 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "NONEXISTENT");
03961 return 0;
03962 }
03963
03964
03965 if (current_dest_chan->_state != AST_STATE_UP)
03966 ast_answer(current_dest_chan);
03967
03968
03969 if (!(final_dest_chan = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
03970 NULL, NULL, 0, "Bridge/%s", current_dest_chan->name))) {
03971 ast_log(LOG_WARNING, "Cannot create placeholder channel for chan %s\n", args.dest_chan);
03972 manager_event(EVENT_FLAG_CALL, "BridgeExec",
03973 "Response: Failed\r\n"
03974 "Reason: cannot create placeholder\r\n"
03975 "Channel1: %s\r\n"
03976 "Channel2: %s\r\n", chan->name, args.dest_chan);
03977 }
03978 do_bridge_masquerade(current_dest_chan, final_dest_chan);
03979
03980 ast_channel_unlock(current_dest_chan);
03981
03982
03983
03984 if (ast_channel_make_compatible(chan, final_dest_chan) < 0) {
03985 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, final_dest_chan->name);
03986 manager_event(EVENT_FLAG_CALL, "BridgeExec",
03987 "Response: Failed\r\n"
03988 "Reason: Could not make channels compatible for bridge\r\n"
03989 "Channel1: %s\r\n"
03990 "Channel2: %s\r\n", chan->name, final_dest_chan->name);
03991 ast_hangup(final_dest_chan);
03992 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "INCOMPATIBLE");
03993 return 0;
03994 }
03995
03996
03997 manager_event(EVENT_FLAG_CALL, "BridgeExec",
03998 "Response: Success\r\n"
03999 "Channel1: %s\r\n"
04000 "Channel2: %s\r\n", chan->name, final_dest_chan->name);
04001
04002
04003 if (ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE) && !ast_strlen_zero(xfersound)) {
04004 if (!ast_streamfile(final_dest_chan, xfersound, final_dest_chan->language)) {
04005 if (ast_waitstream(final_dest_chan, "") < 0)
04006 ast_log(LOG_WARNING, "Failed to play courtesy tone on %s\n", final_dest_chan->name);
04007 }
04008 }
04009
04010
04011 ast_bridge_call(chan, final_dest_chan, &bconfig);
04012
04013
04014 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "SUCCESS");
04015 if (!ast_check_hangup(final_dest_chan)) {
04016 ast_debug(1, "starting new PBX in %s,%s,%d for chan %s\n",
04017 final_dest_chan->context, final_dest_chan->exten,
04018 final_dest_chan->priority, final_dest_chan->name);
04019
04020 if (ast_pbx_start(final_dest_chan) != AST_PBX_SUCCESS) {
04021 ast_log(LOG_WARNING, "FAILED continuing PBX on dest chan %s\n", final_dest_chan->name);
04022 ast_hangup(final_dest_chan);
04023 } else
04024 ast_debug(1, "SUCCESS continuing PBX on chan %s\n", final_dest_chan->name);
04025 } else {
04026 ast_debug(1, "hangup chan %s since the other endpoint has hung up\n", final_dest_chan->name);
04027 ast_hangup(final_dest_chan);
04028 }
04029
04030 return 0;
04031 }
04032
04033 int ast_features_init(void)
04034 {
04035 int res;
04036
04037 ast_register_application2(app_bridge, bridge_exec, bridge_synopsis, bridge_descrip, NULL);
04038
04039 memset(parking_ext, 0, sizeof(parking_ext));
04040 memset(parking_con, 0, sizeof(parking_con));
04041
04042 if ((res = load_config()))
04043 return res;
04044 ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
04045 ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
04046 res = ast_register_application2(parkedcall, park_exec, synopsis, descrip, NULL);
04047 if (!res)
04048 res = ast_register_application2(parkcall, park_call_exec, synopsis2, descrip2, NULL);
04049 if (!res) {
04050 ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls");
04051 ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park,
04052 "Park a channel", mandescr_park);
04053 ast_manager_register2("Bridge", EVENT_FLAG_CALL, action_bridge, "Bridge two channels already in the PBX", mandescr_bridge);
04054 }
04055
04056 res |= ast_devstate_prov_add("Park", metermaidstate);
04057
04058 return res;
04059 }