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
00027
00028
00029
00030 #include "asterisk.h"
00031
00032 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 372845 $")
00033
00034 #include "asterisk/_private.h"
00035
00036 #include <pthread.h>
00037 #include <signal.h>
00038 #include <sys/time.h>
00039 #include <sys/signal.h>
00040 #include <netinet/in.h>
00041
00042 #include "asterisk/lock.h"
00043 #include "asterisk/file.h"
00044 #include "asterisk/channel.h"
00045 #include "asterisk/pbx.h"
00046 #include "asterisk/causes.h"
00047 #include "asterisk/module.h"
00048 #include "asterisk/translate.h"
00049 #include "asterisk/app.h"
00050 #include "asterisk/say.h"
00051 #include "asterisk/features.h"
00052 #include "asterisk/musiconhold.h"
00053 #include "asterisk/config.h"
00054 #include "asterisk/cli.h"
00055 #include "asterisk/manager.h"
00056 #include "asterisk/utils.h"
00057 #include "asterisk/adsi.h"
00058 #include "asterisk/devicestate.h"
00059 #include "asterisk/monitor.h"
00060 #include "asterisk/audiohook.h"
00061 #include "asterisk/global_datastores.h"
00062 #include "asterisk/astobj2.h"
00063 #include "asterisk/cel.h"
00064 #include "asterisk/test.h"
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
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383 #define DEFAULT_PARK_TIME 45000
00384 #define DEFAULT_PARK_EXTENSION "700"
00385 #define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000
00386 #define DEFAULT_FEATURE_DIGIT_TIMEOUT 1000
00387 #define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000
00388 #define DEFAULT_ATXFER_DROP_CALL 0
00389 #define DEFAULT_ATXFER_LOOP_DELAY 10000
00390 #define DEFAULT_ATXFER_CALLBACK_RETRIES 2
00391
00392 #define AST_MAX_WATCHERS 256
00393 #define MAX_DIAL_FEATURE_OPTIONS 30
00394
00395 struct feature_group_exten {
00396 AST_LIST_ENTRY(feature_group_exten) entry;
00397 AST_DECLARE_STRING_FIELDS(
00398 AST_STRING_FIELD(exten);
00399 );
00400 struct ast_call_feature *feature;
00401 };
00402
00403 struct feature_group {
00404 AST_LIST_ENTRY(feature_group) entry;
00405 AST_DECLARE_STRING_FIELDS(
00406 AST_STRING_FIELD(gname);
00407 );
00408 AST_LIST_HEAD_NOLOCK(, feature_group_exten) features;
00409 };
00410
00411 static AST_RWLIST_HEAD_STATIC(feature_groups, feature_group);
00412
00413 typedef enum {
00414 FEATURE_INTERPRET_DETECT,
00415 FEATURE_INTERPRET_DO,
00416 FEATURE_INTERPRET_CHECK,
00417 } feature_interpret_op;
00418
00419 static const char *parkedcall = "ParkedCall";
00420
00421 static char pickup_ext[AST_MAX_EXTENSION];
00422
00423
00424 struct parking_dp_ramp {
00425
00426 AST_LIST_ENTRY(parking_dp_ramp) node;
00427
00428 unsigned int exclusive:1;
00429
00430 char exten[1];
00431 };
00432
00433
00434 AST_LIST_HEAD_NOLOCK(parking_dp_ramp_map, parking_dp_ramp);
00435
00436
00437 struct parking_dp_spaces {
00438
00439 AST_LIST_ENTRY(parking_dp_spaces) node;
00440
00441 int start;
00442
00443 int stop;
00444 };
00445
00446
00447 AST_LIST_HEAD_NOLOCK(parking_dp_space_map, parking_dp_spaces);
00448
00449
00450 struct parking_dp_context {
00451
00452 AST_LIST_ENTRY(parking_dp_context) node;
00453
00454 struct parking_dp_ramp_map access_extens;
00455
00456 struct parking_dp_space_map spaces;
00457
00458 struct parking_dp_space_map hints;
00459
00460 char context[1];
00461 };
00462
00463
00464 AST_LIST_HEAD_NOLOCK(parking_dp_map, parking_dp_context);
00465
00466
00467
00468
00469
00470 struct parkeduser {
00471 struct ast_channel *chan;
00472 struct timeval start;
00473 int parkingnum;
00474 char parkingexten[AST_MAX_EXTENSION];
00475 char context[AST_MAX_CONTEXT];
00476 char exten[AST_MAX_EXTENSION];
00477 int priority;
00478 int parkingtime;
00479
00480 enum ast_control_frame_type hold_method;
00481 unsigned int notquiteyet:1;
00482 unsigned int options_specified:1;
00483 char peername[AST_CHANNEL_NAME];
00484 unsigned char moh_trys;
00485
00486 struct ast_parkinglot *parkinglot;
00487 AST_LIST_ENTRY(parkeduser) list;
00488 };
00489
00490
00491 struct parkinglot_cfg {
00492
00493 char mohclass[MAX_MUSICCLASS];
00494
00495 char parkext[AST_MAX_EXTENSION];
00496
00497 char parking_con[AST_MAX_EXTENSION];
00498
00499 int parking_start;
00500
00501 int parking_stop;
00502
00503 int parkingtime;
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513 int parkedcalltransfers;
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523 int parkedcallreparking;
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533 int parkedcallhangup;
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543 int parkedcallrecording;
00544
00545
00546 unsigned int parkfindnext:1;
00547
00548 unsigned int parkext_exclusive:1;
00549
00550 unsigned int parkaddhints:1;
00551
00552 unsigned int is_invalid:1;
00553 };
00554
00555
00556 struct ast_parkinglot {
00557
00558 char name[AST_MAX_CONTEXT];
00559
00560 struct parkinglot_cfg cfg;
00561
00562
00563 int next_parking_space;
00564
00565
00566 unsigned int the_mark:1;
00567
00568 unsigned int disabled:1;
00569
00570
00571 AST_LIST_HEAD(parkinglot_parklist, parkeduser) parkings;
00572 };
00573
00574
00575 static struct ao2_container *parkinglots;
00576
00577
00578
00579
00580
00581
00582 static struct ast_parkinglot *default_parkinglot;
00583
00584
00585 static int force_reload_load;
00586
00587 static int parkedplay = 0;
00588 static int parkeddynamic = 0;
00589 static char courtesytone[256];
00590 static char xfersound[256];
00591 static char xferfailsound[256];
00592 static char pickupsound[256];
00593 static char pickupfailsound[256];
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603 static char parking_con_dial[] = "park-dial";
00604
00605
00606 AST_MUTEX_DEFINE_STATIC(features_reload_lock);
00607
00608 static int adsipark;
00609
00610 static int transferdigittimeout;
00611 static int featuredigittimeout;
00612 static int comebacktoorigin = 1;
00613
00614 static int atxfernoanswertimeout;
00615 static unsigned int atxferdropcall;
00616 static unsigned int atxferloopdelay;
00617 static unsigned int atxfercallbackretries;
00618
00619 static char *registrar = "features";
00620
00621
00622 AST_DEFINE_APP_ARGS_TYPE(park_app_args,
00623 AST_APP_ARG(timeout);
00624 AST_APP_ARG(return_con);
00625 AST_APP_ARG(return_ext);
00626 AST_APP_ARG(return_pri);
00627 AST_APP_ARG(options);
00628 AST_APP_ARG(pl_name);
00629 AST_APP_ARG(dummy);
00630 );
00631
00632
00633 static const char *parkcall = "Park";
00634
00635 static struct ast_app *monitor_app = NULL;
00636 static int monitor_ok = 1;
00637
00638 static struct ast_app *mixmonitor_app = NULL;
00639 static int mixmonitor_ok = 1;
00640
00641 static struct ast_app *stopmixmonitor_app = NULL;
00642 static int stopmixmonitor_ok = 1;
00643
00644 static pthread_t parking_thread;
00645 struct ast_dial_features {
00646
00647 struct ast_flags my_features;
00648
00649 struct ast_flags peer_features;
00650 };
00651
00652 #if defined(ATXFER_NULL_TECH)
00653
00654
00655
00656
00657
00658
00659
00660
00661 static void set_kill_chan_tech(struct ast_channel *chan)
00662 {
00663 int idx;
00664
00665 ast_channel_lock(chan);
00666
00667
00668 if (chan->tech->hangup) {
00669 chan->tech->hangup(chan);
00670 }
00671 if (chan->tech_pvt) {
00672 ast_log(LOG_WARNING, "Channel '%s' may not have been hung up properly\n",
00673 chan->name);
00674 ast_free(chan->tech_pvt);
00675 chan->tech_pvt = NULL;
00676 }
00677
00678
00679 chan->tech = &ast_kill_tech;
00680 for (idx = 0; idx < AST_MAX_FDS; ++idx) {
00681 switch (idx) {
00682 case AST_ALERT_FD:
00683 case AST_TIMING_FD:
00684 case AST_GENERATOR_FD:
00685
00686 break;
00687 default:
00688 ast_channel_set_fd(chan, idx, -1);
00689 break;
00690 }
00691 }
00692 ast_queue_frame(chan, &ast_null_frame);
00693
00694 ast_channel_unlock(chan);
00695 }
00696 #endif
00697
00698 #if defined(ATXFER_NULL_TECH)
00699
00700
00701
00702
00703
00704
00705
00706
00707 static void set_new_chan_name(struct ast_channel *chan)
00708 {
00709 static int seq_num_last;
00710 int seq_num;
00711 int len;
00712 char *chan_name;
00713 char dummy[1];
00714
00715
00716 ast_channel_lock(chan);
00717 seq_num = ast_atomic_fetchadd_int(&seq_num_last, +1);
00718 len = snprintf(dummy, sizeof(dummy), "%s<XFER_%x>", chan->name, seq_num) + 1;
00719 chan_name = alloca(len);
00720 snprintf(chan_name, len, "%s<XFER_%x>", chan->name, seq_num);
00721 ast_channel_unlock(chan);
00722
00723 ast_change_name(chan, chan_name);
00724 }
00725 #endif
00726
00727 static void *dial_features_duplicate(void *data)
00728 {
00729 struct ast_dial_features *df = data, *df_copy;
00730
00731 if (!(df_copy = ast_calloc(1, sizeof(*df)))) {
00732 return NULL;
00733 }
00734
00735 memcpy(df_copy, df, sizeof(*df));
00736
00737 return df_copy;
00738 }
00739
00740 static void dial_features_destroy(void *data)
00741 {
00742 struct ast_dial_features *df = data;
00743 if (df) {
00744 ast_free(df);
00745 }
00746 }
00747
00748 static const struct ast_datastore_info dial_features_info = {
00749 .type = "dial-features",
00750 .destroy = dial_features_destroy,
00751 .duplicate = dial_features_duplicate,
00752 };
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764 static int add_features_datastore(struct ast_channel *chan, const struct ast_flags *my_features, const struct ast_flags *peer_features)
00765 {
00766 struct ast_datastore *datastore;
00767 struct ast_dial_features *dialfeatures;
00768
00769 ast_channel_lock(chan);
00770 datastore = ast_channel_datastore_find(chan, &dial_features_info, NULL);
00771 ast_channel_unlock(chan);
00772 if (datastore) {
00773
00774 return 1;
00775 }
00776
00777
00778 datastore = ast_datastore_alloc(&dial_features_info, NULL);
00779 if (!datastore) {
00780 ast_log(LOG_WARNING, "Unable to create channel features datastore.\n");
00781 return 0;
00782 }
00783 dialfeatures = ast_calloc(1, sizeof(*dialfeatures));
00784 if (!dialfeatures) {
00785 ast_log(LOG_WARNING, "Unable to allocate memory for feature flags.\n");
00786 ast_datastore_free(datastore);
00787 return 0;
00788 }
00789 ast_copy_flags(&dialfeatures->my_features, my_features, AST_FLAGS_ALL);
00790 ast_copy_flags(&dialfeatures->peer_features, peer_features, AST_FLAGS_ALL);
00791 datastore->inheritance = DATASTORE_INHERIT_FOREVER;
00792 datastore->data = dialfeatures;
00793 ast_channel_lock(chan);
00794 ast_channel_datastore_add(chan, datastore);
00795 ast_channel_unlock(chan);
00796 return 0;
00797 }
00798
00799
00800 static struct ast_parkinglot *parkinglot_addref(struct ast_parkinglot *parkinglot);
00801 static void parkinglot_unref(struct ast_parkinglot *parkinglot);
00802 static struct ast_parkinglot *find_parkinglot(const char *name);
00803 static struct ast_parkinglot *create_parkinglot(const char *name);
00804 static struct ast_parkinglot *copy_parkinglot(const char *name, const struct ast_parkinglot *parkinglot);
00805 static int parkinglot_activate(struct ast_parkinglot *parkinglot);
00806 static int play_message_on_chan(struct ast_channel *play_to, struct ast_channel *other, const char *msg, const char *audiofile);
00807
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819 static struct ast_exten *get_parking_exten(const char *exten_str, struct ast_channel *chan, const char *context)
00820 {
00821 struct ast_exten *exten;
00822 struct pbx_find_info q = { .stacklen = 0 };
00823 const char *app_at_exten;
00824
00825 ast_debug(4, "Checking if %s@%s is a parking exten\n", exten_str, context);
00826 exten = pbx_find_extension(chan, NULL, &q, context, exten_str, 1, NULL, NULL,
00827 E_MATCH);
00828 if (!exten) {
00829 return NULL;
00830 }
00831
00832 app_at_exten = ast_get_extension_app(exten);
00833 if (!app_at_exten || strcasecmp(parkcall, app_at_exten)) {
00834 return NULL;
00835 }
00836
00837 return exten;
00838 }
00839
00840 int ast_parking_ext_valid(const char *exten_str, struct ast_channel *chan, const char *context)
00841 {
00842 return get_parking_exten(exten_str, chan, context) ? 1 : 0;
00843 }
00844
00845 const char *ast_pickup_ext(void)
00846 {
00847 return pickup_ext;
00848 }
00849
00850 struct ast_bridge_thread_obj
00851 {
00852 struct ast_bridge_config bconfig;
00853 struct ast_channel *chan;
00854 struct ast_channel *peer;
00855 unsigned int return_to_pbx:1;
00856 };
00857
00858 static int parkinglot_hash_cb(const void *obj, const int flags)
00859 {
00860 const struct ast_parkinglot *parkinglot = obj;
00861
00862 return ast_str_case_hash(parkinglot->name);
00863 }
00864
00865 static int parkinglot_cmp_cb(void *obj, void *arg, int flags)
00866 {
00867 struct ast_parkinglot *parkinglot = obj;
00868 struct ast_parkinglot *parkinglot2 = arg;
00869
00870 return !strcasecmp(parkinglot->name, parkinglot2->name) ? CMP_MATCH | CMP_STOP : 0;
00871 }
00872
00873
00874
00875
00876
00877 static void set_c_e_p(struct ast_channel *chan, const char *context, const char *ext, int pri)
00878 {
00879 ast_copy_string(chan->context, context, sizeof(chan->context));
00880 ast_copy_string(chan->exten, ext, sizeof(chan->exten));
00881 chan->priority = pri;
00882 }
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892 static void check_goto_on_transfer(struct ast_channel *chan)
00893 {
00894 struct ast_channel *xferchan;
00895 const char *val;
00896 char *goto_on_transfer;
00897 char *x;
00898
00899 ast_channel_lock(chan);
00900 val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR");
00901 if (ast_strlen_zero(val)) {
00902 ast_channel_unlock(chan);
00903 return;
00904 }
00905 goto_on_transfer = ast_strdupa(val);
00906 ast_channel_unlock(chan);
00907
00908 ast_debug(1, "Attempting GOTO_ON_BLINDXFR=%s for %s.\n", val, chan->name);
00909
00910 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", chan->linkedid, 0,
00911 "%s", chan->name);
00912 if (!xferchan) {
00913 return;
00914 }
00915
00916
00917 xferchan->readformat = chan->readformat;
00918 xferchan->writeformat = chan->writeformat;
00919
00920 if (ast_channel_masquerade(xferchan, chan)) {
00921
00922 ast_hangup(xferchan);
00923 return;
00924 }
00925
00926 for (x = goto_on_transfer; *x; ++x) {
00927 if (*x == '^') {
00928 *x = ',';
00929 }
00930 }
00931 ast_parseable_goto(xferchan, goto_on_transfer);
00932 xferchan->_state = AST_STATE_UP;
00933 ast_clear_flag(xferchan, AST_FLAGS_ALL);
00934 ast_channel_clear_softhangup(xferchan, AST_SOFTHANGUP_ALL);
00935
00936 ast_do_masquerade(xferchan);
00937 if (ast_pbx_start(xferchan)) {
00938
00939 ast_hangup(xferchan);
00940 }
00941 }
00942
00943 static struct ast_channel *feature_request_and_dial(struct ast_channel *caller,
00944 const char *caller_name, struct ast_channel *requestor,
00945 struct ast_channel *transferee, const char *type, format_t format, void *data,
00946 int timeout, int *outstate, const char *language);
00947
00948 static const struct ast_datastore_info channel_app_data_datastore = {
00949 .type = "Channel appdata datastore",
00950 .destroy = ast_free_ptr,
00951 };
00952
00953 static int set_chan_app_data(struct ast_channel *chan, const char *src_app_data)
00954 {
00955 struct ast_datastore *datastore;
00956 char *dst_app_data;
00957
00958 datastore = ast_datastore_alloc(&channel_app_data_datastore, NULL);
00959 if (!datastore) {
00960 return -1;
00961 }
00962
00963 dst_app_data = ast_malloc(strlen(src_app_data) + 1);
00964 if (!dst_app_data) {
00965 ast_datastore_free(datastore);
00966 return -1;
00967 }
00968
00969 chan->data = strcpy(dst_app_data, src_app_data);
00970 datastore->data = dst_app_data;
00971 ast_channel_datastore_add(chan, datastore);
00972 return 0;
00973 }
00974
00975
00976
00977
00978
00979
00980
00981
00982
00983 static void *bridge_call_thread(void *data)
00984 {
00985 struct ast_bridge_thread_obj *tobj = data;
00986
00987 tobj->chan->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge";
00988 if (set_chan_app_data(tobj->chan, tobj->peer->name)) {
00989 tobj->chan->data = "(Empty)";
00990 }
00991 tobj->peer->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge";
00992 if (set_chan_app_data(tobj->peer, tobj->chan->name)) {
00993 tobj->peer->data = "(Empty)";
00994 }
00995
00996 ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
00997
00998 if (tobj->return_to_pbx) {
00999 if (!ast_check_hangup(tobj->peer)) {
01000 ast_log(LOG_VERBOSE, "putting peer %s into PBX again\n", tobj->peer->name);
01001 if (ast_pbx_start(tobj->peer)) {
01002 ast_log(LOG_WARNING, "FAILED continuing PBX on peer %s\n", tobj->peer->name);
01003 ast_hangup(tobj->peer);
01004 }
01005 } else {
01006 ast_hangup(tobj->peer);
01007 }
01008 if (!ast_check_hangup(tobj->chan)) {
01009 ast_log(LOG_VERBOSE, "putting chan %s into PBX again\n", tobj->chan->name);
01010 if (ast_pbx_start(tobj->chan)) {
01011 ast_log(LOG_WARNING, "FAILED continuing PBX on chan %s\n", tobj->chan->name);
01012 ast_hangup(tobj->chan);
01013 }
01014 } else {
01015 ast_hangup(tobj->chan);
01016 }
01017 } else {
01018 ast_hangup(tobj->chan);
01019 ast_hangup(tobj->peer);
01020 }
01021
01022 ast_free(tobj);
01023
01024 return NULL;
01025 }
01026
01027
01028
01029
01030
01031
01032
01033 static void bridge_call_thread_launch(struct ast_bridge_thread_obj *data)
01034 {
01035 pthread_t thread;
01036 pthread_attr_t attr;
01037 struct sched_param sched;
01038
01039 pthread_attr_init(&attr);
01040 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
01041 if (ast_pthread_create(&thread, &attr, bridge_call_thread, data)) {
01042 ast_hangup(data->chan);
01043 ast_hangup(data->peer);
01044 ast_log(LOG_ERROR, "Failed to create bridge_call_thread.\n");
01045 }
01046 pthread_attr_destroy(&attr);
01047 memset(&sched, 0, sizeof(sched));
01048 pthread_setschedparam(thread, SCHED_RR, &sched);
01049 }
01050
01051
01052
01053
01054
01055
01056
01057
01058
01059 static int adsi_announce_park(struct ast_channel *chan, char *parkingexten)
01060 {
01061 int res;
01062 int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
01063 char tmp[256];
01064 char *message[5] = {NULL, NULL, NULL, NULL, NULL};
01065
01066 snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten);
01067 message[0] = tmp;
01068 res = ast_adsi_load_session(chan, NULL, 0, 1);
01069 if (res == -1)
01070 return res;
01071 return ast_adsi_print(chan, message, justify, 1);
01072 }
01073
01074
01075
01076
01077
01078 static const char *findparkinglotname(struct ast_channel *chan)
01079 {
01080 const char *name;
01081
01082
01083 name = pbx_builtin_getvar_helper(chan, "PARKINGLOT");
01084 if (!name && !ast_strlen_zero(chan->parkinglot)) {
01085
01086 name = chan->parkinglot;
01087 }
01088 return name;
01089 }
01090
01091
01092 static void notify_metermaids(const char *exten, char *context, enum ast_device_state state)
01093 {
01094 ast_debug(4, "Notification of state change to metermaids %s@%s\n to state '%s'",
01095 exten, context, ast_devstate2str(state));
01096
01097 ast_devstate_changed(state, "park:%s@%s", exten, context);
01098 }
01099
01100
01101 static enum ast_device_state metermaidstate(const char *data)
01102 {
01103 char *context;
01104 char *exten;
01105
01106 context = ast_strdupa(data);
01107
01108 exten = strsep(&context, "@");
01109 if (!context)
01110 return AST_DEVICE_INVALID;
01111
01112 ast_debug(4, "Checking state of exten %s in context %s\n", exten, context);
01113
01114 if (!ast_exists_extension(NULL, context, exten, 1, NULL))
01115 return AST_DEVICE_NOT_INUSE;
01116
01117 return AST_DEVICE_INUSE;
01118 }
01119
01120
01121 enum ast_park_call_options {
01122
01123 AST_PARK_OPT_RINGING = (1 << 0),
01124
01125
01126 AST_PARK_OPT_RANDOMIZE = (1 << 1),
01127
01128 AST_PARK_OPT_SILENCE = (1 << 2),
01129 };
01130
01131
01132 struct ast_park_call_args {
01133
01134
01135
01136 int timeout;
01137
01138
01139 int *extout;
01140 const char *orig_chan_name;
01141 const char *return_con;
01142 const char *return_ext;
01143 int return_pri;
01144 uint32_t flags;
01145
01146 struct parkeduser *pu;
01147
01148 struct ast_parkinglot *parkinglot;
01149 };
01150
01151
01152
01153
01154
01155
01156
01157
01158
01159
01160
01161 static struct ast_parkinglot *create_dynamic_parkinglot(const char *name, struct ast_channel *chan)
01162 {
01163 const char *dyn_context;
01164 const char *dyn_exten;
01165 const char *dyn_range;
01166 const char *template_name;
01167 struct ast_parkinglot *template_parkinglot = NULL;
01168 struct ast_parkinglot *parkinglot;
01169 int dyn_start;
01170 int dyn_end;
01171
01172 ast_channel_lock(chan);
01173 template_name = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNAMIC"), ""));
01174 dyn_context = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNCONTEXT"), ""));
01175 dyn_exten = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNEXTEN"), ""));
01176 dyn_range = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNPOS"), ""));
01177 ast_channel_unlock(chan);
01178
01179 if (!ast_strlen_zero(template_name)) {
01180 template_parkinglot = find_parkinglot(template_name);
01181 if (!template_parkinglot) {
01182 ast_debug(1, "PARKINGDYNAMIC lot %s does not exist.\n",
01183 template_name);
01184 } else if (template_parkinglot->cfg.is_invalid) {
01185 ast_debug(1, "PARKINGDYNAMIC lot %s has invalid config.\n",
01186 template_name);
01187 parkinglot_unref(template_parkinglot);
01188 template_parkinglot = NULL;
01189 }
01190 }
01191 if (!template_parkinglot) {
01192 template_parkinglot = parkinglot_addref(default_parkinglot);
01193 ast_debug(1, "Using default parking lot for template\n");
01194 }
01195
01196 parkinglot = copy_parkinglot(name, template_parkinglot);
01197 if (!parkinglot) {
01198 ast_log(LOG_ERROR, "Could not build dynamic parking lot!\n");
01199 } else {
01200
01201 if (!ast_strlen_zero(dyn_context)) {
01202 ast_copy_string(parkinglot->cfg.parking_con, dyn_context,
01203 sizeof(parkinglot->cfg.parking_con));
01204 }
01205 if (!ast_strlen_zero(dyn_exten)) {
01206 ast_copy_string(parkinglot->cfg.parkext, dyn_exten,
01207 sizeof(parkinglot->cfg.parkext));
01208 }
01209 if (!ast_strlen_zero(dyn_range)) {
01210 if (sscanf(dyn_range, "%30d-%30d", &dyn_start, &dyn_end) != 2) {
01211 ast_log(LOG_WARNING,
01212 "Format for parking positions is a-b, where a and b are numbers\n");
01213 } else if (dyn_end < dyn_start || dyn_start <= 0 || dyn_end <= 0) {
01214 ast_log(LOG_WARNING,
01215 "Format for parking positions is a-b, where a <= b\n");
01216 } else {
01217 parkinglot->cfg.parking_start = dyn_start;
01218 parkinglot->cfg.parking_stop = dyn_end;
01219 }
01220 }
01221
01222
01223
01224
01225
01226
01227
01228
01229 if (!strcmp(parkinglot->cfg.parking_con, template_parkinglot->cfg.parking_con)) {
01230 if (!strcmp(parkinglot->cfg.parkext, template_parkinglot->cfg.parkext)
01231 && parkinglot->cfg.parkext_exclusive) {
01232 ast_log(LOG_WARNING,
01233 "Parking lot '%s' conflicts with template parking lot '%s'!\n"
01234 "Change either PARKINGDYNCONTEXT or PARKINGDYNEXTEN.\n",
01235 parkinglot->name, template_parkinglot->name);
01236 }
01237 if ((template_parkinglot->cfg.parking_start <= parkinglot->cfg.parking_start
01238 && parkinglot->cfg.parking_start <= template_parkinglot->cfg.parking_stop)
01239 || (template_parkinglot->cfg.parking_start <= parkinglot->cfg.parking_stop
01240 && parkinglot->cfg.parking_stop <= template_parkinglot->cfg.parking_stop)
01241 || (parkinglot->cfg.parking_start < template_parkinglot->cfg.parking_start
01242 && template_parkinglot->cfg.parking_stop < parkinglot->cfg.parking_stop)) {
01243 ast_log(LOG_WARNING,
01244 "Parking lot '%s' parking spaces overlap template parking lot '%s'!\n"
01245 "Change PARKINGDYNPOS.\n",
01246 parkinglot->name, template_parkinglot->name);
01247 }
01248 }
01249
01250 parkinglot_activate(parkinglot);
01251 ao2_link(parkinglots, parkinglot);
01252 }
01253 parkinglot_unref(template_parkinglot);
01254
01255 return parkinglot;
01256 }
01257
01258
01259
01260
01261
01262
01263
01264
01265
01266
01267
01268 static void park_space_abort(struct parkeduser *pu)
01269 {
01270 struct ast_parkinglot *parkinglot;
01271
01272 parkinglot = pu->parkinglot;
01273
01274
01275 --parkinglot->next_parking_space;
01276
01277 AST_LIST_REMOVE(&parkinglot->parkings, pu, list);
01278
01279 AST_LIST_UNLOCK(&parkinglot->parkings);
01280 parkinglot_unref(parkinglot);
01281 ast_free(pu);
01282 }
01283
01284
01285
01286
01287
01288
01289
01290
01291
01292
01293
01294
01295 static struct parkeduser *park_space_reserve(struct ast_channel *park_me, struct ast_channel *parker, struct ast_park_call_args *args)
01296 {
01297 struct parkeduser *pu;
01298 int i;
01299 int parking_space = -1;
01300 const char *parkinglotname;
01301 const char *parkingexten;
01302 struct parkeduser *cur;
01303 struct ast_parkinglot *parkinglot = NULL;
01304
01305 if (args->parkinglot) {
01306 parkinglot = parkinglot_addref(args->parkinglot);
01307 parkinglotname = parkinglot->name;
01308 } else {
01309 if (parker) {
01310 parkinglotname = findparkinglotname(parker);
01311 } else {
01312 parkinglotname = findparkinglotname(park_me);
01313 }
01314 if (!ast_strlen_zero(parkinglotname)) {
01315 parkinglot = find_parkinglot(parkinglotname);
01316 } else {
01317
01318 ast_debug(4, "This could be an indication channel driver needs updating, using default lot.\n");
01319 parkinglot = parkinglot_addref(default_parkinglot);
01320 }
01321 }
01322
01323
01324 if (!parkinglot && parkeddynamic && !ast_strlen_zero(parkinglotname)) {
01325 parkinglot = create_dynamic_parkinglot(parkinglotname, park_me);
01326 }
01327
01328 if (!parkinglot) {
01329 ast_log(LOG_WARNING, "Parking lot not available to park %s.\n", park_me->name);
01330 return NULL;
01331 }
01332
01333 ast_debug(1, "Parking lot: %s\n", parkinglot->name);
01334 if (parkinglot->disabled || parkinglot->cfg.is_invalid) {
01335 ast_log(LOG_WARNING, "Parking lot %s is not in a useable state.\n",
01336 parkinglot->name);
01337 parkinglot_unref(parkinglot);
01338 return NULL;
01339 }
01340
01341
01342 if (!(pu = ast_calloc(1, sizeof(*pu)))) {
01343 parkinglot_unref(parkinglot);
01344 return NULL;
01345 }
01346
01347
01348 AST_LIST_LOCK(&parkinglot->parkings);
01349
01350
01351 parkingexten = ast_strdupa(S_OR(pbx_builtin_getvar_helper(park_me, "PARKINGEXTEN"), ""));
01352 if (!ast_strlen_zero(parkingexten)) {
01353
01354
01355
01356
01357
01358
01359
01360 if (sscanf(parkingexten, "%30d", &parking_space) != 1 || parking_space <= 0) {
01361 ast_log(LOG_WARNING, "PARKINGEXTEN='%s' is not a valid parking space.\n",
01362 parkingexten);
01363 AST_LIST_UNLOCK(&parkinglot->parkings);
01364 parkinglot_unref(parkinglot);
01365 ast_free(pu);
01366 return NULL;
01367 }
01368
01369 if (parking_space < parkinglot->cfg.parking_start
01370 || parkinglot->cfg.parking_stop < parking_space) {
01371
01372
01373
01374
01375
01376 ast_log(LOG_WARNING, "PARKINGEXTEN=%d is not in %s (%d-%d).\n",
01377 parking_space, parkinglot->name, parkinglot->cfg.parking_start,
01378 parkinglot->cfg.parking_stop);
01379 AST_LIST_UNLOCK(&parkinglot->parkings);
01380 parkinglot_unref(parkinglot);
01381 ast_free(pu);
01382 return NULL;
01383 }
01384
01385
01386 AST_LIST_TRAVERSE(&parkinglot->parkings, cur, list) {
01387 if (cur->parkingnum == parking_space) {
01388 ast_log(LOG_WARNING, "PARKINGEXTEN=%d is already in use in %s\n",
01389 parking_space, parkinglot->name);
01390 AST_LIST_UNLOCK(&parkinglot->parkings);
01391 parkinglot_unref(parkinglot);
01392 ast_free(pu);
01393 return NULL;
01394 }
01395 }
01396 } else {
01397
01398 int start;
01399 int start_checked = 0;
01400
01401
01402 if (ast_test_flag(args, AST_PARK_OPT_RANDOMIZE)) {
01403 start = ast_random() % (parkinglot->cfg.parking_stop - parkinglot->cfg.parking_start + 1);
01404 start += parkinglot->cfg.parking_start;
01405 } else if (parkinglot->cfg.parkfindnext
01406 && parkinglot->cfg.parking_start <= parkinglot->next_parking_space
01407 && parkinglot->next_parking_space <= parkinglot->cfg.parking_stop) {
01408
01409 start = parkinglot->next_parking_space;
01410 } else {
01411
01412 start = parkinglot->cfg.parking_start;
01413 }
01414
01415
01416 for (i = start; ; i++) {
01417
01418 if (i == parkinglot->cfg.parking_stop + 1) {
01419 i = parkinglot->cfg.parking_start;
01420 }
01421
01422 if (i == start) {
01423
01424 if (start_checked) {
01425 break;
01426 } else {
01427 start_checked = 1;
01428 }
01429 }
01430
01431
01432 AST_LIST_TRAVERSE(&parkinglot->parkings, cur, list) {
01433 if (cur->parkingnum == i) {
01434 break;
01435 }
01436 }
01437 if (!cur) {
01438
01439 parking_space = i;
01440 break;
01441 }
01442 }
01443 if (parking_space == -1) {
01444
01445 ast_log(LOG_WARNING, "No more parking spaces in %s\n", parkinglot->name);
01446 AST_LIST_UNLOCK(&parkinglot->parkings);
01447 parkinglot_unref(parkinglot);
01448 ast_free(pu);
01449 return NULL;
01450 }
01451 }
01452
01453
01454 parkinglot->next_parking_space = parking_space + 1;
01455
01456 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space);
01457 pu->notquiteyet = 1;
01458 pu->parkingnum = parking_space;
01459 pu->parkinglot = parkinglot;
01460 AST_LIST_INSERT_TAIL(&parkinglot->parkings, pu, list);
01461
01462 return pu;
01463 }
01464
01465
01466 static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, struct ast_park_call_args *args)
01467 {
01468 struct parkeduser *pu = args->pu;
01469 const char *event_from;
01470 char app_data[AST_MAX_EXTENSION + AST_MAX_CONTEXT];
01471
01472 if (pu == NULL) {
01473 args->pu = pu = park_space_reserve(chan, peer, args);
01474 if (pu == NULL) {
01475 return -1;
01476 }
01477 }
01478
01479 chan->appl = "Parked Call";
01480 chan->data = NULL;
01481
01482 pu->chan = chan;
01483
01484
01485 if (chan != peer) {
01486 if (ast_test_flag(args, AST_PARK_OPT_RINGING)) {
01487 pu->hold_method = AST_CONTROL_RINGING;
01488 ast_indicate(chan, AST_CONTROL_RINGING);
01489 } else {
01490 pu->hold_method = AST_CONTROL_HOLD;
01491 ast_indicate_data(chan, AST_CONTROL_HOLD,
01492 S_OR(pu->parkinglot->cfg.mohclass, NULL),
01493 !ast_strlen_zero(pu->parkinglot->cfg.mohclass) ? strlen(pu->parkinglot->cfg.mohclass) + 1 : 0);
01494 }
01495 }
01496
01497 pu->start = ast_tvnow();
01498 pu->parkingtime = (args->timeout > 0) ? args->timeout : pu->parkinglot->cfg.parkingtime;
01499 if (args->extout)
01500 *(args->extout) = pu->parkingnum;
01501
01502 if (peer) {
01503 event_from = S_OR(args->orig_chan_name, peer->name);
01504
01505
01506
01507
01508
01509
01510
01511
01512
01513
01514 if (!strcasecmp(peer->tech->type, "Local")) {
01515 struct ast_channel *tmpchan, *base_peer;
01516 char other_side[AST_CHANNEL_NAME];
01517 char *c;
01518
01519 ast_copy_string(other_side, event_from, sizeof(other_side));
01520 if ((c = strrchr(other_side, ';'))) {
01521 *++c = '1';
01522 }
01523 if ((tmpchan = ast_channel_get_by_name(other_side))) {
01524 ast_channel_lock(tmpchan);
01525 if ((base_peer = ast_bridged_channel(tmpchan))) {
01526 ast_copy_string(pu->peername, base_peer->name, sizeof(pu->peername));
01527 }
01528 ast_channel_unlock(tmpchan);
01529 tmpchan = ast_channel_unref(tmpchan);
01530 }
01531 } else {
01532 ast_copy_string(pu->peername, event_from, sizeof(pu->peername));
01533 }
01534 } else {
01535 event_from = S_OR(pbx_builtin_getvar_helper(chan, "BLINDTRANSFER"), chan->name);
01536 }
01537
01538
01539
01540
01541
01542 pu->options_specified = (!ast_strlen_zero(args->return_con) || !ast_strlen_zero(args->return_ext) || args->return_pri);
01543
01544
01545
01546
01547
01548
01549
01550 ast_copy_string(pu->context,
01551 S_OR(args->return_con, S_OR(chan->macrocontext, chan->context)),
01552 sizeof(pu->context));
01553 ast_copy_string(pu->exten,
01554 S_OR(args->return_ext, S_OR(chan->macroexten, chan->exten)),
01555 sizeof(pu->exten));
01556 pu->priority = args->return_pri ? args->return_pri :
01557 (chan->macropriority ? chan->macropriority : chan->priority);
01558
01559
01560
01561
01562
01563
01564 if (peer != chan) {
01565 pu->notquiteyet = 0;
01566 }
01567
01568
01569 pthread_kill(parking_thread, SIGURG);
01570 ast_verb(2, "Parked %s on %d (lot %s). Will timeout back to extension [%s] %s, %d in %d seconds\n",
01571 chan->name, pu->parkingnum, pu->parkinglot->name,
01572 pu->context, pu->exten, pu->priority, (pu->parkingtime / 1000));
01573
01574 ast_cel_report_event(chan, AST_CEL_PARK_START, NULL, pu->parkinglot->name, peer);
01575
01576 ast_manager_event(chan, EVENT_FLAG_CALL, "ParkedCall",
01577 "Exten: %s\r\n"
01578 "Channel: %s\r\n"
01579 "Parkinglot: %s\r\n"
01580 "From: %s\r\n"
01581 "Timeout: %ld\r\n"
01582 "CallerIDNum: %s\r\n"
01583 "CallerIDName: %s\r\n"
01584 "ConnectedLineNum: %s\r\n"
01585 "ConnectedLineName: %s\r\n"
01586 "Uniqueid: %s\r\n",
01587 pu->parkingexten, chan->name, pu->parkinglot->name, event_from,
01588 (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL),
01589 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, "<unknown>"),
01590 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, "<unknown>"),
01591 S_COR(chan->connected.id.number.valid, chan->connected.id.number.str, "<unknown>"),
01592 S_COR(chan->connected.id.name.valid, chan->connected.id.name.str, "<unknown>"),
01593 chan->uniqueid
01594 );
01595 ast_debug(4, "peer->name: %s\n", peer ? peer->name : "-No peer-");
01596 ast_debug(4, "args->orig_chan_name: %s\n", args->orig_chan_name ? args->orig_chan_name : "-none-");
01597 ast_debug(4, "pu->peername: %s\n", pu->peername);
01598 ast_debug(4, "AMI ParkedCall Channel: %s\n", chan->name);
01599 ast_debug(4, "AMI ParkedCall From: %s\n", event_from);
01600
01601 if (peer && adsipark && ast_adsi_available(peer)) {
01602 adsi_announce_park(peer, pu->parkingexten);
01603 ast_adsi_unload_session(peer);
01604 }
01605
01606 snprintf(app_data, sizeof(app_data), "%s,%s", pu->parkingexten,
01607 pu->parkinglot->name);
01608 if (ast_add_extension(pu->parkinglot->cfg.parking_con, 1, pu->parkingexten, 1,
01609 NULL, NULL, parkedcall, ast_strdup(app_data), ast_free_ptr, registrar)) {
01610 ast_log(LOG_ERROR, "Could not create parked call exten: %s@%s\n",
01611 pu->parkingexten, pu->parkinglot->cfg.parking_con);
01612 } else {
01613 notify_metermaids(pu->parkingexten, pu->parkinglot->cfg.parking_con, AST_DEVICE_INUSE);
01614 }
01615
01616 AST_LIST_UNLOCK(&pu->parkinglot->parkings);
01617
01618
01619 if (peer && !ast_test_flag(args, AST_PARK_OPT_SILENCE)
01620 && (ast_strlen_zero(args->orig_chan_name) || !strcasecmp(peer->name, args->orig_chan_name))) {
01621
01622
01623
01624
01625
01626 ast_set_flag(peer, AST_FLAG_MASQ_NOSTREAM);
01627
01628 ast_say_digits(peer, pu->parkingnum, "", peer->language);
01629 ast_clear_flag(peer, AST_FLAG_MASQ_NOSTREAM);
01630 }
01631 if (peer == chan) {
01632
01633 pu->hold_method = AST_CONTROL_HOLD;
01634 ast_indicate_data(chan, AST_CONTROL_HOLD,
01635 S_OR(pu->parkinglot->cfg.mohclass, NULL),
01636 !ast_strlen_zero(pu->parkinglot->cfg.mohclass) ? strlen(pu->parkinglot->cfg.mohclass) + 1 : 0);
01637 pu->notquiteyet = 0;
01638 pthread_kill(parking_thread, SIGURG);
01639 }
01640 return 0;
01641 }
01642
01643 int ast_park_call_exten(struct ast_channel *park_me, struct ast_channel *parker, const char *park_exten, const char *park_context, int timeout, int *extout)
01644 {
01645 int res;
01646 char *parse;
01647 const char *app_data;
01648 struct ast_exten *exten;
01649 struct park_app_args app_args;
01650 struct ast_park_call_args args = {
01651 .timeout = timeout,
01652 .extout = extout,
01653 };
01654
01655 if (!park_exten || !park_context) {
01656 return park_call_full(park_me, parker, &args);
01657 }
01658
01659
01660
01661
01662
01663 if (parker && parker != park_me) {
01664 ast_autoservice_start(park_me);
01665 }
01666 exten = get_parking_exten(park_exten, parker, park_context);
01667 if (exten) {
01668 app_data = ast_get_extension_app_data(exten);
01669 if (!app_data) {
01670 app_data = "";
01671 }
01672 parse = ast_strdupa(app_data);
01673 AST_STANDARD_APP_ARGS(app_args, parse);
01674
01675 if (!ast_strlen_zero(app_args.pl_name)) {
01676
01677 args.parkinglot = find_parkinglot(app_args.pl_name);
01678 if (!args.parkinglot && parkeddynamic) {
01679 args.parkinglot = create_dynamic_parkinglot(app_args.pl_name, park_me);
01680 }
01681 }
01682 }
01683 if (parker && parker != park_me) {
01684 ast_autoservice_stop(park_me);
01685 }
01686
01687 res = park_call_full(park_me, parker, &args);
01688 if (args.parkinglot) {
01689 parkinglot_unref(args.parkinglot);
01690 }
01691 return res;
01692 }
01693
01694 int ast_park_call(struct ast_channel *park_me, struct ast_channel *parker, int timeout, const char *park_exten, int *extout)
01695 {
01696 struct ast_park_call_args args = {
01697 .timeout = timeout,
01698 .extout = extout,
01699 };
01700
01701 return park_call_full(park_me, parker, &args);
01702 }
01703
01704
01705
01706
01707
01708
01709
01710
01711
01712
01713
01714 static int masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, struct ast_park_call_args *args)
01715 {
01716 struct ast_channel *chan;
01717
01718
01719 chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten,
01720 rchan->context, rchan->linkedid, rchan->amaflags, "Parked/%s", rchan->name);
01721 if (!chan) {
01722 ast_log(LOG_WARNING, "Unable to create parked channel\n");
01723 if (!ast_test_flag(args, AST_PARK_OPT_SILENCE)) {
01724 if (peer == rchan) {
01725
01726 ast_stream_and_wait(peer, "pbx-parkingfailed", "");
01727 } else if (peer) {
01728
01729 play_message_on_chan(peer, rchan, "failure message", "pbx-parkingfailed");
01730 }
01731 }
01732 return -1;
01733 }
01734
01735 args->pu = park_space_reserve(rchan, peer, args);
01736 if (!args->pu) {
01737 ast_hangup(chan);
01738 if (!ast_test_flag(args, AST_PARK_OPT_SILENCE)) {
01739 if (peer == rchan) {
01740
01741 ast_stream_and_wait(peer, "pbx-parkingfailed", "");
01742 } else if (peer) {
01743
01744 play_message_on_chan(peer, rchan, "failure message", "pbx-parkingfailed");
01745 }
01746 }
01747 return -1;
01748 }
01749
01750
01751 chan->readformat = rchan->readformat;
01752 chan->writeformat = rchan->writeformat;
01753
01754 if (ast_channel_masquerade(chan, rchan)) {
01755 park_space_abort(args->pu);
01756 args->pu = NULL;
01757 ast_hangup(chan);
01758 if (!ast_test_flag(args, AST_PARK_OPT_SILENCE)) {
01759 if (peer == rchan) {
01760
01761 ast_stream_and_wait(peer, "pbx-parkingfailed", "");
01762 } else if (peer) {
01763
01764 play_message_on_chan(peer, rchan, "failure message", "pbx-parkingfailed");
01765 }
01766 }
01767 return -1;
01768 }
01769
01770
01771 set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority);
01772
01773
01774 ast_copy_string(chan->macrocontext,rchan->macrocontext,sizeof(chan->macrocontext));
01775 ast_copy_string(chan->macroexten,rchan->macroexten,sizeof(chan->macroexten));
01776 chan->macropriority = rchan->macropriority;
01777
01778
01779 ast_do_masquerade(chan);
01780
01781 if (peer == rchan) {
01782 peer = chan;
01783 }
01784
01785
01786 park_call_full(chan, peer, args);
01787
01788 return 0;
01789 }
01790
01791 int ast_masq_park_call_exten(struct ast_channel *park_me, struct ast_channel *parker, const char *park_exten, const char *park_context, int timeout, int *extout)
01792 {
01793 int res;
01794 char *parse;
01795 const char *app_data;
01796 struct ast_exten *exten;
01797 struct park_app_args app_args;
01798 struct ast_park_call_args args = {
01799 .timeout = timeout,
01800 .extout = extout,
01801 };
01802
01803 if (parker) {
01804 args.orig_chan_name = ast_strdupa(parker->name);
01805 }
01806 if (!park_exten || !park_context) {
01807 return masq_park_call(park_me, parker, &args);
01808 }
01809
01810
01811
01812
01813
01814 if (parker && parker != park_me) {
01815 ast_autoservice_start(park_me);
01816 }
01817 exten = get_parking_exten(park_exten, parker, park_context);
01818 if (exten) {
01819 app_data = ast_get_extension_app_data(exten);
01820 if (!app_data) {
01821 app_data = "";
01822 }
01823 parse = ast_strdupa(app_data);
01824 AST_STANDARD_APP_ARGS(app_args, parse);
01825
01826 if (!ast_strlen_zero(app_args.pl_name)) {
01827
01828 args.parkinglot = find_parkinglot(app_args.pl_name);
01829 if (!args.parkinglot && parkeddynamic) {
01830 args.parkinglot = create_dynamic_parkinglot(app_args.pl_name, park_me);
01831 }
01832 }
01833 }
01834 if (parker && parker != park_me) {
01835 ast_autoservice_stop(park_me);
01836 }
01837
01838 res = masq_park_call(park_me, parker, &args);
01839 if (args.parkinglot) {
01840 parkinglot_unref(args.parkinglot);
01841 }
01842 return res;
01843 }
01844
01845 int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
01846 {
01847 struct ast_park_call_args args = {
01848 .timeout = timeout,
01849 .extout = extout,
01850 };
01851
01852 if (peer) {
01853 args.orig_chan_name = ast_strdupa(peer->name);
01854 }
01855 return masq_park_call(rchan, peer, &args);
01856 }
01857
01858 static int finishup(struct ast_channel *chan)
01859 {
01860 ast_indicate(chan, AST_CONTROL_UNHOLD);
01861
01862 return ast_autoservice_stop(chan);
01863 }
01864
01865
01866
01867
01868
01869
01870
01871
01872
01873
01874
01875
01876
01877
01878
01879 static int xfer_park_call_helper(struct ast_channel *park_me, struct ast_channel *parker, struct ast_exten *park_exten)
01880 {
01881 char *parse;
01882 const char *app_data;
01883 const char *pl_name;
01884 struct ast_park_call_args args = { 0, };
01885 struct park_app_args app_args;
01886 int res;
01887
01888 app_data = ast_get_extension_app_data(park_exten);
01889 if (!app_data) {
01890 app_data = "";
01891 }
01892 parse = ast_strdupa(app_data);
01893 AST_STANDARD_APP_ARGS(app_args, parse);
01894
01895
01896 if (!ast_strlen_zero(app_args.pl_name)) {
01897 pl_name = app_args.pl_name;
01898 } else {
01899 pl_name = findparkinglotname(parker);
01900 }
01901 if (ast_strlen_zero(pl_name)) {
01902
01903 args.parkinglot = parkinglot_addref(default_parkinglot);
01904 } else {
01905 args.parkinglot = find_parkinglot(pl_name);
01906 if (!args.parkinglot && parkeddynamic) {
01907 args.parkinglot = create_dynamic_parkinglot(pl_name, park_me);
01908 }
01909 }
01910
01911 if (args.parkinglot) {
01912
01913 res = finishup(park_me);
01914 if (res) {
01915
01916 parkinglot_unref(args.parkinglot);
01917 return -1;
01918 }
01919 res = masq_park_call(park_me, parker, &args);
01920 parkinglot_unref(args.parkinglot);
01921 } else {
01922
01923 if (!ast_test_flag(&args, AST_PARK_OPT_SILENCE)) {
01924 ast_stream_and_wait(parker, "pbx-parkingfailed", "");
01925 }
01926 finishup(park_me);
01927 res = -1;
01928 }
01929
01930 return res ? AST_FEATURE_RETURN_SUCCESS : -1;
01931 }
01932
01933
01934
01935
01936
01937
01938
01939 static void set_peers(struct ast_channel **caller, struct ast_channel **callee,
01940 struct ast_channel *peer, struct ast_channel *chan, int sense)
01941 {
01942 if (sense == FEATURE_SENSE_PEER) {
01943 *caller = peer;
01944 *callee = chan;
01945 } else {
01946 *callee = peer;
01947 *caller = chan;
01948 }
01949 }
01950
01951
01952
01953
01954
01955
01956
01957
01958
01959
01960
01961
01962
01963
01964 static int builtin_parkcall(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
01965 {
01966 struct ast_channel *parker;
01967 struct ast_channel *parkee;
01968 struct ast_park_call_args args = { 0, };
01969
01970
01971
01972
01973
01974
01975
01976
01977
01978
01979
01980 if (chan->_state != AST_STATE_UP) {
01981
01982
01983
01984
01985 if (ast_answer(chan)) {
01986 return -1;
01987 }
01988
01989
01990 if (ast_safe_sleep(chan, 1000)) {
01991 return -1;
01992 }
01993 }
01994
01995
01996 set_peers(&parker, &parkee, peer, chan, sense);
01997 return masq_park_call(parkee, parker, &args) ? AST_FEATURE_RETURN_SUCCESS : -1;
01998 }
01999
02000
02001
02002
02003
02004
02005
02006
02007
02008
02009
02010
02011
02012 static int play_message_on_chan(struct ast_channel *play_to, struct ast_channel *other, const char *msg, const char *audiofile)
02013 {
02014
02015 if (ast_autoservice_start(other)) {
02016 return -1;
02017 }
02018 ast_autoservice_ignore(other, AST_FRAME_DTMF_BEGIN);
02019 ast_autoservice_ignore(other, AST_FRAME_DTMF_END);
02020 if (ast_stream_and_wait(play_to, audiofile, "")) {
02021 ast_log(LOG_WARNING, "Failed to play %s '%s'!\n", msg, audiofile);
02022 ast_autoservice_stop(other);
02023 return -1;
02024 }
02025 if (ast_autoservice_stop(other)) {
02026 return -1;
02027 }
02028 return 0;
02029 }
02030
02031
02032
02033
02034
02035
02036
02037
02038
02039
02040
02041
02042
02043
02044
02045
02046
02047 static int play_message_to_chans(struct ast_channel *left, struct ast_channel *right, int which, const char *msg, const char *audiofile)
02048 {
02049
02050 if (which <= 0 && play_message_on_chan(left, right, msg, audiofile)) {
02051 return -1;
02052 }
02053
02054
02055 if (which >= 0 && play_message_on_chan(right, left, msg, audiofile)) {
02056 return -1;
02057 }
02058
02059 return 0;
02060 }
02061
02062
02063
02064
02065
02066 static int play_message_in_bridged_call(struct ast_channel *caller_chan, struct ast_channel *callee_chan, const char *audiofile)
02067 {
02068 return play_message_to_chans(caller_chan, callee_chan, 0, "automon message",
02069 audiofile);
02070 }
02071
02072
02073
02074
02075
02076
02077
02078
02079
02080
02081
02082
02083
02084
02085
02086 static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
02087 {
02088 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
02089 int x = 0;
02090 size_t len;
02091 struct ast_channel *caller_chan, *callee_chan;
02092 const char *automon_message_start = NULL;
02093 const char *automon_message_stop = NULL;
02094 const char *touch_format = NULL;
02095 const char *touch_monitor = NULL;
02096 const char *touch_monitor_prefix = NULL;
02097
02098 if (!monitor_ok) {
02099 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
02100 return -1;
02101 }
02102
02103 if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) {
02104 monitor_ok = 0;
02105 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
02106 return -1;
02107 }
02108
02109 set_peers(&caller_chan, &callee_chan, peer, chan, sense);
02110
02111
02112 automon_message_start = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_START");
02113 automon_message_stop = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_STOP");
02114
02115 if (!ast_strlen_zero(courtesytone)) {
02116 if(play_message_in_bridged_call(caller_chan, callee_chan, courtesytone) == -1) {
02117 return -1;
02118 }
02119 }
02120
02121 if (callee_chan->monitor) {
02122 ast_verb(4, "User hit '%s' to stop recording call.\n", code);
02123 if (!ast_strlen_zero(automon_message_stop)) {
02124 play_message_in_bridged_call(caller_chan, callee_chan, automon_message_stop);
02125 }
02126 callee_chan->monitor->stop(callee_chan, 1);
02127 return AST_FEATURE_RETURN_SUCCESS;
02128 }
02129
02130 touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT");
02131 touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
02132 touch_monitor_prefix = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_PREFIX");
02133
02134 if (!touch_format)
02135 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
02136
02137 if (!touch_monitor)
02138 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
02139
02140 if (!touch_monitor_prefix)
02141 touch_monitor_prefix = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_PREFIX");
02142
02143 if (touch_monitor) {
02144 len = strlen(touch_monitor) + 50;
02145 args = alloca(len);
02146 touch_filename = alloca(len);
02147 snprintf(touch_filename, len, "%s-%ld-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), touch_monitor);
02148 snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename);
02149 } else {
02150 caller_chan_id = ast_strdupa(S_COR(caller_chan->caller.id.number.valid,
02151 caller_chan->caller.id.number.str, caller_chan->name));
02152 callee_chan_id = ast_strdupa(S_COR(callee_chan->caller.id.number.valid,
02153 callee_chan->caller.id.number.str, callee_chan->name));
02154 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
02155 args = alloca(len);
02156 touch_filename = alloca(len);
02157 snprintf(touch_filename, len, "%s-%ld-%s-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), caller_chan_id, callee_chan_id);
02158 snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename);
02159 }
02160
02161 for(x = 0; x < strlen(args); x++) {
02162 if (args[x] == '/')
02163 args[x] = '-';
02164 }
02165
02166 ast_verb(4, "User hit '%s' to record call. filename: %s\n", code, args);
02167
02168 pbx_exec(callee_chan, monitor_app, args);
02169 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
02170 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
02171
02172 if (!ast_strlen_zero(automon_message_start)) {
02173 play_message_in_bridged_call(caller_chan, callee_chan, automon_message_start);
02174 }
02175
02176 return AST_FEATURE_RETURN_SUCCESS;
02177 }
02178
02179 static int builtin_automixmonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
02180 {
02181 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
02182 int x = 0;
02183 size_t len;
02184 struct ast_channel *caller_chan, *callee_chan;
02185 const char *mixmonitor_spy_type = "MixMonitor";
02186 const char *touch_format;
02187 const char *touch_monitor;
02188 int count = 0;
02189
02190 if (!mixmonitor_ok) {
02191 ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n");
02192 return -1;
02193 }
02194
02195 if (!(mixmonitor_app = pbx_findapp("MixMonitor"))) {
02196 mixmonitor_ok = 0;
02197 ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n");
02198 return -1;
02199 }
02200
02201 set_peers(&caller_chan, &callee_chan, peer, chan, sense);
02202
02203 if (!ast_strlen_zero(courtesytone)) {
02204 if (ast_autoservice_start(callee_chan))
02205 return -1;
02206 ast_autoservice_ignore(callee_chan, AST_FRAME_DTMF_END);
02207 if (ast_stream_and_wait(caller_chan, courtesytone, "")) {
02208 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
02209 ast_autoservice_stop(callee_chan);
02210 return -1;
02211 }
02212 if (ast_autoservice_stop(callee_chan))
02213 return -1;
02214 }
02215
02216 ast_channel_lock(callee_chan);
02217 count = ast_channel_audiohook_count_by_source(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY);
02218 ast_channel_unlock(callee_chan);
02219
02220
02221 if (count > 0) {
02222 ast_verb(3, "User hit '%s' to stop recording call.\n", code);
02223
02224
02225 ast_channel_lock(callee_chan);
02226 count = ast_channel_audiohook_count_by_source_running(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY);
02227 ast_channel_unlock(callee_chan);
02228 if (count > 0) {
02229 if (!stopmixmonitor_ok) {
02230 ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n");
02231 return -1;
02232 }
02233 if (!(stopmixmonitor_app = pbx_findapp("StopMixMonitor"))) {
02234 stopmixmonitor_ok = 0;
02235 ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n");
02236 return -1;
02237 } else {
02238 pbx_exec(callee_chan, stopmixmonitor_app, "");
02239 return AST_FEATURE_RETURN_SUCCESS;
02240 }
02241 }
02242
02243 ast_log(LOG_WARNING,"Stopped MixMonitors are attached to the channel.\n");
02244 }
02245
02246 touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR_FORMAT");
02247 touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR");
02248
02249 if (!touch_format)
02250 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR_FORMAT");
02251
02252 if (!touch_monitor)
02253 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR");
02254
02255 if (touch_monitor) {
02256 len = strlen(touch_monitor) + 50;
02257 args = alloca(len);
02258 touch_filename = alloca(len);
02259 snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor);
02260 snprintf(args, len, "%s.%s,b", touch_filename, (touch_format) ? touch_format : "wav");
02261 } else {
02262 caller_chan_id = ast_strdupa(S_COR(caller_chan->caller.id.number.valid,
02263 caller_chan->caller.id.number.str, caller_chan->name));
02264 callee_chan_id = ast_strdupa(S_COR(callee_chan->caller.id.number.valid,
02265 callee_chan->caller.id.number.str, callee_chan->name));
02266 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
02267 args = alloca(len);
02268 touch_filename = alloca(len);
02269 snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id);
02270 snprintf(args, len, "%s.%s,b", touch_filename, S_OR(touch_format, "wav"));
02271 }
02272
02273 for( x = 0; x < strlen(args); x++) {
02274 if (args[x] == '/')
02275 args[x] = '-';
02276 }
02277
02278 ast_verb(3, "User hit '%s' to record call. filename: %s\n", code, touch_filename);
02279
02280 pbx_exec(callee_chan, mixmonitor_app, args);
02281 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename);
02282 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename);
02283 return AST_FEATURE_RETURN_SUCCESS;
02284 }
02285
02286 static int builtin_disconnect(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
02287 {
02288 ast_verb(4, "User hit '%s' to disconnect call.\n", code);
02289 return AST_FEATURE_RETURN_HANGUP;
02290 }
02291
02292
02293
02294
02295
02296
02297
02298
02299
02300 static const char *real_ctx(struct ast_channel *transferer, struct ast_channel *transferee)
02301 {
02302 const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT");
02303 if (ast_strlen_zero(s)) {
02304 s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT");
02305 }
02306 if (ast_strlen_zero(s)) {
02307 s = transferer->macrocontext;
02308 }
02309 if (ast_strlen_zero(s)) {
02310 s = transferer->context;
02311 }
02312 return s;
02313 }
02314
02315
02316
02317
02318
02319
02320
02321
02322
02323
02324
02325
02326
02327
02328
02329 static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
02330 {
02331 struct ast_channel *transferer;
02332 struct ast_channel *transferee;
02333 struct ast_exten *park_exten;
02334 const char *transferer_real_context;
02335 char xferto[256] = "";
02336 int res;
02337
02338 ast_debug(1, "Executing Blind Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense);
02339 set_peers(&transferer, &transferee, peer, chan, sense);
02340 transferer_real_context = real_ctx(transferer, transferee);
02341
02342
02343 ast_autoservice_start(transferee);
02344 ast_indicate(transferee, AST_CONTROL_HOLD);
02345
02346
02347 res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY);
02348 if (res < 0) {
02349 finishup(transferee);
02350 return -1;
02351 }
02352 if (res > 0) {
02353 xferto[0] = (char) res;
02354 }
02355
02356 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
02357 if (res < 0) {
02358 finishup(transferee);
02359 return -1;
02360 }
02361 if (res == 0) {
02362 if (xferto[0]) {
02363 ast_log(LOG_WARNING, "Extension '%s' does not exist in context '%s'\n",
02364 xferto, transferer_real_context);
02365 } else {
02366
02367 ast_log(LOG_WARNING, "No digits dialed.\n");
02368 }
02369 ast_stream_and_wait(transferer, "pbx-invalid", "");
02370 finishup(transferee);
02371 return AST_FEATURE_RETURN_SUCCESS;
02372 }
02373
02374 park_exten = get_parking_exten(xferto, transferer, transferer_real_context);
02375 if (park_exten) {
02376
02377 return xfer_park_call_helper(transferee, transferer, park_exten);
02378 }
02379
02380
02381 ast_verb(3, "Blind transferring %s to '%s' (context %s) priority 1\n",
02382 transferee->name, xferto, transferer_real_context);
02383 ast_cel_report_event(transferer, AST_CEL_BLINDTRANSFER, NULL, xferto, transferee);
02384 pbx_builtin_setvar_helper(transferer, "BLINDTRANSFER", transferee->name);
02385 pbx_builtin_setvar_helper(transferee, "BLINDTRANSFER", transferer->name);
02386 finishup(transferee);
02387 ast_channel_lock(transferer);
02388 if (!transferer->cdr) {
02389 transferer->cdr = ast_cdr_alloc();
02390 if (transferer->cdr) {
02391 ast_cdr_init(transferer->cdr, transferer);
02392 ast_cdr_start(transferer->cdr);
02393 }
02394 }
02395 ast_channel_unlock(transferer);
02396 if (transferer->cdr) {
02397 struct ast_cdr *swap = transferer->cdr;
02398
02399 ast_debug(1,
02400 "transferer=%s; transferee=%s; lastapp=%s; lastdata=%s; chan=%s; dstchan=%s\n",
02401 transferer->name, transferee->name, transferer->cdr->lastapp,
02402 transferer->cdr->lastdata, transferer->cdr->channel,
02403 transferer->cdr->dstchannel);
02404 ast_debug(1, "TRANSFEREE; lastapp=%s; lastdata=%s, chan=%s; dstchan=%s\n",
02405 transferee->cdr->lastapp, transferee->cdr->lastdata, transferee->cdr->channel,
02406 transferee->cdr->dstchannel);
02407 ast_debug(1, "transferer_real_context=%s; xferto=%s\n",
02408 transferer_real_context, xferto);
02409
02410 transferer->cdr = transferee->cdr;
02411 transferee->cdr = swap;
02412 }
02413 if (!transferee->pbx) {
02414
02415 ast_debug(1, "About to ast_async_goto %s.\n", transferee->name);
02416 if (ast_async_goto(transferee, transferer_real_context, xferto, 1)) {
02417 ast_log(LOG_WARNING, "Async goto failed :-(\n");
02418 }
02419
02420
02421 res = -1;
02422 } else {
02423
02424 ast_debug(1, "About to explicit goto %s, it has a PBX.\n", transferee->name);
02425 ast_set_flag(transferee, AST_FLAG_BRIDGE_HANGUP_DONT);
02426 set_c_e_p(transferee, transferer_real_context, xferto, 0);
02427
02428
02429
02430
02431
02432 res = AST_FEATURE_RETURN_SUCCESSBREAK;
02433 }
02434 check_goto_on_transfer(transferer);
02435 return res;
02436 }
02437
02438
02439
02440
02441
02442
02443
02444
02445 static int check_compat(struct ast_channel *c, struct ast_channel *newchan)
02446 {
02447 if (ast_channel_make_compatible(c, newchan) < 0) {
02448 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n",
02449 c->name, newchan->name);
02450 ast_hangup(newchan);
02451 return -1;
02452 }
02453 return 0;
02454 }
02455
02456
02457
02458
02459
02460
02461
02462
02463
02464
02465
02466
02467
02468
02469 static void atxfer_fail_cleanup(struct ast_channel *transferee, struct ast_channel *transferer, struct ast_party_connected_line *connected_line)
02470 {
02471 finishup(transferee);
02472
02473
02474
02475
02476
02477
02478
02479 if (ast_channel_connected_line_macro(transferee, transferer, connected_line, 1, 0)) {
02480 ast_channel_update_connected_line(transferer, connected_line, NULL);
02481 }
02482 ast_party_connected_line_free(connected_line);
02483 }
02484
02485
02486
02487
02488
02489
02490
02491
02492
02493
02494
02495
02496
02497
02498
02499
02500 static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
02501 {
02502 struct ast_channel *transferer;
02503 struct ast_channel *transferee;
02504 struct ast_exten *park_exten;
02505 const char *chan1_attended_sound;
02506 const char *chan2_attended_sound;
02507 const char *transferer_real_context;
02508 char xferto[256] = "";
02509 int res;
02510 int outstate=0;
02511 struct ast_channel *newchan;
02512 struct ast_channel *xferchan;
02513 struct ast_bridge_thread_obj *tobj;
02514 struct ast_bridge_config bconfig;
02515 int l;
02516 struct ast_party_connected_line connected_line;
02517 struct ast_datastore *features_datastore;
02518 struct ast_dial_features *dialfeatures;
02519 char *transferer_tech;
02520 char *transferer_name;
02521 char *transferer_name_orig;
02522 char *dash;
02523
02524 ast_debug(1, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense);
02525 set_peers(&transferer, &transferee, peer, chan, sense);
02526 transferer_real_context = real_ctx(transferer, transferee);
02527
02528
02529 ast_autoservice_start(transferee);
02530 ast_indicate(transferee, AST_CONTROL_HOLD);
02531
02532
02533 res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY);
02534 if (res < 0) {
02535 finishup(transferee);
02536 return -1;
02537 }
02538 if (res > 0) {
02539 xferto[0] = (char) res;
02540 }
02541
02542
02543 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
02544 if (res < 0) {
02545 finishup(transferee);
02546 return -1;
02547 }
02548 l = strlen(xferto);
02549 if (res == 0) {
02550 if (l) {
02551 ast_log(LOG_WARNING, "Extension '%s' does not exist in context '%s'\n",
02552 xferto, transferer_real_context);
02553 } else {
02554
02555 ast_log(LOG_WARNING, "No digits dialed for atxfer.\n");
02556 }
02557 ast_stream_and_wait(transferer, "pbx-invalid", "");
02558 finishup(transferee);
02559 return AST_FEATURE_RETURN_SUCCESS;
02560 }
02561
02562 park_exten = get_parking_exten(xferto, transferer, transferer_real_context);
02563 if (park_exten) {
02564
02565 return xfer_park_call_helper(transferee, transferer, park_exten);
02566 }
02567
02568
02569
02570
02571
02572
02573
02574
02575 snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context);
02576
02577
02578
02579 chan1_attended_sound = pbx_builtin_getvar_helper(transferer, "ATTENDED_TRANSFER_COMPLETE_SOUND");
02580 chan2_attended_sound = pbx_builtin_getvar_helper(transferee, "ATTENDED_TRANSFER_COMPLETE_SOUND");
02581 if (!ast_strlen_zero(chan1_attended_sound)) {
02582 pbx_builtin_setvar_helper(transferer, "BRIDGE_PLAY_SOUND", chan1_attended_sound);
02583 }
02584 if (!ast_strlen_zero(chan2_attended_sound)) {
02585 pbx_builtin_setvar_helper(transferee, "BRIDGE_PLAY_SOUND", chan2_attended_sound);
02586 }
02587
02588
02589 transferer_name_orig = ast_strdupa(transferer->name);
02590 transferer_name = ast_strdupa(transferer_name_orig);
02591 transferer_tech = strsep(&transferer_name, "/");
02592 dash = strrchr(transferer_name, '-');
02593 if (dash) {
02594
02595 *dash = '\0';
02596 }
02597
02598
02599 if (ast_autoservice_stop(transferee) < 0) {
02600 ast_indicate(transferee, AST_CONTROL_UNHOLD);
02601 return -1;
02602 }
02603
02604
02605 ast_party_connected_line_init(&connected_line);
02606 ast_channel_lock(transferer);
02607 ast_party_connected_line_copy(&connected_line, &transferer->connected);
02608 ast_channel_unlock(transferer);
02609 connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
02610
02611
02612 newchan = feature_request_and_dial(transferer, transferer_name_orig, transferer,
02613 transferee, "Local", ast_best_codec(transferer->nativeformats), xferto,
02614 atxfernoanswertimeout, &outstate, transferer->language);
02615 ast_debug(2, "Dial party C result: newchan:%d, outstate:%d\n", !!newchan, outstate);
02616
02617 if (!ast_check_hangup(transferer)) {
02618 int hangup_dont = 0;
02619
02620
02621 ast_debug(1, "Actually doing an attended transfer.\n");
02622
02623
02624 ast_autoservice_start(transferee);
02625
02626 ast_indicate(transferer, -1);
02627 if (!newchan) {
02628
02629 switch (outstate) {
02630 case AST_CONTROL_UNHOLD:
02631 case AST_CONTROL_BUSY:
02632 case AST_CONTROL_CONGESTION:
02633 if (ast_stream_and_wait(transferer, xfersound, "")) {
02634 ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
02635 }
02636 break;
02637 default:
02638 if (ast_stream_and_wait(transferer, xferfailsound, "")) {
02639 ast_log(LOG_WARNING, "Failed to play transfer failed sound!\n");
02640 }
02641 break;
02642 }
02643 atxfer_fail_cleanup(transferee, transferer, &connected_line);
02644 return AST_FEATURE_RETURN_SUCCESS;
02645 }
02646
02647 if (check_compat(transferer, newchan)) {
02648 if (ast_stream_and_wait(transferer, xferfailsound, "")) {
02649 ast_log(LOG_WARNING, "Failed to play transfer failed sound!\n");
02650 }
02651 atxfer_fail_cleanup(transferee, transferer, &connected_line);
02652 return AST_FEATURE_RETURN_SUCCESS;
02653 }
02654 memset(&bconfig,0,sizeof(struct ast_bridge_config));
02655 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
02656 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
02657
02658
02659
02660
02661
02662
02663 if (ast_test_flag(transferer, AST_FLAG_BRIDGE_HANGUP_DONT)) {
02664 hangup_dont = 1;
02665 }
02666
02667
02668
02669
02670
02671 ast_set_flag(transferer, AST_FLAG_BRIDGE_HANGUP_DONT);
02672
02673
02674
02675
02676
02677 ast_bridge_call(transferer, newchan, &bconfig);
02678
02679 if (hangup_dont) {
02680
02681 ast_set_flag(transferer, AST_FLAG_BRIDGE_HANGUP_DONT);
02682 }
02683
02684 if (ast_check_hangup(newchan) || !ast_check_hangup(transferer)) {
02685 ast_hangup(newchan);
02686 if (ast_stream_and_wait(transferer, xfersound, "")) {
02687 ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
02688 }
02689 atxfer_fail_cleanup(transferee, transferer, &connected_line);
02690 return AST_FEATURE_RETURN_SUCCESS;
02691 }
02692
02693
02694 if (check_compat(transferee, newchan)) {
02695 finishup(transferee);
02696 ast_party_connected_line_free(&connected_line);
02697 return -1;
02698 }
02699
02700 ast_indicate(transferee, AST_CONTROL_UNHOLD);
02701 if ((ast_autoservice_stop(transferee) < 0)
02702 || (ast_waitfordigit(transferee, 100) < 0)
02703 || (ast_waitfordigit(newchan, 100) < 0)
02704 || ast_check_hangup(transferee)
02705 || ast_check_hangup(newchan)) {
02706 ast_hangup(newchan);
02707 ast_party_connected_line_free(&connected_line);
02708 return -1;
02709 }
02710 } else if (!ast_check_hangup(transferee)) {
02711
02712 ast_debug(1, "Actually doing a blonde transfer.\n");
02713
02714 if (!newchan && !atxferdropcall) {
02715
02716 unsigned int tries = 0;
02717
02718 if (ast_strlen_zero(transferer_name) || ast_strlen_zero(transferer_tech)) {
02719 ast_log(LOG_WARNING,
02720 "Transferer channel name: '%s' cannot be used for callback.\n",
02721 transferer_name_orig);
02722 ast_indicate(transferee, AST_CONTROL_UNHOLD);
02723 ast_party_connected_line_free(&connected_line);
02724 return -1;
02725 }
02726
02727 tries = 0;
02728 for (;;) {
02729
02730 ast_debug(1, "We're trying to callback %s/%s\n",
02731 transferer_tech, transferer_name);
02732 newchan = feature_request_and_dial(transferer, transferer_name_orig,
02733 transferee, transferee, transferer_tech,
02734 ast_best_codec(transferee->nativeformats), transferer_name,
02735 atxfernoanswertimeout, &outstate, transferer->language);
02736 ast_debug(2, "Dial party B result: newchan:%d, outstate:%d\n",
02737 !!newchan, outstate);
02738 if (newchan) {
02739
02740
02741
02742
02743
02744 ast_channel_lock(transferer);
02745 features_datastore = ast_channel_datastore_find(transferer,
02746 &dial_features_info, NULL);
02747 if (features_datastore && (dialfeatures = features_datastore->data)) {
02748 struct ast_flags my_features = { 0 };
02749 struct ast_flags peer_features = { 0 };
02750
02751 ast_copy_flags(&my_features, &dialfeatures->my_features,
02752 AST_FLAGS_ALL);
02753 ast_copy_flags(&peer_features, &dialfeatures->peer_features,
02754 AST_FLAGS_ALL);
02755 ast_channel_unlock(transferer);
02756 add_features_datastore(newchan, &my_features, &peer_features);
02757 } else {
02758 ast_channel_unlock(transferer);
02759 }
02760 break;
02761 }
02762 if (ast_check_hangup(transferee)) {
02763 break;
02764 }
02765
02766 ++tries;
02767 if (atxfercallbackretries <= tries) {
02768
02769 break;
02770 }
02771
02772 if (atxferloopdelay) {
02773
02774 ast_debug(1, "Sleeping for %d ms before retrying atxfer.\n",
02775 atxferloopdelay);
02776 ast_safe_sleep(transferee, atxferloopdelay);
02777 if (ast_check_hangup(transferee)) {
02778 ast_party_connected_line_free(&connected_line);
02779 return -1;
02780 }
02781 }
02782
02783
02784 ast_debug(1, "We're retrying to call %s/%s\n", "Local", xferto);
02785 newchan = feature_request_and_dial(transferer, transferer_name_orig,
02786 transferer, transferee, "Local",
02787 ast_best_codec(transferee->nativeformats), xferto,
02788 atxfernoanswertimeout, &outstate, transferer->language);
02789 ast_debug(2, "Redial party C result: newchan:%d, outstate:%d\n",
02790 !!newchan, outstate);
02791 if (newchan || ast_check_hangup(transferee)) {
02792 break;
02793 }
02794 }
02795 }
02796 ast_indicate(transferee, AST_CONTROL_UNHOLD);
02797 if (!newchan) {
02798
02799 ast_party_connected_line_free(&connected_line);
02800 return -1;
02801 }
02802
02803
02804 if (ast_check_hangup(newchan)) {
02805 ast_hangup(newchan);
02806 ast_party_connected_line_free(&connected_line);
02807 return -1;
02808 }
02809 if (check_compat(transferee, newchan)) {
02810 ast_party_connected_line_free(&connected_line);
02811 return -1;
02812 }
02813 } else {
02814
02815
02816
02817
02818 ast_debug(1, "Everyone is hungup.\n");
02819 if (newchan) {
02820 ast_hangup(newchan);
02821 }
02822 ast_party_connected_line_free(&connected_line);
02823 return -1;
02824 }
02825
02826
02827 ast_cel_report_event(transferee, AST_CEL_ATTENDEDTRANSFER, NULL, NULL, newchan);
02828
02829 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", transferee->linkedid, 0, "Transfered/%s", transferee->name);
02830 if (!xferchan) {
02831 ast_hangup(newchan);
02832 ast_party_connected_line_free(&connected_line);
02833 return -1;
02834 }
02835
02836
02837 xferchan->visible_indication = AST_CONTROL_RINGING;
02838
02839
02840 xferchan->readformat = transferee->readformat;
02841 xferchan->writeformat = transferee->writeformat;
02842
02843 if (ast_channel_masquerade(xferchan, transferee)) {
02844 ast_hangup(xferchan);
02845 ast_hangup(newchan);
02846 ast_party_connected_line_free(&connected_line);
02847 return -1;
02848 }
02849 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
02850 xferchan->_state = AST_STATE_UP;
02851 ast_clear_flag(xferchan, AST_FLAGS_ALL);
02852
02853
02854 ast_do_masquerade(xferchan);
02855
02856 newchan->_state = AST_STATE_UP;
02857 ast_clear_flag(newchan, AST_FLAGS_ALL);
02858 tobj = ast_calloc(1, sizeof(*tobj));
02859 if (!tobj) {
02860 ast_hangup(xferchan);
02861 ast_hangup(newchan);
02862 ast_party_connected_line_free(&connected_line);
02863 return -1;
02864 }
02865
02866 tobj->chan = newchan;
02867 tobj->peer = xferchan;
02868 tobj->bconfig = *config;
02869
02870 ast_channel_lock(newchan);
02871 features_datastore = ast_channel_datastore_find(newchan, &dial_features_info, NULL);
02872 if (features_datastore && (dialfeatures = features_datastore->data)) {
02873 ast_copy_flags(&tobj->bconfig.features_callee, &dialfeatures->my_features,
02874 AST_FLAGS_ALL);
02875 }
02876 ast_channel_unlock(newchan);
02877
02878 ast_channel_lock(xferchan);
02879 features_datastore = ast_channel_datastore_find(xferchan, &dial_features_info, NULL);
02880 if (features_datastore && (dialfeatures = features_datastore->data)) {
02881 ast_copy_flags(&tobj->bconfig.features_caller, &dialfeatures->my_features,
02882 AST_FLAGS_ALL);
02883 }
02884 ast_channel_unlock(xferchan);
02885
02886 if (tobj->bconfig.end_bridge_callback_data_fixup) {
02887 tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan);
02888 }
02889
02890
02891
02892
02893
02894
02895
02896
02897
02898
02899
02900
02901
02902
02903
02904
02905
02906
02907
02908
02909
02910
02911
02912
02913
02914
02915
02916
02917
02918
02919
02920 ast_channel_lock(transferer);
02921
02922
02923
02924
02925 ast_party_connected_line_copy(&connected_line, &transferer->connected);
02926 ast_channel_unlock(transferer);
02927 connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
02928 if (ast_channel_connected_line_macro(newchan, xferchan, &connected_line, 1, 0)) {
02929 ast_channel_update_connected_line(xferchan, &connected_line, NULL);
02930 }
02931
02932
02933 ast_channel_lock(xferchan);
02934 ast_connected_line_copy_from_caller(&connected_line, &xferchan->caller);
02935 ast_channel_unlock(xferchan);
02936 connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
02937 if (ast_channel_connected_line_macro(xferchan, newchan, &connected_line, 0, 0)) {
02938 ast_channel_update_connected_line(newchan, &connected_line, NULL);
02939 }
02940
02941 if (ast_stream_and_wait(newchan, xfersound, ""))
02942 ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
02943 bridge_call_thread_launch(tobj);
02944
02945 ast_party_connected_line_free(&connected_line);
02946 return -1;
02947 }
02948
02949
02950 #define FEATURES_COUNT ARRAY_LEN(builtin_features)
02951
02952 AST_RWLOCK_DEFINE_STATIC(features_lock);
02953
02954 static struct ast_call_feature builtin_features[] = {
02955 { AST_FEATURE_REDIRECT, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
02956 { AST_FEATURE_REDIRECT, "Attended Transfer", "atxfer", "", "", builtin_atxfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
02957 { AST_FEATURE_AUTOMON, "One Touch Monitor", "automon", "", "", builtin_automonitor, AST_FEATURE_FLAG_NEEDSDTMF, "" },
02958 { AST_FEATURE_DISCONNECT, "Disconnect Call", "disconnect", "*", "*", builtin_disconnect, AST_FEATURE_FLAG_NEEDSDTMF, "" },
02959 { AST_FEATURE_PARKCALL, "Park Call", "parkcall", "", "", builtin_parkcall, AST_FEATURE_FLAG_NEEDSDTMF, "" },
02960 { AST_FEATURE_AUTOMIXMON, "One Touch MixMonitor", "automixmon", "", "", builtin_automixmonitor, AST_FEATURE_FLAG_NEEDSDTMF, "" },
02961 };
02962
02963
02964 static AST_RWLIST_HEAD_STATIC(feature_list, ast_call_feature);
02965
02966
02967 void ast_register_feature(struct ast_call_feature *feature)
02968 {
02969 if (!feature) {
02970 ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
02971 return;
02972 }
02973
02974 AST_RWLIST_WRLOCK(&feature_list);
02975 AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry);
02976 AST_RWLIST_UNLOCK(&feature_list);
02977
02978 ast_verb(2, "Registered Feature '%s'\n",feature->sname);
02979 }
02980
02981
02982
02983
02984
02985
02986
02987
02988 static struct feature_group *register_group(const char *fgname)
02989 {
02990 struct feature_group *fg;
02991
02992 if (!fgname) {
02993 ast_log(LOG_NOTICE, "You didn't pass a new group name!\n");
02994 return NULL;
02995 }
02996
02997 if (!(fg = ast_calloc_with_stringfields(1, struct feature_group, 128))) {
02998 return NULL;
02999 }
03000
03001 ast_string_field_set(fg, gname, fgname);
03002
03003 AST_LIST_INSERT_HEAD(&feature_groups, fg, entry);
03004
03005 ast_verb(2, "Registered group '%s'\n", fg->gname);
03006
03007 return fg;
03008 }
03009
03010
03011
03012
03013
03014
03015
03016
03017
03018
03019 static void register_group_feature(struct feature_group *fg, const char *exten, struct ast_call_feature *feature)
03020 {
03021 struct feature_group_exten *fge;
03022
03023 if (!fg) {
03024 ast_log(LOG_NOTICE, "You didn't pass a group!\n");
03025 return;
03026 }
03027
03028 if (!feature) {
03029 ast_log(LOG_NOTICE, "You didn't pass a feature!\n");
03030 return;
03031 }
03032
03033 if (!(fge = ast_calloc_with_stringfields(1, struct feature_group_exten, 128))) {
03034 return;
03035 }
03036
03037 ast_string_field_set(fge, exten, S_OR(exten, feature->exten));
03038
03039 fge->feature = feature;
03040
03041 AST_LIST_INSERT_HEAD(&fg->features, fge, entry);
03042
03043 ast_verb(2, "Registered feature '%s' for group '%s' at exten '%s'\n",
03044 feature->sname, fg->gname, fge->exten);
03045 }
03046
03047 void ast_unregister_feature(struct ast_call_feature *feature)
03048 {
03049 if (!feature) {
03050 return;
03051 }
03052
03053 AST_RWLIST_WRLOCK(&feature_list);
03054 AST_RWLIST_REMOVE(&feature_list, feature, feature_entry);
03055 AST_RWLIST_UNLOCK(&feature_list);
03056
03057 ast_free(feature);
03058 }
03059
03060
03061 static void ast_unregister_features(void)
03062 {
03063 struct ast_call_feature *feature;
03064
03065 AST_RWLIST_WRLOCK(&feature_list);
03066 while ((feature = AST_RWLIST_REMOVE_HEAD(&feature_list, feature_entry))) {
03067 ast_free(feature);
03068 }
03069 AST_RWLIST_UNLOCK(&feature_list);
03070 }
03071
03072
03073 static struct ast_call_feature *find_dynamic_feature(const char *name)
03074 {
03075 struct ast_call_feature *tmp;
03076
03077 AST_RWLIST_TRAVERSE(&feature_list, tmp, feature_entry) {
03078 if (!strcasecmp(tmp->sname, name)) {
03079 break;
03080 }
03081 }
03082
03083 return tmp;
03084 }
03085
03086
03087 static void ast_unregister_groups(void)
03088 {
03089 struct feature_group *fg;
03090 struct feature_group_exten *fge;
03091
03092 AST_RWLIST_WRLOCK(&feature_groups);
03093 while ((fg = AST_LIST_REMOVE_HEAD(&feature_groups, entry))) {
03094 while ((fge = AST_LIST_REMOVE_HEAD(&fg->features, entry))) {
03095 ast_string_field_free_memory(fge);
03096 ast_free(fge);
03097 }
03098
03099 ast_string_field_free_memory(fg);
03100 ast_free(fg);
03101 }
03102 AST_RWLIST_UNLOCK(&feature_groups);
03103 }
03104
03105
03106
03107
03108
03109
03110
03111 static struct feature_group *find_group(const char *name)
03112 {
03113 struct feature_group *fg = NULL;
03114
03115 AST_LIST_TRAVERSE(&feature_groups, fg, entry) {
03116 if (!strcasecmp(fg->gname, name))
03117 break;
03118 }
03119
03120 return fg;
03121 }
03122
03123 void ast_rdlock_call_features(void)
03124 {
03125 ast_rwlock_rdlock(&features_lock);
03126 }
03127
03128 void ast_unlock_call_features(void)
03129 {
03130 ast_rwlock_unlock(&features_lock);
03131 }
03132
03133 struct ast_call_feature *ast_find_call_feature(const char *name)
03134 {
03135 int x;
03136 for (x = 0; x < FEATURES_COUNT; x++) {
03137 if (!strcasecmp(name, builtin_features[x].sname))
03138 return &builtin_features[x];
03139 }
03140 return NULL;
03141 }
03142
03143
03144
03145
03146
03147
03148
03149
03150
03151
03152 static int feature_exec_app(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
03153 {
03154 struct ast_app *app;
03155 struct ast_call_feature *feature = data;
03156 struct ast_channel *work, *idle;
03157 int res;
03158
03159 if (!feature) {
03160 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
03161 return -1;
03162 }
03163
03164 if (sense == FEATURE_SENSE_CHAN) {
03165 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
03166 return AST_FEATURE_RETURN_KEEPTRYING;
03167 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
03168 work = chan;
03169 idle = peer;
03170 } else {
03171 work = peer;
03172 idle = chan;
03173 }
03174 } else {
03175 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
03176 return AST_FEATURE_RETURN_KEEPTRYING;
03177 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
03178 work = peer;
03179 idle = chan;
03180 } else {
03181 work = chan;
03182 idle = peer;
03183 }
03184 }
03185
03186 if (!(app = pbx_findapp(feature->app))) {
03187 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
03188 return -2;
03189 }
03190
03191 ast_autoservice_start(idle);
03192 ast_autoservice_ignore(idle, AST_FRAME_DTMF_END);
03193
03194 pbx_builtin_setvar_helper(work, "DYNAMIC_PEERNAME", idle->name);
03195 pbx_builtin_setvar_helper(idle, "DYNAMIC_PEERNAME", work->name);
03196 pbx_builtin_setvar_helper(work, "DYNAMIC_FEATURENAME", feature->sname);
03197 pbx_builtin_setvar_helper(idle, "DYNAMIC_FEATURENAME", feature->sname);
03198
03199 if (!ast_strlen_zero(feature->moh_class))
03200 ast_moh_start(idle, feature->moh_class, NULL);
03201
03202 res = pbx_exec(work, app, feature->app_args);
03203
03204 if (!ast_strlen_zero(feature->moh_class))
03205 ast_moh_stop(idle);
03206
03207 ast_autoservice_stop(idle);
03208
03209 if (res) {
03210 return AST_FEATURE_RETURN_SUCCESSBREAK;
03211 }
03212 return AST_FEATURE_RETURN_SUCCESS;
03213 }
03214
03215 static void unmap_features(void)
03216 {
03217 int x;
03218
03219 ast_rwlock_wrlock(&features_lock);
03220 for (x = 0; x < FEATURES_COUNT; x++)
03221 strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
03222 ast_rwlock_unlock(&features_lock);
03223 }
03224
03225 static int remap_feature(const char *name, const char *value)
03226 {
03227 int x, res = -1;
03228
03229 ast_rwlock_wrlock(&features_lock);
03230 for (x = 0; x < FEATURES_COUNT; x++) {
03231 if (strcasecmp(builtin_features[x].sname, name))
03232 continue;
03233
03234 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
03235 res = 0;
03236 break;
03237 }
03238 ast_rwlock_unlock(&features_lock);
03239
03240 return res;
03241 }
03242
03243
03244
03245
03246
03247
03248
03249
03250
03251
03252
03253 static int feature_interpret_helper(struct ast_channel *chan, struct ast_channel *peer,
03254 struct ast_bridge_config *config, const char *code, int sense, char *dynamic_features_buf,
03255 struct ast_flags *features, feature_interpret_op operation, struct ast_call_feature *feature)
03256 {
03257 int x;
03258 struct feature_group *fg = NULL;
03259 struct feature_group_exten *fge;
03260 struct ast_call_feature *tmpfeature;
03261 char *tmp, *tok;
03262 int res = AST_FEATURE_RETURN_PASSDIGITS;
03263 int feature_detected = 0;
03264
03265 if (!(peer && chan && config) && operation == FEATURE_INTERPRET_DO) {
03266 return -1;
03267 }
03268
03269 ast_rwlock_rdlock(&features_lock);
03270 for (x = 0; x < FEATURES_COUNT; x++) {
03271 if ((ast_test_flag(features, builtin_features[x].feature_mask)) &&
03272 !ast_strlen_zero(builtin_features[x].exten)) {
03273
03274 if (!strcmp(builtin_features[x].exten, code)) {
03275 ast_debug(3, "Feature detected: fname=%s sname=%s exten=%s\n", builtin_features[x].fname, builtin_features[x].sname, builtin_features[x].exten);
03276 if (operation == FEATURE_INTERPRET_CHECK) {
03277 res = AST_FEATURE_RETURN_SUCCESS;
03278 } else if (operation == FEATURE_INTERPRET_DO) {
03279 res = builtin_features[x].operation(chan, peer, config, code, sense, NULL);
03280 }
03281 if (feature) {
03282 memcpy(feature, &builtin_features[x], sizeof(*feature));
03283 }
03284 feature_detected = 1;
03285 break;
03286 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
03287 if (res == AST_FEATURE_RETURN_PASSDIGITS) {
03288 res = AST_FEATURE_RETURN_STOREDIGITS;
03289 }
03290 }
03291 }
03292 }
03293 ast_rwlock_unlock(&features_lock);
03294
03295 if (ast_strlen_zero(dynamic_features_buf) || feature_detected) {
03296 return res;
03297 }
03298
03299 tmp = dynamic_features_buf;
03300
03301 while ((tok = strsep(&tmp, "#"))) {
03302 AST_RWLIST_RDLOCK(&feature_groups);
03303
03304 fg = find_group(tok);
03305
03306 if (fg) {
03307 AST_LIST_TRAVERSE(&fg->features, fge, entry) {
03308 if (!strcmp(fge->exten, code)) {
03309 if (operation) {
03310 res = fge->feature->operation(chan, peer, config, code, sense, fge->feature);
03311 }
03312 if (feature) {
03313 memcpy(feature, fge->feature, sizeof(*feature));
03314 }
03315 if (res != AST_FEATURE_RETURN_KEEPTRYING) {
03316 AST_RWLIST_UNLOCK(&feature_groups);
03317 break;
03318 }
03319 res = AST_FEATURE_RETURN_PASSDIGITS;
03320 } else if (!strncmp(fge->exten, code, strlen(code))) {
03321 res = AST_FEATURE_RETURN_STOREDIGITS;
03322 }
03323 }
03324 if (fge) {
03325 break;
03326 }
03327 }
03328
03329 AST_RWLIST_UNLOCK(&feature_groups);
03330
03331 AST_RWLIST_RDLOCK(&feature_list);
03332
03333 if (!(tmpfeature = find_dynamic_feature(tok))) {
03334 AST_RWLIST_UNLOCK(&feature_list);
03335 continue;
03336 }
03337
03338
03339 if (!strcmp(tmpfeature->exten, code)) {
03340 ast_verb(3, " Feature Found: %s exten: %s\n",tmpfeature->sname, tok);
03341 if (operation == FEATURE_INTERPRET_CHECK) {
03342 res = AST_FEATURE_RETURN_SUCCESS;
03343 } else if (operation == FEATURE_INTERPRET_DO) {
03344 res = tmpfeature->operation(chan, peer, config, code, sense, tmpfeature);
03345 }
03346 if (feature) {
03347 memcpy(feature, tmpfeature, sizeof(*feature));
03348 }
03349 if (res != AST_FEATURE_RETURN_KEEPTRYING) {
03350 AST_RWLIST_UNLOCK(&feature_list);
03351 break;
03352 }
03353 res = AST_FEATURE_RETURN_PASSDIGITS;
03354 } else if (!strncmp(tmpfeature->exten, code, strlen(code)))
03355 res = AST_FEATURE_RETURN_STOREDIGITS;
03356
03357 AST_RWLIST_UNLOCK(&feature_list);
03358 }
03359
03360 return res;
03361 }
03362
03363
03364
03365
03366
03367
03368
03369
03370 static int feature_interpret(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense) {
03371
03372 char dynamic_features_buf[128];
03373 const char *peer_dynamic_features, *chan_dynamic_features;
03374 struct ast_flags features;
03375 struct ast_call_feature feature;
03376 if (sense == FEATURE_SENSE_CHAN) {
03377
03378 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
03379 }
03380 else {
03381
03382 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);
03383 }
03384
03385 ast_channel_lock(peer);
03386 peer_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES"),""));
03387 ast_channel_unlock(peer);
03388
03389 ast_channel_lock(chan);
03390 chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),""));
03391 ast_channel_unlock(chan);
03392
03393 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,""));
03394
03395 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);
03396
03397 return feature_interpret_helper(chan, peer, config, code, sense, dynamic_features_buf, &features, FEATURE_INTERPRET_DO, &feature);
03398 }
03399
03400
03401 int ast_feature_detect(struct ast_channel *chan, struct ast_flags *features, const char *code, struct ast_call_feature *feature) {
03402
03403 return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, FEATURE_INTERPRET_DETECT, feature);
03404 }
03405
03406
03407 static int feature_check(struct ast_channel *chan, struct ast_flags *features, char *code) {
03408 char *chan_dynamic_features;
03409 ast_channel_lock(chan);
03410 chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),""));
03411 ast_channel_unlock(chan);
03412
03413 return feature_interpret_helper(chan, NULL, NULL, code, 0, chan_dynamic_features, features, FEATURE_INTERPRET_CHECK, NULL);
03414 }
03415
03416 static void set_config_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
03417 {
03418 int x;
03419
03420 ast_clear_flag(config, AST_FLAGS_ALL);
03421
03422 ast_rwlock_rdlock(&features_lock);
03423 for (x = 0; x < FEATURES_COUNT; x++) {
03424 if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF))
03425 continue;
03426
03427 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
03428 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
03429
03430 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
03431 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
03432 }
03433 ast_rwlock_unlock(&features_lock);
03434
03435 if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
03436 const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
03437
03438 if (dynamic_features) {
03439 char *tmp = ast_strdupa(dynamic_features);
03440 char *tok;
03441 struct ast_call_feature *feature;
03442
03443
03444 while ((tok = strsep(&tmp, "#"))) {
03445 struct feature_group *fg;
03446
03447 AST_RWLIST_RDLOCK(&feature_groups);
03448 AST_RWLIST_TRAVERSE(&feature_groups, fg, entry) {
03449 struct feature_group_exten *fge;
03450
03451 AST_LIST_TRAVERSE(&fg->features, fge, entry) {
03452 if (ast_test_flag(fge->feature, AST_FEATURE_FLAG_BYCALLER)) {
03453 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
03454 }
03455 if (ast_test_flag(fge->feature, AST_FEATURE_FLAG_BYCALLEE)) {
03456 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
03457 }
03458 }
03459 }
03460 AST_RWLIST_UNLOCK(&feature_groups);
03461
03462 AST_RWLIST_RDLOCK(&feature_list);
03463 if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
03464 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) {
03465 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
03466 }
03467 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) {
03468 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
03469 }
03470 }
03471 AST_RWLIST_UNLOCK(&feature_list);
03472 }
03473 }
03474 }
03475 }
03476
03477
03478
03479
03480
03481
03482
03483
03484
03485
03486
03487
03488
03489
03490
03491
03492
03493
03494
03495
03496
03497
03498
03499
03500
03501
03502
03503
03504
03505
03506
03507
03508
03509
03510
03511 static struct ast_channel *feature_request_and_dial(struct ast_channel *caller,
03512 const char *caller_name, struct ast_channel *requestor,
03513 struct ast_channel *transferee, const char *type, format_t format, void *data,
03514 int timeout, int *outstate, const char *language)
03515 {
03516 int state = 0;
03517 int cause = 0;
03518 int to;
03519 int caller_hungup;
03520 int transferee_hungup;
03521 struct ast_channel *chan;
03522 struct ast_channel *monitor_chans[3];
03523 struct ast_channel *active_channel;
03524 int res;
03525 int ready = 0;
03526 struct timeval started;
03527 int x, len = 0;
03528 char *disconnect_code = NULL, *dialed_code = NULL;
03529 struct ast_frame *f;
03530 AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames;
03531
03532 caller_hungup = ast_check_hangup(caller);
03533
03534 if (!(chan = ast_request(type, format, requestor, data, &cause))) {
03535 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
03536 switch (cause) {
03537 case AST_CAUSE_BUSY:
03538 state = AST_CONTROL_BUSY;
03539 break;
03540 case AST_CAUSE_CONGESTION:
03541 state = AST_CONTROL_CONGESTION;
03542 break;
03543 default:
03544 state = 0;
03545 break;
03546 }
03547 goto done;
03548 }
03549
03550 ast_string_field_set(chan, language, language);
03551 ast_channel_inherit_variables(caller, chan);
03552 pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller_name);
03553
03554 ast_channel_lock(chan);
03555 ast_connected_line_copy_from_caller(&chan->connected, &requestor->caller);
03556 ast_channel_unlock(chan);
03557
03558 if (ast_call(chan, data, timeout)) {
03559 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
03560 switch (chan->hangupcause) {
03561 case AST_CAUSE_BUSY:
03562 state = AST_CONTROL_BUSY;
03563 break;
03564 case AST_CAUSE_CONGESTION:
03565 state = AST_CONTROL_CONGESTION;
03566 break;
03567 default:
03568 state = 0;
03569 break;
03570 }
03571 goto done;
03572 }
03573
03574
03575 ast_rwlock_rdlock(&features_lock);
03576 for (x = 0; x < FEATURES_COUNT; x++) {
03577 if (strcasecmp(builtin_features[x].sname, "disconnect"))
03578 continue;
03579
03580 disconnect_code = builtin_features[x].exten;
03581 len = strlen(disconnect_code) + 1;
03582 dialed_code = alloca(len);
03583 memset(dialed_code, 0, len);
03584 break;
03585 }
03586 ast_rwlock_unlock(&features_lock);
03587 x = 0;
03588 started = ast_tvnow();
03589 to = timeout;
03590 AST_LIST_HEAD_INIT_NOLOCK(&deferred_frames);
03591
03592 ast_poll_channel_add(caller, chan);
03593
03594 transferee_hungup = 0;
03595 while (!ast_check_hangup(transferee) && (chan->_state != AST_STATE_UP)) {
03596 int num_chans = 0;
03597
03598 monitor_chans[num_chans++] = transferee;
03599 monitor_chans[num_chans++] = chan;
03600 if (!caller_hungup) {
03601 if (ast_check_hangup(caller)) {
03602 caller_hungup = 1;
03603
03604 #if defined(ATXFER_NULL_TECH)
03605
03606 set_new_chan_name(caller);
03607
03608
03609
03610
03611
03612 set_kill_chan_tech(caller);
03613 #endif
03614 } else {
03615
03616 monitor_chans[num_chans++] = caller;
03617 }
03618 }
03619
03620
03621 if (ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
03622 state = AST_CONTROL_UNHOLD;
03623 ast_log(LOG_NOTICE, "We exceeded our AT-timeout for %s\n", chan->name);
03624 break;
03625 }
03626
03627 active_channel = ast_waitfor_n(monitor_chans, num_chans, &to);
03628 if (!active_channel)
03629 continue;
03630
03631 f = NULL;
03632 if (transferee == active_channel) {
03633 struct ast_frame *dup_f;
03634
03635 f = ast_read(transferee);
03636 if (f == NULL) {
03637 transferee_hungup = 1;
03638 state = 0;
03639 break;
03640 }
03641 if (ast_is_deferrable_frame(f)) {
03642 dup_f = ast_frisolate(f);
03643 if (dup_f) {
03644 if (dup_f == f) {
03645 f = NULL;
03646 }
03647 AST_LIST_INSERT_HEAD(&deferred_frames, dup_f, frame_list);
03648 }
03649 }
03650 } else if (chan == active_channel) {
03651 if (!ast_strlen_zero(chan->call_forward)) {
03652 state = 0;
03653 ast_autoservice_start(transferee);
03654 chan = ast_call_forward(caller, chan, NULL, format, NULL, &state);
03655 ast_autoservice_stop(transferee);
03656 if (!chan) {
03657 break;
03658 }
03659 continue;
03660 }
03661 f = ast_read(chan);
03662 if (f == NULL) {
03663 switch (chan->hangupcause) {
03664 case AST_CAUSE_BUSY:
03665 state = AST_CONTROL_BUSY;
03666 break;
03667 case AST_CAUSE_CONGESTION:
03668 state = AST_CONTROL_CONGESTION;
03669 break;
03670 default:
03671 state = 0;
03672 break;
03673 }
03674 break;
03675 }
03676
03677 if (f->frametype == AST_FRAME_CONTROL) {
03678 if (f->subclass.integer == AST_CONTROL_RINGING) {
03679 ast_verb(3, "%s is ringing\n", chan->name);
03680 ast_indicate(caller, AST_CONTROL_RINGING);
03681 } else if (f->subclass.integer == AST_CONTROL_BUSY) {
03682 state = f->subclass.integer;
03683 ast_verb(3, "%s is busy\n", chan->name);
03684 ast_indicate(caller, AST_CONTROL_BUSY);
03685 ast_frfree(f);
03686 break;
03687 } else if (f->subclass.integer == AST_CONTROL_INCOMPLETE) {
03688 ast_verb(3, "%s dialed incomplete extension %s; ignoring\n", chan->name, chan->exten);
03689 } else if (f->subclass.integer == AST_CONTROL_CONGESTION) {
03690 state = f->subclass.integer;
03691 ast_verb(3, "%s is congested\n", chan->name);
03692 ast_indicate(caller, AST_CONTROL_CONGESTION);
03693 ast_frfree(f);
03694 break;
03695 } else if (f->subclass.integer == AST_CONTROL_ANSWER) {
03696
03697 state = f->subclass.integer;
03698 ast_frfree(f);
03699 ready=1;
03700 break;
03701 } else if (f->subclass.integer == AST_CONTROL_CONNECTED_LINE) {
03702 if (caller_hungup) {
03703 struct ast_party_connected_line connected;
03704
03705
03706 ast_party_connected_line_set_init(&connected, &caller->connected);
03707 res = ast_connected_line_parse_data(f->data.ptr, f->datalen,
03708 &connected);
03709 if (!res) {
03710 ast_channel_set_connected_line(caller, &connected, NULL);
03711 }
03712 ast_party_connected_line_free(&connected);
03713 } else {
03714 ast_autoservice_start(transferee);
03715 if (ast_channel_connected_line_macro(chan, caller, f, 1, 1)) {
03716 ast_indicate_data(caller, AST_CONTROL_CONNECTED_LINE,
03717 f->data.ptr, f->datalen);
03718 }
03719 ast_autoservice_stop(transferee);
03720 }
03721 } else if (f->subclass.integer == AST_CONTROL_REDIRECTING) {
03722 if (!caller_hungup) {
03723 ast_autoservice_start(transferee);
03724 if (ast_channel_redirecting_macro(chan, caller, f, 1, 1)) {
03725 ast_indicate_data(caller, AST_CONTROL_REDIRECTING,
03726 f->data.ptr, f->datalen);
03727 }
03728 ast_autoservice_stop(transferee);
03729 }
03730 } else if (f->subclass.integer != -1
03731 && f->subclass.integer != AST_CONTROL_PROGRESS
03732 && f->subclass.integer != AST_CONTROL_PROCEEDING) {
03733 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass.integer);
03734 }
03735
03736 } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) {
03737 ast_write(caller, f);
03738 }
03739 } else if (caller == active_channel) {
03740 f = ast_read(caller);
03741 if (f) {
03742 if (f->frametype == AST_FRAME_DTMF) {
03743 dialed_code[x++] = f->subclass.integer;
03744 dialed_code[x] = '\0';
03745 if (strlen(dialed_code) == len) {
03746 x = 0;
03747 } else if (x && strncmp(dialed_code, disconnect_code, x)) {
03748 x = 0;
03749 dialed_code[x] = '\0';
03750 }
03751 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
03752
03753 state = AST_CONTROL_UNHOLD;
03754 ast_frfree(f);
03755 break;
03756 }
03757 } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) {
03758 ast_write(chan, f);
03759 }
03760 }
03761 }
03762 if (f)
03763 ast_frfree(f);
03764 }
03765
03766 ast_poll_channel_del(caller, chan);
03767
03768
03769
03770
03771
03772 ast_channel_lock(transferee);
03773 transferee_hungup = (transferee_hungup || ast_check_hangup(transferee));
03774 while ((f = AST_LIST_REMOVE_HEAD(&deferred_frames, frame_list))) {
03775 if (!transferee_hungup) {
03776 ast_queue_frame_head(transferee, f);
03777 }
03778 ast_frfree(f);
03779 }
03780 ast_channel_unlock(transferee);
03781
03782 done:
03783 ast_indicate(caller, -1);
03784 if (chan && (ready || chan->_state == AST_STATE_UP)) {
03785 state = AST_CONTROL_ANSWER;
03786 } else if (chan) {
03787 ast_hangup(chan);
03788 chan = NULL;
03789 }
03790
03791 if (outstate)
03792 *outstate = state;
03793
03794 return chan;
03795 }
03796
03797 void ast_channel_log(char *title, struct ast_channel *chan);
03798
03799 void ast_channel_log(char *title, struct ast_channel *chan)
03800 {
03801 ast_log(LOG_NOTICE, "______ %s (%lx)______\n", title, (unsigned long)chan);
03802 ast_log(LOG_NOTICE, "CHAN: name: %s; appl: %s; data: %s; contxt: %s; exten: %s; pri: %d;\n",
03803 chan->name, chan->appl, chan->data, chan->context, chan->exten, chan->priority);
03804 ast_log(LOG_NOTICE, "CHAN: acctcode: %s; dialcontext: %s; amaflags: %x; maccontxt: %s; macexten: %s; macpri: %d;\n",
03805 chan->accountcode, chan->dialcontext, chan->amaflags, chan->macrocontext, chan->macroexten, chan->macropriority);
03806 ast_log(LOG_NOTICE, "CHAN: masq: %p; masqr: %p; _bridge: %p; uniqueID: %s; linkedID:%s\n",
03807 chan->masq, chan->masqr,
03808 chan->_bridge, chan->uniqueid, chan->linkedid);
03809 if (chan->masqr)
03810 ast_log(LOG_NOTICE, "CHAN: masquerading as: %s; cdr: %p;\n",
03811 chan->masqr->name, chan->masqr->cdr);
03812 if (chan->_bridge)
03813 ast_log(LOG_NOTICE, "CHAN: Bridged to %s\n", chan->_bridge->name);
03814
03815 ast_log(LOG_NOTICE, "===== done ====\n");
03816 }
03817
03818
03819
03820
03821 static struct ast_cdr *pick_unlocked_cdr(struct ast_cdr *cdr)
03822 {
03823 struct ast_cdr *cdr_orig = cdr;
03824 while (cdr) {
03825 if (!ast_test_flag(cdr,AST_CDR_FLAG_LOCKED))
03826 return cdr;
03827 cdr = cdr->next;
03828 }
03829 return cdr_orig;
03830 }
03831
03832 static void set_bridge_features_on_config(struct ast_bridge_config *config, const char *features)
03833 {
03834 const char *feature;
03835
03836 if (ast_strlen_zero(features)) {
03837 return;
03838 }
03839
03840 for (feature = features; *feature; feature++) {
03841 switch (*feature) {
03842 case 'T' :
03843 case 't' :
03844 ast_set_flag(&(config->features_caller), AST_FEATURE_REDIRECT);
03845 break;
03846 case 'K' :
03847 case 'k' :
03848 ast_set_flag(&(config->features_caller), AST_FEATURE_PARKCALL);
03849 break;
03850 case 'H' :
03851 case 'h' :
03852 ast_set_flag(&(config->features_caller), AST_FEATURE_DISCONNECT);
03853 break;
03854 case 'W' :
03855 case 'w' :
03856 ast_set_flag(&(config->features_caller), AST_FEATURE_AUTOMON);
03857 break;
03858 default :
03859 ast_log(LOG_WARNING, "Skipping unknown feature code '%c'\n", *feature);
03860 }
03861 }
03862 }
03863
03864 static void add_features_datastores(struct ast_channel *caller, struct ast_channel *callee, struct ast_bridge_config *config)
03865 {
03866 if (add_features_datastore(caller, &config->features_caller, &config->features_callee)) {
03867
03868
03869
03870
03871
03872 return;
03873 }
03874
03875 add_features_datastore(callee, &config->features_callee, &config->features_caller);
03876 }
03877
03878 static void clear_dialed_interfaces(struct ast_channel *chan)
03879 {
03880 struct ast_datastore *di_datastore;
03881
03882 ast_channel_lock(chan);
03883 if ((di_datastore = ast_channel_datastore_find(chan, &dialed_interface_info, NULL))) {
03884 if (option_debug) {
03885 ast_log(LOG_DEBUG, "Removing dialed interfaces datastore on %s since we're bridging\n", chan->name);
03886 }
03887 if (!ast_channel_datastore_remove(chan, di_datastore)) {
03888 ast_datastore_free(di_datastore);
03889 }
03890 }
03891 ast_channel_unlock(chan);
03892 }
03893
03894
03895
03896
03897
03898
03899
03900
03901
03902
03903
03904
03905
03906 int ast_bridge_call(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
03907 {
03908
03909
03910 struct ast_frame *f;
03911 struct ast_channel *who;
03912 char chan_featurecode[FEATURE_MAX_LEN + 1]="";
03913 char peer_featurecode[FEATURE_MAX_LEN + 1]="";
03914 char orig_channame[AST_CHANNEL_NAME];
03915 char orig_peername[AST_CHANNEL_NAME];
03916 int res;
03917 int diff;
03918 int hasfeatures=0;
03919 int hadfeatures=0;
03920 int autoloopflag;
03921 int sendingdtmfdigit = 0;
03922 int we_disabled_peer_cdr = 0;
03923 struct ast_option_header *aoh;
03924 struct ast_cdr *bridge_cdr = NULL;
03925 struct ast_cdr *chan_cdr = chan->cdr;
03926 struct ast_cdr *peer_cdr = peer->cdr;
03927 struct ast_cdr *new_chan_cdr = NULL;
03928 struct ast_cdr *new_peer_cdr = NULL;
03929 struct ast_silence_generator *silgen = NULL;
03930 const char *h_context;
03931
03932 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
03933 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
03934
03935
03936 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
03937 pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", NULL);
03938
03939 set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES"));
03940 add_features_datastores(chan, peer, config);
03941
03942
03943
03944
03945 if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) {
03946 ast_indicate(peer, AST_CONTROL_RINGING);
03947 }
03948
03949 if (monitor_ok) {
03950 const char *monitor_exec;
03951 struct ast_channel *src = NULL;
03952 if (!monitor_app) {
03953 if (!(monitor_app = pbx_findapp("Monitor")))
03954 monitor_ok=0;
03955 }
03956 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR")))
03957 src = chan;
03958 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
03959 src = peer;
03960 if (monitor_app && src) {
03961 char *tmp = ast_strdupa(monitor_exec);
03962 pbx_exec(src, monitor_app, tmp);
03963 }
03964 }
03965
03966 set_config_flags(chan, peer, config);
03967
03968
03969 if (chan->_state != AST_STATE_UP) {
03970 if (ast_raw_answer(chan, 1)) {
03971 return -1;
03972 }
03973 }
03974
03975 #ifdef FOR_DEBUG
03976
03977 ast_channel_log("Pre-bridge CHAN Channel info", chan);
03978 ast_channel_log("Pre-bridge PEER Channel info", peer);
03979 #endif
03980
03981 ast_channel_set_linkgroup(chan,peer);
03982
03983
03984 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
03985 char tmp[256];
03986
03987 ast_channel_lock(chan);
03988 if (!ast_strlen_zero(chan->cdr->userfield)) {
03989 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield);
03990 ast_cdr_appenduserfield(chan, tmp);
03991 } else {
03992 ast_cdr_setuserfield(chan, peer->cdr->userfield);
03993 }
03994 ast_channel_unlock(chan);
03995
03996 ast_set_flag(peer->cdr, AST_CDR_FLAG_POST_DISABLED);
03997 we_disabled_peer_cdr = 1;
03998 }
03999 ast_copy_string(orig_channame,chan->name,sizeof(orig_channame));
04000 ast_copy_string(orig_peername,peer->name,sizeof(orig_peername));
04001
04002 if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) {
04003 ast_channel_lock_both(chan, peer);
04004 if (chan_cdr) {
04005 ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN);
04006 ast_cdr_update(chan);
04007 bridge_cdr = ast_cdr_dup_unique_swap(chan_cdr);
04008
04009
04010 bridge_cdr->next = chan_cdr->next;
04011 chan_cdr->next = NULL;
04012 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp));
04013 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata));
04014 if (peer_cdr && !ast_strlen_zero(peer_cdr->userfield)) {
04015 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield));
04016 }
04017 ast_cdr_setaccount(peer, chan->accountcode);
04018 } else {
04019
04020 bridge_cdr = ast_cdr_alloc();
04021 ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel));
04022 ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel));
04023 ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid));
04024 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp));
04025 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata));
04026 ast_cdr_setcid(bridge_cdr, chan);
04027 bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ? AST_CDR_ANSWERED : AST_CDR_NULL;
04028 bridge_cdr->amaflags = chan->amaflags ? chan->amaflags : ast_default_amaflags;
04029 ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode));
04030
04031 ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst));
04032 ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext));
04033 if (peer_cdr) {
04034 bridge_cdr->start = peer_cdr->start;
04035 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield));
04036 } else {
04037 ast_cdr_start(bridge_cdr);
04038 }
04039 }
04040 ast_channel_unlock(chan);
04041 ast_channel_unlock(peer);
04042
04043 ast_debug(4,"bridge answer set, chan answer set\n");
04044
04045
04046
04047
04048
04049
04050
04051
04052
04053
04054
04055
04056
04057
04058
04059 if (peer_cdr && !ast_tvzero(peer_cdr->answer) && ast_tvcmp(peer_cdr->answer, bridge_cdr->start) >= 0) {
04060 ast_cdr_setanswer(bridge_cdr, peer_cdr->answer);
04061 ast_cdr_setdisposition(bridge_cdr, peer_cdr->disposition);
04062 if (chan_cdr) {
04063 ast_cdr_setanswer(chan_cdr, peer_cdr->answer);
04064 ast_cdr_setdisposition(chan_cdr, peer_cdr->disposition);
04065 }
04066 } else {
04067 ast_cdr_answer(bridge_cdr);
04068 if (chan_cdr) {
04069 ast_cdr_answer(chan_cdr);
04070 }
04071 }
04072 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT) && (chan_cdr || peer_cdr)) {
04073 if (chan_cdr) {
04074 ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED);
04075 }
04076 if (peer_cdr) {
04077 ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED);
04078 }
04079 }
04080
04081
04082
04083
04084 ast_clear_flag(bridge_cdr, AST_CDR_FLAG_DIALED);
04085 }
04086 ast_cel_report_event(chan, AST_CEL_BRIDGE_START, NULL, NULL, peer);
04087
04088
04089
04090
04091 clear_dialed_interfaces(chan);
04092 clear_dialed_interfaces(peer);
04093
04094 for (;;) {
04095 struct ast_channel *other;
04096
04097 res = ast_channel_bridge(chan, peer, config, &f, &who);
04098
04099 if (ast_test_flag(chan, AST_FLAG_ZOMBIE)
04100 || ast_test_flag(peer, AST_FLAG_ZOMBIE)) {
04101
04102 res = -1;
04103 if (f) {
04104 ast_frfree(f);
04105 }
04106 goto before_you_go;
04107 }
04108
04109
04110
04111
04112
04113
04114
04115
04116 if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) {
04117
04118 diff = ast_tvdiff_ms(ast_tvnow(), config->feature_start_time);
04119 if (res == AST_BRIDGE_RETRY) {
04120
04121
04122
04123 config->feature_timer = -1;
04124 } else {
04125 config->feature_timer -= diff;
04126 }
04127
04128 if (hasfeatures) {
04129 if (config->feature_timer <= 0) {
04130
04131
04132 ast_debug(1, "Timed out for feature!\n");
04133 if (!ast_strlen_zero(peer_featurecode)) {
04134 ast_dtmf_stream(chan, peer, peer_featurecode, 0, 0);
04135 memset(peer_featurecode, 0, sizeof(peer_featurecode));
04136 }
04137 if (!ast_strlen_zero(chan_featurecode)) {
04138 ast_dtmf_stream(peer, chan, chan_featurecode, 0, 0);
04139 memset(chan_featurecode, 0, sizeof(chan_featurecode));
04140 }
04141 if (f)
04142 ast_frfree(f);
04143 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
04144 if (!hasfeatures) {
04145
04146 config->feature_timer = 0;
04147 }
04148 hadfeatures = hasfeatures;
04149
04150 continue;
04151 } else if (!f) {
04152
04153
04154
04155 continue;
04156 }
04157 } else {
04158 if (config->feature_timer <=0) {
04159
04160 config->feature_timer = 0;
04161 who = chan;
04162 if (f)
04163 ast_frfree(f);
04164 f = NULL;
04165 res = 0;
04166 }
04167 }
04168 }
04169 if (res < 0) {
04170 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) {
04171 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
04172 }
04173 goto before_you_go;
04174 }
04175
04176 if (!f || (f->frametype == AST_FRAME_CONTROL &&
04177 (f->subclass.integer == AST_CONTROL_HANGUP || f->subclass.integer == AST_CONTROL_BUSY ||
04178 f->subclass.integer == AST_CONTROL_CONGESTION))) {
04179
04180
04181
04182
04183
04184
04185 ast_channel_lock(chan);
04186 if (chan->_softhangup & (AST_SOFTHANGUP_ASYNCGOTO | AST_SOFTHANGUP_UNBRIDGE)) {
04187 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT);
04188 }
04189 ast_channel_unlock(chan);
04190 res = -1;
04191 break;
04192 }
04193
04194 other = (who == chan) ? peer : chan;
04195 if (f->frametype == AST_FRAME_CONTROL) {
04196 switch (f->subclass.integer) {
04197 case AST_CONTROL_RINGING:
04198 case AST_CONTROL_FLASH:
04199 case -1:
04200 ast_indicate(other, f->subclass.integer);
04201 break;
04202 case AST_CONTROL_CONNECTED_LINE:
04203 if (!ast_channel_connected_line_macro(who, other, f, who != chan, 1)) {
04204 break;
04205 }
04206 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen);
04207 break;
04208 case AST_CONTROL_REDIRECTING:
04209 if (!ast_channel_redirecting_macro(who, other, f, who != chan, 1)) {
04210 break;
04211 }
04212 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen);
04213 break;
04214 case AST_CONTROL_AOC:
04215 case AST_CONTROL_HOLD:
04216 case AST_CONTROL_UNHOLD:
04217 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen);
04218 break;
04219 case AST_CONTROL_OPTION:
04220 aoh = f->data.ptr;
04221
04222
04223
04224
04225 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) {
04226 switch (ntohs(aoh->option)) {
04227 case AST_OPTION_TONE_VERIFY:
04228 case AST_OPTION_TDD:
04229 case AST_OPTION_RELAXDTMF:
04230 case AST_OPTION_AUDIO_MODE:
04231 case AST_OPTION_DIGIT_DETECT:
04232 case AST_OPTION_FAX_DETECT:
04233 ast_channel_setoption(other, ntohs(aoh->option), aoh->data,
04234 f->datalen - sizeof(struct ast_option_header), 0);
04235 }
04236 }
04237 break;
04238 }
04239 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
04240 struct ast_flags *cfg;
04241 char dtmfcode[2] = { f->subclass.integer, };
04242 size_t featurelen;
04243
04244 if (who == chan) {
04245 featurelen = strlen(chan_featurecode);
04246 cfg = &(config->features_caller);
04247 } else {
04248 featurelen = strlen(peer_featurecode);
04249 cfg = &(config->features_callee);
04250 }
04251
04252
04253
04254 if (featurelen == 0
04255 && feature_check(chan, cfg, &dtmfcode[0]) == AST_FEATURE_RETURN_PASSDIGITS) {
04256 if (option_debug > 3) {
04257 ast_log(LOG_DEBUG, "Passing DTMF through, since it is not a feature code\n");
04258 }
04259 ast_write(other, f);
04260 sendingdtmfdigit = 1;
04261 } else {
04262
04263
04264
04265 if (!silgen && ast_opt_transmit_silence) {
04266 silgen = ast_channel_start_silence_generator(other);
04267 }
04268 if (option_debug > 3) {
04269 ast_log(LOG_DEBUG, "Not passing DTMF through, since it may be a feature code\n");
04270 }
04271 }
04272 } else if (f->frametype == AST_FRAME_DTMF_END) {
04273 char *featurecode;
04274 int sense;
04275
04276 hadfeatures = hasfeatures;
04277
04278 if (who == chan) {
04279 sense = FEATURE_SENSE_CHAN;
04280 featurecode = chan_featurecode;
04281 } else {
04282 sense = FEATURE_SENSE_PEER;
04283 featurecode = peer_featurecode;
04284 }
04285
04286 if (sendingdtmfdigit == 1) {
04287
04288
04289 ast_write(other, f);
04290 sendingdtmfdigit = 0;
04291 } else {
04292
04293
04294
04295
04296 featurecode[strlen(featurecode)] = f->subclass.integer;
04297
04298 ast_frfree(f);
04299 f = NULL;
04300 if (silgen) {
04301 ast_channel_stop_silence_generator(other, silgen);
04302 silgen = NULL;
04303 }
04304 config->feature_timer = 0;
04305 res = feature_interpret(chan, peer, config, featurecode, sense);
04306 switch(res) {
04307 case AST_FEATURE_RETURN_PASSDIGITS:
04308 ast_dtmf_stream(other, who, featurecode, 0, 0);
04309
04310 case AST_FEATURE_RETURN_SUCCESS:
04311 memset(featurecode, 0, sizeof(chan_featurecode));
04312 break;
04313 }
04314 if (res >= AST_FEATURE_RETURN_PASSDIGITS) {
04315 res = 0;
04316 } else {
04317 break;
04318 }
04319 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
04320 if (hadfeatures && !hasfeatures) {
04321
04322 config->feature_timer = 0;
04323 } else if (hasfeatures) {
04324 if (config->timelimit) {
04325
04326 ast_set_flag(config, AST_FEATURE_WARNING_ACTIVE);
04327 }
04328 config->feature_start_time = ast_tvnow();
04329 config->feature_timer = featuredigittimeout;
04330 ast_debug(1, "Set feature timer to %ld ms\n", config->feature_timer);
04331 }
04332 }
04333 }
04334 if (f)
04335 ast_frfree(f);
04336 }
04337 ast_cel_report_event(chan, AST_CEL_BRIDGE_END, NULL, NULL, peer);
04338
04339 before_you_go:
04340
04341 if (silgen) {
04342 ast_channel_stop_silence_generator(who == chan ? peer : chan, silgen);
04343 silgen = NULL;
04344 }
04345
04346 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) {
04347 ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT);
04348 if (bridge_cdr) {
04349 ast_cdr_discard(bridge_cdr);
04350
04351 }
04352 return res;
04353 }
04354
04355 if (config->end_bridge_callback) {
04356 config->end_bridge_callback(config->end_bridge_callback_data);
04357 }
04358
04359
04360
04361
04362
04363 if (ast_test_flag(&config->features_caller, AST_FEATURE_NO_H_EXTEN)) {
04364 h_context = NULL;
04365 } else if (ast_exists_extension(chan, chan->context, "h", 1,
04366 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
04367 h_context = chan->context;
04368 } else if (!ast_strlen_zero(chan->macrocontext)
04369 && ast_exists_extension(chan, chan->macrocontext, "h", 1,
04370 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
04371 h_context = chan->macrocontext;
04372 } else {
04373 h_context = NULL;
04374 }
04375 if (h_context) {
04376 struct ast_cdr *swapper = NULL;
04377 char savelastapp[AST_MAX_EXTENSION];
04378 char savelastdata[AST_MAX_EXTENSION];
04379 char save_context[AST_MAX_CONTEXT];
04380 char save_exten[AST_MAX_EXTENSION];
04381 int save_prio;
04382 int found = 0;
04383 int spawn_error = 0;
04384
04385
04386
04387
04388
04389 ast_softhangup(chan, AST_SOFTHANGUP_APPUNLOAD);
04390
04391 autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP);
04392 ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP);
04393 if (bridge_cdr && ast_opt_end_cdr_before_h_exten) {
04394 ast_cdr_end(bridge_cdr);
04395 }
04396
04397
04398
04399 ast_channel_lock(chan);
04400 if (bridge_cdr) {
04401 swapper = chan->cdr;
04402 ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp));
04403 ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata));
04404 chan->cdr = bridge_cdr;
04405 }
04406 ast_copy_string(save_context, chan->context, sizeof(save_context));
04407 ast_copy_string(save_exten, chan->exten, sizeof(save_exten));
04408 save_prio = chan->priority;
04409 if (h_context != chan->context) {
04410 ast_copy_string(chan->context, h_context, sizeof(chan->context));
04411 }
04412 ast_copy_string(chan->exten, "h", sizeof(chan->exten));
04413 chan->priority = 1;
04414 ast_channel_unlock(chan);
04415
04416 while ((spawn_error = ast_spawn_extension(chan, chan->context, chan->exten,
04417 chan->priority,
04418 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
04419 &found, 1)) == 0) {
04420 chan->priority++;
04421 }
04422 if (found && spawn_error) {
04423
04424 ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name);
04425 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name);
04426 }
04427
04428
04429 ast_channel_lock(chan);
04430 ast_copy_string(chan->context, save_context, sizeof(chan->context));
04431 ast_copy_string(chan->exten, save_exten, sizeof(chan->exten));
04432 chan->priority = save_prio;
04433 if (bridge_cdr) {
04434 if (chan->cdr == bridge_cdr) {
04435 chan->cdr = swapper;
04436 } else {
04437 bridge_cdr = NULL;
04438 }
04439 }
04440
04441 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN);
04442 ast_channel_unlock(chan);
04443
04444
04445 if (bridge_cdr) {
04446 ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp));
04447 ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata));
04448 }
04449 ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP);
04450 }
04451
04452
04453 new_chan_cdr = pick_unlocked_cdr(chan->cdr);
04454
04455
04456
04457 if (new_chan_cdr && bridge_cdr && !h_context) {
04458 ast_cdr_copy_vars(bridge_cdr, new_chan_cdr);
04459 ast_copy_string(bridge_cdr->userfield, new_chan_cdr->userfield, sizeof(bridge_cdr->userfield));
04460 bridge_cdr->amaflags = new_chan_cdr->amaflags;
04461 ast_copy_string(bridge_cdr->accountcode, new_chan_cdr->accountcode, sizeof(bridge_cdr->accountcode));
04462 if (ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED)) {
04463 ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED);
04464 }
04465 }
04466
04467
04468 if (bridge_cdr) {
04469 ast_cdr_end(bridge_cdr);
04470 ast_cdr_detach(bridge_cdr);
04471 }
04472
04473
04474
04475
04476
04477
04478
04479
04480
04481
04482
04483
04484
04485
04486
04487
04488
04489
04490
04491
04492
04493
04494
04495
04496
04497 if (new_chan_cdr) {
04498 struct ast_channel *chan_ptr = NULL;
04499
04500 if (strcasecmp(orig_channame, chan->name) != 0) {
04501
04502 if ((chan_ptr = ast_channel_get_by_name(orig_channame))) {
04503 ast_channel_lock(chan_ptr);
04504 if (!ast_bridged_channel(chan_ptr)) {
04505 struct ast_cdr *cur;
04506 for (cur = chan_ptr->cdr; cur; cur = cur->next) {
04507 if (cur == chan_cdr) {
04508 break;
04509 }
04510 }
04511 if (cur) {
04512 ast_cdr_specialized_reset(chan_cdr, 0);
04513 }
04514 }
04515 ast_channel_unlock(chan_ptr);
04516 chan_ptr = ast_channel_unref(chan_ptr);
04517 }
04518
04519 ast_cdr_specialized_reset(new_chan_cdr, 0);
04520 } else {
04521 ast_cdr_specialized_reset(chan->cdr, 0);
04522 }
04523 }
04524
04525 {
04526 struct ast_channel *chan_ptr = NULL;
04527 new_peer_cdr = pick_unlocked_cdr(peer->cdr);
04528 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))
04529 ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED);
04530 if (strcasecmp(orig_peername, peer->name) != 0) {
04531
04532 if ((chan_ptr = ast_channel_get_by_name(orig_peername))) {
04533 ast_channel_lock(chan_ptr);
04534 if (!ast_bridged_channel(chan_ptr)) {
04535 struct ast_cdr *cur;
04536 for (cur = chan_ptr->cdr; cur; cur = cur->next) {
04537 if (cur == peer_cdr) {
04538 break;
04539 }
04540 }
04541 if (cur) {
04542 ast_cdr_specialized_reset(peer_cdr, 0);
04543 }
04544 }
04545 ast_channel_unlock(chan_ptr);
04546 chan_ptr = ast_channel_unref(chan_ptr);
04547 }
04548
04549 if (new_peer_cdr) {
04550 ast_cdr_specialized_reset(new_peer_cdr, 0);
04551 }
04552 } else {
04553 if (we_disabled_peer_cdr) {
04554 ast_clear_flag(peer->cdr, AST_CDR_FLAG_POST_DISABLED);
04555 }
04556 ast_cdr_specialized_reset(peer->cdr, 0);
04557 }
04558 }
04559
04560 return res;
04561 }
04562
04563
04564 static void post_manager_event(const char *s, struct parkeduser *pu)
04565 {
04566 manager_event(EVENT_FLAG_CALL, s,
04567 "Exten: %s\r\n"
04568 "Channel: %s\r\n"
04569 "Parkinglot: %s\r\n"
04570 "CallerIDNum: %s\r\n"
04571 "CallerIDName: %s\r\n"
04572 "ConnectedLineNum: %s\r\n"
04573 "ConnectedLineName: %s\r\n"
04574 "UniqueID: %s\r\n",
04575 pu->parkingexten,
04576 pu->chan->name,
04577 pu->parkinglot->name,
04578 S_COR(pu->chan->caller.id.number.valid, pu->chan->caller.id.number.str, "<unknown>"),
04579 S_COR(pu->chan->caller.id.name.valid, pu->chan->caller.id.name.str, "<unknown>"),
04580 S_COR(pu->chan->connected.id.number.valid, pu->chan->connected.id.number.str, "<unknown>"),
04581 S_COR(pu->chan->connected.id.name.valid, pu->chan->connected.id.name.str, "<unknown>"),
04582 pu->chan->uniqueid
04583 );
04584 }
04585
04586 static char *callback_dialoptions(struct ast_flags *features_callee, struct ast_flags *features_caller, char *options, size_t len)
04587 {
04588 int i = 0;
04589 enum {
04590 OPT_CALLEE_REDIRECT = 't',
04591 OPT_CALLER_REDIRECT = 'T',
04592 OPT_CALLEE_AUTOMON = 'w',
04593 OPT_CALLER_AUTOMON = 'W',
04594 OPT_CALLEE_DISCONNECT = 'h',
04595 OPT_CALLER_DISCONNECT = 'H',
04596 OPT_CALLEE_PARKCALL = 'k',
04597 OPT_CALLER_PARKCALL = 'K',
04598 };
04599
04600 memset(options, 0, len);
04601 if (ast_test_flag(features_caller, AST_FEATURE_REDIRECT) && i < len) {
04602 options[i++] = OPT_CALLER_REDIRECT;
04603 }
04604 if (ast_test_flag(features_caller, AST_FEATURE_AUTOMON) && i < len) {
04605 options[i++] = OPT_CALLER_AUTOMON;
04606 }
04607 if (ast_test_flag(features_caller, AST_FEATURE_DISCONNECT) && i < len) {
04608 options[i++] = OPT_CALLER_DISCONNECT;
04609 }
04610 if (ast_test_flag(features_caller, AST_FEATURE_PARKCALL) && i < len) {
04611 options[i++] = OPT_CALLER_PARKCALL;
04612 }
04613
04614 if (ast_test_flag(features_callee, AST_FEATURE_REDIRECT) && i < len) {
04615 options[i++] = OPT_CALLEE_REDIRECT;
04616 }
04617 if (ast_test_flag(features_callee, AST_FEATURE_AUTOMON) && i < len) {
04618 options[i++] = OPT_CALLEE_AUTOMON;
04619 }
04620 if (ast_test_flag(features_callee, AST_FEATURE_DISCONNECT) && i < len) {
04621 options[i++] = OPT_CALLEE_DISCONNECT;
04622 }
04623 if (ast_test_flag(features_callee, AST_FEATURE_PARKCALL) && i < len) {
04624 options[i++] = OPT_CALLEE_PARKCALL;
04625 }
04626
04627 return options;
04628 }
04629
04630
04631
04632
04633
04634
04635
04636
04637
04638 static int manage_parked_call(struct parkeduser *pu, const struct pollfd *pfds, int nfds, struct pollfd **new_pfds, int *new_nfds, int *ms)
04639 {
04640 struct ast_channel *chan = pu->chan;
04641 int tms;
04642 int x;
04643
04644 tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
04645 if (tms > pu->parkingtime) {
04646
04647
04648
04649
04650 switch (pu->hold_method) {
04651 case AST_CONTROL_HOLD:
04652 ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
04653 break;
04654 case AST_CONTROL_RINGING:
04655 ast_indicate(pu->chan, -1);
04656 break;
04657 default:
04658 break;
04659 }
04660 pu->hold_method = 0;
04661
04662
04663 if (pu->peername[0]) {
04664 char *peername;
04665 char *dash;
04666 char *peername_flat;
04667 int i;
04668
04669 peername = ast_strdupa(pu->peername);
04670 dash = strrchr(peername, '-');
04671 if (dash) {
04672 *dash = '\0';
04673 }
04674
04675 peername_flat = ast_strdupa(peername);
04676 for (i = 0; peername_flat[i]; i++) {
04677 if (peername_flat[i] == '/') {
04678 peername_flat[i] = '_';
04679 }
04680 }
04681
04682 if (!ast_context_find_or_create(NULL, NULL, parking_con_dial, registrar)) {
04683 ast_log(LOG_ERROR,
04684 "Parking dial context '%s' does not exist and unable to create\n",
04685 parking_con_dial);
04686 } else {
04687 char returnexten[AST_MAX_EXTENSION];
04688 struct ast_datastore *features_datastore;
04689 struct ast_dial_features *dialfeatures;
04690
04691 if (!strncmp(peername, "Parked/", 7)) {
04692 peername += 7;
04693 }
04694
04695 ast_channel_lock(chan);
04696 features_datastore = ast_channel_datastore_find(chan, &dial_features_info,
04697 NULL);
04698 if (features_datastore && (dialfeatures = features_datastore->data)) {
04699 char buf[MAX_DIAL_FEATURE_OPTIONS] = {0,};
04700
04701 snprintf(returnexten, sizeof(returnexten), "%s,30,%s", peername,
04702 callback_dialoptions(&dialfeatures->peer_features,
04703 &dialfeatures->my_features, buf, sizeof(buf)));
04704 } else {
04705 ast_log(LOG_NOTICE, "Dial features not found on %s, using default!\n",
04706 chan->name);
04707 snprintf(returnexten, sizeof(returnexten), "%s,30,t", peername);
04708 }
04709 ast_channel_unlock(chan);
04710
04711 if (ast_add_extension(parking_con_dial, 1, peername_flat, 1, NULL, NULL,
04712 "Dial", ast_strdup(returnexten), ast_free_ptr, registrar)) {
04713 ast_log(LOG_ERROR,
04714 "Could not create parking return dial exten: %s@%s\n",
04715 peername_flat, parking_con_dial);
04716 }
04717 }
04718 if (pu->options_specified) {
04719
04720
04721
04722
04723 set_c_e_p(chan, pu->context, pu->exten, pu->priority);
04724 } else if (comebacktoorigin) {
04725 set_c_e_p(chan, parking_con_dial, peername_flat, 1);
04726 } else {
04727 char parkingslot[AST_MAX_EXTENSION];
04728
04729 snprintf(parkingslot, sizeof(parkingslot), "%d", pu->parkingnum);
04730 pbx_builtin_setvar_helper(chan, "PARKINGSLOT", parkingslot);
04731 set_c_e_p(chan, "parkedcallstimeout", peername_flat, 1);
04732 }
04733 } else {
04734
04735
04736
04737
04738
04739 set_c_e_p(chan, pu->context, pu->exten, pu->priority);
04740 }
04741 post_manager_event("ParkedCallTimeOut", pu);
04742 ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "ParkedCallTimeOut", NULL);
04743
04744 ast_verb(2, "Timeout for %s parked on %d (%s). Returning to %s,%s,%d\n",
04745 pu->chan->name, pu->parkingnum, pu->parkinglot->name, pu->chan->context,
04746 pu->chan->exten, pu->chan->priority);
04747
04748
04749 if (ast_pbx_start(chan)) {
04750 ast_log(LOG_WARNING,
04751 "Unable to restart the PBX for user on '%s', hanging them up...\n",
04752 pu->chan->name);
04753 ast_hangup(chan);
04754 }
04755
04756
04757 return 1;
04758 }
04759
04760
04761 if (pfds) {
04762 for (x = 0; x < AST_MAX_FDS; x++) {
04763 struct ast_frame *f;
04764 int y;
04765
04766 if (chan->fds[x] == -1) {
04767 continue;
04768 }
04769
04770 for (y = 0; y < nfds; y++) {
04771 if (pfds[y].fd == chan->fds[x]) {
04772
04773 break;
04774 }
04775 }
04776 if (y == nfds) {
04777
04778 continue;
04779 }
04780
04781 if (!(pfds[y].revents & (POLLIN | POLLERR | POLLPRI))) {
04782
04783 continue;
04784 }
04785
04786 if (pfds[y].revents & POLLPRI) {
04787 ast_set_flag(chan, AST_FLAG_EXCEPTION);
04788 } else {
04789 ast_clear_flag(chan, AST_FLAG_EXCEPTION);
04790 }
04791 chan->fdno = x;
04792
04793
04794 f = ast_read(pu->chan);
04795
04796 if (!f || (f->frametype == AST_FRAME_CONTROL
04797 && f->subclass.integer == AST_CONTROL_HANGUP)) {
04798 if (f) {
04799 ast_frfree(f);
04800 }
04801 post_manager_event("ParkedCallGiveUp", pu);
04802 ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "ParkedCallGiveUp",
04803 NULL);
04804
04805
04806 ast_verb(2, "%s got tired of being parked\n", chan->name);
04807 ast_hangup(chan);
04808
04809
04810 return 1;
04811 } else {
04812
04813 ast_frfree(f);
04814 if (pu->hold_method == AST_CONTROL_HOLD
04815 && pu->moh_trys < 3
04816 && !chan->generatordata) {
04817 ast_debug(1,
04818 "MOH on parked call stopped by outside source. Restarting on channel %s.\n",
04819 chan->name);
04820 ast_indicate_data(chan, AST_CONTROL_HOLD,
04821 S_OR(pu->parkinglot->cfg.mohclass, NULL),
04822 (!ast_strlen_zero(pu->parkinglot->cfg.mohclass)
04823 ? strlen(pu->parkinglot->cfg.mohclass) + 1 : 0));
04824 pu->moh_trys++;
04825 }
04826 break;
04827 }
04828 }
04829 }
04830
04831
04832 for (x = 0; x < AST_MAX_FDS; x++) {
04833 if (chan->fds[x] > -1) {
04834 void *tmp = ast_realloc(*new_pfds,
04835 (*new_nfds + 1) * sizeof(struct pollfd));
04836
04837 if (!tmp) {
04838 continue;
04839 }
04840 *new_pfds = tmp;
04841 (*new_pfds)[*new_nfds].fd = chan->fds[x];
04842 (*new_pfds)[*new_nfds].events = POLLIN | POLLERR | POLLPRI;
04843 (*new_pfds)[*new_nfds].revents = 0;
04844 (*new_nfds)++;
04845 }
04846 }
04847
04848 if (tms < *ms || *ms < 0) {
04849 *ms = tms;
04850 }
04851
04852
04853 return 0;
04854 }
04855
04856
04857 static void manage_parkinglot(struct ast_parkinglot *curlot, const struct pollfd *pfds, int nfds, struct pollfd **new_pfds, int *new_nfds, int *ms)
04858 {
04859 struct parkeduser *pu;
04860 struct ast_context *con;
04861
04862
04863 AST_LIST_LOCK(&curlot->parkings);
04864 AST_LIST_TRAVERSE_SAFE_BEGIN(&curlot->parkings, pu, list) {
04865 if (pu->notquiteyet) {
04866 continue;
04867 }
04868 if (manage_parked_call(pu, pfds, nfds, new_pfds, new_nfds, ms)) {
04869
04870 con = ast_context_find(pu->parkinglot->cfg.parking_con);
04871 if (con) {
04872 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0)) {
04873 ast_log(LOG_WARNING,
04874 "Whoa, failed to remove the parking extension %s@%s!\n",
04875 pu->parkingexten, pu->parkinglot->cfg.parking_con);
04876 }
04877 notify_metermaids(pu->parkingexten, pu->parkinglot->cfg.parking_con,
04878 AST_DEVICE_NOT_INUSE);
04879 } else {
04880 ast_log(LOG_WARNING,
04881 "Whoa, parking lot '%s' context '%s' does not exist.\n",
04882 pu->parkinglot->name, pu->parkinglot->cfg.parking_con);
04883 }
04884 AST_LIST_REMOVE_CURRENT(list);
04885 parkinglot_unref(pu->parkinglot);
04886 ast_free(pu);
04887 }
04888 }
04889 AST_LIST_TRAVERSE_SAFE_END;
04890 AST_LIST_UNLOCK(&curlot->parkings);
04891 }
04892
04893
04894
04895
04896
04897
04898
04899
04900
04901 static void *do_parking_thread(void *ignore)
04902 {
04903 struct pollfd *pfds = NULL, *new_pfds = NULL;
04904 int nfds = 0, new_nfds = 0;
04905
04906 for (;;) {
04907 struct ao2_iterator iter;
04908 struct ast_parkinglot *curlot;
04909 int ms = -1;
04910
04911 iter = ao2_iterator_init(parkinglots, 0);
04912 while ((curlot = ao2_iterator_next(&iter))) {
04913 manage_parkinglot(curlot, pfds, nfds, &new_pfds, &new_nfds, &ms);
04914 ao2_ref(curlot, -1);
04915 }
04916 ao2_iterator_destroy(&iter);
04917
04918
04919 ast_free(pfds);
04920 pfds = new_pfds;
04921 nfds = new_nfds;
04922 new_pfds = NULL;
04923 new_nfds = 0;
04924
04925
04926 ast_poll(pfds, nfds, ms);
04927 pthread_testcancel();
04928 }
04929
04930 return NULL;
04931 }
04932
04933
04934 static struct ast_parkinglot *find_parkinglot(const char *name)
04935 {
04936 struct ast_parkinglot *parkinglot;
04937
04938 if (ast_strlen_zero(name)) {
04939 return NULL;
04940 }
04941
04942 parkinglot = ao2_find(parkinglots, (void *) name, 0);
04943 if (parkinglot) {
04944 ast_debug(1, "Found Parking lot: %s\n", parkinglot->name);
04945 }
04946
04947 return parkinglot;
04948 }
04949
04950
04951 static struct ast_parkinglot *copy_parkinglot(const char *name, const struct ast_parkinglot *parkinglot)
04952 {
04953 struct ast_parkinglot *copylot;
04954
04955 if ((copylot = find_parkinglot(name))) {
04956 ao2_ref(copylot, -1);
04957 return NULL;
04958 }
04959
04960 copylot = create_parkinglot(name);
04961 if (!copylot) {
04962 return NULL;
04963 }
04964
04965 ast_debug(1, "Building parking lot %s\n", name);
04966
04967
04968 copylot->cfg = parkinglot->cfg;
04969
04970 return copylot;
04971 }
04972
04973 AST_APP_OPTIONS(park_call_options, BEGIN_OPTIONS
04974 AST_APP_OPTION('r', AST_PARK_OPT_RINGING),
04975 AST_APP_OPTION('R', AST_PARK_OPT_RANDOMIZE),
04976 AST_APP_OPTION('s', AST_PARK_OPT_SILENCE),
04977 END_OPTIONS );
04978
04979
04980 static int park_call_exec(struct ast_channel *chan, const char *data)
04981 {
04982 struct ast_park_call_args args = { 0, };
04983 struct ast_flags flags = { 0 };
04984 char orig_exten[AST_MAX_EXTENSION];
04985 int orig_priority;
04986 int res;
04987 const char *pl_name;
04988 char *parse;
04989 struct park_app_args app_args;
04990
04991
04992
04993
04994
04995
04996
04997
04998
04999
05000
05001 args.orig_chan_name = ast_strdupa(S_OR(
05002 pbx_builtin_getvar_helper(chan, "BLINDTRANSFER"), chan->name));
05003
05004
05005 if (chan->_state != AST_STATE_UP) {
05006 if (ast_answer(chan)) {
05007 return -1;
05008 }
05009
05010
05011 if (ast_safe_sleep(chan, 1000)) {
05012 return -1;
05013 }
05014 }
05015
05016
05017 parse = ast_strdupa(data);
05018 AST_STANDARD_APP_ARGS(app_args, parse);
05019
05020 if (!ast_strlen_zero(app_args.timeout)) {
05021 if (sscanf(app_args.timeout, "%30d", &args.timeout) != 1) {
05022 ast_log(LOG_WARNING, "Invalid timeout '%s' provided\n", app_args.timeout);
05023 args.timeout = 0;
05024 }
05025 }
05026 if (!ast_strlen_zero(app_args.return_con)) {
05027 args.return_con = app_args.return_con;
05028 }
05029 if (!ast_strlen_zero(app_args.return_ext)) {
05030 args.return_ext = app_args.return_ext;
05031 }
05032 if (!ast_strlen_zero(app_args.return_pri)) {
05033 if (sscanf(app_args.return_pri, "%30d", &args.return_pri) != 1) {
05034 ast_log(LOG_WARNING, "Invalid priority '%s' specified\n", app_args.return_pri);
05035 args.return_pri = 0;
05036 }
05037 }
05038
05039 ast_app_parse_options(park_call_options, &flags, NULL, app_args.options);
05040 args.flags = flags.flags;
05041
05042
05043
05044
05045
05046 ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten));
05047 orig_priority = chan->priority;
05048 strcpy(chan->exten, "s");
05049 chan->priority = 1;
05050
05051
05052 if (!ast_strlen_zero(app_args.pl_name)) {
05053 pl_name = app_args.pl_name;
05054 } else {
05055 pl_name = findparkinglotname(chan);
05056 }
05057 if (ast_strlen_zero(pl_name)) {
05058
05059 args.parkinglot = parkinglot_addref(default_parkinglot);
05060 } else {
05061 args.parkinglot = find_parkinglot(pl_name);
05062 if (!args.parkinglot && parkeddynamic) {
05063 args.parkinglot = create_dynamic_parkinglot(pl_name, chan);
05064 }
05065 }
05066 if (args.parkinglot) {
05067 res = masq_park_call(chan, chan, &args);
05068 parkinglot_unref(args.parkinglot);
05069 } else {
05070
05071 if (!ast_test_flag(&args, AST_PARK_OPT_SILENCE)) {
05072 ast_stream_and_wait(chan, "pbx-parkingfailed", "");
05073 }
05074 res = -1;
05075 }
05076 if (res) {
05077
05078 ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten));
05079 chan->priority = orig_priority;
05080 res = 0;
05081 } else {
05082
05083 res = -1;
05084 }
05085
05086 return res;
05087 }
05088
05089
05090 static int parked_call_exec(struct ast_channel *chan, const char *data)
05091 {
05092 int res;
05093 struct ast_channel *peer = NULL;
05094 struct parkeduser *pu;
05095 struct ast_context *con;
05096 char *parse;
05097 const char *pl_name;
05098 int park = 0;
05099 struct ast_bridge_config config;
05100 struct ast_parkinglot *parkinglot;
05101 AST_DECLARE_APP_ARGS(app_args,
05102 AST_APP_ARG(pl_space);
05103 AST_APP_ARG(pl_name);
05104 AST_APP_ARG(dummy);
05105 );
05106
05107 parse = ast_strdupa(data);
05108 AST_STANDARD_APP_ARGS(app_args, parse);
05109
05110 if (!ast_strlen_zero(app_args.pl_space)) {
05111 if (sscanf(app_args.pl_space, "%30u", &park) != 1) {
05112 ast_log(LOG_WARNING, "Specified parking extension not a number: %s\n",
05113 app_args.pl_space);
05114 park = -1;
05115 }
05116 }
05117
05118 if (!ast_strlen_zero(app_args.pl_name)) {
05119 pl_name = app_args.pl_name;
05120 } else {
05121 pl_name = findparkinglotname(chan);
05122 }
05123 if (ast_strlen_zero(pl_name)) {
05124
05125 parkinglot = parkinglot_addref(default_parkinglot);
05126 } else {
05127 parkinglot = find_parkinglot(pl_name);
05128 if (!parkinglot) {
05129
05130 if (chan->_state != AST_STATE_UP) {
05131 ast_answer(chan);
05132 }
05133 if (ast_stream_and_wait(chan, "pbx-invalidpark", "")) {
05134 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n",
05135 "pbx-invalidpark", chan->name);
05136 }
05137 ast_log(LOG_WARNING,
05138 "Channel %s tried to retrieve parked call from unknown parking lot '%s'\n",
05139 chan->name, pl_name);
05140 return -1;
05141 }
05142 }
05143
05144 AST_LIST_LOCK(&parkinglot->parkings);
05145 AST_LIST_TRAVERSE_SAFE_BEGIN(&parkinglot->parkings, pu, list) {
05146 if ((ast_strlen_zero(app_args.pl_space) || pu->parkingnum == park)
05147 && !pu->notquiteyet && !pu->chan->pbx) {
05148
05149 AST_LIST_REMOVE_CURRENT(list);
05150 break;
05151 }
05152 }
05153 AST_LIST_TRAVERSE_SAFE_END;
05154 if (pu) {
05155
05156 peer = pu->chan;
05157 con = ast_context_find(parkinglot->cfg.parking_con);
05158 if (con) {
05159 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0)) {
05160 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
05161 } else {
05162 notify_metermaids(pu->parkingexten, parkinglot->cfg.parking_con, AST_DEVICE_NOT_INUSE);
05163 }
05164 } else {
05165 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
05166 }
05167
05168 ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "UnParkedCall", chan);
05169 ast_manager_event(pu->chan, EVENT_FLAG_CALL, "UnParkedCall",
05170 "Exten: %s\r\n"
05171 "Channel: %s\r\n"
05172 "Parkinglot: %s\r\n"
05173 "From: %s\r\n"
05174 "CallerIDNum: %s\r\n"
05175 "CallerIDName: %s\r\n"
05176 "ConnectedLineNum: %s\r\n"
05177 "ConnectedLineName: %s\r\n"
05178 "Uniqueid: %s\r\n",
05179 pu->parkingexten, pu->chan->name, pu->parkinglot->name, chan->name,
05180 S_COR(pu->chan->caller.id.number.valid, pu->chan->caller.id.number.str, "<unknown>"),
05181 S_COR(pu->chan->caller.id.name.valid, pu->chan->caller.id.name.str, "<unknown>"),
05182 S_COR(pu->chan->connected.id.number.valid, pu->chan->connected.id.number.str, "<unknown>"),
05183 S_COR(pu->chan->connected.id.name.valid, pu->chan->connected.id.name.str, "<unknown>"),
05184 pu->chan->uniqueid
05185 );
05186
05187
05188 switch (pu->hold_method) {
05189 case AST_CONTROL_HOLD:
05190 ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
05191 break;
05192 case AST_CONTROL_RINGING:
05193 ast_indicate(pu->chan, -1);
05194 break;
05195 default:
05196 break;
05197 }
05198 pu->hold_method = 0;
05199
05200 parkinglot_unref(pu->parkinglot);
05201 ast_free(pu);
05202 }
05203 AST_LIST_UNLOCK(&parkinglot->parkings);
05204
05205 if (peer) {
05206
05207 struct ast_party_connected_line connected;
05208
05209 ast_party_connected_line_init(&connected);
05210
05211
05212 ast_channel_lock(chan);
05213 ast_connected_line_copy_from_caller(&connected, &chan->caller);
05214 ast_channel_unlock(chan);
05215 connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
05216 if (ast_channel_connected_line_macro(chan, peer, &connected, 0, 0)) {
05217 ast_channel_update_connected_line(peer, &connected, NULL);
05218 }
05219
05220
05221
05222
05223
05224
05225
05226
05227 ast_channel_lock(peer);
05228 ast_connected_line_copy_from_caller(&connected, &peer->caller);
05229 ast_channel_unlock(peer);
05230 connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
05231 if (ast_channel_connected_line_macro(peer, chan, &connected, 1, 0)) {
05232 ast_channel_update_connected_line(chan, &connected, NULL);
05233 }
05234
05235 ast_party_connected_line_free(&connected);
05236 }
05237
05238
05239 if (chan->_state != AST_STATE_UP) {
05240 ast_answer(chan);
05241 }
05242
05243 if (peer) {
05244 struct ast_datastore *features_datastore;
05245 struct ast_dial_features *dialfeatures;
05246
05247
05248 if (!ast_strlen_zero(courtesytone)) {
05249 static const char msg[] = "courtesy tone";
05250
05251 switch (parkedplay) {
05252 case 0:
05253 res = play_message_to_chans(chan, peer, -1, msg, courtesytone);
05254 break;
05255 case 1:
05256 res = play_message_to_chans(chan, peer, 1, msg, courtesytone);
05257 break;
05258 case 2:
05259 res = play_message_to_chans(chan, peer, 0, msg, courtesytone);
05260 break;
05261 default:
05262 res = 0;
05263 break;
05264 }
05265 if (res) {
05266 ast_hangup(peer);
05267 parkinglot_unref(parkinglot);
05268 return -1;
05269 }
05270 }
05271
05272 res = ast_channel_make_compatible(chan, peer);
05273 if (res < 0) {
05274 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
05275 ast_hangup(peer);
05276 parkinglot_unref(parkinglot);
05277 return -1;
05278 }
05279
05280
05281 ast_verb(3, "Channel %s connected to parked call %d\n", chan->name, park);
05282
05283 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
05284 ast_cdr_setdestchan(chan->cdr, peer->name);
05285 memset(&config, 0, sizeof(struct ast_bridge_config));
05286
05287
05288 ast_channel_lock(peer);
05289 features_datastore = ast_channel_datastore_find(peer, &dial_features_info, NULL);
05290 if (features_datastore && (dialfeatures = features_datastore->data)) {
05291 ast_copy_flags(&config.features_callee, &dialfeatures->my_features,
05292 AST_FLAGS_ALL);
05293 }
05294 ast_channel_unlock(peer);
05295
05296 if ((parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
05297 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
05298 }
05299 if ((parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
05300 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
05301 }
05302 if ((parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
05303 ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL);
05304 }
05305 if ((parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
05306 ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL);
05307 }
05308 if ((parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
05309 ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT);
05310 }
05311 if ((parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
05312 ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT);
05313 }
05314 if ((parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
05315 ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
05316 }
05317 if ((parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
05318 ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
05319 }
05320
05321 res = ast_bridge_call(chan, peer, &config);
05322
05323 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
05324 ast_cdr_setdestchan(chan->cdr, peer->name);
05325
05326
05327 ast_hangup(peer);
05328 } else {
05329 if (ast_stream_and_wait(chan, "pbx-invalidpark", "")) {
05330 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark",
05331 chan->name);
05332 }
05333 ast_verb(3, "Channel %s tried to retrieve nonexistent parked call %d\n",
05334 chan->name, park);
05335 res = -1;
05336 }
05337
05338 parkinglot_unref(parkinglot);
05339 return res;
05340 }
05341
05342
05343
05344
05345 static void parkinglot_unref(struct ast_parkinglot *parkinglot)
05346 {
05347 ast_debug(3, "Multiparking: %s refcount now %d\n", parkinglot->name,
05348 ao2_ref(parkinglot, 0) - 1);
05349 ao2_ref(parkinglot, -1);
05350 }
05351
05352 static struct ast_parkinglot *parkinglot_addref(struct ast_parkinglot *parkinglot)
05353 {
05354 int refcount;
05355
05356 refcount = ao2_ref(parkinglot, +1);
05357 ast_debug(3, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount + 1);
05358 return parkinglot;
05359 }
05360
05361
05362 static void parkinglot_destroy(void *obj)
05363 {
05364 struct ast_parkinglot *doomed = obj;
05365
05366
05367
05368
05369
05370
05371 ast_assert(AST_LIST_EMPTY(&doomed->parkings));
05372 AST_LIST_HEAD_DESTROY(&doomed->parkings);
05373 }
05374
05375
05376 static struct ast_parkinglot *create_parkinglot(const char *name)
05377 {
05378 struct ast_parkinglot *newlot;
05379
05380 if (ast_strlen_zero(name)) {
05381 return NULL;
05382 }
05383
05384 newlot = ao2_alloc(sizeof(*newlot), parkinglot_destroy);
05385 if (!newlot)
05386 return NULL;
05387
05388 ast_copy_string(newlot->name, name, sizeof(newlot->name));
05389 newlot->cfg.is_invalid = 1;
05390 AST_LIST_HEAD_INIT(&newlot->parkings);
05391
05392 return newlot;
05393 }
05394
05395
05396
05397
05398
05399
05400
05401 static void park_add_hints(const char *context, int start, int stop)
05402 {
05403 int numext;
05404 char device[AST_MAX_EXTENSION];
05405 char exten[10];
05406
05407 for (numext = start; numext <= stop; numext++) {
05408 snprintf(exten, sizeof(exten), "%d", numext);
05409 snprintf(device, sizeof(device), "park:%s@%s", exten, context);
05410 ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
05411 }
05412 }
05413
05414
05415 static const struct parkinglot_cfg parkinglot_cfg_default_default = {
05416 .mohclass = "default",
05417 .parkext = DEFAULT_PARK_EXTENSION,
05418 .parking_con = "parkedcalls",
05419 .parking_start = 701,
05420 .parking_stop = 750,
05421 .parkingtime = DEFAULT_PARK_TIME,
05422 };
05423
05424
05425 static const struct parkinglot_cfg parkinglot_cfg_default = {
05426 .parkext = DEFAULT_PARK_EXTENSION,
05427 .parkingtime = DEFAULT_PARK_TIME,
05428 };
05429
05430
05431
05432
05433
05434
05435
05436
05437
05438
05439
05440 static void parkinglot_feature_flag_cfg(const char *pl_name, int *param, struct ast_variable *var)
05441 {
05442 ast_debug(1, "Setting parking lot %s %s to %s\n", pl_name, var->name, var->value);
05443 if (!strcasecmp(var->value, "both")) {
05444 *param = AST_FEATURE_FLAG_BYBOTH;
05445 } else if (!strcasecmp(var->value, "caller")) {
05446 *param = AST_FEATURE_FLAG_BYCALLER;
05447 } else if (!strcasecmp(var->value, "callee")) {
05448 *param = AST_FEATURE_FLAG_BYCALLEE;
05449 }
05450 }
05451
05452
05453
05454
05455
05456
05457
05458
05459
05460
05461
05462
05463 static int parkinglot_config_read(const char *pl_name, struct parkinglot_cfg *cfg, struct ast_variable *var)
05464 {
05465 int error = 0;
05466
05467 while (var) {
05468 if (!strcasecmp(var->name, "context")) {
05469 ast_copy_string(cfg->parking_con, var->value, sizeof(cfg->parking_con));
05470 } else if (!strcasecmp(var->name, "parkext")) {
05471 ast_copy_string(cfg->parkext, var->value, sizeof(cfg->parkext));
05472 } else if (!strcasecmp(var->name, "parkext_exclusive")) {
05473 cfg->parkext_exclusive = ast_true(var->value);
05474 } else if (!strcasecmp(var->name, "parkinghints")) {
05475 cfg->parkaddhints = ast_true(var->value);
05476 } else if (!strcasecmp(var->name, "parkedmusicclass")) {
05477 ast_copy_string(cfg->mohclass, var->value, sizeof(cfg->mohclass));
05478 } else if (!strcasecmp(var->name, "parkingtime")) {
05479 int parkingtime = 0;
05480
05481 if ((sscanf(var->value, "%30d", &parkingtime) != 1) || parkingtime < 1) {
05482 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
05483 error = -1;
05484 } else {
05485 cfg->parkingtime = parkingtime * 1000;
05486 }
05487 } else if (!strcasecmp(var->name, "parkpos")) {
05488 int start = 0;
05489 int end = 0;
05490
05491 if (sscanf(var->value, "%30d-%30d", &start, &end) != 2) {
05492 ast_log(LOG_WARNING,
05493 "Format for parking positions is a-b, where a and b are numbers at line %d of %s\n",
05494 var->lineno, var->file);
05495 error = -1;
05496 } else if (end < start || start <= 0 || end <= 0) {
05497 ast_log(LOG_WARNING, "Parking range is invalid. Must be a <= b, at line %d of %s\n",
05498 var->lineno, var->file);
05499 error = -1;
05500 } else {
05501 cfg->parking_start = start;
05502 cfg->parking_stop = end;
05503 }
05504 } else if (!strcasecmp(var->name, "findslot")) {
05505 cfg->parkfindnext = (!strcasecmp(var->value, "next"));
05506 } else if (!strcasecmp(var->name, "parkedcalltransfers")) {
05507 parkinglot_feature_flag_cfg(pl_name, &cfg->parkedcalltransfers, var);
05508 } else if (!strcasecmp(var->name, "parkedcallreparking")) {
05509 parkinglot_feature_flag_cfg(pl_name, &cfg->parkedcallreparking, var);
05510 } else if (!strcasecmp(var->name, "parkedcallhangup")) {
05511 parkinglot_feature_flag_cfg(pl_name, &cfg->parkedcallhangup, var);
05512 } else if (!strcasecmp(var->name, "parkedcallrecording")) {
05513 parkinglot_feature_flag_cfg(pl_name, &cfg->parkedcallrecording, var);
05514 }
05515 var = var->next;
05516 }
05517
05518
05519 if (ast_strlen_zero(cfg->parking_con)) {
05520 ast_log(LOG_WARNING, "Parking lot %s needs context\n", pl_name);
05521 error = -1;
05522 }
05523 if (ast_strlen_zero(cfg->parkext)) {
05524 ast_log(LOG_WARNING, "Parking lot %s needs parkext\n", pl_name);
05525 error = -1;
05526 }
05527 if (!cfg->parking_start) {
05528 ast_log(LOG_WARNING, "Parking lot %s needs parkpos\n", pl_name);
05529 error = -1;
05530 }
05531 if (error) {
05532 cfg->is_invalid = 1;
05533 }
05534
05535 return error;
05536 }
05537
05538
05539
05540
05541
05542
05543
05544
05545
05546
05547
05548
05549
05550
05551 static int parkinglot_activate(struct ast_parkinglot *parkinglot)
05552 {
05553 int disabled = 0;
05554 char app_data[5 + AST_MAX_CONTEXT];
05555
05556
05557 if (parkinglot->cfg.parkext_exclusive) {
05558
05559 snprintf(app_data, sizeof(app_data), ",,,,,%s", parkinglot->name);
05560 } else {
05561
05562 app_data[0] = '\0';
05563 }
05564
05565
05566 if (!ast_context_find_or_create(NULL, NULL, parkinglot->cfg.parking_con, registrar)) {
05567 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n",
05568 parkinglot->cfg.parking_con);
05569 disabled = 1;
05570
05571
05572 } else if (ast_add_extension(parkinglot->cfg.parking_con, 1, parkinglot->cfg.parkext,
05573 1, NULL, NULL, parkcall, ast_strdup(app_data), ast_free_ptr, registrar)) {
05574 ast_log(LOG_ERROR, "Could not create parking lot %s access exten %s@%s\n",
05575 parkinglot->name, parkinglot->cfg.parkext, parkinglot->cfg.parking_con);
05576 disabled = 1;
05577 } else {
05578
05579 if (parkinglot->cfg.parkaddhints) {
05580 park_add_hints(parkinglot->cfg.parking_con, parkinglot->cfg.parking_start,
05581 parkinglot->cfg.parking_stop);
05582 }
05583
05584
05585
05586
05587
05588
05589
05590
05591 notify_metermaids(parkinglot->cfg.parkext, parkinglot->cfg.parking_con,
05592 AST_DEVICE_INUSE);
05593 }
05594
05595 parkinglot->disabled = disabled;
05596 return disabled ? -1 : 0;
05597 }
05598
05599
05600 static struct ast_parkinglot *build_parkinglot(const char *pl_name, struct ast_variable *var)
05601 {
05602 struct ast_parkinglot *parkinglot;
05603 const struct parkinglot_cfg *cfg_defaults;
05604 struct parkinglot_cfg new_cfg;
05605 int cfg_error;
05606 int oldparkinglot = 0;
05607
05608 parkinglot = find_parkinglot(pl_name);
05609 if (parkinglot) {
05610 oldparkinglot = 1;
05611 } else {
05612 parkinglot = create_parkinglot(pl_name);
05613 if (!parkinglot) {
05614 return NULL;
05615 }
05616 }
05617 if (!strcmp(parkinglot->name, DEFAULT_PARKINGLOT)) {
05618 cfg_defaults = &parkinglot_cfg_default_default;
05619 } else {
05620 cfg_defaults = &parkinglot_cfg_default;
05621 }
05622 new_cfg = *cfg_defaults;
05623
05624 ast_debug(1, "Building parking lot %s\n", parkinglot->name);
05625
05626 ao2_lock(parkinglot);
05627
05628
05629 cfg_error = parkinglot_config_read(parkinglot->name, &new_cfg, var);
05630 if (oldparkinglot) {
05631 if (cfg_error) {
05632
05633 ast_log(LOG_WARNING, "Changes to parking lot %s are discarded.\n",
05634 parkinglot->name);
05635 cfg_error = 0;
05636 } else if (!AST_LIST_EMPTY(&parkinglot->parkings)
05637 && memcmp(&new_cfg, &parkinglot->cfg, sizeof(parkinglot->cfg))) {
05638
05639 ast_log(LOG_WARNING,
05640 "Parking lot %s has parked calls. Parking lot changes discarded.\n",
05641 parkinglot->name);
05642 force_reload_load = 1;
05643 } else {
05644
05645 parkinglot->cfg = new_cfg;
05646 }
05647 } else {
05648
05649 parkinglot->cfg = new_cfg;
05650 }
05651 parkinglot->the_mark = 0;
05652
05653 ao2_unlock(parkinglot);
05654
05655 if (cfg_error) {
05656
05657 ast_log(LOG_WARNING, "New parking lot %s is discarded.\n", parkinglot->name);
05658 parkinglot_unref(parkinglot);
05659 return NULL;
05660 }
05661
05662
05663 if (!oldparkinglot) {
05664 ao2_link(parkinglots, parkinglot);
05665 }
05666 parkinglot_unref(parkinglot);
05667
05668 return parkinglot;
05669 }
05670
05671
05672
05673
05674
05675
05676
05677
05678
05679 static void process_applicationmap_line(struct ast_variable *var)
05680 {
05681 char *tmp_val = ast_strdupa(var->value);
05682 char *activateon, *new_syn;
05683 struct ast_call_feature *feature;
05684 AST_DECLARE_APP_ARGS(args,
05685 AST_APP_ARG(exten);
05686 AST_APP_ARG(activatedby);
05687 AST_APP_ARG(app);
05688 AST_APP_ARG(app_args);
05689 AST_APP_ARG(moh_class);
05690 );
05691
05692 AST_STANDARD_APP_ARGS(args, tmp_val);
05693 if ((new_syn = strchr(args.app, '('))) {
05694
05695 args.moh_class = args.app_args;
05696 args.app_args = new_syn;
05697 *args.app_args++ = '\0';
05698 if (args.app_args[strlen(args.app_args) - 1] == ')') {
05699 args.app_args[strlen(args.app_args) - 1] = '\0';
05700 }
05701 }
05702
05703 activateon = strsep(&args.activatedby, "/");
05704
05705
05706 if (ast_strlen_zero(args.app)
05707 || ast_strlen_zero(args.exten)
05708 || ast_strlen_zero(activateon)
05709 || ast_strlen_zero(var->name)) {
05710 ast_log(LOG_NOTICE,
05711 "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",
05712 args.app, args.exten, activateon, var->name);
05713 return;
05714 }
05715
05716 AST_RWLIST_RDLOCK(&feature_list);
05717 if (find_dynamic_feature(var->name)) {
05718 AST_RWLIST_UNLOCK(&feature_list);
05719 ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n",
05720 var->name);
05721 return;
05722 }
05723 AST_RWLIST_UNLOCK(&feature_list);
05724
05725 if (!(feature = ast_calloc(1, sizeof(*feature)))) {
05726 return;
05727 }
05728
05729 ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN);
05730 ast_copy_string(feature->app, args.app, FEATURE_APP_LEN);
05731 ast_copy_string(feature->exten, args.exten, FEATURE_EXTEN_LEN);
05732
05733 if (args.app_args) {
05734 ast_copy_string(feature->app_args, args.app_args, FEATURE_APP_ARGS_LEN);
05735 }
05736
05737 if (args.moh_class) {
05738 ast_copy_string(feature->moh_class, args.moh_class, FEATURE_MOH_LEN);
05739 }
05740
05741 ast_copy_string(feature->exten, args.exten, sizeof(feature->exten));
05742 feature->operation = feature_exec_app;
05743 ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF);
05744
05745
05746 if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller")) {
05747 ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF);
05748 } else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee")) {
05749 ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER);
05750 } else {
05751 ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s',"
05752 " must be 'self', or 'peer'\n", var->name);
05753 ast_free(feature);
05754 return;
05755 }
05756
05757 if (ast_strlen_zero(args.activatedby)) {
05758 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
05759 } else if (!strcasecmp(args.activatedby, "caller")) {
05760 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER);
05761 } else if (!strcasecmp(args.activatedby, "callee")) {
05762 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE);
05763 } else if (!strcasecmp(args.activatedby, "both")) {
05764 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
05765 } else {
05766 ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s',"
05767 " must be 'caller', or 'callee', or 'both'\n", var->name);
05768 ast_free(feature);
05769 return;
05770 }
05771
05772 ast_register_feature(feature);
05773
05774 ast_verb(2, "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n",
05775 var->name, args.app, args.app_args, args.exten);
05776 }
05777
05778 static int process_config(struct ast_config *cfg)
05779 {
05780 int i;
05781 struct ast_variable *var = NULL;
05782 struct feature_group *fg = NULL;
05783 char *ctg;
05784 static const char * const categories[] = {
05785
05786
05787
05788 "general",
05789 "featuremap",
05790 "applicationmap"
05791 };
05792
05793
05794 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
05795
05796
05797 strcpy(pickup_ext, "*8");
05798 pickupsound[0] = '\0';
05799 pickupfailsound[0] = '\0';
05800
05801
05802 strcpy(xfersound, "beep");
05803 strcpy(xferfailsound, "beeperr");
05804 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
05805 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
05806 atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY;
05807 atxferdropcall = DEFAULT_ATXFER_DROP_CALL;
05808 atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES;
05809
05810
05811 comebacktoorigin = 1;
05812 courtesytone[0] = '\0';
05813 parkedplay = 0;
05814 adsipark = 0;
05815 parkeddynamic = 0;
05816
05817 var = ast_variable_browse(cfg, "general");
05818 build_parkinglot(DEFAULT_PARKINGLOT, var);
05819 for (; var; var = var->next) {
05820 if (!strcasecmp(var->name, "parkeddynamic")) {
05821 parkeddynamic = ast_true(var->value);
05822 } else if (!strcasecmp(var->name, "adsipark")) {
05823 adsipark = ast_true(var->value);
05824 } else if (!strcasecmp(var->name, "transferdigittimeout")) {
05825 if ((sscanf(var->value, "%30d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
05826 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
05827 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
05828 } else {
05829 transferdigittimeout = transferdigittimeout * 1000;
05830 }
05831 } else if (!strcasecmp(var->name, "featuredigittimeout")) {
05832 if ((sscanf(var->value, "%30d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
05833 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
05834 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
05835 }
05836 } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) {
05837 if ((sscanf(var->value, "%30d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) {
05838 ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value);
05839 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
05840 } else {
05841 atxfernoanswertimeout = atxfernoanswertimeout * 1000;
05842 }
05843 } else if (!strcasecmp(var->name, "atxferloopdelay")) {
05844 if ((sscanf(var->value, "%30u", &atxferloopdelay) != 1)) {
05845 ast_log(LOG_WARNING, "%s is not a valid atxferloopdelay\n", var->value);
05846 atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY;
05847 } else {
05848 atxferloopdelay *= 1000;
05849 }
05850 } else if (!strcasecmp(var->name, "atxferdropcall")) {
05851 atxferdropcall = ast_true(var->value);
05852 } else if (!strcasecmp(var->name, "atxfercallbackretries")) {
05853 if ((sscanf(var->value, "%30u", &atxfercallbackretries) != 1)) {
05854 ast_log(LOG_WARNING, "%s is not a valid atxfercallbackretries\n", var->value);
05855 atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES;
05856 }
05857 } else if (!strcasecmp(var->name, "courtesytone")) {
05858 ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
05859 } else if (!strcasecmp(var->name, "parkedplay")) {
05860 if (!strcasecmp(var->value, "both")) {
05861 parkedplay = 2;
05862 } else if (!strcasecmp(var->value, "parked")) {
05863 parkedplay = 1;
05864 } else {
05865 parkedplay = 0;
05866 }
05867 } else if (!strcasecmp(var->name, "xfersound")) {
05868 ast_copy_string(xfersound, var->value, sizeof(xfersound));
05869 } else if (!strcasecmp(var->name, "xferfailsound")) {
05870 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
05871 } else if (!strcasecmp(var->name, "pickupexten")) {
05872 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
05873 } else if (!strcasecmp(var->name, "pickupsound")) {
05874 ast_copy_string(pickupsound, var->value, sizeof(pickupsound));
05875 } else if (!strcasecmp(var->name, "pickupfailsound")) {
05876 ast_copy_string(pickupfailsound, var->value, sizeof(pickupfailsound));
05877 } else if (!strcasecmp(var->name, "comebacktoorigin")) {
05878 comebacktoorigin = ast_true(var->value);
05879 }
05880 }
05881
05882 unmap_features();
05883 for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) {
05884 if (remap_feature(var->name, var->value)) {
05885 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
05886 }
05887 }
05888
05889
05890 ast_unregister_features();
05891 for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) {
05892 process_applicationmap_line(var);
05893 }
05894
05895 ast_unregister_groups();
05896 AST_RWLIST_WRLOCK(&feature_groups);
05897
05898 ctg = NULL;
05899 while ((ctg = ast_category_browse(cfg, ctg))) {
05900
05901 if (!strncasecmp(ctg, "parkinglot_", strlen("parkinglot_"))) {
05902 ast_debug(2, "Found configuration section %s, assume parking context\n", ctg);
05903 if (!build_parkinglot(ctg, ast_variable_browse(cfg, ctg))) {
05904 ast_log(LOG_ERROR, "Could not build parking lot %s. Configuration error.\n", ctg);
05905 } else {
05906 ast_debug(1, "Configured parking context %s\n", ctg);
05907 }
05908 continue;
05909 }
05910
05911
05912 for (i = 0; i < ARRAY_LEN(categories); i++) {
05913 if (!strcasecmp(categories[i], ctg)) {
05914 break;
05915 }
05916 }
05917 if (i < ARRAY_LEN(categories)) {
05918 continue;
05919 }
05920
05921 if (!(fg = register_group(ctg))) {
05922 continue;
05923 }
05924
05925 for (var = ast_variable_browse(cfg, ctg); var; var = var->next) {
05926 struct ast_call_feature *feature;
05927
05928 AST_RWLIST_RDLOCK(&feature_list);
05929 if (!(feature = find_dynamic_feature(var->name)) &&
05930 !(feature = ast_find_call_feature(var->name))) {
05931 AST_RWLIST_UNLOCK(&feature_list);
05932 ast_log(LOG_WARNING, "Feature '%s' was not found.\n", var->name);
05933 continue;
05934 }
05935 AST_RWLIST_UNLOCK(&feature_list);
05936
05937 register_group_feature(fg, var->value, feature);
05938 }
05939 }
05940
05941 AST_RWLIST_UNLOCK(&feature_groups);
05942
05943 return 0;
05944 }
05945
05946
05947
05948
05949
05950
05951
05952
05953
05954 static void destroy_dialplan_usage_context(struct parking_dp_context *doomed)
05955 {
05956 struct parking_dp_ramp *ramp;
05957 struct parking_dp_spaces *spaces;
05958
05959 while ((ramp = AST_LIST_REMOVE_HEAD(&doomed->access_extens, node))) {
05960 ast_free(ramp);
05961 }
05962 while ((spaces = AST_LIST_REMOVE_HEAD(&doomed->spaces, node))) {
05963 ast_free(spaces);
05964 }
05965 while ((spaces = AST_LIST_REMOVE_HEAD(&doomed->hints, node))) {
05966 ast_free(spaces);
05967 }
05968 ast_free(doomed);
05969 }
05970
05971
05972
05973
05974
05975
05976
05977
05978
05979 static void destroy_dialplan_usage_map(struct parking_dp_map *doomed)
05980 {
05981 struct parking_dp_context *item;
05982
05983 while ((item = AST_LIST_REMOVE_HEAD(doomed, node))) {
05984 destroy_dialplan_usage_context(item);
05985 }
05986 }
05987
05988
05989
05990
05991
05992
05993
05994
05995
05996
05997
05998 static struct parking_dp_ramp *build_dialplan_useage_ramp(const char *exten, int exclusive)
05999 {
06000 struct parking_dp_ramp *ramp_node;
06001
06002 ramp_node = ast_calloc(1, sizeof(*ramp_node) + strlen(exten));
06003 if (!ramp_node) {
06004 return NULL;
06005 }
06006 ramp_node->exclusive = exclusive;
06007 strcpy(ramp_node->exten, exten);
06008 return ramp_node;
06009 }
06010
06011
06012
06013
06014
06015
06016
06017
06018
06019
06020
06021
06022
06023
06024 static int usage_context_add_ramp(struct parking_dp_ramp_map *ramp_map, const char *exten, int exclusive, struct ast_parkinglot *lot, int complain)
06025 {
06026 struct parking_dp_ramp *cur_ramp;
06027 struct parking_dp_ramp *new_ramp;
06028 int cmp;
06029
06030
06031 if (exclusive) {
06032 exclusive = 1;
06033 }
06034
06035 AST_LIST_TRAVERSE_SAFE_BEGIN(ramp_map, cur_ramp, node) {
06036 cmp = strcmp(exten, cur_ramp->exten);
06037 if (cmp > 0) {
06038
06039 continue;
06040 }
06041 if (cmp == 0) {
06042
06043 if (complain && (cur_ramp->exclusive || exclusive)) {
06044 ast_log(LOG_WARNING,
06045 "Parking lot '%s' parkext %s@%s used by another parking lot.\n",
06046 lot->name, exten, lot->cfg.parking_con);
06047 }
06048 return 0;
06049 }
06050
06051 new_ramp = build_dialplan_useage_ramp(exten, exclusive);
06052 if (!new_ramp) {
06053 return -1;
06054 }
06055 AST_LIST_INSERT_BEFORE_CURRENT(new_ramp, node);
06056 return 0;
06057 }
06058 AST_LIST_TRAVERSE_SAFE_END;
06059
06060
06061 new_ramp = build_dialplan_useage_ramp(exten, exclusive);
06062 if (!new_ramp) {
06063 return -1;
06064 }
06065 AST_LIST_INSERT_TAIL(ramp_map, new_ramp, node);
06066 return 0;
06067 }
06068
06069
06070
06071
06072
06073
06074
06075
06076
06077
06078
06079 static struct parking_dp_spaces *build_dialplan_useage_spaces(int start, int stop)
06080 {
06081 struct parking_dp_spaces *spaces_node;
06082
06083 spaces_node = ast_calloc(1, sizeof(*spaces_node));
06084 if (!spaces_node) {
06085 return NULL;
06086 }
06087 spaces_node->start = start;
06088 spaces_node->stop = stop;
06089 return spaces_node;
06090 }
06091
06092
06093
06094
06095
06096
06097
06098
06099
06100
06101
06102
06103
06104
06105 static int usage_context_add_spaces(struct parking_dp_space_map *space_map, int start, int stop, struct ast_parkinglot *lot, int complain)
06106 {
06107 struct parking_dp_spaces *cur_node;
06108 struct parking_dp_spaces *expand_node;
06109 struct parking_dp_spaces *new_node;
06110
06111 expand_node = NULL;
06112 AST_LIST_TRAVERSE_SAFE_BEGIN(space_map, cur_node, node) {
06113
06114 if (expand_node) {
06115
06116 if (expand_node->stop + 1 < cur_node->start) {
06117
06118 return 0;
06119 }
06120
06121 if (complain
06122 && ((cur_node->start <= start && start <= cur_node->stop)
06123 || (cur_node->start <= stop && stop <= cur_node->stop)
06124 || (start < cur_node->start && cur_node->stop < stop))) {
06125
06126 complain = 0;
06127 ast_log(LOG_WARNING,
06128 "Parking lot '%s' parkpos %d-%d@%s overlaps another parking lot.\n",
06129 lot->name, start, stop, lot->cfg.parking_con);
06130 }
06131
06132
06133 if (expand_node->stop < cur_node->stop) {
06134 expand_node->stop = cur_node->stop;
06135 }
06136 AST_LIST_REMOVE_CURRENT(node);
06137 ast_free(cur_node);
06138 continue;
06139 }
06140
06141 if (cur_node->stop + 1 < start) {
06142
06143 continue;
06144 }
06145 if (stop + 1 < cur_node->start) {
06146
06147 new_node = build_dialplan_useage_spaces(start, stop);
06148 if (!new_node) {
06149 return -1;
06150 }
06151 AST_LIST_INSERT_BEFORE_CURRENT(new_node, node);
06152 return 0;
06153 }
06154
06155 if (complain
06156 && ((cur_node->start <= start && start <= cur_node->stop)
06157 || (cur_node->start <= stop && stop <= cur_node->stop)
06158 || (start < cur_node->start && cur_node->stop < stop))) {
06159
06160 complain = 0;
06161 ast_log(LOG_WARNING,
06162 "Parking lot '%s' parkpos %d-%d@%s overlaps another parking lot.\n",
06163 lot->name, start, stop, lot->cfg.parking_con);
06164 }
06165
06166
06167 if (start < cur_node->start) {
06168
06169 cur_node->start = start;
06170 }
06171 if (stop <= cur_node->stop) {
06172
06173 return 0;
06174 }
06175 cur_node->stop = stop;
06176 expand_node = cur_node;
06177 }
06178 AST_LIST_TRAVERSE_SAFE_END;
06179
06180 if (expand_node) {
06181
06182
06183
06184
06185 return 0;
06186 }
06187
06188
06189 new_node = build_dialplan_useage_spaces(start, stop);
06190 if (!new_node) {
06191 return -1;
06192 }
06193 AST_LIST_INSERT_TAIL(space_map, new_node, node);
06194 return 0;
06195 }
06196
06197
06198
06199
06200
06201
06202
06203
06204
06205
06206
06207
06208 static int dialplan_usage_add_parkinglot_data(struct parking_dp_context *ctx_node, struct ast_parkinglot *lot, int complain)
06209 {
06210 if (usage_context_add_ramp(&ctx_node->access_extens, lot->cfg.parkext,
06211 lot->cfg.parkext_exclusive, lot, complain)) {
06212 return -1;
06213 }
06214 if (usage_context_add_spaces(&ctx_node->spaces, lot->cfg.parking_start,
06215 lot->cfg.parking_stop, lot, complain)) {
06216 return -1;
06217 }
06218 if (lot->cfg.parkaddhints
06219 && usage_context_add_spaces(&ctx_node->hints, lot->cfg.parking_start,
06220 lot->cfg.parking_stop, lot, 0)) {
06221 return -1;
06222 }
06223 return 0;
06224 }
06225
06226
06227
06228
06229
06230
06231
06232
06233
06234
06235 static struct parking_dp_context *build_dialplan_useage_context(struct ast_parkinglot *lot)
06236 {
06237 struct parking_dp_context *ctx_node;
06238
06239 ctx_node = ast_calloc(1, sizeof(*ctx_node) + strlen(lot->cfg.parking_con));
06240 if (!ctx_node) {
06241 return NULL;
06242 }
06243 if (dialplan_usage_add_parkinglot_data(ctx_node, lot, 0)) {
06244 destroy_dialplan_usage_context(ctx_node);
06245 return NULL;
06246 }
06247 strcpy(ctx_node->context, lot->cfg.parking_con);
06248 return ctx_node;
06249 }
06250
06251
06252
06253
06254
06255
06256
06257
06258
06259
06260
06261
06262 static int dialplan_usage_add_parkinglot(struct parking_dp_map *usage_map, struct ast_parkinglot *lot, int complain)
06263 {
06264 struct parking_dp_context *cur_ctx;
06265 struct parking_dp_context *new_ctx;
06266 int cmp;
06267
06268 AST_LIST_TRAVERSE_SAFE_BEGIN(usage_map, cur_ctx, node) {
06269 cmp = strcmp(lot->cfg.parking_con, cur_ctx->context);
06270 if (cmp > 0) {
06271
06272 continue;
06273 }
06274 if (cmp == 0) {
06275
06276 return dialplan_usage_add_parkinglot_data(cur_ctx, lot, complain);
06277 }
06278
06279 new_ctx = build_dialplan_useage_context(lot);
06280 if (!new_ctx) {
06281 return -1;
06282 }
06283 AST_LIST_INSERT_BEFORE_CURRENT(new_ctx, node);
06284 return 0;
06285 }
06286 AST_LIST_TRAVERSE_SAFE_END;
06287
06288
06289 new_ctx = build_dialplan_useage_context(lot);
06290 if (!new_ctx) {
06291 return -1;
06292 }
06293 AST_LIST_INSERT_TAIL(usage_map, new_ctx, node);
06294 return 0;
06295 }
06296
06297
06298
06299
06300
06301
06302
06303
06304
06305
06306
06307 static int build_dialplan_useage_map(struct parking_dp_map *usage_map, int complain)
06308 {
06309 int status = 0;
06310 struct ao2_iterator iter;
06311 struct ast_parkinglot *curlot;
06312
06313
06314 iter = ao2_iterator_init(parkinglots, 0);
06315 for (; (curlot = ao2_iterator_next(&iter)); ao2_ref(curlot, -1)) {
06316
06317 if (dialplan_usage_add_parkinglot(usage_map, curlot, complain)) {
06318 ao2_ref(curlot, -1);
06319 status = -1;
06320 break;
06321 }
06322 }
06323 ao2_iterator_destroy(&iter);
06324
06325 return status;
06326 }
06327
06328
06329
06330
06331
06332
06333
06334
06335
06336
06337
06338 static void remove_exten_if_exist(const char *context, const char *exten, int priority)
06339 {
06340 struct pbx_find_info q = { .stacklen = 0 };
06341
06342 if (pbx_find_extension(NULL, NULL, &q, context, exten, priority, NULL, NULL,
06343 E_MATCH)) {
06344 ast_debug(1, "Removing unneeded parking lot exten: %s@%s priority:%d\n",
06345 context, exten, priority);
06346 ast_context_remove_extension(context, exten, priority, registrar);
06347 }
06348 }
06349
06350
06351
06352
06353
06354
06355
06356
06357
06358
06359
06360
06361
06362
06363
06364 static void remove_dead_ramp_usage(const char *context, struct parking_dp_ramp_map *old_ramps, struct parking_dp_ramp_map *new_ramps)
06365 {
06366 struct parking_dp_ramp *old_ramp;
06367 struct parking_dp_ramp *new_ramp;
06368 int cmp;
06369
06370 old_ramp = AST_LIST_FIRST(old_ramps);
06371 new_ramp = AST_LIST_FIRST(new_ramps);
06372
06373 while (new_ramp) {
06374 if (!old_ramp) {
06375
06376 return;
06377 }
06378 cmp = strcmp(old_ramp->exten, new_ramp->exten);
06379 if (cmp < 0) {
06380
06381 remove_exten_if_exist(context, old_ramp->exten, 1);
06382 old_ramp = AST_LIST_NEXT(old_ramp, node);
06383 continue;
06384 }
06385 if (cmp == 0) {
06386
06387 old_ramp = AST_LIST_NEXT(old_ramp, node);
06388 } else {
06389
06390 }
06391 new_ramp = AST_LIST_NEXT(new_ramp, node);
06392 }
06393
06394
06395 for (; old_ramp; old_ramp = AST_LIST_NEXT(old_ramp, node)) {
06396 remove_exten_if_exist(context, old_ramp->exten, 1);
06397 }
06398 }
06399
06400
06401
06402
06403
06404
06405
06406
06407
06408
06409 static void destroy_space(const char *context, int space)
06410 {
06411 char exten[AST_MAX_EXTENSION];
06412
06413
06414 snprintf(exten, sizeof(exten), "%d", space);
06415 remove_exten_if_exist(context, exten, PRIORITY_HINT);
06416 remove_exten_if_exist(context, exten, 1);
06417 }
06418
06419
06420
06421
06422
06423
06424
06425
06426
06427
06428
06429
06430
06431
06432
06433
06434 static void remove_dead_spaces_usage(const char *context,
06435 struct parking_dp_space_map *old_spaces, struct parking_dp_space_map *new_spaces,
06436 void (*destroy_space)(const char *context, int space))
06437 {
06438 struct parking_dp_spaces *old_range;
06439 struct parking_dp_spaces *new_range;
06440 int space;
06441 int stop;
06442
06443 old_range = AST_LIST_FIRST(old_spaces);
06444 new_range = AST_LIST_FIRST(new_spaces);
06445 space = -1;
06446
06447 while (old_range) {
06448 if (space < old_range->start) {
06449 space = old_range->start;
06450 }
06451 if (new_range) {
06452 if (space < new_range->start) {
06453
06454 if (old_range->stop < new_range->start) {
06455
06456 stop = old_range->stop;
06457 old_range = AST_LIST_NEXT(old_range, node);
06458 } else {
06459
06460 stop = new_range->start - 1;
06461 }
06462 } else if ( space <= new_range->stop) {
06463
06464 if (old_range->stop <= new_range->stop) {
06465
06466 old_range = AST_LIST_NEXT(old_range, node);
06467 } else {
06468
06469 space = new_range->stop + 1;
06470 new_range = AST_LIST_NEXT(new_range, node);
06471 }
06472 continue;
06473 } else {
06474
06475 new_range = AST_LIST_NEXT(new_range, node);
06476 continue;
06477 }
06478 } else {
06479
06480 stop = old_range->stop;
06481 old_range = AST_LIST_NEXT(old_range, node);
06482 }
06483
06484
06485 for (; space <= stop; ++space) {
06486 destroy_space(context, space);
06487 }
06488 }
06489 }
06490
06491
06492
06493
06494
06495
06496
06497
06498
06499
06500
06501
06502
06503
06504
06505 static void remove_dead_context_usage(const char *context, struct parking_dp_context *old_ctx, struct parking_dp_context *new_ctx)
06506 {
06507 remove_dead_ramp_usage(context, &old_ctx->access_extens, &new_ctx->access_extens);
06508 remove_dead_spaces_usage(context, &old_ctx->spaces, &new_ctx->spaces, destroy_space);
06509 #if 0
06510
06511 remove_dead_spaces_usage(context, &old_ctx->hints, &new_ctx->hints, destroy_space_hint);
06512 #endif
06513 }
06514
06515
06516
06517
06518
06519
06520
06521
06522
06523
06524
06525
06526
06527
06528 static void remove_dead_dialplan_useage(struct parking_dp_map *old_map, struct parking_dp_map *new_map)
06529 {
06530 struct parking_dp_context *old_ctx;
06531 struct parking_dp_context *new_ctx;
06532 struct ast_context *con;
06533 int cmp;
06534
06535 old_ctx = AST_LIST_FIRST(old_map);
06536 new_ctx = AST_LIST_FIRST(new_map);
06537
06538 while (new_ctx) {
06539 if (!old_ctx) {
06540
06541 return;
06542 }
06543 cmp = strcmp(old_ctx->context, new_ctx->context);
06544 if (cmp < 0) {
06545
06546 con = ast_context_find(old_ctx->context);
06547 if (con) {
06548 ast_context_destroy(con, registrar);
06549 }
06550 old_ctx = AST_LIST_NEXT(old_ctx, node);
06551 continue;
06552 }
06553 if (cmp == 0) {
06554
06555 remove_dead_context_usage(old_ctx->context, old_ctx, new_ctx);
06556 old_ctx = AST_LIST_NEXT(old_ctx, node);
06557 } else {
06558
06559 }
06560 new_ctx = AST_LIST_NEXT(new_ctx, node);
06561 }
06562
06563
06564 for (; old_ctx; old_ctx = AST_LIST_NEXT(old_ctx, node)) {
06565 con = ast_context_find(old_ctx->context);
06566 if (con) {
06567 ast_context_destroy(con, registrar);
06568 }
06569 }
06570 }
06571
06572 static int parkinglot_markall_cb(void *obj, void *arg, int flags)
06573 {
06574 struct ast_parkinglot *parkinglot = obj;
06575
06576 parkinglot->the_mark = 1;
06577 return 0;
06578 }
06579
06580 static int parkinglot_is_marked_cb(void *obj, void *arg, int flags)
06581 {
06582 struct ast_parkinglot *parkinglot = obj;
06583
06584 if (parkinglot->the_mark) {
06585 if (AST_LIST_EMPTY(&parkinglot->parkings)) {
06586
06587 return CMP_MATCH;
06588 }
06589
06590 ast_log(LOG_WARNING,
06591 "Parking lot %s has parked calls. Could not remove.\n",
06592 parkinglot->name);
06593 parkinglot->disabled = 1;
06594 force_reload_load = 1;
06595 }
06596
06597 return 0;
06598 }
06599
06600 static int parkinglot_activate_cb(void *obj, void *arg, int flags)
06601 {
06602 struct ast_parkinglot *parkinglot = obj;
06603
06604 if (parkinglot->the_mark) {
06605
06606
06607
06608
06609 return 0;
06610 }
06611
06612 if (parkinglot_activate(parkinglot)) {
06613
06614
06615
06616
06617 force_reload_load = 1;
06618 ast_log(LOG_WARNING, "Parking lot %s not open for business.\n", parkinglot->name);
06619 } else {
06620 ast_debug(1, "Parking lot %s now open for business. (parkpos %d-%d)\n",
06621 parkinglot->name, parkinglot->cfg.parking_start,
06622 parkinglot->cfg.parking_stop);
06623 }
06624
06625 return 0;
06626 }
06627
06628 static int load_config(int reload)
06629 {
06630 struct ast_flags config_flags = {
06631 reload && !force_reload_load ? CONFIG_FLAG_FILEUNCHANGED : 0 };
06632 struct ast_config *cfg;
06633 struct parking_dp_map old_usage_map = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
06634 struct parking_dp_map new_usage_map = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
06635
06636
06637 force_reload_load = 0;
06638
06639 if (!default_parkinglot) {
06640
06641 default_parkinglot = build_parkinglot(DEFAULT_PARKINGLOT, NULL);
06642 if (!default_parkinglot) {
06643 ast_log(LOG_ERROR, "Configuration of default default parking lot failed.\n");
06644 return -1;
06645 }
06646 ast_debug(1, "Configuration of default default parking lot done.\n");
06647 parkinglot_addref(default_parkinglot);
06648 }
06649
06650 cfg = ast_config_load2("features.conf", "features", config_flags);
06651 if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
06652
06653 ast_debug(1, "features.conf did not change.\n");
06654 return 0;
06655 }
06656 if (cfg == CONFIG_STATUS_FILEMISSING
06657 || cfg == CONFIG_STATUS_FILEINVALID) {
06658 ast_log(LOG_WARNING, "Could not load features.conf\n");
06659 return 0;
06660 }
06661
06662
06663 if (build_dialplan_useage_map(&old_usage_map, 0)) {
06664 destroy_dialplan_usage_map(&old_usage_map);
06665
06666
06667 force_reload_load = 1;
06668 return -1;
06669 }
06670
06671 ao2_t_callback(parkinglots, OBJ_NODATA, parkinglot_markall_cb, NULL,
06672 "callback to mark all parking lots");
06673 process_config(cfg);
06674 ast_config_destroy(cfg);
06675 ao2_t_callback(parkinglots, OBJ_NODATA | OBJ_UNLINK, parkinglot_is_marked_cb, NULL,
06676 "callback to remove marked parking lots");
06677
06678
06679 if (build_dialplan_useage_map(&new_usage_map, 1)) {
06680
06681
06682
06683
06684
06685 destroy_dialplan_usage_map(&old_usage_map);
06686 destroy_dialplan_usage_map(&new_usage_map);
06687 return -1;
06688 }
06689
06690
06691 remove_dead_dialplan_useage(&old_usage_map, &new_usage_map);
06692
06693 destroy_dialplan_usage_map(&old_usage_map);
06694 destroy_dialplan_usage_map(&new_usage_map);
06695
06696 ao2_t_callback(parkinglots, OBJ_NODATA, parkinglot_activate_cb, NULL,
06697 "callback to activate all parking lots");
06698
06699 return 0;
06700 }
06701
06702
06703
06704
06705
06706
06707
06708
06709
06710
06711 static char *handle_feature_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
06712 {
06713 int i;
06714 struct ast_call_feature *feature;
06715 struct ao2_iterator iter;
06716 struct ast_parkinglot *curlot;
06717 #define HFS_FORMAT "%-25s %-7s %-7s\n"
06718
06719 switch (cmd) {
06720
06721 case CLI_INIT:
06722 e->command = "features show";
06723 e->usage =
06724 "Usage: features show\n"
06725 " Lists configured features\n";
06726 return NULL;
06727 case CLI_GENERATE:
06728 return NULL;
06729 }
06730
06731 ast_cli(a->fd, HFS_FORMAT, "Builtin Feature", "Default", "Current");
06732 ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
06733
06734 ast_cli(a->fd, HFS_FORMAT, "Pickup", "*8", ast_pickup_ext());
06735
06736 ast_rwlock_rdlock(&features_lock);
06737 for (i = 0; i < FEATURES_COUNT; i++)
06738 ast_cli(a->fd, HFS_FORMAT, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
06739 ast_rwlock_unlock(&features_lock);
06740
06741 ast_cli(a->fd, "\n");
06742 ast_cli(a->fd, HFS_FORMAT, "Dynamic Feature", "Default", "Current");
06743 ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
06744 if (AST_RWLIST_EMPTY(&feature_list)) {
06745 ast_cli(a->fd, "(none)\n");
06746 } else {
06747 AST_RWLIST_RDLOCK(&feature_list);
06748 AST_RWLIST_TRAVERSE(&feature_list, feature, feature_entry) {
06749 ast_cli(a->fd, HFS_FORMAT, feature->sname, "no def", feature->exten);
06750 }
06751 AST_RWLIST_UNLOCK(&feature_list);
06752 }
06753
06754 ast_cli(a->fd, "\nFeature Groups:\n");
06755 ast_cli(a->fd, "---------------\n");
06756 if (AST_RWLIST_EMPTY(&feature_groups)) {
06757 ast_cli(a->fd, "(none)\n");
06758 } else {
06759 struct feature_group *fg;
06760 struct feature_group_exten *fge;
06761
06762 AST_RWLIST_RDLOCK(&feature_groups);
06763 AST_RWLIST_TRAVERSE(&feature_groups, fg, entry) {
06764 ast_cli(a->fd, "===> Group: %s\n", fg->gname);
06765 AST_LIST_TRAVERSE(&fg->features, fge, entry) {
06766 ast_cli(a->fd, "===> --> %s (%s)\n", fge->feature->sname, fge->exten);
06767 }
06768 }
06769 AST_RWLIST_UNLOCK(&feature_groups);
06770 }
06771
06772 iter = ao2_iterator_init(parkinglots, 0);
06773 while ((curlot = ao2_iterator_next(&iter))) {
06774 ast_cli(a->fd, "\nCall parking (Parking lot: %s)\n", curlot->name);
06775 ast_cli(a->fd, "------------\n");
06776 ast_cli(a->fd,"%-22s: %s\n", "Parking extension", curlot->cfg.parkext);
06777 ast_cli(a->fd,"%-22s: %s\n", "Parking context", curlot->cfg.parking_con);
06778 ast_cli(a->fd,"%-22s: %d-%d\n", "Parked call extensions",
06779 curlot->cfg.parking_start, curlot->cfg.parking_stop);
06780 ast_cli(a->fd,"%-22s: %d ms\n", "Parkingtime", curlot->cfg.parkingtime);
06781 ast_cli(a->fd,"%-22s: %s\n", "MusicOnHold class", curlot->cfg.mohclass);
06782 ast_cli(a->fd,"%-22s: %s\n", "Enabled", AST_CLI_YESNO(!curlot->disabled));
06783 ast_cli(a->fd,"\n");
06784 ao2_ref(curlot, -1);
06785 }
06786 ao2_iterator_destroy(&iter);
06787
06788 return CLI_SUCCESS;
06789 }
06790
06791 int ast_features_reload(void)
06792 {
06793 struct ast_context *con;
06794 int res;
06795
06796 ast_mutex_lock(&features_reload_lock);
06797
06798
06799
06800
06801
06802
06803
06804
06805
06806 con = ast_context_find(parking_con_dial);
06807 if (con) {
06808 ast_context_destroy(con, registrar);
06809 }
06810
06811 res = load_config(1);
06812 ast_mutex_unlock(&features_reload_lock);
06813
06814 return res;
06815 }
06816
06817 static char *handle_features_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
06818 {
06819 switch (cmd) {
06820 case CLI_INIT:
06821 e->command = "features reload";
06822 e->usage =
06823 "Usage: features reload\n"
06824 " Reloads configured call features from features.conf\n";
06825 return NULL;
06826 case CLI_GENERATE:
06827 return NULL;
06828 }
06829 ast_features_reload();
06830
06831 return CLI_SUCCESS;
06832 }
06833
06834
06835
06836
06837
06838
06839
06840
06841
06842
06843
06844
06845 static int do_bridge_masquerade(struct ast_channel *chan, struct ast_channel *tmpchan)
06846 {
06847 const char *context;
06848 const char *exten;
06849 int priority;
06850
06851 ast_moh_stop(chan);
06852 ast_channel_lock_both(chan, tmpchan);
06853 context = ast_strdupa(chan->context);
06854 exten = ast_strdupa(chan->exten);
06855 priority = chan->priority;
06856 ast_setstate(tmpchan, chan->_state);
06857 tmpchan->readformat = chan->readformat;
06858 tmpchan->writeformat = chan->writeformat;
06859 ast_channel_unlock(chan);
06860 ast_channel_unlock(tmpchan);
06861
06862
06863 if (ast_channel_masquerade(tmpchan, chan)) {
06864 return -1;
06865 }
06866 ast_do_masquerade(tmpchan);
06867
06868
06869 ast_explicit_goto(tmpchan, context, exten, priority + 1);
06870
06871 return 0;
06872 }
06873
06874
06875
06876
06877
06878
06879
06880
06881
06882
06883
06884
06885
06886
06887 static int action_bridge(struct mansession *s, const struct message *m)
06888 {
06889 const char *channela = astman_get_header(m, "Channel1");
06890 const char *channelb = astman_get_header(m, "Channel2");
06891 const char *playtone = astman_get_header(m, "Tone");
06892 struct ast_channel *chana = NULL, *chanb = NULL, *chans[2];
06893 struct ast_channel *tmpchana = NULL, *tmpchanb = NULL;
06894 struct ast_bridge_thread_obj *tobj = NULL;
06895 char buf[256];
06896
06897
06898 if (ast_strlen_zero(channela) || ast_strlen_zero(channelb)) {
06899 astman_send_error(s, m, "Missing channel parameter in request");
06900 return 0;
06901 }
06902
06903
06904 chana = ast_channel_get_by_name_prefix(channela, strlen(channela));
06905 if (!chana) {
06906 snprintf(buf, sizeof(buf), "Channel1 does not exists: %s", channela);
06907 astman_send_error(s, m, buf);
06908 return 0;
06909 }
06910
06911
06912 if (chana->_state != AST_STATE_UP)
06913 ast_answer(chana);
06914
06915
06916 if (!(tmpchana = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
06917 NULL, NULL, chana->linkedid, 0, "Bridge/%s", chana->name))) {
06918 astman_send_error(s, m, "Unable to create temporary channel!");
06919 chana = ast_channel_unref(chana);
06920 return 0;
06921 }
06922
06923 if (do_bridge_masquerade(chana, tmpchana)) {
06924 snprintf(buf, sizeof(buf), "Unable to masquerade channel %s!", channela);
06925 astman_send_error(s, m, buf);
06926 ast_hangup(tmpchana);
06927 chana = ast_channel_unref(chana);
06928 return 0;
06929 }
06930
06931 chana = ast_channel_unref(chana);
06932
06933
06934 chanb = ast_channel_get_by_name_prefix(channelb, strlen(channelb));
06935 if (!chanb) {
06936 snprintf(buf, sizeof(buf), "Channel2 does not exists: %s", channelb);
06937 astman_send_error(s, m, buf);
06938 ast_hangup(tmpchana);
06939 return 0;
06940 }
06941
06942
06943 if (chanb->_state != AST_STATE_UP)
06944 ast_answer(chanb);
06945
06946
06947 if (!(tmpchanb = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
06948 NULL, NULL, chanb->linkedid, 0, "Bridge/%s", chanb->name))) {
06949 astman_send_error(s, m, "Unable to create temporary channels!");
06950 ast_hangup(tmpchana);
06951 chanb = ast_channel_unref(chanb);
06952 return 0;
06953 }
06954
06955 if (do_bridge_masquerade(chanb, tmpchanb)) {
06956 snprintf(buf, sizeof(buf), "Unable to masquerade channel %s!", channelb);
06957 astman_send_error(s, m, buf);
06958 ast_hangup(tmpchana);
06959 ast_hangup(tmpchanb);
06960 chanb = ast_channel_unref(chanb);
06961 return 0;
06962 }
06963
06964 chanb = ast_channel_unref(chanb);
06965
06966
06967 if (ast_channel_make_compatible(tmpchana, tmpchanb)) {
06968 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for manager bridge\n", tmpchana->name, tmpchanb->name);
06969 astman_send_error(s, m, "Could not make channels compatible for manager bridge");
06970 ast_hangup(tmpchana);
06971 ast_hangup(tmpchanb);
06972 return 0;
06973 }
06974
06975
06976 if (!(tobj = ast_calloc(1, sizeof(*tobj)))) {
06977 ast_log(LOG_WARNING, "Unable to spawn a new bridge thread on %s and %s: %s\n", tmpchana->name, tmpchanb->name, strerror(errno));
06978 astman_send_error(s, m, "Unable to spawn a new bridge thread");
06979 ast_hangup(tmpchana);
06980 ast_hangup(tmpchanb);
06981 return 0;
06982 }
06983
06984 tobj->chan = tmpchana;
06985 tobj->peer = tmpchanb;
06986 tobj->return_to_pbx = 1;
06987
06988 if (ast_true(playtone)) {
06989 if (!ast_strlen_zero(xfersound) && !ast_streamfile(tmpchanb, xfersound, tmpchanb->language)) {
06990 if (ast_waitstream(tmpchanb, "") < 0)
06991 ast_log(LOG_WARNING, "Failed to play a courtesy tone on chan %s\n", tmpchanb->name);
06992 }
06993 }
06994
06995 chans[0] = tmpchana;
06996 chans[1] = tmpchanb;
06997
06998 ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeAction", 2, chans,
06999 "Response: Success\r\n"
07000 "Channel1: %s\r\n"
07001 "Channel2: %s\r\n", tmpchana->name, tmpchanb->name);
07002
07003 bridge_call_thread_launch(tobj);
07004
07005 astman_send_ack(s, m, "Launched bridge thread with success");
07006
07007 return 0;
07008 }
07009
07010
07011
07012
07013
07014
07015
07016
07017
07018
07019
07020
07021 static char *handle_parkedcalls(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
07022 {
07023 struct parkeduser *cur;
07024 int numparked = 0;
07025 struct ao2_iterator iter;
07026 struct ast_parkinglot *curlot;
07027
07028 switch (cmd) {
07029 case CLI_INIT:
07030 e->command = "parkedcalls show";
07031 e->usage =
07032 "Usage: parkedcalls show\n"
07033 " List currently parked calls\n";
07034 return NULL;
07035 case CLI_GENERATE:
07036 return NULL;
07037 }
07038
07039 if (a->argc > e->args)
07040 return CLI_SHOWUSAGE;
07041
07042 ast_cli(a->fd, "%-10s %-25s (%-15s %-12s %4s) %s\n", "Num", "Channel",
07043 "Context", "Extension", "Pri", "Timeout");
07044
07045 iter = ao2_iterator_init(parkinglots, 0);
07046 while ((curlot = ao2_iterator_next(&iter))) {
07047 int lotparked = 0;
07048
07049
07050 ast_cli(a->fd, "*** Parking lot: %s (%d)\n", curlot->name,
07051 ao2_ref(curlot, 0) - 2 - (curlot == default_parkinglot));
07052
07053 AST_LIST_LOCK(&curlot->parkings);
07054 AST_LIST_TRAVERSE(&curlot->parkings, cur, list) {
07055 ast_cli(a->fd, "%-10.10s %-25s (%-15s %-12s %4d) %6lds\n",
07056 cur->parkingexten, cur->chan->name, cur->context, cur->exten,
07057 cur->priority,
07058 (long) (cur->start.tv_sec + (cur->parkingtime / 1000) - time(NULL)));
07059 ++lotparked;
07060 }
07061 AST_LIST_UNLOCK(&curlot->parkings);
07062 if (lotparked) {
07063 numparked += lotparked;
07064 ast_cli(a->fd, " %d parked call%s in parking lot %s\n", lotparked,
07065 ESS(lotparked), curlot->name);
07066 }
07067
07068 ao2_ref(curlot, -1);
07069 }
07070 ao2_iterator_destroy(&iter);
07071
07072 ast_cli(a->fd, "---\n%d parked call%s in total.\n", numparked, ESS(numparked));
07073
07074 return CLI_SUCCESS;
07075 }
07076
07077 static struct ast_cli_entry cli_features[] = {
07078 AST_CLI_DEFINE(handle_feature_show, "Lists configured features"),
07079 AST_CLI_DEFINE(handle_features_reload, "Reloads configured features"),
07080 AST_CLI_DEFINE(handle_parkedcalls, "List currently parked calls"),
07081 };
07082
07083
07084
07085
07086
07087
07088
07089
07090
07091 static int manager_parking_status(struct mansession *s, const struct message *m)
07092 {
07093 struct parkeduser *cur;
07094 const char *id = astman_get_header(m, "ActionID");
07095 char idText[256] = "";
07096 struct ao2_iterator iter;
07097 struct ast_parkinglot *curlot;
07098 int numparked = 0;
07099
07100 if (!ast_strlen_zero(id))
07101 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
07102
07103 astman_send_ack(s, m, "Parked calls will follow");
07104
07105 iter = ao2_iterator_init(parkinglots, 0);
07106 while ((curlot = ao2_iterator_next(&iter))) {
07107 AST_LIST_LOCK(&curlot->parkings);
07108 AST_LIST_TRAVERSE(&curlot->parkings, cur, list) {
07109 astman_append(s, "Event: ParkedCall\r\n"
07110 "Parkinglot: %s\r\n"
07111 "Exten: %d\r\n"
07112 "Channel: %s\r\n"
07113 "From: %s\r\n"
07114 "Timeout: %ld\r\n"
07115 "CallerIDNum: %s\r\n"
07116 "CallerIDName: %s\r\n"
07117 "ConnectedLineNum: %s\r\n"
07118 "ConnectedLineName: %s\r\n"
07119 "%s"
07120 "\r\n",
07121 curlot->name,
07122 cur->parkingnum, cur->chan->name, cur->peername,
07123 (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
07124 S_COR(cur->chan->caller.id.number.valid, cur->chan->caller.id.number.str, ""),
07125 S_COR(cur->chan->caller.id.name.valid, cur->chan->caller.id.name.str, ""),
07126 S_COR(cur->chan->connected.id.number.valid, cur->chan->connected.id.number.str, ""),
07127 S_COR(cur->chan->connected.id.name.valid, cur->chan->connected.id.name.str, ""),
07128 idText);
07129 ++numparked;
07130 }
07131 AST_LIST_UNLOCK(&curlot->parkings);
07132 ao2_ref(curlot, -1);
07133 }
07134 ao2_iterator_destroy(&iter);
07135
07136 astman_append(s,
07137 "Event: ParkedCallsComplete\r\n"
07138 "Total: %d\r\n"
07139 "%s"
07140 "\r\n",
07141 numparked, idText);
07142
07143 return RESULT_SUCCESS;
07144 }
07145
07146
07147
07148
07149
07150
07151
07152
07153
07154
07155
07156
07157 static int manager_park(struct mansession *s, const struct message *m)
07158 {
07159 const char *channel = astman_get_header(m, "Channel");
07160 const char *channel2 = astman_get_header(m, "Channel2");
07161 const char *timeout = astman_get_header(m, "Timeout");
07162 const char *parkinglotname = astman_get_header(m, "Parkinglot");
07163 char buf[BUFSIZ];
07164 int res = 0;
07165 struct ast_channel *ch1, *ch2;
07166 struct ast_park_call_args args = {
07167
07168
07169
07170
07171
07172
07173
07174
07175
07176
07177
07178
07179
07180
07181
07182
07183
07184
07185
07186 .flags = AST_PARK_OPT_SILENCE,
07187 };
07188
07189 if (ast_strlen_zero(channel)) {
07190 astman_send_error(s, m, "Channel not specified");
07191 return 0;
07192 }
07193
07194 if (ast_strlen_zero(channel2)) {
07195 astman_send_error(s, m, "Channel2 not specified");
07196 return 0;
07197 }
07198
07199 if (!ast_strlen_zero(timeout)) {
07200 if (sscanf(timeout, "%30d", &args.timeout) != 1) {
07201 astman_send_error(s, m, "Invalid timeout value.");
07202 return 0;
07203 }
07204 }
07205
07206 if (!(ch1 = ast_channel_get_by_name(channel))) {
07207 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
07208 astman_send_error(s, m, buf);
07209 return 0;
07210 }
07211
07212 if (!(ch2 = ast_channel_get_by_name(channel2))) {
07213 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
07214 astman_send_error(s, m, buf);
07215 ast_channel_unref(ch1);
07216 return 0;
07217 }
07218
07219 if (!ast_strlen_zero(parkinglotname)) {
07220 args.parkinglot = find_parkinglot(parkinglotname);
07221 }
07222
07223 res = masq_park_call(ch1, ch2, &args);
07224 if (!res) {
07225 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
07226 astman_send_ack(s, m, "Park successful");
07227 } else {
07228 astman_send_error(s, m, "Park failure");
07229 }
07230
07231 if (args.parkinglot) {
07232 parkinglot_unref(args.parkinglot);
07233 }
07234 ch1 = ast_channel_unref(ch1);
07235 ch2 = ast_channel_unref(ch2);
07236
07237 return 0;
07238 }
07239
07240
07241
07242
07243
07244
07245
07246 static const struct ast_datastore_info pickup_active = {
07247 .type = "pickup-active",
07248 };
07249
07250 int ast_can_pickup(struct ast_channel *chan)
07251 {
07252 if (!chan->pbx && !chan->masq && !ast_test_flag(chan, AST_FLAG_ZOMBIE)
07253 && (chan->_state == AST_STATE_RINGING
07254 || chan->_state == AST_STATE_RING
07255
07256
07257
07258
07259
07260
07261 || chan->_state == AST_STATE_DOWN)
07262 && !ast_channel_datastore_find(chan, &pickup_active, NULL)) {
07263 return 1;
07264 }
07265 return 0;
07266 }
07267
07268 static int find_channel_by_group(void *obj, void *arg, void *data, int flags)
07269 {
07270 struct ast_channel *target = obj;
07271 struct ast_channel *chan = data;
07272
07273 ast_channel_lock(target);
07274 if (chan != target && (chan->pickupgroup & target->callgroup)
07275 && ast_can_pickup(target)) {
07276
07277 return CMP_MATCH | CMP_STOP;
07278 }
07279 ast_channel_unlock(target);
07280
07281 return 0;
07282 }
07283
07284
07285
07286
07287
07288
07289
07290
07291
07292 int ast_pickup_call(struct ast_channel *chan)
07293 {
07294 struct ast_channel *target;
07295 int res = -1;
07296 ast_debug(1, "pickup attempt by %s\n", chan->name);
07297
07298
07299 target = ast_channel_callback(find_channel_by_group, NULL, chan, 0);
07300 if (target) {
07301 ast_log(LOG_NOTICE, "pickup %s attempt by %s\n", target->name, chan->name);
07302
07303 res = ast_do_pickup(chan, target);
07304 ast_channel_unlock(target);
07305 if (!res) {
07306 if (!ast_strlen_zero(pickupsound)) {
07307 pbx_builtin_setvar_helper(target, "BRIDGE_PLAY_SOUND", pickupsound);
07308 }
07309 } else {
07310 ast_log(LOG_WARNING, "pickup %s failed by %s\n", target->name, chan->name);
07311 }
07312 target = ast_channel_unref(target);
07313 }
07314
07315 if (res < 0) {
07316 ast_debug(1, "No call pickup possible... for %s\n", chan->name);
07317 if (!ast_strlen_zero(pickupfailsound)) {
07318 ast_answer(chan);
07319 ast_stream_and_wait(chan, pickupfailsound, "");
07320 }
07321 }
07322
07323 return res;
07324 }
07325
07326 int ast_do_pickup(struct ast_channel *chan, struct ast_channel *target)
07327 {
07328 struct ast_party_connected_line connected_caller;
07329 struct ast_channel *chans[2] = { chan, target };
07330 struct ast_datastore *ds_pickup;
07331 const char *chan_name;
07332 const char *target_name;
07333 int res = -1;
07334
07335 target_name = ast_strdupa(target->name);
07336 ast_debug(1, "Call pickup on '%s' by '%s'\n", target_name, chan->name);
07337
07338
07339 ds_pickup = ast_datastore_alloc(&pickup_active, NULL);
07340 if (!ds_pickup) {
07341 ast_log(LOG_WARNING,
07342 "Unable to create channel datastore on '%s' for call pickup\n", target_name);
07343 return -1;
07344 }
07345 ast_channel_datastore_add(target, ds_pickup);
07346
07347 ast_party_connected_line_init(&connected_caller);
07348 ast_party_connected_line_copy(&connected_caller, &target->connected);
07349 ast_channel_unlock(target);
07350 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
07351 if (ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) {
07352 ast_channel_update_connected_line(chan, &connected_caller, NULL);
07353 }
07354 ast_party_connected_line_free(&connected_caller);
07355
07356 ast_channel_lock(chan);
07357 chan_name = ast_strdupa(chan->name);
07358 ast_connected_line_copy_from_caller(&connected_caller, &chan->caller);
07359 ast_channel_unlock(chan);
07360 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
07361
07362 ast_cel_report_event(target, AST_CEL_PICKUP, NULL, NULL, chan);
07363
07364 if (ast_answer(chan)) {
07365 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name);
07366 goto pickup_failed;
07367 }
07368
07369 if (ast_queue_control(chan, AST_CONTROL_ANSWER)) {
07370 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan_name);
07371 goto pickup_failed;
07372 }
07373
07374 ast_channel_queue_connected_line_update(chan, &connected_caller, NULL);
07375
07376
07377 ast_set_flag(chan, AST_FLAG_ANSWERED_ELSEWHERE);
07378
07379 if (ast_channel_masquerade(target, chan)) {
07380 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan_name,
07381 target_name);
07382 goto pickup_failed;
07383 }
07384
07385
07386 ast_manager_event_multichan(EVENT_FLAG_CALL, "Pickup", 2, chans,
07387 "Channel: %s\r\n"
07388 "TargetChannel: %s\r\n",
07389 chan_name, target_name);
07390
07391
07392 ast_do_masquerade(target);
07393 res = 0;
07394
07395 pickup_failed:
07396 ast_channel_lock(target);
07397 if (!ast_channel_datastore_remove(target, ds_pickup)) {
07398 ast_datastore_free(ds_pickup);
07399 }
07400 ast_party_connected_line_free(&connected_caller);
07401
07402 return res;
07403 }
07404
07405 static char *app_bridge = "Bridge";
07406
07407 enum {
07408 BRIDGE_OPT_PLAYTONE = (1 << 0),
07409 OPT_CALLEE_HANGUP = (1 << 1),
07410 OPT_CALLER_HANGUP = (1 << 2),
07411 OPT_DURATION_LIMIT = (1 << 3),
07412 OPT_DURATION_STOP = (1 << 4),
07413 OPT_CALLEE_TRANSFER = (1 << 5),
07414 OPT_CALLER_TRANSFER = (1 << 6),
07415 OPT_CALLEE_MONITOR = (1 << 7),
07416 OPT_CALLER_MONITOR = (1 << 8),
07417 OPT_CALLEE_PARK = (1 << 9),
07418 OPT_CALLER_PARK = (1 << 10),
07419 OPT_CALLEE_KILL = (1 << 11),
07420 };
07421
07422 enum {
07423 OPT_ARG_DURATION_LIMIT = 0,
07424 OPT_ARG_DURATION_STOP,
07425
07426 OPT_ARG_ARRAY_SIZE,
07427 };
07428
07429 AST_APP_OPTIONS(bridge_exec_options, BEGIN_OPTIONS
07430 AST_APP_OPTION('p', BRIDGE_OPT_PLAYTONE),
07431 AST_APP_OPTION('h', OPT_CALLEE_HANGUP),
07432 AST_APP_OPTION('H', OPT_CALLER_HANGUP),
07433 AST_APP_OPTION('k', OPT_CALLEE_PARK),
07434 AST_APP_OPTION('K', OPT_CALLER_PARK),
07435 AST_APP_OPTION_ARG('L', OPT_DURATION_LIMIT, OPT_ARG_DURATION_LIMIT),
07436 AST_APP_OPTION_ARG('S', OPT_DURATION_STOP, OPT_ARG_DURATION_STOP),
07437 AST_APP_OPTION('t', OPT_CALLEE_TRANSFER),
07438 AST_APP_OPTION('T', OPT_CALLER_TRANSFER),
07439 AST_APP_OPTION('w', OPT_CALLEE_MONITOR),
07440 AST_APP_OPTION('W', OPT_CALLER_MONITOR),
07441 AST_APP_OPTION('x', OPT_CALLEE_KILL),
07442 END_OPTIONS );
07443
07444 int ast_bridge_timelimit(struct ast_channel *chan, struct ast_bridge_config *config,
07445 char *parse, struct timeval *calldurationlimit)
07446 {
07447 char *stringp = ast_strdupa(parse);
07448 char *limit_str, *warning_str, *warnfreq_str;
07449 const char *var;
07450 int play_to_caller = 0, play_to_callee = 0;
07451 int delta;
07452
07453 limit_str = strsep(&stringp, ":");
07454 warning_str = strsep(&stringp, ":");
07455 warnfreq_str = strsep(&stringp, ":");
07456
07457 config->timelimit = atol(limit_str);
07458 if (warning_str)
07459 config->play_warning = atol(warning_str);
07460 if (warnfreq_str)
07461 config->warning_freq = atol(warnfreq_str);
07462
07463 if (!config->timelimit) {
07464 ast_log(LOG_WARNING, "Bridge does not accept L(%s), hanging up.\n", limit_str);
07465 config->timelimit = config->play_warning = config->warning_freq = 0;
07466 config->warning_sound = NULL;
07467 return -1;
07468 } else if ( (delta = config->play_warning - config->timelimit) > 0) {
07469 int w = config->warning_freq;
07470
07471
07472
07473
07474
07475
07476
07477
07478
07479
07480
07481
07482
07483
07484
07485 if (w == 0) {
07486 config->play_warning = 0;
07487 } else {
07488 config->play_warning -= w * ( 1 + (delta-1)/w );
07489 if (config->play_warning < 1)
07490 config->play_warning = config->warning_freq = 0;
07491 }
07492 }
07493
07494 ast_channel_lock(chan);
07495
07496 var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLER");
07497 play_to_caller = var ? ast_true(var) : 1;
07498
07499 var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLEE");
07500 play_to_callee = var ? ast_true(var) : 0;
07501
07502 if (!play_to_caller && !play_to_callee)
07503 play_to_caller = 1;
07504
07505 var = pbx_builtin_getvar_helper(chan, "LIMIT_WARNING_FILE");
07506 config->warning_sound = !ast_strlen_zero(var) ? ast_strdup(var) : ast_strdup("timeleft");
07507
07508
07509
07510
07511
07512
07513
07514 var = pbx_builtin_getvar_helper(chan, "LIMIT_TIMEOUT_FILE");
07515 config->end_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL;
07516
07517 var = pbx_builtin_getvar_helper(chan, "LIMIT_CONNECT_FILE");
07518 config->start_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL;
07519
07520 ast_channel_unlock(chan);
07521
07522
07523 calldurationlimit->tv_sec = 0;
07524 calldurationlimit->tv_usec = 0;
07525
07526
07527 if (!config->play_warning && !config->start_sound && !config->end_sound && config->timelimit) {
07528 calldurationlimit->tv_sec = config->timelimit / 1000;
07529 calldurationlimit->tv_usec = (config->timelimit % 1000) * 1000;
07530 ast_verb(3, "Setting call duration limit to %.3lf seconds.\n",
07531 calldurationlimit->tv_sec + calldurationlimit->tv_usec / 1000000.0);
07532 config->timelimit = play_to_caller = play_to_callee =
07533 config->play_warning = config->warning_freq = 0;
07534 } else {
07535 ast_verb(4, "Limit Data for this call:\n");
07536 ast_verb(4, "timelimit = %ld ms (%.3lf s)\n", config->timelimit, config->timelimit / 1000.0);
07537 ast_verb(4, "play_warning = %ld ms (%.3lf s)\n", config->play_warning, config->play_warning / 1000.0);
07538 ast_verb(4, "play_to_caller = %s\n", play_to_caller ? "yes" : "no");
07539 ast_verb(4, "play_to_callee = %s\n", play_to_callee ? "yes" : "no");
07540 ast_verb(4, "warning_freq = %ld ms (%.3lf s)\n", config->warning_freq, config->warning_freq / 1000.0);
07541 ast_verb(4, "start_sound = %s\n", S_OR(config->start_sound, ""));
07542 ast_verb(4, "warning_sound = %s\n", config->warning_sound);
07543 ast_verb(4, "end_sound = %s\n", S_OR(config->end_sound, ""));
07544 }
07545 if (play_to_caller)
07546 ast_set_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
07547 if (play_to_callee)
07548 ast_set_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
07549 return 0;
07550 }
07551
07552
07553
07554
07555
07556
07557
07558
07559
07560
07561
07562 static int bridge_exec(struct ast_channel *chan, const char *data)
07563 {
07564 struct ast_channel *current_dest_chan, *final_dest_chan, *chans[2];
07565 char *tmp_data = NULL;
07566 struct ast_flags opts = { 0, };
07567 struct ast_bridge_config bconfig = { { 0, }, };
07568 char *opt_args[OPT_ARG_ARRAY_SIZE];
07569 struct timeval calldurationlimit = { 0, };
07570
07571 AST_DECLARE_APP_ARGS(args,
07572 AST_APP_ARG(dest_chan);
07573 AST_APP_ARG(options);
07574 );
07575
07576 if (ast_strlen_zero(data)) {
07577 ast_log(LOG_WARNING, "Bridge require at least 1 argument specifying the other end of the bridge\n");
07578 return -1;
07579 }
07580
07581 tmp_data = ast_strdupa(data);
07582 AST_STANDARD_APP_ARGS(args, tmp_data);
07583 if (!ast_strlen_zero(args.options))
07584 ast_app_parse_options(bridge_exec_options, &opts, opt_args, args.options);
07585
07586
07587 if (!strcmp(chan->name, args.dest_chan)) {
07588 ast_log(LOG_WARNING, "Unable to bridge channel %s with itself\n", chan->name);
07589 ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
07590 "Response: Failed\r\n"
07591 "Reason: Unable to bridge channel to itself\r\n"
07592 "Channel1: %s\r\n"
07593 "Channel2: %s\r\n",
07594 chan->name, args.dest_chan);
07595 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "LOOP");
07596 return 0;
07597 }
07598
07599
07600 if (!(current_dest_chan = ast_channel_get_by_name_prefix(args.dest_chan,
07601 strlen(args.dest_chan)))) {
07602 ast_log(LOG_WARNING, "Bridge failed because channel %s does not exist\n",
07603 args.dest_chan);
07604 ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
07605 "Response: Failed\r\n"
07606 "Reason: Channel2 does not exist\r\n"
07607 "Channel1: %s\r\n"
07608 "Channel2: %s\r\n", chan->name, args.dest_chan);
07609 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "NONEXISTENT");
07610 return 0;
07611 }
07612
07613
07614 if (!(final_dest_chan = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
07615 NULL, NULL, current_dest_chan->linkedid, 0, "Bridge/%s", current_dest_chan->name))) {
07616 ast_log(LOG_WARNING, "Cannot create placeholder channel for chan %s\n", args.dest_chan);
07617 ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
07618 "Response: Failed\r\n"
07619 "Reason: Cannot create placeholder channel\r\n"
07620 "Channel1: %s\r\n"
07621 "Channel2: %s\r\n", chan->name, args.dest_chan);
07622 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "FAILURE");
07623 ast_channel_unref(current_dest_chan);
07624 return 0;
07625 }
07626
07627 if (ast_test_flag(&opts, OPT_DURATION_LIMIT)
07628 && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_LIMIT])
07629 && ast_bridge_timelimit(chan, &bconfig, opt_args[OPT_ARG_DURATION_LIMIT], &calldurationlimit)) {
07630 ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
07631 "Response: Failed\r\n"
07632 "Reason: Cannot setup bridge time limit\r\n"
07633 "Channel1: %s\r\n"
07634 "Channel2: %s\r\n", chan->name, args.dest_chan);
07635 ast_hangup(final_dest_chan);
07636 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "FAILURE");
07637 current_dest_chan = ast_channel_unref(current_dest_chan);
07638 goto done;
07639 }
07640
07641 if (do_bridge_masquerade(current_dest_chan, final_dest_chan)) {
07642 ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
07643 "Response: Failed\r\n"
07644 "Reason: Cannot masquerade channels\r\n"
07645 "Channel1: %s\r\n"
07646 "Channel2: %s\r\n", chan->name, args.dest_chan);
07647 ast_hangup(final_dest_chan);
07648 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "FAILURE");
07649 current_dest_chan = ast_channel_unref(current_dest_chan);
07650 goto done;
07651 }
07652
07653
07654 if (final_dest_chan->_state != AST_STATE_UP) {
07655 ast_answer(final_dest_chan);
07656 }
07657
07658 chans[0] = current_dest_chan;
07659 chans[1] = final_dest_chan;
07660
07661
07662
07663 if (ast_channel_make_compatible(chan, final_dest_chan) < 0) {
07664 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, final_dest_chan->name);
07665 ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeExec", 2, chans,
07666 "Response: Failed\r\n"
07667 "Reason: Could not make channels compatible for bridge\r\n"
07668 "Channel1: %s\r\n"
07669 "Channel2: %s\r\n", chan->name, final_dest_chan->name);
07670
07671
07672 ast_hangup(final_dest_chan);
07673
07674 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "INCOMPATIBLE");
07675 current_dest_chan = ast_channel_unref(current_dest_chan);
07676 goto done;
07677 }
07678
07679
07680 ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeExec", 2, chans,
07681 "Response: Success\r\n"
07682 "Channel1: %s\r\n"
07683 "Channel2: %s\r\n", chan->name, final_dest_chan->name);
07684
07685 current_dest_chan = ast_channel_unref(current_dest_chan);
07686
07687
07688 if (ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE) && !ast_strlen_zero(xfersound)) {
07689 if (!ast_streamfile(final_dest_chan, xfersound, final_dest_chan->language)) {
07690 if (ast_waitstream(final_dest_chan, "") < 0)
07691 ast_log(LOG_WARNING, "Failed to play courtesy tone on %s\n", final_dest_chan->name);
07692 }
07693 }
07694
07695 if (ast_test_flag(&opts, OPT_CALLEE_TRANSFER))
07696 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_REDIRECT);
07697 if (ast_test_flag(&opts, OPT_CALLER_TRANSFER))
07698 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_REDIRECT);
07699 if (ast_test_flag(&opts, OPT_CALLEE_HANGUP))
07700 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
07701 if (ast_test_flag(&opts, OPT_CALLER_HANGUP))
07702 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
07703 if (ast_test_flag(&opts, OPT_CALLEE_MONITOR))
07704 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_AUTOMON);
07705 if (ast_test_flag(&opts, OPT_CALLER_MONITOR))
07706 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_AUTOMON);
07707 if (ast_test_flag(&opts, OPT_CALLEE_PARK))
07708 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_PARKCALL);
07709 if (ast_test_flag(&opts, OPT_CALLER_PARK))
07710 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_PARKCALL);
07711
07712
07713
07714
07715
07716 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT);
07717 ast_bridge_call(chan, final_dest_chan, &bconfig);
07718
07719
07720 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "SUCCESS");
07721
07722
07723 if (!ast_check_hangup(final_dest_chan)) {
07724 if (!ast_test_flag(&opts, OPT_CALLEE_KILL)) {
07725 ast_debug(1, "starting new PBX in %s,%s,%d for chan %s\n",
07726 final_dest_chan->context, final_dest_chan->exten,
07727 final_dest_chan->priority, final_dest_chan->name);
07728
07729 if (ast_pbx_start(final_dest_chan)) {
07730 ast_log(LOG_WARNING, "FAILED continuing PBX on dest chan %s\n", final_dest_chan->name);
07731 ast_hangup(final_dest_chan);
07732 } else {
07733 ast_debug(1, "SUCCESS continuing PBX on chan %s\n", final_dest_chan->name);
07734 }
07735 } else {
07736 ast_hangup(final_dest_chan);
07737 }
07738 } else {
07739 ast_debug(1, "chan %s was hungup\n", final_dest_chan->name);
07740 ast_hangup(final_dest_chan);
07741 }
07742 done:
07743 ast_free((char *) bconfig.warning_sound);
07744 ast_free((char *) bconfig.end_sound);
07745 ast_free((char *) bconfig.start_sound);
07746
07747 return 0;
07748 }
07749
07750 #if defined(TEST_FRAMEWORK)
07751
07752
07753
07754
07755
07756
07757
07758
07759
07760 static void create_spaces_str(struct ast_str **str, struct parking_dp_space_map *spaces)
07761 {
07762 const char *comma;
07763 struct parking_dp_spaces *cur;
07764
07765 ast_str_reset(*str);
07766 comma = "";
07767 AST_LIST_TRAVERSE(spaces, cur, node) {
07768 if (cur->start == cur->stop) {
07769 ast_str_append(str, 0, "%s%d", comma, cur->start);
07770 } else {
07771 ast_str_append(str, 0, "%s%d-%d", comma, cur->start, cur->stop);
07772 }
07773 comma = ",";
07774 }
07775 }
07776 #endif
07777
07778 #if defined(TEST_FRAMEWORK)
07779
07780
07781
07782
07783
07784
07785
07786
07787
07788
07789
07790
07791 static int check_spaces(struct ast_test *test, struct parking_dp_space_map *spaces, const char *expected, const char *what)
07792 {
07793 int cmp;
07794 struct ast_str *str = ast_str_alloca(1024);
07795
07796 create_spaces_str(&str, spaces);
07797 cmp = strcmp(expected, ast_str_buffer(str));
07798 if (cmp) {
07799 ast_test_status_update(test,
07800 "Unexpected parking space map for %s. Expect:'%s' Got:'%s'\n",
07801 what, expected, ast_str_buffer(str));
07802 }
07803 return cmp;
07804 }
07805 #endif
07806
07807 #if defined(TEST_FRAMEWORK)
07808
07809
07810
07811
07812
07813
07814
07815
07816
07817 static void test_add_dead_space(const char *context, int space)
07818 {
07819 struct parking_dp_space_map *dead_spaces = (struct parking_dp_space_map *) context;
07820
07821 usage_context_add_spaces(dead_spaces, space, space, NULL, 0);
07822 }
07823 #endif
07824
07825 #if defined(TEST_FRAMEWORK)
07826 struct test_map {
07827 const char *ramp;
07828 int start;
07829 int stop;
07830 const char *expect;
07831 };
07832
07833
07834
07835
07836
07837
07838
07839
07840
07841
07842
07843
07844
07845
07846 static struct parking_dp_context *test_build_maps(struct ast_test *test,
07847 struct ast_parkinglot *lot, const char *table_name, const struct test_map *table,
07848 size_t num_entries)
07849 {
07850 struct parking_dp_context *ctx_node;
07851 int cur_index = 0;
07852 char what[40];
07853
07854 snprintf(what, sizeof(what), "%s[%d]", table_name, cur_index);
07855 ast_copy_string(lot->cfg.parkext, table->ramp, sizeof(lot->cfg.parkext));
07856 lot->cfg.parking_start = table->start;
07857 lot->cfg.parking_stop = table->stop;
07858 ctx_node = build_dialplan_useage_context(lot);
07859 if (!ctx_node) {
07860 ast_test_status_update(test, "Failed to create parking lot context map for %s\n",
07861 what);
07862 return NULL;
07863 }
07864 if (check_spaces(test, &ctx_node->spaces, table->expect, what)) {
07865 destroy_dialplan_usage_context(ctx_node);
07866 return NULL;
07867 }
07868 while (--num_entries) {
07869 ++cur_index;
07870 ++table;
07871 snprintf(what, sizeof(what), "%s[%d]", table_name, cur_index);
07872 ast_copy_string(lot->cfg.parkext, table->ramp, sizeof(lot->cfg.parkext));
07873 lot->cfg.parking_start = table->start;
07874 lot->cfg.parking_stop = table->stop;
07875 if (dialplan_usage_add_parkinglot_data(ctx_node, lot, 1)) {
07876 ast_test_status_update(test, "Failed to add parking lot data for %s\n", what);
07877 destroy_dialplan_usage_context(ctx_node);
07878 return NULL;
07879 }
07880 if (check_spaces(test, &ctx_node->spaces, table->expect, what)) {
07881 destroy_dialplan_usage_context(ctx_node);
07882 return NULL;
07883 }
07884 }
07885 return ctx_node;
07886 }
07887
07888 static const struct test_map test_old_ctx[] = {
07889
07890 { "702", 14, 15, "14-15" },
07891 { "700", 10, 11, "10-11,14-15" },
07892 { "701", 18, 19, "10-11,14-15,18-19" },
07893 { "703", 12, 13, "10-15,18-19" },
07894 { "704", 16, 17, "10-19" },
07895
07896
07897 { "704", 9, 19, "9-19" },
07898 { "704", 9, 20, "9-20" },
07899 { "704", 8, 21, "8-21" },
07900
07901
07902 { "705", 23, 25, "8-21,23-25" },
07903 { "706", 28, 31, "8-21,23-25,28-31" },
07904 { "707", 33, 34, "8-21,23-25,28-31,33-34" },
07905 { "708", 38, 40, "8-21,23-25,28-31,33-34,38-40" },
07906 { "709", 42, 43, "8-21,23-25,28-31,33-34,38-40,42-43" },
07907 };
07908
07909 static const struct test_map test_new_ctx[] = {
07910 { "702", 4, 5, "4-5" },
07911 { "704", 24, 26, "4-5,24-26" },
07912 { "709", 29, 30, "4-5,24-26,29-30" },
07913 { "710", 32, 35, "4-5,24-26,29-30,32-35" },
07914 { "711", 37, 39, "4-5,24-26,29-30,32-35,37-39" },
07915 };
07916 #endif
07917
07918 #if defined(TEST_FRAMEWORK)
07919
07920
07921
07922
07923
07924
07925
07926
07927
07928 static int test_dialplan_usage_map(struct ast_test *test)
07929 {
07930 struct parking_dp_context *old_ctx;
07931 struct parking_dp_context *new_ctx;
07932 struct ast_parkinglot *lot;
07933 struct parking_dp_spaces *spaces;
07934 struct parking_dp_space_map dead_spaces = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
07935 int res;
07936
07937 ast_test_status_update(test, "Test parking dialplan usage map code\n");
07938
07939 lot = create_parkinglot("test_lot");
07940 if (!lot) {
07941 return -1;
07942 }
07943 ast_copy_string(lot->cfg.parking_con, "test-ctx", sizeof(lot->cfg.parking_con));
07944 lot->cfg.parkext_exclusive = 1;
07945
07946 ast_test_status_update(test,
07947 "Build old_ctx map\n");
07948 ast_log(LOG_NOTICE, "6 Ramp and space conflict warnings are expected.\n");
07949 old_ctx = test_build_maps(test, lot, "test_old_ctx", test_old_ctx,
07950 ARRAY_LEN(test_old_ctx));
07951 if (!old_ctx) {
07952 ao2_ref(lot, -1);
07953 return -1;
07954 }
07955
07956 ast_test_status_update(test, "Build new_ctx map\n");
07957 new_ctx = test_build_maps(test, lot, "test_new_ctx", test_new_ctx,
07958 ARRAY_LEN(test_new_ctx));
07959 if (!new_ctx) {
07960 res = -1;
07961 goto fail_old_ctx;
07962 }
07963
07964 ast_test_status_update(test, "Test removing dead parking spaces\n");
07965 remove_dead_spaces_usage((void *) &dead_spaces, &old_ctx->spaces,
07966 &new_ctx->spaces, test_add_dead_space);
07967 if (check_spaces(test, &dead_spaces, "8-21,23,28,31,40,42-43", "dead_spaces")) {
07968 res = -1;
07969 goto fail_dead_spaces;
07970 }
07971
07972 res = 0;
07973
07974 fail_dead_spaces:
07975 while ((spaces = AST_LIST_REMOVE_HEAD(&dead_spaces, node))) {
07976 ast_free(spaces);
07977 }
07978 destroy_dialplan_usage_context(new_ctx);
07979
07980 fail_old_ctx:
07981 destroy_dialplan_usage_context(old_ctx);
07982 ao2_ref(lot, -1);
07983 return res;
07984 }
07985 #endif
07986
07987 #if defined(TEST_FRAMEWORK)
07988 static int fake_fixup(struct ast_channel *clonechan, struct ast_channel *original)
07989 {
07990 return 0;
07991 }
07992 #endif
07993
07994 #if defined(TEST_FRAMEWORK)
07995 static struct ast_channel *create_test_channel(const struct ast_channel_tech *fake_tech)
07996 {
07997 struct ast_channel *test_channel1;
07998
07999 if (!(test_channel1 = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
08000 NULL, NULL, 0, 0, "TestChannel1"))) {
08001 ast_log(LOG_WARNING, "Whoa, test channel creation failed.\n");
08002 return NULL;
08003 }
08004
08005
08006 test_channel1->nativeformats = AST_FORMAT_GSM;
08007 test_channel1->writeformat = AST_FORMAT_GSM;
08008 test_channel1->rawwriteformat = AST_FORMAT_GSM;
08009 test_channel1->readformat = AST_FORMAT_GSM;
08010 test_channel1->rawreadformat = AST_FORMAT_GSM;
08011 test_channel1->tech = fake_tech;
08012
08013 return test_channel1;
08014 }
08015 #endif
08016
08017 #if defined(TEST_FRAMEWORK)
08018 static int unpark_test_channel(struct ast_channel *toremove, struct ast_park_call_args *args)
08019 {
08020 struct ast_context *con;
08021 struct parkeduser *pu_toremove;
08022 int res = 0;
08023
08024 args->pu->notquiteyet = 1;
08025
08026 AST_LIST_LOCK(&args->pu->parkinglot->parkings);
08027 AST_LIST_TRAVERSE_SAFE_BEGIN(&args->pu->parkinglot->parkings, pu_toremove, list) {
08028 if (pu_toremove == args->pu) {
08029 AST_LIST_REMOVE_CURRENT(list);
08030 break;
08031 }
08032 }
08033 AST_LIST_TRAVERSE_SAFE_END;
08034 AST_LIST_UNLOCK(&args->pu->parkinglot->parkings);
08035
08036 if (!pu_toremove) {
08037 ast_log(LOG_WARNING, "Whoa, could not find parking test call!\n");
08038 return -1;
08039 }
08040
08041 con = ast_context_find(args->pu->parkinglot->cfg.parking_con);
08042 if (con) {
08043 if (ast_context_remove_extension2(con, args->pu->parkingexten, 1, NULL, 0)) {
08044 ast_log(LOG_WARNING, "Whoa, failed to remove the parking extension!\n");
08045 res = -1;
08046 } else {
08047 notify_metermaids(args->pu->parkingexten,
08048 pu_toremove->parkinglot->cfg.parking_con, AST_DEVICE_NOT_INUSE);
08049 }
08050 } else {
08051 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
08052 res = -1;
08053 }
08054
08055 parkinglot_unref(pu_toremove->parkinglot);
08056 ast_free(pu_toremove);
08057 args->pu = NULL;
08058
08059 if (!res && toremove) {
08060 ast_hangup(toremove);
08061 }
08062 return res;
08063 }
08064 #endif
08065
08066 #if defined(TEST_FRAMEWORK)
08067 AST_TEST_DEFINE(features_test)
08068 {
08069 struct ast_channel *test_channel1 = NULL;
08070 struct ast_channel *parked_chan = NULL;
08071 struct ast_parkinglot *dynlot;
08072 struct ast_park_call_args args = {
08073 .timeout = DEFAULT_PARK_TIME,
08074 };
08075
08076 int res = 0;
08077
08078 static const struct ast_channel_tech fake_tech = {
08079 .fixup = fake_fixup,
08080 };
08081
08082 static const char unique_lot_1[] = "myuniquetestparkinglot314";
08083 static const char unique_lot_2[] = "myuniquetestparkinglot3141592654";
08084 static const char unique_context_1[] = "myuniquetestcontext314";
08085 static const char unique_context_2[] = "myuniquetestcontext3141592654";
08086 static const char parkinglot_parkext[] = "750";
08087 static const char parkinglot_range[] = "751-760";
08088
08089 switch (cmd) {
08090 case TEST_INIT:
08091 info->name = "features_test";
08092 info->category = "/main/features/";
08093 info->summary = "Features unit test";
08094 info->description =
08095 "Tests whether parking respects PARKINGLOT settings";
08096 return AST_TEST_NOT_RUN;
08097 case TEST_EXECUTE:
08098 break;
08099 }
08100
08101 if (test_dialplan_usage_map(test)) {
08102 res = -1;
08103 goto exit_features_test;
08104 }
08105
08106
08107 parkeddynamic = 1;
08108
08109 ast_test_status_update(test, "Test parking functionality with defaults\n");
08110 if (!(test_channel1 = create_test_channel(&fake_tech))) {
08111 res = -1;
08112 goto exit_features_test;
08113 }
08114 if (park_call_full(test_channel1, NULL, &args)) {
08115 res = -1;
08116 goto exit_features_test;
08117 }
08118 if (unpark_test_channel(test_channel1, &args)) {
08119 res = -1;
08120 goto exit_features_test;
08121 }
08122
08123
08124 ast_test_status_update(test, "Check that certain parking options are respected\n");
08125 if (!(test_channel1 = create_test_channel(&fake_tech))) {
08126 res = -1;
08127 goto exit_features_test;
08128 }
08129 pbx_builtin_setvar_helper(test_channel1, "PARKINGLOT", unique_lot_1);
08130 pbx_builtin_setvar_helper(test_channel1, "PARKINGDYNCONTEXT", unique_context_1);
08131 pbx_builtin_setvar_helper(test_channel1, "PARKINGDYNEXTEN", parkinglot_parkext);
08132 pbx_builtin_setvar_helper(test_channel1, "PARKINGDYNPOS", parkinglot_range);
08133 if (park_call_full(test_channel1, NULL, &args)) {
08134 res = -1;
08135 goto exit_features_test;
08136 }
08137
08138 dynlot = args.pu->parkinglot;
08139 if (args.pu->parkingnum != 751
08140 || strcmp(dynlot->name, unique_lot_1)
08141 || strcmp(dynlot->cfg.parking_con, unique_context_1)
08142 || strcmp(dynlot->cfg.parkext, parkinglot_parkext)
08143 || dynlot->cfg.parking_start != 751
08144 || dynlot->cfg.parking_stop != 760) {
08145 ast_test_status_update(test, "Parking settings were not respected\n");
08146 ast_test_status_update(test, "Dyn-name:%s\n", dynlot->name);
08147 ast_test_status_update(test, "Dyn-context:%s\n", dynlot->cfg.parking_con);
08148 ast_test_status_update(test, "Dyn-parkext:%s\n", dynlot->cfg.parkext);
08149 ast_test_status_update(test, "Dyn-parkpos:%d-%d\n", dynlot->cfg.parking_start,
08150 dynlot->cfg.parking_stop);
08151 ast_test_status_update(test, "Parked in space:%d\n", args.pu->parkingnum);
08152 if (!unpark_test_channel(test_channel1, &args)) {
08153 test_channel1 = NULL;
08154 }
08155 res = -1;
08156 goto exit_features_test;
08157 } else {
08158 ast_test_status_update(test, "Parking settings for non-masquerading park verified\n");
08159 }
08160 if (unpark_test_channel(test_channel1, &args)) {
08161 res = -1;
08162 goto exit_features_test;
08163 }
08164
08165
08166 ast_test_status_update(test, "Check #2 that certain parking options are respected\n");
08167 if (!(test_channel1 = create_test_channel(&fake_tech))) {
08168 res = -1;
08169 goto exit_features_test;
08170 }
08171 pbx_builtin_setvar_helper(test_channel1, "PARKINGLOT", unique_lot_2);
08172 pbx_builtin_setvar_helper(test_channel1, "PARKINGDYNCONTEXT", unique_context_2);
08173 pbx_builtin_setvar_helper(test_channel1, "PARKINGDYNEXTEN", parkinglot_parkext);
08174 pbx_builtin_setvar_helper(test_channel1, "PARKINGDYNPOS", parkinglot_range);
08175 if (masq_park_call(test_channel1, NULL, &args)) {
08176 res = -1;
08177 goto exit_features_test;
08178 }
08179
08180 ast_hangup(test_channel1);
08181 test_channel1 = NULL;
08182
08183 dynlot = args.pu->parkinglot;
08184 if (args.pu->parkingnum != 751
08185 || strcmp(dynlot->name, unique_lot_2)
08186 || strcmp(dynlot->cfg.parking_con, unique_context_2)
08187 || strcmp(dynlot->cfg.parkext, parkinglot_parkext)
08188 || dynlot->cfg.parking_start != 751
08189 || dynlot->cfg.parking_stop != 760) {
08190 ast_test_status_update(test, "Parking settings were not respected\n");
08191 ast_test_status_update(test, "Dyn-name:%s\n", dynlot->name);
08192 ast_test_status_update(test, "Dyn-context:%s\n", dynlot->cfg.parking_con);
08193 ast_test_status_update(test, "Dyn-parkext:%s\n", dynlot->cfg.parkext);
08194 ast_test_status_update(test, "Dyn-parkpos:%d-%d\n", dynlot->cfg.parking_start,
08195 dynlot->cfg.parking_stop);
08196 ast_test_status_update(test, "Parked in space:%d\n", args.pu->parkingnum);
08197 res = -1;
08198 } else {
08199 ast_test_status_update(test, "Parking settings for masquerading park verified\n");
08200 }
08201
08202
08203 parked_chan = ast_channel_get_by_name("TestChannel1");
08204 if (unpark_test_channel(parked_chan, &args)) {
08205 if (parked_chan) {
08206 ast_hangup(parked_chan);
08207 }
08208 res = -1;
08209 }
08210
08211
08212 exit_features_test:
08213
08214 if (test_channel1) {
08215 ast_hangup(test_channel1);
08216 }
08217
08218 force_reload_load = 1;
08219 ast_features_reload();
08220 return res ? AST_TEST_FAIL : AST_TEST_PASS;
08221 }
08222 #endif
08223
08224 int ast_features_init(void)
08225 {
08226 int res;
08227
08228 parkinglots = ao2_container_alloc(7, parkinglot_hash_cb, parkinglot_cmp_cb);
08229 if (!parkinglots) {
08230 return -1;
08231 }
08232
08233 res = load_config(0);
08234 if (res) {
08235 return res;
08236 }
08237 ast_cli_register_multiple(cli_features, ARRAY_LEN(cli_features));
08238 if (ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL)) {
08239 return -1;
08240 }
08241 ast_register_application2(app_bridge, bridge_exec, NULL, NULL, NULL);
08242 res = ast_register_application2(parkedcall, parked_call_exec, NULL, NULL, NULL);
08243 if (!res)
08244 res = ast_register_application2(parkcall, park_call_exec, NULL, NULL, NULL);
08245 if (!res) {
08246 ast_manager_register_xml("ParkedCalls", 0, manager_parking_status);
08247 ast_manager_register_xml("Park", EVENT_FLAG_CALL, manager_park);
08248 ast_manager_register_xml("Bridge", EVENT_FLAG_CALL, action_bridge);
08249 }
08250
08251 res |= ast_devstate_prov_add("Park", metermaidstate);
08252 #if defined(TEST_FRAMEWORK)
08253 res |= AST_TEST_REGISTER(features_test);
08254 #endif
08255
08256 return res;
08257 }