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