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