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