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