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