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