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