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: 419630 $")
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 %u 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 if (!strcasecmp("Gosub", feature->app)) {
03214 res = ast_app_exec_sub(NULL, work, feature->app_args, 0);
03215 } else if (!strcasecmp("Macro", feature->app)) {
03216 res = ast_app_exec_macro(NULL, work, feature->app_args);
03217 } else {
03218 res = pbx_exec(work, app, feature->app_args);
03219 }
03220
03221 if (!ast_strlen_zero(feature->moh_class))
03222 ast_moh_stop(idle);
03223
03224 ast_autoservice_stop(idle);
03225
03226 if (res) {
03227 return AST_FEATURE_RETURN_SUCCESSBREAK;
03228 }
03229 return AST_FEATURE_RETURN_SUCCESS;
03230 }
03231
03232 static void unmap_features(void)
03233 {
03234 int x;
03235
03236 ast_rwlock_wrlock(&features_lock);
03237 for (x = 0; x < FEATURES_COUNT; x++)
03238 strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
03239 ast_rwlock_unlock(&features_lock);
03240 }
03241
03242 static int remap_feature(const char *name, const char *value)
03243 {
03244 int x, res = -1;
03245
03246 ast_rwlock_wrlock(&features_lock);
03247 for (x = 0; x < FEATURES_COUNT; x++) {
03248 if (strcasecmp(builtin_features[x].sname, name))
03249 continue;
03250
03251 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
03252 res = 0;
03253 break;
03254 }
03255 ast_rwlock_unlock(&features_lock);
03256
03257 return res;
03258 }
03259
03260
03261
03262
03263
03264
03265
03266
03267
03268
03269
03270 static int feature_interpret_helper(struct ast_channel *chan, struct ast_channel *peer,
03271 struct ast_bridge_config *config, const char *code, int sense, char *dynamic_features_buf,
03272 struct ast_flags *features, feature_interpret_op operation, struct ast_call_feature *feature)
03273 {
03274 int x;
03275 struct feature_group *fg = NULL;
03276 struct feature_group_exten *fge;
03277 struct ast_call_feature *tmpfeature;
03278 char *tmp, *tok;
03279 int res = AST_FEATURE_RETURN_PASSDIGITS;
03280 int feature_detected = 0;
03281
03282 if (!(peer && chan && config) && operation == FEATURE_INTERPRET_DO) {
03283 return -1;
03284 }
03285
03286 ast_rwlock_rdlock(&features_lock);
03287 for (x = 0; x < FEATURES_COUNT; x++) {
03288 if ((ast_test_flag(features, builtin_features[x].feature_mask)) &&
03289 !ast_strlen_zero(builtin_features[x].exten)) {
03290
03291 if (!strcmp(builtin_features[x].exten, code)) {
03292 ast_debug(3, "Feature detected: fname=%s sname=%s exten=%s\n", builtin_features[x].fname, builtin_features[x].sname, builtin_features[x].exten);
03293 if (operation == FEATURE_INTERPRET_CHECK) {
03294 res = AST_FEATURE_RETURN_SUCCESS;
03295 } else if (operation == FEATURE_INTERPRET_DO) {
03296 res = builtin_features[x].operation(chan, peer, config, code, sense, NULL);
03297 }
03298 if (feature) {
03299 memcpy(feature, &builtin_features[x], sizeof(*feature));
03300 }
03301 feature_detected = 1;
03302 break;
03303 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
03304 if (res == AST_FEATURE_RETURN_PASSDIGITS) {
03305 res = AST_FEATURE_RETURN_STOREDIGITS;
03306 }
03307 }
03308 }
03309 }
03310 ast_rwlock_unlock(&features_lock);
03311
03312 if (ast_strlen_zero(dynamic_features_buf) || feature_detected) {
03313 return res;
03314 }
03315
03316 tmp = dynamic_features_buf;
03317
03318 while ((tok = strsep(&tmp, "#"))) {
03319 AST_RWLIST_RDLOCK(&feature_groups);
03320
03321 fg = find_group(tok);
03322
03323 if (fg) {
03324 AST_LIST_TRAVERSE(&fg->features, fge, entry) {
03325 if (!strcmp(fge->exten, code)) {
03326 if (operation) {
03327 res = fge->feature->operation(chan, peer, config, code, sense, fge->feature);
03328 }
03329 if (feature) {
03330 memcpy(feature, fge->feature, sizeof(*feature));
03331 }
03332 if (res != AST_FEATURE_RETURN_KEEPTRYING) {
03333 AST_RWLIST_UNLOCK(&feature_groups);
03334 break;
03335 }
03336 res = AST_FEATURE_RETURN_PASSDIGITS;
03337 } else if (!strncmp(fge->exten, code, strlen(code))) {
03338 res = AST_FEATURE_RETURN_STOREDIGITS;
03339 }
03340 }
03341 if (fge) {
03342 break;
03343 }
03344 }
03345
03346 AST_RWLIST_UNLOCK(&feature_groups);
03347
03348 AST_RWLIST_RDLOCK(&feature_list);
03349
03350 if (!(tmpfeature = find_dynamic_feature(tok))) {
03351 AST_RWLIST_UNLOCK(&feature_list);
03352 continue;
03353 }
03354
03355
03356 if (!strcmp(tmpfeature->exten, code)) {
03357 ast_verb(3, " Feature Found: %s exten: %s\n",tmpfeature->sname, tok);
03358 if (operation == FEATURE_INTERPRET_CHECK) {
03359 res = AST_FEATURE_RETURN_SUCCESS;
03360 } else if (operation == FEATURE_INTERPRET_DO) {
03361 res = tmpfeature->operation(chan, peer, config, code, sense, tmpfeature);
03362 }
03363 if (feature) {
03364 memcpy(feature, tmpfeature, sizeof(*feature));
03365 }
03366 if (res != AST_FEATURE_RETURN_KEEPTRYING) {
03367 AST_RWLIST_UNLOCK(&feature_list);
03368 break;
03369 }
03370 res = AST_FEATURE_RETURN_PASSDIGITS;
03371 } else if (!strncmp(tmpfeature->exten, code, strlen(code)))
03372 res = AST_FEATURE_RETURN_STOREDIGITS;
03373
03374 AST_RWLIST_UNLOCK(&feature_list);
03375 }
03376
03377 return res;
03378 }
03379
03380
03381
03382
03383
03384
03385
03386
03387 static int feature_interpret(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense) {
03388
03389 char dynamic_features_buf[128];
03390 const char *peer_dynamic_features, *chan_dynamic_features;
03391 struct ast_flags features;
03392 struct ast_call_feature feature;
03393 if (sense == FEATURE_SENSE_CHAN) {
03394
03395 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
03396 }
03397 else {
03398
03399 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);
03400 }
03401
03402 ast_channel_lock(peer);
03403 peer_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES"),""));
03404 ast_channel_unlock(peer);
03405
03406 ast_channel_lock(chan);
03407 chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),""));
03408 ast_channel_unlock(chan);
03409
03410 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,""));
03411
03412 ast_debug(3, "Feature interpret: chan=%s, peer=%s, code=%s, sense=%d, features=%u, dynamic=%s\n", chan->name, peer->name, code, sense, features.flags, dynamic_features_buf);
03413
03414 return feature_interpret_helper(chan, peer, config, code, sense, dynamic_features_buf, &features, FEATURE_INTERPRET_DO, &feature);
03415 }
03416
03417
03418 int ast_feature_detect(struct ast_channel *chan, struct ast_flags *features, const char *code, struct ast_call_feature *feature) {
03419
03420 return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, FEATURE_INTERPRET_DETECT, feature);
03421 }
03422
03423
03424 static int feature_check(struct ast_channel *chan, struct ast_flags *features, char *code) {
03425 char *chan_dynamic_features;
03426 ast_channel_lock(chan);
03427 chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),""));
03428 ast_channel_unlock(chan);
03429
03430 return feature_interpret_helper(chan, NULL, NULL, code, 0, chan_dynamic_features, features, FEATURE_INTERPRET_CHECK, NULL);
03431 }
03432
03433 static void set_config_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
03434 {
03435 int x;
03436
03437 ast_clear_flag(config, AST_FLAGS_ALL);
03438
03439 ast_rwlock_rdlock(&features_lock);
03440 for (x = 0; x < FEATURES_COUNT; x++) {
03441 if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF))
03442 continue;
03443
03444 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
03445 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
03446
03447 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
03448 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
03449 }
03450 ast_rwlock_unlock(&features_lock);
03451
03452 if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
03453 const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
03454
03455 if (dynamic_features) {
03456 char *tmp = ast_strdupa(dynamic_features);
03457 char *tok;
03458 struct ast_call_feature *feature;
03459
03460
03461 while ((tok = strsep(&tmp, "#"))) {
03462 struct feature_group *fg;
03463
03464 AST_RWLIST_RDLOCK(&feature_groups);
03465 AST_RWLIST_TRAVERSE(&feature_groups, fg, entry) {
03466 struct feature_group_exten *fge;
03467
03468 AST_LIST_TRAVERSE(&fg->features, fge, entry) {
03469 if (ast_test_flag(fge->feature, AST_FEATURE_FLAG_BYCALLER)) {
03470 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
03471 }
03472 if (ast_test_flag(fge->feature, AST_FEATURE_FLAG_BYCALLEE)) {
03473 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
03474 }
03475 }
03476 }
03477 AST_RWLIST_UNLOCK(&feature_groups);
03478
03479 AST_RWLIST_RDLOCK(&feature_list);
03480 if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
03481 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) {
03482 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
03483 }
03484 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) {
03485 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
03486 }
03487 }
03488 AST_RWLIST_UNLOCK(&feature_list);
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
03523
03524
03525
03526
03527
03528 static struct ast_channel *feature_request_and_dial(struct ast_channel *caller,
03529 const char *caller_name, struct ast_channel *requestor,
03530 struct ast_channel *transferee, const char *type, format_t format, void *data,
03531 int timeout, int *outstate, const char *language)
03532 {
03533 int state = 0;
03534 int cause = 0;
03535 int to;
03536 int caller_hungup;
03537 int transferee_hungup;
03538 struct ast_channel *chan;
03539 struct ast_channel *monitor_chans[3];
03540 struct ast_channel *active_channel;
03541 int res;
03542 int ready = 0;
03543 struct timeval started;
03544 int x, len = 0;
03545 char *disconnect_code = NULL, *dialed_code = NULL;
03546 struct ast_frame *f;
03547 AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames;
03548
03549 caller_hungup = ast_check_hangup(caller);
03550
03551 if (!(chan = ast_request(type, format, requestor, data, &cause))) {
03552 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
03553 switch (cause) {
03554 case AST_CAUSE_BUSY:
03555 state = AST_CONTROL_BUSY;
03556 break;
03557 case AST_CAUSE_CONGESTION:
03558 state = AST_CONTROL_CONGESTION;
03559 break;
03560 default:
03561 state = 0;
03562 break;
03563 }
03564 goto done;
03565 }
03566
03567 ast_string_field_set(chan, language, language);
03568 ast_channel_inherit_variables(caller, chan);
03569 pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller_name);
03570
03571 ast_channel_lock(chan);
03572 ast_connected_line_copy_from_caller(&chan->connected, &requestor->caller);
03573 ast_channel_unlock(chan);
03574
03575 if (ast_call(chan, data, timeout)) {
03576 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
03577 switch (chan->hangupcause) {
03578 case AST_CAUSE_BUSY:
03579 state = AST_CONTROL_BUSY;
03580 break;
03581 case AST_CAUSE_CONGESTION:
03582 state = AST_CONTROL_CONGESTION;
03583 break;
03584 default:
03585 state = 0;
03586 break;
03587 }
03588 goto done;
03589 }
03590
03591
03592 ast_rwlock_rdlock(&features_lock);
03593 for (x = 0; x < FEATURES_COUNT; x++) {
03594 if (strcasecmp(builtin_features[x].sname, "disconnect"))
03595 continue;
03596
03597 disconnect_code = builtin_features[x].exten;
03598 len = strlen(disconnect_code) + 1;
03599 dialed_code = ast_alloca(len);
03600 memset(dialed_code, 0, len);
03601 break;
03602 }
03603 ast_rwlock_unlock(&features_lock);
03604 x = 0;
03605 started = ast_tvnow();
03606 to = timeout;
03607 AST_LIST_HEAD_INIT_NOLOCK(&deferred_frames);
03608
03609 ast_poll_channel_add(caller, chan);
03610
03611 transferee_hungup = 0;
03612 while (!ast_check_hangup(transferee) && (chan->_state != AST_STATE_UP)) {
03613 int num_chans = 0;
03614
03615 monitor_chans[num_chans++] = transferee;
03616 monitor_chans[num_chans++] = chan;
03617 if (!caller_hungup) {
03618 if (ast_check_hangup(caller)) {
03619 caller_hungup = 1;
03620
03621 #if defined(ATXFER_NULL_TECH)
03622
03623 set_new_chan_name(caller);
03624
03625
03626
03627
03628
03629 set_kill_chan_tech(caller);
03630 #endif
03631 } else {
03632
03633 monitor_chans[num_chans++] = caller;
03634 }
03635 }
03636
03637
03638 if (ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
03639 state = AST_CONTROL_UNHOLD;
03640 ast_log(LOG_NOTICE, "We exceeded our AT-timeout for %s\n", chan->name);
03641 break;
03642 }
03643
03644 active_channel = ast_waitfor_n(monitor_chans, num_chans, &to);
03645 if (!active_channel)
03646 continue;
03647
03648 f = NULL;
03649 if (transferee == active_channel) {
03650 struct ast_frame *dup_f;
03651
03652 f = ast_read(transferee);
03653 if (f == NULL) {
03654 transferee_hungup = 1;
03655 state = 0;
03656 break;
03657 }
03658 if (ast_is_deferrable_frame(f)) {
03659 dup_f = ast_frisolate(f);
03660 if (dup_f) {
03661 if (dup_f == f) {
03662 f = NULL;
03663 }
03664 AST_LIST_INSERT_HEAD(&deferred_frames, dup_f, frame_list);
03665 }
03666 }
03667 } else if (chan == active_channel) {
03668 if (!ast_strlen_zero(chan->call_forward)) {
03669 state = 0;
03670 ast_autoservice_start(transferee);
03671 chan = ast_call_forward(caller, chan, NULL, format, NULL, &state);
03672 ast_autoservice_stop(transferee);
03673 if (!chan) {
03674 break;
03675 }
03676 continue;
03677 }
03678 f = ast_read(chan);
03679 if (f == NULL) {
03680 switch (chan->hangupcause) {
03681 case AST_CAUSE_BUSY:
03682 state = AST_CONTROL_BUSY;
03683 break;
03684 case AST_CAUSE_CONGESTION:
03685 state = AST_CONTROL_CONGESTION;
03686 break;
03687 default:
03688 state = 0;
03689 break;
03690 }
03691 break;
03692 }
03693
03694 if (f->frametype == AST_FRAME_CONTROL) {
03695 if (f->subclass.integer == AST_CONTROL_RINGING) {
03696 ast_verb(3, "%s is ringing\n", chan->name);
03697 ast_indicate(caller, AST_CONTROL_RINGING);
03698 } else if (f->subclass.integer == AST_CONTROL_BUSY) {
03699 state = f->subclass.integer;
03700 ast_verb(3, "%s is busy\n", chan->name);
03701 ast_indicate(caller, AST_CONTROL_BUSY);
03702 ast_frfree(f);
03703 break;
03704 } else if (f->subclass.integer == AST_CONTROL_INCOMPLETE) {
03705 ast_verb(3, "%s dialed incomplete extension %s; ignoring\n", chan->name, chan->exten);
03706 } else if (f->subclass.integer == AST_CONTROL_CONGESTION) {
03707 state = f->subclass.integer;
03708 ast_verb(3, "%s is congested\n", chan->name);
03709 ast_indicate(caller, AST_CONTROL_CONGESTION);
03710 ast_frfree(f);
03711 break;
03712 } else if (f->subclass.integer == AST_CONTROL_ANSWER) {
03713
03714 state = f->subclass.integer;
03715 ast_frfree(f);
03716 ready=1;
03717 break;
03718 } else if (f->subclass.integer == AST_CONTROL_CONNECTED_LINE) {
03719 if (caller_hungup) {
03720 struct ast_party_connected_line connected;
03721
03722
03723 ast_party_connected_line_set_init(&connected, &caller->connected);
03724 res = ast_connected_line_parse_data(f->data.ptr, f->datalen,
03725 &connected);
03726 if (!res) {
03727 ast_channel_set_connected_line(caller, &connected, NULL);
03728 }
03729 ast_party_connected_line_free(&connected);
03730 } else {
03731 ast_autoservice_start(transferee);
03732 if (ast_channel_connected_line_macro(chan, caller, f, 1, 1)) {
03733 ast_indicate_data(caller, AST_CONTROL_CONNECTED_LINE,
03734 f->data.ptr, f->datalen);
03735 }
03736 ast_autoservice_stop(transferee);
03737 }
03738 } else if (f->subclass.integer == AST_CONTROL_REDIRECTING) {
03739 if (!caller_hungup) {
03740 ast_autoservice_start(transferee);
03741 if (ast_channel_redirecting_macro(chan, caller, f, 1, 1)) {
03742 ast_indicate_data(caller, AST_CONTROL_REDIRECTING,
03743 f->data.ptr, f->datalen);
03744 }
03745 ast_autoservice_stop(transferee);
03746 }
03747 } else if (f->subclass.integer != -1
03748 && f->subclass.integer != AST_CONTROL_PROGRESS
03749 && f->subclass.integer != AST_CONTROL_PROCEEDING) {
03750 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass.integer);
03751 }
03752
03753 } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) {
03754 ast_write(caller, f);
03755 }
03756 } else if (caller == active_channel) {
03757 f = ast_read(caller);
03758 if (f) {
03759 if (f->frametype == AST_FRAME_DTMF) {
03760 dialed_code[x++] = f->subclass.integer;
03761 dialed_code[x] = '\0';
03762 if (strlen(dialed_code) == len) {
03763 x = 0;
03764 } else if (x && strncmp(dialed_code, disconnect_code, x)) {
03765 x = 0;
03766 dialed_code[x] = '\0';
03767 }
03768 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
03769
03770 state = AST_CONTROL_UNHOLD;
03771 ast_frfree(f);
03772 break;
03773 }
03774 } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) {
03775 ast_write(chan, f);
03776 }
03777 }
03778 }
03779 if (f)
03780 ast_frfree(f);
03781 }
03782
03783 ast_poll_channel_del(caller, chan);
03784
03785
03786
03787
03788
03789 ast_channel_lock(transferee);
03790 transferee_hungup = (transferee_hungup || ast_check_hangup(transferee));
03791 while ((f = AST_LIST_REMOVE_HEAD(&deferred_frames, frame_list))) {
03792 if (!transferee_hungup) {
03793 ast_queue_frame_head(transferee, f);
03794 }
03795 ast_frfree(f);
03796 }
03797 ast_channel_unlock(transferee);
03798
03799 done:
03800 ast_indicate(caller, -1);
03801 if (chan && (ready || chan->_state == AST_STATE_UP)) {
03802 state = AST_CONTROL_ANSWER;
03803 } else if (chan) {
03804 ast_hangup(chan);
03805 chan = NULL;
03806 }
03807
03808 if (outstate)
03809 *outstate = state;
03810
03811 return chan;
03812 }
03813
03814 void ast_channel_log(char *title, struct ast_channel *chan);
03815
03816 void ast_channel_log(char *title, struct ast_channel *chan)
03817 {
03818 ast_log(LOG_NOTICE, "______ %s (%lx)______\n", title, (unsigned long)chan);
03819 ast_log(LOG_NOTICE, "CHAN: name: %s; appl: %s; data: %s; contxt: %s; exten: %s; pri: %d;\n",
03820 chan->name, chan->appl, chan->data, chan->context, chan->exten, chan->priority);
03821 ast_log(LOG_NOTICE, "CHAN: acctcode: %s; dialcontext: %s; amaflags: %x; maccontxt: %s; macexten: %s; macpri: %d;\n",
03822 chan->accountcode, chan->dialcontext, (unsigned)chan->amaflags, chan->macrocontext, chan->macroexten, chan->macropriority);
03823 ast_log(LOG_NOTICE, "CHAN: masq: %p; masqr: %p; _bridge: %p; uniqueID: %s; linkedID:%s\n",
03824 chan->masq, chan->masqr,
03825 chan->_bridge, chan->uniqueid, chan->linkedid);
03826 if (chan->masqr)
03827 ast_log(LOG_NOTICE, "CHAN: masquerading as: %s; cdr: %p;\n",
03828 chan->masqr->name, chan->masqr->cdr);
03829 if (chan->_bridge)
03830 ast_log(LOG_NOTICE, "CHAN: Bridged to %s\n", chan->_bridge->name);
03831
03832 ast_log(LOG_NOTICE, "===== done ====\n");
03833 }
03834
03835
03836
03837
03838 static struct ast_cdr *pick_unlocked_cdr(struct ast_cdr *cdr)
03839 {
03840 struct ast_cdr *cdr_orig = cdr;
03841 while (cdr) {
03842 if (!ast_test_flag(cdr,AST_CDR_FLAG_LOCKED))
03843 return cdr;
03844 cdr = cdr->next;
03845 }
03846 return cdr_orig;
03847 }
03848
03849 static void set_bridge_features_on_config(struct ast_bridge_config *config, const char *features)
03850 {
03851 const char *feature;
03852
03853 if (ast_strlen_zero(features)) {
03854 return;
03855 }
03856
03857 for (feature = features; *feature; feature++) {
03858 switch (*feature) {
03859 case 'T' :
03860 case 't' :
03861 ast_set_flag(&(config->features_caller), AST_FEATURE_REDIRECT);
03862 break;
03863 case 'K' :
03864 case 'k' :
03865 ast_set_flag(&(config->features_caller), AST_FEATURE_PARKCALL);
03866 break;
03867 case 'H' :
03868 case 'h' :
03869 ast_set_flag(&(config->features_caller), AST_FEATURE_DISCONNECT);
03870 break;
03871 case 'W' :
03872 case 'w' :
03873 ast_set_flag(&(config->features_caller), AST_FEATURE_AUTOMON);
03874 break;
03875 default :
03876 ast_log(LOG_WARNING, "Skipping unknown feature code '%c'\n", *feature);
03877 }
03878 }
03879 }
03880
03881 static void add_features_datastores(struct ast_channel *caller, struct ast_channel *callee, struct ast_bridge_config *config)
03882 {
03883 if (add_features_datastore(caller, &config->features_caller, &config->features_callee)) {
03884
03885
03886
03887
03888
03889 return;
03890 }
03891
03892 add_features_datastore(callee, &config->features_callee, &config->features_caller);
03893 }
03894
03895 static void clear_dialed_interfaces(struct ast_channel *chan)
03896 {
03897 struct ast_datastore *di_datastore;
03898
03899 ast_channel_lock(chan);
03900 if ((di_datastore = ast_channel_datastore_find(chan, &dialed_interface_info, NULL))) {
03901 if (option_debug) {
03902 ast_log(LOG_DEBUG, "Removing dialed interfaces datastore on %s since we're bridging\n", chan->name);
03903 }
03904 if (!ast_channel_datastore_remove(chan, di_datastore)) {
03905 ast_datastore_free(di_datastore);
03906 }
03907 }
03908 ast_channel_unlock(chan);
03909 }
03910
03911 void ast_bridge_end_dtmf(struct ast_channel *chan, char digit, struct timeval start, const char *why)
03912 {
03913 int dead;
03914 long duration;
03915
03916 ast_channel_lock(chan);
03917 dead = ast_test_flag(chan, AST_FLAG_ZOMBIE)
03918 || (chan->_softhangup
03919 & ~(AST_SOFTHANGUP_ASYNCGOTO | AST_SOFTHANGUP_UNBRIDGE));
03920 ast_channel_unlock(chan);
03921 if (dead) {
03922
03923 return;
03924 }
03925
03926 duration = ast_tvdiff_ms(ast_tvnow(), start);
03927 ast_senddigit_end(chan, digit, duration);
03928 ast_log(LOG_DTMF, "DTMF end '%c' simulated on %s due to %s, duration %ld ms\n",
03929 digit, chan->name, why, duration);
03930 }
03931
03932
03933
03934
03935
03936
03937
03938
03939
03940
03941
03942
03943
03944 int ast_bridge_call(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
03945 {
03946
03947
03948 struct ast_frame *f;
03949 struct ast_channel *who;
03950 char chan_featurecode[FEATURE_MAX_LEN + 1]="";
03951 char peer_featurecode[FEATURE_MAX_LEN + 1]="";
03952 char orig_channame[AST_CHANNEL_NAME];
03953 char orig_peername[AST_CHANNEL_NAME];
03954 int res;
03955 int diff;
03956 int hasfeatures=0;
03957 int hadfeatures=0;
03958 int autoloopflag;
03959 int sendingdtmfdigit = 0;
03960 int we_disabled_peer_cdr = 0;
03961 struct ast_option_header *aoh;
03962 struct ast_cdr *bridge_cdr = NULL;
03963 struct ast_cdr *chan_cdr = chan->cdr;
03964 struct ast_cdr *peer_cdr = peer->cdr;
03965 struct ast_cdr *new_chan_cdr = NULL;
03966 struct ast_cdr *new_peer_cdr = NULL;
03967 struct ast_silence_generator *silgen = NULL;
03968 const char *h_context;
03969
03970 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
03971 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
03972
03973
03974 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
03975 pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", NULL);
03976
03977 set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES"));
03978 add_features_datastores(chan, peer, config);
03979
03980
03981
03982
03983 if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) {
03984 ast_indicate(peer, AST_CONTROL_RINGING);
03985 }
03986
03987 if (monitor_ok) {
03988 const char *monitor_exec;
03989 struct ast_channel *src = NULL;
03990 if (!monitor_app) {
03991 if (!(monitor_app = pbx_findapp("Monitor")))
03992 monitor_ok=0;
03993 }
03994 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR")))
03995 src = chan;
03996 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
03997 src = peer;
03998 if (monitor_app && src) {
03999 char *tmp = ast_strdupa(monitor_exec);
04000 pbx_exec(src, monitor_app, tmp);
04001 }
04002 }
04003
04004 set_config_flags(chan, peer, config);
04005
04006
04007 if (chan->_state != AST_STATE_UP) {
04008 if (ast_raw_answer(chan, 1)) {
04009 return -1;
04010 }
04011 }
04012
04013 #ifdef FOR_DEBUG
04014
04015 ast_channel_log("Pre-bridge CHAN Channel info", chan);
04016 ast_channel_log("Pre-bridge PEER Channel info", peer);
04017 #endif
04018
04019 ast_channel_set_linkgroup(chan,peer);
04020
04021
04022 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
04023 char tmp[256];
04024
04025 ast_channel_lock(chan);
04026 if (!ast_strlen_zero(chan->cdr->userfield)) {
04027 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield);
04028 ast_cdr_appenduserfield(chan, tmp);
04029 } else {
04030 ast_cdr_setuserfield(chan, peer->cdr->userfield);
04031 }
04032 ast_channel_unlock(chan);
04033
04034 ast_set_flag(peer->cdr, AST_CDR_FLAG_POST_DISABLED);
04035 we_disabled_peer_cdr = 1;
04036 }
04037 ast_copy_string(orig_channame,chan->name,sizeof(orig_channame));
04038 ast_copy_string(orig_peername,peer->name,sizeof(orig_peername));
04039
04040 if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) {
04041 ast_channel_lock_both(chan, peer);
04042 if (chan_cdr) {
04043 ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN);
04044 ast_cdr_update(chan);
04045 bridge_cdr = ast_cdr_dup_unique_swap(chan_cdr);
04046
04047
04048 bridge_cdr->next = chan_cdr->next;
04049 chan_cdr->next = NULL;
04050 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp));
04051 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata));
04052 if (peer_cdr && !ast_strlen_zero(peer_cdr->userfield)) {
04053 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield));
04054 }
04055 ast_cdr_setaccount(peer, chan->accountcode);
04056 } else {
04057
04058 bridge_cdr = ast_cdr_alloc();
04059 ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel));
04060 ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel));
04061 ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid));
04062 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp));
04063 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata));
04064 ast_cdr_setcid(bridge_cdr, chan);
04065 bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ? AST_CDR_ANSWERED : AST_CDR_NULL;
04066 bridge_cdr->amaflags = chan->amaflags ? chan->amaflags : ast_default_amaflags;
04067 ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode));
04068
04069 ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst));
04070 ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext));
04071 if (peer_cdr) {
04072 bridge_cdr->start = peer_cdr->start;
04073 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield));
04074 } else {
04075 ast_cdr_start(bridge_cdr);
04076 }
04077 }
04078 ast_channel_unlock(chan);
04079 ast_channel_unlock(peer);
04080
04081 ast_debug(4,"bridge answer set, chan answer set\n");
04082
04083
04084
04085
04086
04087
04088
04089
04090
04091
04092
04093
04094
04095
04096
04097 if (peer_cdr && !ast_tvzero(peer_cdr->answer) && ast_tvcmp(peer_cdr->answer, bridge_cdr->start) >= 0) {
04098 ast_cdr_setanswer(bridge_cdr, peer_cdr->answer);
04099 ast_cdr_setdisposition(bridge_cdr, peer_cdr->disposition);
04100 if (chan_cdr) {
04101 ast_cdr_setanswer(chan_cdr, peer_cdr->answer);
04102 ast_cdr_setdisposition(chan_cdr, peer_cdr->disposition);
04103 }
04104 } else {
04105 ast_cdr_answer(bridge_cdr);
04106 if (chan_cdr) {
04107 ast_cdr_answer(chan_cdr);
04108 }
04109 }
04110 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT) && (chan_cdr || peer_cdr)) {
04111 if (chan_cdr) {
04112 ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED);
04113 }
04114 if (peer_cdr) {
04115 ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED);
04116 }
04117 }
04118
04119
04120
04121
04122 ast_clear_flag(bridge_cdr, AST_CDR_FLAG_DIALED);
04123 }
04124 ast_cel_report_event(chan, AST_CEL_BRIDGE_START, NULL, NULL, peer);
04125
04126
04127
04128
04129 clear_dialed_interfaces(chan);
04130 clear_dialed_interfaces(peer);
04131
04132 for (;;) {
04133 struct ast_channel *other;
04134
04135 res = ast_channel_bridge(chan, peer, config, &f, &who);
04136
04137 if (ast_test_flag(chan, AST_FLAG_ZOMBIE)
04138 || ast_test_flag(peer, AST_FLAG_ZOMBIE)) {
04139
04140 res = -1;
04141 if (f) {
04142 ast_frfree(f);
04143 }
04144 goto before_you_go;
04145 }
04146
04147
04148
04149
04150
04151
04152
04153
04154 if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) {
04155
04156 diff = ast_tvdiff_ms(ast_tvnow(), config->feature_start_time);
04157 if (res == AST_BRIDGE_RETRY) {
04158
04159
04160
04161 config->feature_timer = -1;
04162 } else {
04163 config->feature_timer -= diff;
04164 }
04165
04166 if (hasfeatures) {
04167 if (config->feature_timer <= 0) {
04168
04169
04170 ast_debug(1, "Timed out for feature!\n");
04171 if (!ast_strlen_zero(peer_featurecode)) {
04172 ast_dtmf_stream(chan, peer, peer_featurecode, 0, 0);
04173 memset(peer_featurecode, 0, sizeof(peer_featurecode));
04174 }
04175 if (!ast_strlen_zero(chan_featurecode)) {
04176 ast_dtmf_stream(peer, chan, chan_featurecode, 0, 0);
04177 memset(chan_featurecode, 0, sizeof(chan_featurecode));
04178 }
04179 if (f)
04180 ast_frfree(f);
04181 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
04182 if (!hasfeatures) {
04183
04184 config->feature_timer = 0;
04185 }
04186 hadfeatures = hasfeatures;
04187
04188 continue;
04189 } else if (!f) {
04190
04191
04192
04193 continue;
04194 }
04195 } else {
04196 if (config->feature_timer <=0) {
04197
04198 config->feature_timer = 0;
04199 who = chan;
04200 if (f)
04201 ast_frfree(f);
04202 f = NULL;
04203 res = 0;
04204 }
04205 }
04206 }
04207 if (res < 0) {
04208 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) {
04209 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
04210 }
04211 goto before_you_go;
04212 }
04213
04214 if (!f || (f->frametype == AST_FRAME_CONTROL &&
04215 (f->subclass.integer == AST_CONTROL_HANGUP || f->subclass.integer == AST_CONTROL_BUSY ||
04216 f->subclass.integer == AST_CONTROL_CONGESTION))) {
04217 res = -1;
04218 break;
04219 }
04220
04221 other = (who == chan) ? peer : chan;
04222 if (f->frametype == AST_FRAME_CONTROL) {
04223 switch (f->subclass.integer) {
04224 case AST_CONTROL_RINGING:
04225 case AST_CONTROL_FLASH:
04226 case -1:
04227 ast_indicate(other, f->subclass.integer);
04228 break;
04229 case AST_CONTROL_CONNECTED_LINE:
04230 if (!ast_channel_connected_line_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_REDIRECTING:
04236 if (!ast_channel_redirecting_macro(who, other, f, who != chan, 1)) {
04237 break;
04238 }
04239 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen);
04240 break;
04241 case AST_CONTROL_AOC:
04242 case AST_CONTROL_HOLD:
04243 case AST_CONTROL_UNHOLD:
04244 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen);
04245 break;
04246 case AST_CONTROL_OPTION:
04247 aoh = f->data.ptr;
04248
04249
04250
04251
04252 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) {
04253 switch (ntohs(aoh->option)) {
04254 case AST_OPTION_TONE_VERIFY:
04255 case AST_OPTION_TDD:
04256 case AST_OPTION_RELAXDTMF:
04257 case AST_OPTION_AUDIO_MODE:
04258 case AST_OPTION_DIGIT_DETECT:
04259 case AST_OPTION_FAX_DETECT:
04260 ast_channel_setoption(other, ntohs(aoh->option), aoh->data,
04261 f->datalen - sizeof(struct ast_option_header), 0);
04262 }
04263 }
04264 break;
04265 }
04266 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
04267 struct ast_flags *cfg;
04268 char dtmfcode[2] = { f->subclass.integer, };
04269 size_t featurelen;
04270
04271 if (who == chan) {
04272 featurelen = strlen(chan_featurecode);
04273 cfg = &(config->features_caller);
04274 } else {
04275 featurelen = strlen(peer_featurecode);
04276 cfg = &(config->features_callee);
04277 }
04278
04279
04280
04281 if (featurelen == 0
04282 && feature_check(chan, cfg, &dtmfcode[0]) == AST_FEATURE_RETURN_PASSDIGITS) {
04283 if (option_debug > 3) {
04284 ast_log(LOG_DEBUG, "Passing DTMF through, since it is not a feature code\n");
04285 }
04286 ast_write(other, f);
04287 sendingdtmfdigit = 1;
04288 } else {
04289
04290
04291
04292 if (!silgen && ast_opt_transmit_silence) {
04293 silgen = ast_channel_start_silence_generator(other);
04294 }
04295 if (option_debug > 3) {
04296 ast_log(LOG_DEBUG, "Not passing DTMF through, since it may be a feature code\n");
04297 }
04298 }
04299 } else if (f->frametype == AST_FRAME_DTMF_END) {
04300 char *featurecode;
04301 int sense;
04302
04303 hadfeatures = hasfeatures;
04304
04305 if (who == chan) {
04306 sense = FEATURE_SENSE_CHAN;
04307 featurecode = chan_featurecode;
04308 } else {
04309 sense = FEATURE_SENSE_PEER;
04310 featurecode = peer_featurecode;
04311 }
04312
04313 if (sendingdtmfdigit == 1) {
04314
04315
04316 ast_write(other, f);
04317 sendingdtmfdigit = 0;
04318 } else {
04319
04320
04321
04322
04323 featurecode[strlen(featurecode)] = f->subclass.integer;
04324
04325 ast_frfree(f);
04326 f = NULL;
04327 if (silgen) {
04328 ast_channel_stop_silence_generator(other, silgen);
04329 silgen = NULL;
04330 }
04331 config->feature_timer = 0;
04332 res = feature_interpret(chan, peer, config, featurecode, sense);
04333 switch(res) {
04334 case AST_FEATURE_RETURN_PASSDIGITS:
04335 ast_dtmf_stream(other, who, featurecode, 0, 0);
04336
04337 case AST_FEATURE_RETURN_SUCCESS:
04338 memset(featurecode, 0, sizeof(chan_featurecode));
04339 break;
04340 }
04341 if (res >= AST_FEATURE_RETURN_PASSDIGITS) {
04342 res = 0;
04343 } else {
04344 break;
04345 }
04346 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
04347 if (hadfeatures && !hasfeatures) {
04348
04349 config->feature_timer = 0;
04350 } else if (hasfeatures) {
04351 if (config->timelimit) {
04352
04353 ast_set_flag(config, AST_FEATURE_WARNING_ACTIVE);
04354 }
04355 config->feature_start_time = ast_tvnow();
04356 config->feature_timer = featuredigittimeout;
04357 ast_debug(1, "Set feature timer to %ld ms\n", config->feature_timer);
04358 }
04359 }
04360 }
04361 if (f)
04362 ast_frfree(f);
04363 }
04364 ast_cel_report_event(chan, AST_CEL_BRIDGE_END, NULL, NULL, peer);
04365
04366 before_you_go:
04367 if (chan->sending_dtmf_digit) {
04368 ast_bridge_end_dtmf(chan, chan->sending_dtmf_digit, chan->sending_dtmf_tv,
04369 "bridge end");
04370 }
04371 if (peer->sending_dtmf_digit) {
04372 ast_bridge_end_dtmf(peer, peer->sending_dtmf_digit, peer->sending_dtmf_tv,
04373 "bridge end");
04374 }
04375
04376
04377 if (silgen) {
04378 ast_channel_stop_silence_generator(who == chan ? peer : chan, silgen);
04379 silgen = NULL;
04380 }
04381
04382
04383 while (ast_test_flag(chan, AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT)) {
04384 sched_yield();
04385 }
04386
04387 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) {
04388 ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT);
04389 if (bridge_cdr) {
04390 ast_cdr_discard(bridge_cdr);
04391
04392 }
04393 return res;
04394 }
04395
04396 if (config->end_bridge_callback) {
04397 config->end_bridge_callback(config->end_bridge_callback_data);
04398 }
04399
04400
04401
04402
04403
04404 if (chan->_softhangup & (AST_SOFTHANGUP_ASYNCGOTO | AST_SOFTHANGUP_UNBRIDGE)) {
04405
04406
04407
04408
04409
04410
04411 h_context = NULL;
04412 } else if (ast_test_flag(&config->features_caller, AST_FEATURE_NO_H_EXTEN)) {
04413 h_context = NULL;
04414 } else if (ast_exists_extension(chan, chan->context, "h", 1,
04415 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
04416 h_context = chan->context;
04417 } else if (!ast_strlen_zero(chan->macrocontext)
04418 && ast_exists_extension(chan, chan->macrocontext, "h", 1,
04419 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
04420 h_context = chan->macrocontext;
04421 } else {
04422 h_context = NULL;
04423 }
04424 if (h_context) {
04425 struct ast_cdr *swapper = NULL;
04426 char savelastapp[AST_MAX_EXTENSION];
04427 char savelastdata[AST_MAX_EXTENSION];
04428 char save_context[AST_MAX_CONTEXT];
04429 char save_exten[AST_MAX_EXTENSION];
04430 int save_prio;
04431 int found = 0;
04432 int spawn_error = 0;
04433
04434
04435
04436
04437
04438 ast_softhangup(chan, AST_SOFTHANGUP_APPUNLOAD);
04439
04440 autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP);
04441 ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP);
04442 if (bridge_cdr && ast_opt_end_cdr_before_h_exten) {
04443 ast_cdr_end(bridge_cdr);
04444 }
04445
04446
04447
04448 ast_channel_lock(chan);
04449 if (bridge_cdr) {
04450 swapper = chan->cdr;
04451 ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp));
04452 ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata));
04453 chan->cdr = bridge_cdr;
04454 }
04455 ast_copy_string(save_context, chan->context, sizeof(save_context));
04456 ast_copy_string(save_exten, chan->exten, sizeof(save_exten));
04457 save_prio = chan->priority;
04458 if (h_context != chan->context) {
04459 ast_copy_string(chan->context, h_context, sizeof(chan->context));
04460 }
04461 ast_copy_string(chan->exten, "h", sizeof(chan->exten));
04462 chan->priority = 1;
04463 ast_channel_unlock(chan);
04464
04465 while ((spawn_error = ast_spawn_extension(chan, chan->context, chan->exten,
04466 chan->priority,
04467 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
04468 &found, 1)) == 0) {
04469 chan->priority++;
04470 }
04471 if (found && spawn_error) {
04472
04473 ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name);
04474 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name);
04475 }
04476
04477
04478 ast_channel_lock(chan);
04479 ast_copy_string(chan->context, save_context, sizeof(chan->context));
04480 ast_copy_string(chan->exten, save_exten, sizeof(chan->exten));
04481 chan->priority = save_prio;
04482 if (bridge_cdr) {
04483 if (chan->cdr == bridge_cdr) {
04484 chan->cdr = swapper;
04485 } else {
04486 bridge_cdr = NULL;
04487 }
04488 }
04489
04490 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN);
04491 ast_channel_unlock(chan);
04492
04493
04494 if (bridge_cdr) {
04495 ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp));
04496 ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata));
04497 }
04498 ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP);
04499 }
04500
04501
04502 new_chan_cdr = pick_unlocked_cdr(chan->cdr);
04503
04504
04505
04506 if (new_chan_cdr && bridge_cdr && !h_context) {
04507 ast_cdr_copy_vars(bridge_cdr, new_chan_cdr);
04508 ast_copy_string(bridge_cdr->userfield, new_chan_cdr->userfield, sizeof(bridge_cdr->userfield));
04509 bridge_cdr->amaflags = new_chan_cdr->amaflags;
04510 ast_copy_string(bridge_cdr->accountcode, new_chan_cdr->accountcode, sizeof(bridge_cdr->accountcode));
04511 if (ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED)) {
04512 ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED);
04513 }
04514 }
04515
04516
04517 if (bridge_cdr) {
04518 ast_cdr_end(bridge_cdr);
04519 ast_cdr_detach(bridge_cdr);
04520 }
04521
04522
04523
04524
04525
04526
04527
04528
04529
04530
04531
04532
04533
04534
04535
04536
04537
04538
04539
04540
04541
04542
04543
04544
04545
04546 if (new_chan_cdr) {
04547 struct ast_channel *chan_ptr = NULL;
04548
04549 if (strcasecmp(orig_channame, chan->name) != 0) {
04550
04551 if ((chan_ptr = ast_channel_get_by_name(orig_channame))) {
04552 ast_channel_lock(chan_ptr);
04553 if (!ast_bridged_channel(chan_ptr)) {
04554 struct ast_cdr *cur;
04555 for (cur = chan_ptr->cdr; cur; cur = cur->next) {
04556 if (cur == chan_cdr) {
04557 break;
04558 }
04559 }
04560 if (cur) {
04561 ast_cdr_specialized_reset(chan_cdr, 0);
04562 }
04563 }
04564 ast_channel_unlock(chan_ptr);
04565 chan_ptr = ast_channel_unref(chan_ptr);
04566 }
04567
04568 ast_cdr_specialized_reset(new_chan_cdr, 0);
04569 } else {
04570 ast_cdr_specialized_reset(chan->cdr, 0);
04571 }
04572 }
04573
04574 {
04575 struct ast_channel *chan_ptr = NULL;
04576 new_peer_cdr = pick_unlocked_cdr(peer->cdr);
04577 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))
04578 ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED);
04579 if (strcasecmp(orig_peername, peer->name) != 0) {
04580
04581 if ((chan_ptr = ast_channel_get_by_name(orig_peername))) {
04582 ast_channel_lock(chan_ptr);
04583 if (!ast_bridged_channel(chan_ptr)) {
04584 struct ast_cdr *cur;
04585 for (cur = chan_ptr->cdr; cur; cur = cur->next) {
04586 if (cur == peer_cdr) {
04587 break;
04588 }
04589 }
04590 if (cur) {
04591 ast_cdr_specialized_reset(peer_cdr, 0);
04592 }
04593 }
04594 ast_channel_unlock(chan_ptr);
04595 chan_ptr = ast_channel_unref(chan_ptr);
04596 }
04597
04598 if (new_peer_cdr) {
04599 ast_cdr_specialized_reset(new_peer_cdr, 0);
04600 }
04601 } else {
04602 if (we_disabled_peer_cdr) {
04603 ast_clear_flag(peer->cdr, AST_CDR_FLAG_POST_DISABLED);
04604 }
04605 ast_cdr_specialized_reset(peer->cdr, 0);
04606 }
04607 }
04608
04609 return res;
04610 }
04611
04612
04613 static void post_manager_event(const char *s, struct parkeduser *pu)
04614 {
04615 manager_event(EVENT_FLAG_CALL, s,
04616 "Exten: %s\r\n"
04617 "Channel: %s\r\n"
04618 "Parkinglot: %s\r\n"
04619 "CallerIDNum: %s\r\n"
04620 "CallerIDName: %s\r\n"
04621 "ConnectedLineNum: %s\r\n"
04622 "ConnectedLineName: %s\r\n"
04623 "UniqueID: %s\r\n",
04624 pu->parkingexten,
04625 pu->chan->name,
04626 pu->parkinglot->name,
04627 S_COR(pu->chan->caller.id.number.valid, pu->chan->caller.id.number.str, "<unknown>"),
04628 S_COR(pu->chan->caller.id.name.valid, pu->chan->caller.id.name.str, "<unknown>"),
04629 S_COR(pu->chan->connected.id.number.valid, pu->chan->connected.id.number.str, "<unknown>"),
04630 S_COR(pu->chan->connected.id.name.valid, pu->chan->connected.id.name.str, "<unknown>"),
04631 pu->chan->uniqueid
04632 );
04633 }
04634
04635 static char *callback_dialoptions(struct ast_flags *features_callee, struct ast_flags *features_caller, char *options, size_t len)
04636 {
04637 int i = 0;
04638 enum {
04639 OPT_CALLEE_REDIRECT = 't',
04640 OPT_CALLER_REDIRECT = 'T',
04641 OPT_CALLEE_AUTOMON = 'w',
04642 OPT_CALLER_AUTOMON = 'W',
04643 OPT_CALLEE_DISCONNECT = 'h',
04644 OPT_CALLER_DISCONNECT = 'H',
04645 OPT_CALLEE_PARKCALL = 'k',
04646 OPT_CALLER_PARKCALL = 'K',
04647 };
04648
04649 memset(options, 0, len);
04650 if (ast_test_flag(features_caller, AST_FEATURE_REDIRECT) && i < len) {
04651 options[i++] = OPT_CALLER_REDIRECT;
04652 }
04653 if (ast_test_flag(features_caller, AST_FEATURE_AUTOMON) && i < len) {
04654 options[i++] = OPT_CALLER_AUTOMON;
04655 }
04656 if (ast_test_flag(features_caller, AST_FEATURE_DISCONNECT) && i < len) {
04657 options[i++] = OPT_CALLER_DISCONNECT;
04658 }
04659 if (ast_test_flag(features_caller, AST_FEATURE_PARKCALL) && i < len) {
04660 options[i++] = OPT_CALLER_PARKCALL;
04661 }
04662
04663 if (ast_test_flag(features_callee, AST_FEATURE_REDIRECT) && i < len) {
04664 options[i++] = OPT_CALLEE_REDIRECT;
04665 }
04666 if (ast_test_flag(features_callee, AST_FEATURE_AUTOMON) && i < len) {
04667 options[i++] = OPT_CALLEE_AUTOMON;
04668 }
04669 if (ast_test_flag(features_callee, AST_FEATURE_DISCONNECT) && i < len) {
04670 options[i++] = OPT_CALLEE_DISCONNECT;
04671 }
04672 if (ast_test_flag(features_callee, AST_FEATURE_PARKCALL) && i < len) {
04673 options[i++] = OPT_CALLEE_PARKCALL;
04674 }
04675
04676 return options;
04677 }
04678
04679
04680
04681
04682
04683
04684
04685
04686
04687 static int manage_parked_call(struct parkeduser *pu, const struct pollfd *pfds, int nfds, struct pollfd **new_pfds, int *new_nfds, int *ms)
04688 {
04689 struct ast_channel *chan = pu->chan;
04690 int tms;
04691 int x;
04692
04693 tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
04694 if (tms > pu->parkingtime) {
04695
04696
04697
04698
04699 switch (pu->hold_method) {
04700 case AST_CONTROL_HOLD:
04701 ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
04702 break;
04703 case AST_CONTROL_RINGING:
04704 ast_indicate(pu->chan, -1);
04705 break;
04706 default:
04707 break;
04708 }
04709 pu->hold_method = 0;
04710
04711
04712 if (pu->peername[0]) {
04713 char *peername;
04714 char *dash;
04715 char *peername_flat;
04716 int i;
04717
04718 peername = ast_strdupa(pu->peername);
04719 dash = strrchr(peername, '-');
04720 if (dash) {
04721 *dash = '\0';
04722 }
04723
04724 peername_flat = ast_strdupa(peername);
04725 for (i = 0; peername_flat[i]; i++) {
04726 if (peername_flat[i] == '/') {
04727 peername_flat[i] = '_';
04728 }
04729 }
04730
04731 if (!ast_context_find_or_create(NULL, NULL, parking_con_dial, registrar)) {
04732 ast_log(LOG_ERROR,
04733 "Parking dial context '%s' does not exist and unable to create\n",
04734 parking_con_dial);
04735 } else {
04736 char returnexten[AST_MAX_EXTENSION];
04737 struct ast_datastore *features_datastore;
04738 struct ast_dial_features *dialfeatures;
04739
04740 if (!strncmp(peername, "Parked/", 7)) {
04741 peername += 7;
04742 }
04743
04744 ast_channel_lock(chan);
04745 features_datastore = ast_channel_datastore_find(chan, &dial_features_info,
04746 NULL);
04747 if (features_datastore && (dialfeatures = features_datastore->data)) {
04748 char buf[MAX_DIAL_FEATURE_OPTIONS] = {0,};
04749
04750 snprintf(returnexten, sizeof(returnexten), "%s,30,%s", peername,
04751 callback_dialoptions(&dialfeatures->peer_features,
04752 &dialfeatures->my_features, buf, sizeof(buf)));
04753 } else {
04754 ast_log(LOG_NOTICE, "Dial features not found on %s, using default!\n",
04755 chan->name);
04756 snprintf(returnexten, sizeof(returnexten), "%s,30,t", peername);
04757 }
04758 ast_channel_unlock(chan);
04759
04760 if (ast_add_extension(parking_con_dial, 1, peername_flat, 1, NULL, NULL,
04761 "Dial", ast_strdup(returnexten), ast_free_ptr, registrar)) {
04762 ast_log(LOG_ERROR,
04763 "Could not create parking return dial exten: %s@%s\n",
04764 peername_flat, parking_con_dial);
04765 }
04766 }
04767 if (pu->options_specified) {
04768
04769
04770
04771
04772 set_c_e_p(chan, pu->context, pu->exten, pu->priority);
04773 } else if (comebacktoorigin) {
04774 set_c_e_p(chan, parking_con_dial, peername_flat, 1);
04775 } else {
04776 char parkingslot[AST_MAX_EXTENSION];
04777
04778 snprintf(parkingslot, sizeof(parkingslot), "%d", pu->parkingnum);
04779 pbx_builtin_setvar_helper(chan, "PARKINGSLOT", parkingslot);
04780 set_c_e_p(chan, "parkedcallstimeout", peername_flat, 1);
04781 }
04782 } else {
04783
04784
04785
04786
04787
04788 set_c_e_p(chan, pu->context, pu->exten, pu->priority);
04789 }
04790 post_manager_event("ParkedCallTimeOut", pu);
04791 ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "ParkedCallTimeOut", NULL);
04792
04793 ast_verb(2, "Timeout for %s parked on %d (%s). Returning to %s,%s,%d\n",
04794 pu->chan->name, pu->parkingnum, pu->parkinglot->name, pu->chan->context,
04795 pu->chan->exten, pu->chan->priority);
04796
04797
04798 if (ast_pbx_start(chan)) {
04799 ast_log(LOG_WARNING,
04800 "Unable to restart the PBX for user on '%s', hanging them up...\n",
04801 pu->chan->name);
04802 ast_hangup(chan);
04803 }
04804
04805
04806 return 1;
04807 }
04808
04809
04810 if (pfds) {
04811 for (x = 0; x < AST_MAX_FDS; x++) {
04812 struct ast_frame *f;
04813 int y;
04814
04815 if (chan->fds[x] == -1) {
04816 continue;
04817 }
04818
04819 for (y = 0; y < nfds; y++) {
04820 if (pfds[y].fd == chan->fds[x]) {
04821
04822 break;
04823 }
04824 }
04825 if (y == nfds) {
04826
04827 continue;
04828 }
04829
04830 if (!(pfds[y].revents & (POLLIN | POLLERR | POLLPRI))) {
04831
04832 continue;
04833 }
04834
04835 if (pfds[y].revents & POLLPRI) {
04836 ast_set_flag(chan, AST_FLAG_EXCEPTION);
04837 } else {
04838 ast_clear_flag(chan, AST_FLAG_EXCEPTION);
04839 }
04840 chan->fdno = x;
04841
04842
04843 f = ast_read(pu->chan);
04844
04845 if (!f || (f->frametype == AST_FRAME_CONTROL
04846 && f->subclass.integer == AST_CONTROL_HANGUP)) {
04847 if (f) {
04848 ast_frfree(f);
04849 }
04850 post_manager_event("ParkedCallGiveUp", pu);
04851 ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "ParkedCallGiveUp",
04852 NULL);
04853
04854
04855 ast_verb(2, "%s got tired of being parked\n", chan->name);
04856 ast_hangup(chan);
04857
04858
04859 return 1;
04860 } else {
04861
04862 ast_frfree(f);
04863 if (pu->hold_method == AST_CONTROL_HOLD
04864 && pu->moh_trys < 3
04865 && !chan->generatordata) {
04866 ast_debug(1,
04867 "MOH on parked call stopped by outside source. Restarting on channel %s.\n",
04868 chan->name);
04869 ast_indicate_data(chan, AST_CONTROL_HOLD,
04870 S_OR(pu->parkinglot->cfg.mohclass, NULL),
04871 (!ast_strlen_zero(pu->parkinglot->cfg.mohclass)
04872 ? strlen(pu->parkinglot->cfg.mohclass) + 1 : 0));
04873 pu->moh_trys++;
04874 }
04875 break;
04876 }
04877 }
04878 }
04879
04880
04881 for (x = 0; x < AST_MAX_FDS; x++) {
04882 if (chan->fds[x] > -1) {
04883 void *tmp = ast_realloc(*new_pfds,
04884 (*new_nfds + 1) * sizeof(struct pollfd));
04885
04886 if (!tmp) {
04887 continue;
04888 }
04889 *new_pfds = tmp;
04890 (*new_pfds)[*new_nfds].fd = chan->fds[x];
04891 (*new_pfds)[*new_nfds].events = POLLIN | POLLERR | POLLPRI;
04892 (*new_pfds)[*new_nfds].revents = 0;
04893 (*new_nfds)++;
04894 }
04895 }
04896
04897 if (tms < *ms || *ms < 0) {
04898 *ms = tms;
04899 }
04900
04901
04902 return 0;
04903 }
04904
04905
04906 static void manage_parkinglot(struct ast_parkinglot *curlot, const struct pollfd *pfds, int nfds, struct pollfd **new_pfds, int *new_nfds, int *ms)
04907 {
04908 struct parkeduser *pu;
04909 struct ast_context *con;
04910
04911
04912 AST_LIST_LOCK(&curlot->parkings);
04913 AST_LIST_TRAVERSE_SAFE_BEGIN(&curlot->parkings, pu, list) {
04914 if (pu->notquiteyet) {
04915 continue;
04916 }
04917 if (manage_parked_call(pu, pfds, nfds, new_pfds, new_nfds, ms)) {
04918
04919 con = ast_context_find(pu->parkinglot->cfg.parking_con);
04920 if (con) {
04921 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0)) {
04922 ast_log(LOG_WARNING,
04923 "Whoa, failed to remove the parking extension %s@%s!\n",
04924 pu->parkingexten, pu->parkinglot->cfg.parking_con);
04925 }
04926 notify_metermaids(pu->parkingexten, pu->parkinglot->cfg.parking_con,
04927 AST_DEVICE_NOT_INUSE);
04928 } else {
04929 ast_log(LOG_WARNING,
04930 "Whoa, parking lot '%s' context '%s' does not exist.\n",
04931 pu->parkinglot->name, pu->parkinglot->cfg.parking_con);
04932 }
04933 AST_LIST_REMOVE_CURRENT(list);
04934 parkinglot_unref(pu->parkinglot);
04935 ast_free(pu);
04936 }
04937 }
04938 AST_LIST_TRAVERSE_SAFE_END;
04939 AST_LIST_UNLOCK(&curlot->parkings);
04940 }
04941
04942
04943
04944
04945
04946
04947
04948
04949
04950 static void *do_parking_thread(void *ignore)
04951 {
04952 struct pollfd *pfds = NULL, *new_pfds = NULL;
04953 int nfds = 0, new_nfds = 0;
04954
04955 for (;;) {
04956 struct ao2_iterator iter;
04957 struct ast_parkinglot *curlot;
04958 int ms = -1;
04959
04960 iter = ao2_iterator_init(parkinglots, 0);
04961 while ((curlot = ao2_iterator_next(&iter))) {
04962 manage_parkinglot(curlot, pfds, nfds, &new_pfds, &new_nfds, &ms);
04963 ao2_ref(curlot, -1);
04964 }
04965 ao2_iterator_destroy(&iter);
04966
04967
04968 ast_free(pfds);
04969 pfds = new_pfds;
04970 nfds = new_nfds;
04971 new_pfds = NULL;
04972 new_nfds = 0;
04973
04974
04975 ast_poll(pfds, nfds, ms);
04976 pthread_testcancel();
04977 }
04978
04979 return NULL;
04980 }
04981
04982
04983 static struct ast_parkinglot *find_parkinglot(const char *name)
04984 {
04985 struct ast_parkinglot *parkinglot;
04986
04987 if (ast_strlen_zero(name)) {
04988 return NULL;
04989 }
04990
04991 parkinglot = ao2_find(parkinglots, (void *) name, 0);
04992 if (parkinglot) {
04993 ast_debug(1, "Found Parking lot: %s\n", parkinglot->name);
04994 }
04995
04996 return parkinglot;
04997 }
04998
04999
05000 static struct ast_parkinglot *copy_parkinglot(const char *name, const struct ast_parkinglot *parkinglot)
05001 {
05002 struct ast_parkinglot *copylot;
05003
05004 if ((copylot = find_parkinglot(name))) {
05005 ao2_ref(copylot, -1);
05006 return NULL;
05007 }
05008
05009 copylot = create_parkinglot(name);
05010 if (!copylot) {
05011 return NULL;
05012 }
05013
05014 ast_debug(1, "Building parking lot %s\n", name);
05015
05016
05017 copylot->cfg = parkinglot->cfg;
05018
05019 return copylot;
05020 }
05021
05022 AST_APP_OPTIONS(park_call_options, BEGIN_OPTIONS
05023 AST_APP_OPTION('r', AST_PARK_OPT_RINGING),
05024 AST_APP_OPTION('R', AST_PARK_OPT_RANDOMIZE),
05025 AST_APP_OPTION('s', AST_PARK_OPT_SILENCE),
05026 END_OPTIONS );
05027
05028
05029 static int park_call_exec(struct ast_channel *chan, const char *data)
05030 {
05031 struct ast_park_call_args args = { 0, };
05032 struct ast_flags flags = { 0 };
05033 char orig_exten[AST_MAX_EXTENSION];
05034 int orig_priority;
05035 int res;
05036 const char *pl_name;
05037 char *parse;
05038 struct park_app_args app_args;
05039
05040
05041
05042
05043
05044
05045
05046
05047
05048
05049
05050 args.orig_chan_name = ast_strdupa(S_OR(
05051 pbx_builtin_getvar_helper(chan, "BLINDTRANSFER"), chan->name));
05052
05053
05054 if (chan->_state != AST_STATE_UP) {
05055 if (ast_answer(chan)) {
05056 return -1;
05057 }
05058
05059
05060 if (ast_safe_sleep(chan, 1000)) {
05061 return -1;
05062 }
05063 }
05064
05065
05066 parse = ast_strdupa(data);
05067 AST_STANDARD_APP_ARGS(app_args, parse);
05068
05069 if (!ast_strlen_zero(app_args.timeout)) {
05070 if (sscanf(app_args.timeout, "%30d", &args.timeout) != 1) {
05071 ast_log(LOG_WARNING, "Invalid timeout '%s' provided\n", app_args.timeout);
05072 args.timeout = 0;
05073 }
05074 }
05075 if (!ast_strlen_zero(app_args.return_con)) {
05076 args.return_con = app_args.return_con;
05077 }
05078 if (!ast_strlen_zero(app_args.return_ext)) {
05079 args.return_ext = app_args.return_ext;
05080 }
05081 if (!ast_strlen_zero(app_args.return_pri)) {
05082 if (sscanf(app_args.return_pri, "%30d", &args.return_pri) != 1) {
05083 ast_log(LOG_WARNING, "Invalid priority '%s' specified\n", app_args.return_pri);
05084 args.return_pri = 0;
05085 }
05086 }
05087
05088 ast_app_parse_options(park_call_options, &flags, NULL, app_args.options);
05089 args.flags = flags.flags;
05090
05091
05092
05093
05094
05095 ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten));
05096 orig_priority = chan->priority;
05097 strcpy(chan->exten, "s");
05098 chan->priority = 1;
05099
05100
05101 if (!ast_strlen_zero(app_args.pl_name)) {
05102 pl_name = app_args.pl_name;
05103 } else {
05104 pl_name = findparkinglotname(chan);
05105 }
05106 if (ast_strlen_zero(pl_name)) {
05107
05108 args.parkinglot = parkinglot_addref(default_parkinglot);
05109 } else {
05110 args.parkinglot = find_parkinglot(pl_name);
05111 if (!args.parkinglot && parkeddynamic) {
05112 args.parkinglot = create_dynamic_parkinglot(pl_name, chan);
05113 }
05114 }
05115 if (args.parkinglot) {
05116 res = masq_park_call(chan, chan, &args);
05117 parkinglot_unref(args.parkinglot);
05118 } else {
05119
05120 if (!ast_test_flag(&args, AST_PARK_OPT_SILENCE)) {
05121 ast_stream_and_wait(chan, "pbx-parkingfailed", "");
05122 }
05123 res = -1;
05124 }
05125 if (res) {
05126
05127 ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten));
05128 chan->priority = orig_priority;
05129 res = 0;
05130 } else {
05131
05132 res = -1;
05133 }
05134
05135 return res;
05136 }
05137
05138
05139 static int parked_call_exec(struct ast_channel *chan, const char *data)
05140 {
05141 int res;
05142 struct ast_channel *peer = NULL;
05143 struct parkeduser *pu;
05144 struct ast_context *con;
05145 char *parse;
05146 const char *pl_name;
05147 unsigned int park = 0;
05148 struct ast_bridge_config config;
05149 struct ast_parkinglot *parkinglot;
05150 AST_DECLARE_APP_ARGS(app_args,
05151 AST_APP_ARG(pl_space);
05152 AST_APP_ARG(pl_name);
05153 AST_APP_ARG(dummy);
05154 );
05155
05156 parse = ast_strdupa(data);
05157 AST_STANDARD_APP_ARGS(app_args, parse);
05158
05159 if (!ast_strlen_zero(app_args.pl_space)) {
05160 if (sscanf(app_args.pl_space, "%30u", &park) != 1) {
05161 ast_log(LOG_WARNING, "Specified parking extension not a number: %s\n",
05162 app_args.pl_space);
05163 park = -1;
05164 }
05165 }
05166
05167 if (!ast_strlen_zero(app_args.pl_name)) {
05168 pl_name = app_args.pl_name;
05169 } else {
05170 pl_name = findparkinglotname(chan);
05171 }
05172 if (ast_strlen_zero(pl_name)) {
05173
05174 parkinglot = parkinglot_addref(default_parkinglot);
05175 } else {
05176 parkinglot = find_parkinglot(pl_name);
05177 if (!parkinglot) {
05178
05179 if (chan->_state != AST_STATE_UP) {
05180 ast_answer(chan);
05181 }
05182 if (ast_stream_and_wait(chan, "pbx-invalidpark", "")) {
05183 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n",
05184 "pbx-invalidpark", chan->name);
05185 }
05186 ast_log(LOG_WARNING,
05187 "Channel %s tried to retrieve parked call from unknown parking lot '%s'\n",
05188 chan->name, pl_name);
05189 return -1;
05190 }
05191 }
05192
05193 AST_LIST_LOCK(&parkinglot->parkings);
05194 AST_LIST_TRAVERSE_SAFE_BEGIN(&parkinglot->parkings, pu, list) {
05195 if ((ast_strlen_zero(app_args.pl_space) || pu->parkingnum == park)
05196 && !pu->notquiteyet && !pu->chan->pbx) {
05197
05198 AST_LIST_REMOVE_CURRENT(list);
05199 break;
05200 }
05201 }
05202 AST_LIST_TRAVERSE_SAFE_END;
05203 if (pu) {
05204
05205 peer = pu->chan;
05206 con = ast_context_find(parkinglot->cfg.parking_con);
05207 if (con) {
05208 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0)) {
05209 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
05210 } else {
05211 notify_metermaids(pu->parkingexten, parkinglot->cfg.parking_con, AST_DEVICE_NOT_INUSE);
05212 }
05213 } else {
05214 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
05215 }
05216
05217 ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "UnParkedCall", chan);
05218 ast_manager_event(pu->chan, EVENT_FLAG_CALL, "UnParkedCall",
05219 "Exten: %s\r\n"
05220 "Channel: %s\r\n"
05221 "Parkinglot: %s\r\n"
05222 "From: %s\r\n"
05223 "CallerIDNum: %s\r\n"
05224 "CallerIDName: %s\r\n"
05225 "ConnectedLineNum: %s\r\n"
05226 "ConnectedLineName: %s\r\n"
05227 "Uniqueid: %s\r\n",
05228 pu->parkingexten, pu->chan->name, pu->parkinglot->name, chan->name,
05229 S_COR(pu->chan->caller.id.number.valid, pu->chan->caller.id.number.str, "<unknown>"),
05230 S_COR(pu->chan->caller.id.name.valid, pu->chan->caller.id.name.str, "<unknown>"),
05231 S_COR(pu->chan->connected.id.number.valid, pu->chan->connected.id.number.str, "<unknown>"),
05232 S_COR(pu->chan->connected.id.name.valid, pu->chan->connected.id.name.str, "<unknown>"),
05233 pu->chan->uniqueid
05234 );
05235
05236
05237 switch (pu->hold_method) {
05238 case AST_CONTROL_HOLD:
05239 ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
05240 break;
05241 case AST_CONTROL_RINGING:
05242 ast_indicate(pu->chan, -1);
05243 break;
05244 default:
05245 break;
05246 }
05247 pu->hold_method = 0;
05248
05249 parkinglot_unref(pu->parkinglot);
05250 ast_free(pu);
05251 }
05252 AST_LIST_UNLOCK(&parkinglot->parkings);
05253
05254 if (peer) {
05255
05256 struct ast_party_connected_line connected;
05257
05258 ast_party_connected_line_init(&connected);
05259
05260
05261 ast_channel_lock(chan);
05262 ast_connected_line_copy_from_caller(&connected, &chan->caller);
05263 ast_channel_unlock(chan);
05264 connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
05265 if (ast_channel_connected_line_macro(chan, peer, &connected, 0, 0)) {
05266 ast_channel_update_connected_line(peer, &connected, NULL);
05267 }
05268
05269
05270
05271
05272
05273
05274
05275
05276 ast_channel_lock(peer);
05277 ast_connected_line_copy_from_caller(&connected, &peer->caller);
05278 ast_channel_unlock(peer);
05279 connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
05280 if (ast_channel_connected_line_macro(peer, chan, &connected, 1, 0)) {
05281 ast_channel_update_connected_line(chan, &connected, NULL);
05282 }
05283
05284 ast_party_connected_line_free(&connected);
05285 }
05286
05287
05288 if (chan->_state != AST_STATE_UP) {
05289 ast_answer(chan);
05290 }
05291
05292 if (peer) {
05293 struct ast_datastore *features_datastore;
05294 struct ast_dial_features *dialfeatures;
05295
05296
05297 if (!ast_strlen_zero(courtesytone)) {
05298 static const char msg[] = "courtesy tone";
05299
05300 switch (parkedplay) {
05301 case 0:
05302 res = play_message_to_chans(chan, peer, -1, msg, courtesytone);
05303 break;
05304 case 1:
05305 res = play_message_to_chans(chan, peer, 1, msg, courtesytone);
05306 break;
05307 case 2:
05308 res = play_message_to_chans(chan, peer, 0, msg, courtesytone);
05309 break;
05310 default:
05311 res = 0;
05312 break;
05313 }
05314 if (res) {
05315 ast_hangup(peer);
05316 parkinglot_unref(parkinglot);
05317 return -1;
05318 }
05319 }
05320
05321 res = ast_channel_make_compatible(chan, peer);
05322 if (res < 0) {
05323 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
05324 ast_hangup(peer);
05325 parkinglot_unref(parkinglot);
05326 return -1;
05327 }
05328
05329
05330 ast_verb(3, "Channel %s connected to parked call %u\n", chan->name, park);
05331
05332 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
05333 ast_cdr_setdestchan(chan->cdr, peer->name);
05334 memset(&config, 0, sizeof(struct ast_bridge_config));
05335
05336
05337 ast_channel_lock(peer);
05338 features_datastore = ast_channel_datastore_find(peer, &dial_features_info, NULL);
05339 if (features_datastore && (dialfeatures = features_datastore->data)) {
05340 ast_copy_flags(&config.features_callee, &dialfeatures->my_features,
05341 AST_FLAGS_ALL);
05342 }
05343 ast_channel_unlock(peer);
05344
05345 if ((parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
05346 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
05347 }
05348 if ((parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
05349 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
05350 }
05351 if ((parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
05352 ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL);
05353 }
05354 if ((parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
05355 ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL);
05356 }
05357 if ((parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
05358 ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT);
05359 }
05360 if ((parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
05361 ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT);
05362 }
05363 if ((parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
05364 ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
05365 }
05366 if ((parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
05367 ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
05368 }
05369
05370 res = ast_bridge_call(chan, peer, &config);
05371
05372 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
05373 ast_cdr_setdestchan(chan->cdr, peer->name);
05374
05375
05376 ast_hangup(peer);
05377 } else {
05378 if (ast_stream_and_wait(chan, "pbx-invalidpark", "")) {
05379 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark",
05380 chan->name);
05381 }
05382 ast_verb(3, "Channel %s tried to retrieve nonexistent parked call %u\n",
05383 chan->name, park);
05384 res = -1;
05385 }
05386
05387 parkinglot_unref(parkinglot);
05388 return res;
05389 }
05390
05391
05392
05393
05394 static void parkinglot_unref(struct ast_parkinglot *parkinglot)
05395 {
05396 ast_debug(3, "Multiparking: %s refcount now %d\n", parkinglot->name,
05397 ao2_ref(parkinglot, 0) - 1);
05398 ao2_ref(parkinglot, -1);
05399 }
05400
05401 static struct ast_parkinglot *parkinglot_addref(struct ast_parkinglot *parkinglot)
05402 {
05403 int refcount;
05404
05405 refcount = ao2_ref(parkinglot, +1);
05406 ast_debug(3, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount + 1);
05407 return parkinglot;
05408 }
05409
05410
05411 static void parkinglot_destroy(void *obj)
05412 {
05413 struct ast_parkinglot *doomed = obj;
05414
05415
05416
05417
05418
05419
05420 ast_assert(AST_LIST_EMPTY(&doomed->parkings));
05421 AST_LIST_HEAD_DESTROY(&doomed->parkings);
05422 }
05423
05424
05425 static struct ast_parkinglot *create_parkinglot(const char *name)
05426 {
05427 struct ast_parkinglot *newlot;
05428
05429 if (ast_strlen_zero(name)) {
05430 return NULL;
05431 }
05432
05433 newlot = ao2_alloc(sizeof(*newlot), parkinglot_destroy);
05434 if (!newlot)
05435 return NULL;
05436
05437 ast_copy_string(newlot->name, name, sizeof(newlot->name));
05438 newlot->cfg.is_invalid = 1;
05439 AST_LIST_HEAD_INIT(&newlot->parkings);
05440
05441 return newlot;
05442 }
05443
05444
05445
05446
05447
05448
05449
05450 static void park_add_hints(const char *context, int start, int stop)
05451 {
05452 int numext;
05453 char device[AST_MAX_EXTENSION];
05454 char exten[10];
05455
05456 for (numext = start; numext <= stop; numext++) {
05457 snprintf(exten, sizeof(exten), "%d", numext);
05458 snprintf(device, sizeof(device), "park:%s@%s", exten, context);
05459 ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
05460 }
05461 }
05462
05463
05464 static const struct parkinglot_cfg parkinglot_cfg_default_default = {
05465 .mohclass = "default",
05466 .parkext = DEFAULT_PARK_EXTENSION,
05467 .parking_con = "parkedcalls",
05468 .parking_start = 701,
05469 .parking_stop = 750,
05470 .parkingtime = DEFAULT_PARK_TIME,
05471 };
05472
05473
05474 static const struct parkinglot_cfg parkinglot_cfg_default = {
05475 .parkext = DEFAULT_PARK_EXTENSION,
05476 .parkingtime = DEFAULT_PARK_TIME,
05477 };
05478
05479
05480
05481
05482
05483
05484
05485
05486
05487
05488
05489 static void parkinglot_feature_flag_cfg(const char *pl_name, int *param, struct ast_variable *var)
05490 {
05491 ast_debug(1, "Setting parking lot %s %s to %s\n", pl_name, var->name, var->value);
05492 if (!strcasecmp(var->value, "both")) {
05493 *param = AST_FEATURE_FLAG_BYBOTH;
05494 } else if (!strcasecmp(var->value, "caller")) {
05495 *param = AST_FEATURE_FLAG_BYCALLER;
05496 } else if (!strcasecmp(var->value, "callee")) {
05497 *param = AST_FEATURE_FLAG_BYCALLEE;
05498 }
05499 }
05500
05501
05502
05503
05504
05505
05506
05507
05508
05509
05510
05511
05512 static int parkinglot_config_read(const char *pl_name, struct parkinglot_cfg *cfg, struct ast_variable *var)
05513 {
05514 int error = 0;
05515
05516 while (var) {
05517 if (!strcasecmp(var->name, "context")) {
05518 ast_copy_string(cfg->parking_con, var->value, sizeof(cfg->parking_con));
05519 } else if (!strcasecmp(var->name, "parkext")) {
05520 ast_copy_string(cfg->parkext, var->value, sizeof(cfg->parkext));
05521 } else if (!strcasecmp(var->name, "parkext_exclusive")) {
05522 cfg->parkext_exclusive = ast_true(var->value);
05523 } else if (!strcasecmp(var->name, "parkinghints")) {
05524 cfg->parkaddhints = ast_true(var->value);
05525 } else if (!strcasecmp(var->name, "parkedmusicclass")) {
05526 ast_copy_string(cfg->mohclass, var->value, sizeof(cfg->mohclass));
05527 } else if (!strcasecmp(var->name, "parkingtime")) {
05528 int parkingtime = 0;
05529
05530 if ((sscanf(var->value, "%30d", &parkingtime) != 1) || parkingtime < 1) {
05531 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
05532 error = -1;
05533 } else {
05534 cfg->parkingtime = parkingtime * 1000;
05535 }
05536 } else if (!strcasecmp(var->name, "parkpos")) {
05537 int start = 0;
05538 int end = 0;
05539
05540 if (sscanf(var->value, "%30d-%30d", &start, &end) != 2) {
05541 ast_log(LOG_WARNING,
05542 "Format for parking positions is a-b, where a and b are numbers at line %d of %s\n",
05543 var->lineno, var->file);
05544 error = -1;
05545 } else if (end < start || start <= 0 || end <= 0) {
05546 ast_log(LOG_WARNING, "Parking range is invalid. Must be a <= b, at line %d of %s\n",
05547 var->lineno, var->file);
05548 error = -1;
05549 } else {
05550 cfg->parking_start = start;
05551 cfg->parking_stop = end;
05552 }
05553 } else if (!strcasecmp(var->name, "findslot")) {
05554 cfg->parkfindnext = (!strcasecmp(var->value, "next"));
05555 } else if (!strcasecmp(var->name, "parkedcalltransfers")) {
05556 parkinglot_feature_flag_cfg(pl_name, &cfg->parkedcalltransfers, var);
05557 } else if (!strcasecmp(var->name, "parkedcallreparking")) {
05558 parkinglot_feature_flag_cfg(pl_name, &cfg->parkedcallreparking, var);
05559 } else if (!strcasecmp(var->name, "parkedcallhangup")) {
05560 parkinglot_feature_flag_cfg(pl_name, &cfg->parkedcallhangup, var);
05561 } else if (!strcasecmp(var->name, "parkedcallrecording")) {
05562 parkinglot_feature_flag_cfg(pl_name, &cfg->parkedcallrecording, var);
05563 }
05564 var = var->next;
05565 }
05566
05567
05568 if (ast_strlen_zero(cfg->parking_con)) {
05569 ast_log(LOG_WARNING, "Parking lot %s needs context\n", pl_name);
05570 error = -1;
05571 }
05572 if (ast_strlen_zero(cfg->parkext)) {
05573 ast_log(LOG_WARNING, "Parking lot %s needs parkext\n", pl_name);
05574 error = -1;
05575 }
05576 if (!cfg->parking_start) {
05577 ast_log(LOG_WARNING, "Parking lot %s needs parkpos\n", pl_name);
05578 error = -1;
05579 }
05580 if (error) {
05581 cfg->is_invalid = 1;
05582 }
05583
05584 return error;
05585 }
05586
05587
05588
05589
05590
05591
05592
05593
05594
05595
05596
05597
05598
05599
05600 static int parkinglot_activate(struct ast_parkinglot *parkinglot)
05601 {
05602 int disabled = 0;
05603 char app_data[5 + AST_MAX_CONTEXT];
05604
05605
05606 if (parkinglot->cfg.parkext_exclusive) {
05607
05608 snprintf(app_data, sizeof(app_data), ",,,,,%s", parkinglot->name);
05609 } else {
05610
05611 app_data[0] = '\0';
05612 }
05613
05614
05615 if (!ast_context_find_or_create(NULL, NULL, parkinglot->cfg.parking_con, registrar)) {
05616 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n",
05617 parkinglot->cfg.parking_con);
05618 disabled = 1;
05619
05620
05621 } else if (ast_add_extension(parkinglot->cfg.parking_con, 1, parkinglot->cfg.parkext,
05622 1, NULL, NULL, parkcall, ast_strdup(app_data), ast_free_ptr, registrar)) {
05623 ast_log(LOG_ERROR, "Could not create parking lot %s access exten %s@%s\n",
05624 parkinglot->name, parkinglot->cfg.parkext, parkinglot->cfg.parking_con);
05625 disabled = 1;
05626 } else {
05627
05628 if (parkinglot->cfg.parkaddhints) {
05629 park_add_hints(parkinglot->cfg.parking_con, parkinglot->cfg.parking_start,
05630 parkinglot->cfg.parking_stop);
05631 }
05632
05633
05634
05635
05636
05637
05638
05639
05640 notify_metermaids(parkinglot->cfg.parkext, parkinglot->cfg.parking_con,
05641 AST_DEVICE_INUSE);
05642 }
05643
05644 parkinglot->disabled = disabled;
05645 return disabled ? -1 : 0;
05646 }
05647
05648
05649 static struct ast_parkinglot *build_parkinglot(const char *pl_name, struct ast_variable *var)
05650 {
05651 struct ast_parkinglot *parkinglot;
05652 const struct parkinglot_cfg *cfg_defaults;
05653 struct parkinglot_cfg new_cfg;
05654 int cfg_error;
05655 int oldparkinglot = 0;
05656
05657 parkinglot = find_parkinglot(pl_name);
05658 if (parkinglot) {
05659 oldparkinglot = 1;
05660 } else {
05661 parkinglot = create_parkinglot(pl_name);
05662 if (!parkinglot) {
05663 return NULL;
05664 }
05665 }
05666 if (!strcmp(parkinglot->name, DEFAULT_PARKINGLOT)) {
05667 cfg_defaults = &parkinglot_cfg_default_default;
05668 } else {
05669 cfg_defaults = &parkinglot_cfg_default;
05670 }
05671 new_cfg = *cfg_defaults;
05672
05673 ast_debug(1, "Building parking lot %s\n", parkinglot->name);
05674
05675 ao2_lock(parkinglot);
05676
05677
05678 cfg_error = parkinglot_config_read(parkinglot->name, &new_cfg, var);
05679 if (oldparkinglot) {
05680 if (cfg_error) {
05681
05682 ast_log(LOG_WARNING, "Changes to parking lot %s are discarded.\n",
05683 parkinglot->name);
05684 cfg_error = 0;
05685 } else if (!AST_LIST_EMPTY(&parkinglot->parkings)
05686 && memcmp(&new_cfg, &parkinglot->cfg, sizeof(parkinglot->cfg))) {
05687
05688 ast_log(LOG_WARNING,
05689 "Parking lot %s has parked calls. Parking lot changes discarded.\n",
05690 parkinglot->name);
05691 force_reload_load = 1;
05692 } else {
05693
05694 parkinglot->cfg = new_cfg;
05695 }
05696 } else {
05697
05698 parkinglot->cfg = new_cfg;
05699 }
05700 parkinglot->the_mark = 0;
05701
05702 ao2_unlock(parkinglot);
05703
05704 if (cfg_error) {
05705
05706 ast_log(LOG_WARNING, "New parking lot %s is discarded.\n", parkinglot->name);
05707 parkinglot_unref(parkinglot);
05708 return NULL;
05709 }
05710
05711
05712 if (!oldparkinglot) {
05713 ao2_link(parkinglots, parkinglot);
05714 }
05715 parkinglot_unref(parkinglot);
05716
05717 return parkinglot;
05718 }
05719
05720
05721
05722
05723
05724
05725
05726
05727
05728 static void process_applicationmap_line(struct ast_variable *var)
05729 {
05730 char *tmp_val = ast_strdupa(var->value);
05731 char *activateon, *new_syn;
05732 struct ast_call_feature *feature;
05733 AST_DECLARE_APP_ARGS(args,
05734 AST_APP_ARG(exten);
05735 AST_APP_ARG(activatedby);
05736 AST_APP_ARG(app);
05737 AST_APP_ARG(app_args);
05738 AST_APP_ARG(moh_class);
05739 );
05740
05741 AST_STANDARD_APP_ARGS(args, tmp_val);
05742
05743 activateon = strsep(&args.activatedby, "/");
05744
05745 if (ast_strlen_zero(args.app)
05746 || ast_strlen_zero(args.exten)
05747 || ast_strlen_zero(activateon)
05748 || ast_strlen_zero(var->name)) {
05749 ast_log(LOG_NOTICE,
05750 "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",
05751 args.app, args.exten, activateon, var->name);
05752 return;
05753 }
05754
05755 if ((new_syn = strchr(args.app, '('))) {
05756
05757 args.moh_class = args.app_args;
05758 args.app_args = new_syn;
05759 *args.app_args++ = '\0';
05760 if (args.app_args[strlen(args.app_args) - 1] == ')') {
05761 args.app_args[strlen(args.app_args) - 1] = '\0';
05762 }
05763 }
05764
05765 AST_RWLIST_RDLOCK(&feature_list);
05766 if (find_dynamic_feature(var->name)) {
05767 AST_RWLIST_UNLOCK(&feature_list);
05768 ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n",
05769 var->name);
05770 return;
05771 }
05772 AST_RWLIST_UNLOCK(&feature_list);
05773
05774 if (!(feature = ast_calloc(1, sizeof(*feature)))) {
05775 return;
05776 }
05777
05778 ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN);
05779 ast_copy_string(feature->app, args.app, FEATURE_APP_LEN);
05780 ast_copy_string(feature->exten, args.exten, FEATURE_EXTEN_LEN);
05781
05782 if (args.app_args) {
05783 ast_copy_string(feature->app_args, args.app_args, FEATURE_APP_ARGS_LEN);
05784 }
05785
05786 if (args.moh_class) {
05787 ast_copy_string(feature->moh_class, args.moh_class, FEATURE_MOH_LEN);
05788 }
05789
05790 ast_copy_string(feature->exten, args.exten, sizeof(feature->exten));
05791 feature->operation = feature_exec_app;
05792 ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF);
05793
05794
05795 if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller")) {
05796 ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF);
05797 } else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee")) {
05798 ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER);
05799 } else {
05800 ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s',"
05801 " must be 'self', or 'peer'\n", var->name);
05802 ast_free(feature);
05803 return;
05804 }
05805
05806 if (ast_strlen_zero(args.activatedby)) {
05807 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
05808 } else if (!strcasecmp(args.activatedby, "caller")) {
05809 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER);
05810 } else if (!strcasecmp(args.activatedby, "callee")) {
05811 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE);
05812 } else if (!strcasecmp(args.activatedby, "both")) {
05813 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
05814 } else {
05815 ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s',"
05816 " must be 'caller', or 'callee', or 'both'\n", var->name);
05817 ast_free(feature);
05818 return;
05819 }
05820
05821 ast_register_feature(feature);
05822
05823 ast_verb(2, "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n",
05824 var->name, args.app, args.app_args, args.exten);
05825 }
05826
05827 static int process_config(struct ast_config *cfg)
05828 {
05829 int i;
05830 struct ast_variable *var = NULL;
05831 struct feature_group *fg = NULL;
05832 char *ctg;
05833 static const char * const categories[] = {
05834
05835
05836
05837 "general",
05838 "featuremap",
05839 "applicationmap"
05840 };
05841
05842
05843 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
05844
05845
05846 strcpy(pickup_ext, "*8");
05847 pickupsound[0] = '\0';
05848 pickupfailsound[0] = '\0';
05849
05850
05851 strcpy(xfersound, "beep");
05852 strcpy(xferfailsound, "beeperr");
05853 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
05854 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
05855 atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY;
05856 atxferdropcall = DEFAULT_ATXFER_DROP_CALL;
05857 atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES;
05858
05859
05860 comebacktoorigin = 1;
05861 courtesytone[0] = '\0';
05862 parkedplay = 0;
05863 adsipark = 0;
05864 parkeddynamic = 0;
05865
05866 var = ast_variable_browse(cfg, "general");
05867 build_parkinglot(DEFAULT_PARKINGLOT, var);
05868 for (; var; var = var->next) {
05869 if (!strcasecmp(var->name, "parkeddynamic")) {
05870 parkeddynamic = ast_true(var->value);
05871 } else if (!strcasecmp(var->name, "adsipark")) {
05872 adsipark = ast_true(var->value);
05873 } else if (!strcasecmp(var->name, "transferdigittimeout")) {
05874 if ((sscanf(var->value, "%30d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
05875 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
05876 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
05877 } else {
05878 transferdigittimeout = transferdigittimeout * 1000;
05879 }
05880 } else if (!strcasecmp(var->name, "featuredigittimeout")) {
05881 if ((sscanf(var->value, "%30d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
05882 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
05883 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
05884 }
05885 } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) {
05886 if ((sscanf(var->value, "%30d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) {
05887 ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value);
05888 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
05889 } else {
05890 atxfernoanswertimeout = atxfernoanswertimeout * 1000;
05891 }
05892 } else if (!strcasecmp(var->name, "atxferloopdelay")) {
05893 if ((sscanf(var->value, "%30u", &atxferloopdelay) != 1)) {
05894 ast_log(LOG_WARNING, "%s is not a valid atxferloopdelay\n", var->value);
05895 atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY;
05896 } else {
05897 atxferloopdelay *= 1000;
05898 }
05899 } else if (!strcasecmp(var->name, "atxferdropcall")) {
05900 atxferdropcall = ast_true(var->value);
05901 } else if (!strcasecmp(var->name, "atxfercallbackretries")) {
05902 if ((sscanf(var->value, "%30u", &atxfercallbackretries) != 1)) {
05903 ast_log(LOG_WARNING, "%s is not a valid atxfercallbackretries\n", var->value);
05904 atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES;
05905 }
05906 } else if (!strcasecmp(var->name, "courtesytone")) {
05907 ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
05908 } else if (!strcasecmp(var->name, "parkedplay")) {
05909 if (!strcasecmp(var->value, "both")) {
05910 parkedplay = 2;
05911 } else if (!strcasecmp(var->value, "parked")) {
05912 parkedplay = 1;
05913 } else {
05914 parkedplay = 0;
05915 }
05916 } else if (!strcasecmp(var->name, "xfersound")) {
05917 ast_copy_string(xfersound, var->value, sizeof(xfersound));
05918 } else if (!strcasecmp(var->name, "xferfailsound")) {
05919 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
05920 } else if (!strcasecmp(var->name, "pickupexten")) {
05921 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
05922 } else if (!strcasecmp(var->name, "pickupsound")) {
05923 ast_copy_string(pickupsound, var->value, sizeof(pickupsound));
05924 } else if (!strcasecmp(var->name, "pickupfailsound")) {
05925 ast_copy_string(pickupfailsound, var->value, sizeof(pickupfailsound));
05926 } else if (!strcasecmp(var->name, "comebacktoorigin")) {
05927 comebacktoorigin = ast_true(var->value);
05928 }
05929 }
05930
05931 unmap_features();
05932 for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) {
05933 if (remap_feature(var->name, var->value)) {
05934 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
05935 }
05936 }
05937
05938
05939 ast_unregister_features();
05940 for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) {
05941 process_applicationmap_line(var);
05942 }
05943
05944 ast_unregister_groups();
05945 AST_RWLIST_WRLOCK(&feature_groups);
05946
05947 ctg = NULL;
05948 while ((ctg = ast_category_browse(cfg, ctg))) {
05949
05950 if (!strncasecmp(ctg, "parkinglot_", strlen("parkinglot_"))) {
05951 ast_debug(2, "Found configuration section %s, assume parking context\n", ctg);
05952 if (!build_parkinglot(ctg, ast_variable_browse(cfg, ctg))) {
05953 ast_log(LOG_ERROR, "Could not build parking lot %s. Configuration error.\n", ctg);
05954 } else {
05955 ast_debug(1, "Configured parking context %s\n", ctg);
05956 }
05957 continue;
05958 }
05959
05960
05961 for (i = 0; i < ARRAY_LEN(categories); i++) {
05962 if (!strcasecmp(categories[i], ctg)) {
05963 break;
05964 }
05965 }
05966 if (i < ARRAY_LEN(categories)) {
05967 continue;
05968 }
05969
05970 if (!(fg = register_group(ctg))) {
05971 continue;
05972 }
05973
05974 for (var = ast_variable_browse(cfg, ctg); var; var = var->next) {
05975 struct ast_call_feature *feature;
05976
05977 AST_RWLIST_RDLOCK(&feature_list);
05978 if (!(feature = find_dynamic_feature(var->name)) &&
05979 !(feature = ast_find_call_feature(var->name))) {
05980 AST_RWLIST_UNLOCK(&feature_list);
05981 ast_log(LOG_WARNING, "Feature '%s' was not found.\n", var->name);
05982 continue;
05983 }
05984 AST_RWLIST_UNLOCK(&feature_list);
05985
05986 register_group_feature(fg, var->value, feature);
05987 }
05988 }
05989
05990 AST_RWLIST_UNLOCK(&feature_groups);
05991
05992 return 0;
05993 }
05994
05995
05996
05997
05998
05999
06000
06001
06002
06003 static void destroy_dialplan_usage_context(struct parking_dp_context *doomed)
06004 {
06005 struct parking_dp_ramp *ramp;
06006 struct parking_dp_spaces *spaces;
06007
06008 while ((ramp = AST_LIST_REMOVE_HEAD(&doomed->access_extens, node))) {
06009 ast_free(ramp);
06010 }
06011 while ((spaces = AST_LIST_REMOVE_HEAD(&doomed->spaces, node))) {
06012 ast_free(spaces);
06013 }
06014 while ((spaces = AST_LIST_REMOVE_HEAD(&doomed->hints, node))) {
06015 ast_free(spaces);
06016 }
06017 ast_free(doomed);
06018 }
06019
06020
06021
06022
06023
06024
06025
06026
06027
06028 static void destroy_dialplan_usage_map(struct parking_dp_map *doomed)
06029 {
06030 struct parking_dp_context *item;
06031
06032 while ((item = AST_LIST_REMOVE_HEAD(doomed, node))) {
06033 destroy_dialplan_usage_context(item);
06034 }
06035 }
06036
06037
06038
06039
06040
06041
06042
06043
06044
06045
06046
06047 static struct parking_dp_ramp *build_dialplan_useage_ramp(const char *exten, int exclusive)
06048 {
06049 struct parking_dp_ramp *ramp_node;
06050
06051 ramp_node = ast_calloc(1, sizeof(*ramp_node) + strlen(exten));
06052 if (!ramp_node) {
06053 return NULL;
06054 }
06055 ramp_node->exclusive = exclusive;
06056 strcpy(ramp_node->exten, exten);
06057 return ramp_node;
06058 }
06059
06060
06061
06062
06063
06064
06065
06066
06067
06068
06069
06070
06071
06072
06073 static int usage_context_add_ramp(struct parking_dp_ramp_map *ramp_map, const char *exten, int exclusive, struct ast_parkinglot *lot, int complain)
06074 {
06075 struct parking_dp_ramp *cur_ramp;
06076 struct parking_dp_ramp *new_ramp;
06077 int cmp;
06078
06079
06080 if (exclusive) {
06081 exclusive = 1;
06082 }
06083
06084 AST_LIST_TRAVERSE_SAFE_BEGIN(ramp_map, cur_ramp, node) {
06085 cmp = strcmp(exten, cur_ramp->exten);
06086 if (cmp > 0) {
06087
06088 continue;
06089 }
06090 if (cmp == 0) {
06091
06092 if (complain && (cur_ramp->exclusive || exclusive)) {
06093 ast_log(LOG_WARNING,
06094 "Parking lot '%s' parkext %s@%s used by another parking lot.\n",
06095 lot->name, exten, lot->cfg.parking_con);
06096 }
06097 return 0;
06098 }
06099
06100 new_ramp = build_dialplan_useage_ramp(exten, exclusive);
06101 if (!new_ramp) {
06102 return -1;
06103 }
06104 AST_LIST_INSERT_BEFORE_CURRENT(new_ramp, node);
06105 return 0;
06106 }
06107 AST_LIST_TRAVERSE_SAFE_END;
06108
06109
06110 new_ramp = build_dialplan_useage_ramp(exten, exclusive);
06111 if (!new_ramp) {
06112 return -1;
06113 }
06114 AST_LIST_INSERT_TAIL(ramp_map, new_ramp, node);
06115 return 0;
06116 }
06117
06118
06119
06120
06121
06122
06123
06124
06125
06126
06127
06128 static struct parking_dp_spaces *build_dialplan_useage_spaces(int start, int stop)
06129 {
06130 struct parking_dp_spaces *spaces_node;
06131
06132 spaces_node = ast_calloc(1, sizeof(*spaces_node));
06133 if (!spaces_node) {
06134 return NULL;
06135 }
06136 spaces_node->start = start;
06137 spaces_node->stop = stop;
06138 return spaces_node;
06139 }
06140
06141
06142
06143
06144
06145
06146
06147
06148
06149
06150
06151
06152
06153
06154 static int usage_context_add_spaces(struct parking_dp_space_map *space_map, int start, int stop, struct ast_parkinglot *lot, int complain)
06155 {
06156 struct parking_dp_spaces *cur_node;
06157 struct parking_dp_spaces *expand_node;
06158 struct parking_dp_spaces *new_node;
06159
06160 expand_node = NULL;
06161 AST_LIST_TRAVERSE_SAFE_BEGIN(space_map, cur_node, node) {
06162
06163 if (expand_node) {
06164
06165 if (expand_node->stop + 1 < cur_node->start) {
06166
06167 return 0;
06168 }
06169
06170 if (complain
06171 && ((cur_node->start <= start && start <= cur_node->stop)
06172 || (cur_node->start <= stop && stop <= cur_node->stop)
06173 || (start < cur_node->start && cur_node->stop < stop))) {
06174
06175 complain = 0;
06176 ast_log(LOG_WARNING,
06177 "Parking lot '%s' parkpos %d-%d@%s overlaps another parking lot.\n",
06178 lot->name, start, stop, lot->cfg.parking_con);
06179 }
06180
06181
06182 if (expand_node->stop < cur_node->stop) {
06183 expand_node->stop = cur_node->stop;
06184 }
06185 AST_LIST_REMOVE_CURRENT(node);
06186 ast_free(cur_node);
06187 continue;
06188 }
06189
06190 if (cur_node->stop + 1 < start) {
06191
06192 continue;
06193 }
06194 if (stop + 1 < cur_node->start) {
06195
06196 new_node = build_dialplan_useage_spaces(start, stop);
06197 if (!new_node) {
06198 return -1;
06199 }
06200 AST_LIST_INSERT_BEFORE_CURRENT(new_node, node);
06201 return 0;
06202 }
06203
06204 if (complain
06205 && ((cur_node->start <= start && start <= cur_node->stop)
06206 || (cur_node->start <= stop && stop <= cur_node->stop)
06207 || (start < cur_node->start && cur_node->stop < stop))) {
06208
06209 complain = 0;
06210 ast_log(LOG_WARNING,
06211 "Parking lot '%s' parkpos %d-%d@%s overlaps another parking lot.\n",
06212 lot->name, start, stop, lot->cfg.parking_con);
06213 }
06214
06215
06216 if (start < cur_node->start) {
06217
06218 cur_node->start = start;
06219 }
06220 if (stop <= cur_node->stop) {
06221
06222 return 0;
06223 }
06224 cur_node->stop = stop;
06225 expand_node = cur_node;
06226 }
06227 AST_LIST_TRAVERSE_SAFE_END;
06228
06229 if (expand_node) {
06230
06231
06232
06233
06234 return 0;
06235 }
06236
06237
06238 new_node = build_dialplan_useage_spaces(start, stop);
06239 if (!new_node) {
06240 return -1;
06241 }
06242 AST_LIST_INSERT_TAIL(space_map, new_node, node);
06243 return 0;
06244 }
06245
06246
06247
06248
06249
06250
06251
06252
06253
06254
06255
06256
06257 static int dialplan_usage_add_parkinglot_data(struct parking_dp_context *ctx_node, struct ast_parkinglot *lot, int complain)
06258 {
06259 if (usage_context_add_ramp(&ctx_node->access_extens, lot->cfg.parkext,
06260 lot->cfg.parkext_exclusive, lot, complain)) {
06261 return -1;
06262 }
06263 if (usage_context_add_spaces(&ctx_node->spaces, lot->cfg.parking_start,
06264 lot->cfg.parking_stop, lot, complain)) {
06265 return -1;
06266 }
06267 if (lot->cfg.parkaddhints
06268 && usage_context_add_spaces(&ctx_node->hints, lot->cfg.parking_start,
06269 lot->cfg.parking_stop, lot, 0)) {
06270 return -1;
06271 }
06272 return 0;
06273 }
06274
06275
06276
06277
06278
06279
06280
06281
06282
06283
06284 static struct parking_dp_context *build_dialplan_useage_context(struct ast_parkinglot *lot)
06285 {
06286 struct parking_dp_context *ctx_node;
06287
06288 ctx_node = ast_calloc(1, sizeof(*ctx_node) + strlen(lot->cfg.parking_con));
06289 if (!ctx_node) {
06290 return NULL;
06291 }
06292 if (dialplan_usage_add_parkinglot_data(ctx_node, lot, 0)) {
06293 destroy_dialplan_usage_context(ctx_node);
06294 return NULL;
06295 }
06296 strcpy(ctx_node->context, lot->cfg.parking_con);
06297 return ctx_node;
06298 }
06299
06300
06301
06302
06303
06304
06305
06306
06307
06308
06309
06310
06311 static int dialplan_usage_add_parkinglot(struct parking_dp_map *usage_map, struct ast_parkinglot *lot, int complain)
06312 {
06313 struct parking_dp_context *cur_ctx;
06314 struct parking_dp_context *new_ctx;
06315 int cmp;
06316
06317 AST_LIST_TRAVERSE_SAFE_BEGIN(usage_map, cur_ctx, node) {
06318 cmp = strcmp(lot->cfg.parking_con, cur_ctx->context);
06319 if (cmp > 0) {
06320
06321 continue;
06322 }
06323 if (cmp == 0) {
06324
06325 return dialplan_usage_add_parkinglot_data(cur_ctx, lot, complain);
06326 }
06327
06328 new_ctx = build_dialplan_useage_context(lot);
06329 if (!new_ctx) {
06330 return -1;
06331 }
06332 AST_LIST_INSERT_BEFORE_CURRENT(new_ctx, node);
06333 return 0;
06334 }
06335 AST_LIST_TRAVERSE_SAFE_END;
06336
06337
06338 new_ctx = build_dialplan_useage_context(lot);
06339 if (!new_ctx) {
06340 return -1;
06341 }
06342 AST_LIST_INSERT_TAIL(usage_map, new_ctx, node);
06343 return 0;
06344 }
06345
06346
06347
06348
06349
06350
06351
06352
06353
06354
06355
06356 static int build_dialplan_useage_map(struct parking_dp_map *usage_map, int complain)
06357 {
06358 int status = 0;
06359 struct ao2_iterator iter;
06360 struct ast_parkinglot *curlot;
06361
06362
06363 iter = ao2_iterator_init(parkinglots, 0);
06364 for (; (curlot = ao2_iterator_next(&iter)); ao2_ref(curlot, -1)) {
06365
06366 if (dialplan_usage_add_parkinglot(usage_map, curlot, complain)) {
06367 ao2_ref(curlot, -1);
06368 status = -1;
06369 break;
06370 }
06371 }
06372 ao2_iterator_destroy(&iter);
06373
06374 return status;
06375 }
06376
06377
06378
06379
06380
06381
06382
06383
06384
06385
06386
06387 static void remove_exten_if_exist(const char *context, const char *exten, int priority)
06388 {
06389 struct pbx_find_info q = { .stacklen = 0 };
06390
06391 if (pbx_find_extension(NULL, NULL, &q, context, exten, priority, NULL, NULL,
06392 E_MATCH)) {
06393 ast_debug(1, "Removing unneeded parking lot exten: %s@%s priority:%d\n",
06394 context, exten, priority);
06395 ast_context_remove_extension(context, exten, priority, registrar);
06396 }
06397 }
06398
06399
06400
06401
06402
06403
06404
06405
06406
06407
06408
06409
06410
06411
06412
06413 static void remove_dead_ramp_usage(const char *context, struct parking_dp_ramp_map *old_ramps, struct parking_dp_ramp_map *new_ramps)
06414 {
06415 struct parking_dp_ramp *old_ramp;
06416 struct parking_dp_ramp *new_ramp;
06417 int cmp;
06418
06419 old_ramp = AST_LIST_FIRST(old_ramps);
06420 new_ramp = AST_LIST_FIRST(new_ramps);
06421
06422 while (new_ramp) {
06423 if (!old_ramp) {
06424
06425 return;
06426 }
06427 cmp = strcmp(old_ramp->exten, new_ramp->exten);
06428 if (cmp < 0) {
06429
06430 remove_exten_if_exist(context, old_ramp->exten, 1);
06431 old_ramp = AST_LIST_NEXT(old_ramp, node);
06432 continue;
06433 }
06434 if (cmp == 0) {
06435
06436 old_ramp = AST_LIST_NEXT(old_ramp, node);
06437 } else {
06438
06439 }
06440 new_ramp = AST_LIST_NEXT(new_ramp, node);
06441 }
06442
06443
06444 for (; old_ramp; old_ramp = AST_LIST_NEXT(old_ramp, node)) {
06445 remove_exten_if_exist(context, old_ramp->exten, 1);
06446 }
06447 }
06448
06449
06450
06451
06452
06453
06454
06455
06456
06457
06458 static void destroy_space(const char *context, int space)
06459 {
06460 char exten[AST_MAX_EXTENSION];
06461
06462
06463 snprintf(exten, sizeof(exten), "%d", space);
06464 remove_exten_if_exist(context, exten, PRIORITY_HINT);
06465 remove_exten_if_exist(context, exten, 1);
06466 }
06467
06468
06469
06470
06471
06472
06473
06474
06475
06476
06477
06478
06479
06480
06481
06482
06483 static void remove_dead_spaces_usage(const char *context,
06484 struct parking_dp_space_map *old_spaces, struct parking_dp_space_map *new_spaces,
06485 void (*destroy_space)(const char *context, int space))
06486 {
06487 struct parking_dp_spaces *old_range;
06488 struct parking_dp_spaces *new_range;
06489 int space;
06490 int stop;
06491
06492 old_range = AST_LIST_FIRST(old_spaces);
06493 new_range = AST_LIST_FIRST(new_spaces);
06494 space = -1;
06495
06496 while (old_range) {
06497 if (space < old_range->start) {
06498 space = old_range->start;
06499 }
06500 if (new_range) {
06501 if (space < new_range->start) {
06502
06503 if (old_range->stop < new_range->start) {
06504
06505 stop = old_range->stop;
06506 old_range = AST_LIST_NEXT(old_range, node);
06507 } else {
06508
06509 stop = new_range->start - 1;
06510 }
06511 } else if ( space <= new_range->stop) {
06512
06513 if (old_range->stop <= new_range->stop) {
06514
06515 old_range = AST_LIST_NEXT(old_range, node);
06516 } else {
06517
06518 space = new_range->stop + 1;
06519 new_range = AST_LIST_NEXT(new_range, node);
06520 }
06521 continue;
06522 } else {
06523
06524 new_range = AST_LIST_NEXT(new_range, node);
06525 continue;
06526 }
06527 } else {
06528
06529 stop = old_range->stop;
06530 old_range = AST_LIST_NEXT(old_range, node);
06531 }
06532
06533
06534 for (; space <= stop; ++space) {
06535 destroy_space(context, space);
06536 }
06537 }
06538 }
06539
06540
06541
06542
06543
06544
06545
06546
06547
06548
06549
06550
06551
06552
06553
06554 static void remove_dead_context_usage(const char *context, struct parking_dp_context *old_ctx, struct parking_dp_context *new_ctx)
06555 {
06556 remove_dead_ramp_usage(context, &old_ctx->access_extens, &new_ctx->access_extens);
06557 remove_dead_spaces_usage(context, &old_ctx->spaces, &new_ctx->spaces, destroy_space);
06558 #if 0
06559
06560 remove_dead_spaces_usage(context, &old_ctx->hints, &new_ctx->hints, destroy_space_hint);
06561 #endif
06562 }
06563
06564
06565
06566
06567
06568
06569
06570
06571
06572
06573
06574
06575
06576
06577 static void remove_dead_dialplan_useage(struct parking_dp_map *old_map, struct parking_dp_map *new_map)
06578 {
06579 struct parking_dp_context *old_ctx;
06580 struct parking_dp_context *new_ctx;
06581 struct ast_context *con;
06582 int cmp;
06583
06584 old_ctx = AST_LIST_FIRST(old_map);
06585 new_ctx = AST_LIST_FIRST(new_map);
06586
06587 while (new_ctx) {
06588 if (!old_ctx) {
06589
06590 return;
06591 }
06592 cmp = strcmp(old_ctx->context, new_ctx->context);
06593 if (cmp < 0) {
06594
06595 con = ast_context_find(old_ctx->context);
06596 if (con) {
06597 ast_context_destroy(con, registrar);
06598 }
06599 old_ctx = AST_LIST_NEXT(old_ctx, node);
06600 continue;
06601 }
06602 if (cmp == 0) {
06603
06604 remove_dead_context_usage(old_ctx->context, old_ctx, new_ctx);
06605 old_ctx = AST_LIST_NEXT(old_ctx, node);
06606 } else {
06607
06608 }
06609 new_ctx = AST_LIST_NEXT(new_ctx, node);
06610 }
06611
06612
06613 for (; old_ctx; old_ctx = AST_LIST_NEXT(old_ctx, node)) {
06614 con = ast_context_find(old_ctx->context);
06615 if (con) {
06616 ast_context_destroy(con, registrar);
06617 }
06618 }
06619 }
06620
06621 static int parkinglot_markall_cb(void *obj, void *arg, int flags)
06622 {
06623 struct ast_parkinglot *parkinglot = obj;
06624
06625 parkinglot->the_mark = 1;
06626 return 0;
06627 }
06628
06629 static int parkinglot_is_marked_cb(void *obj, void *arg, int flags)
06630 {
06631 struct ast_parkinglot *parkinglot = obj;
06632
06633 if (parkinglot->the_mark) {
06634 if (AST_LIST_EMPTY(&parkinglot->parkings)) {
06635
06636 return CMP_MATCH;
06637 }
06638
06639 ast_log(LOG_WARNING,
06640 "Parking lot %s has parked calls. Could not remove.\n",
06641 parkinglot->name);
06642 parkinglot->disabled = 1;
06643 force_reload_load = 1;
06644 }
06645
06646 return 0;
06647 }
06648
06649 static int parkinglot_activate_cb(void *obj, void *arg, int flags)
06650 {
06651 struct ast_parkinglot *parkinglot = obj;
06652
06653 if (parkinglot->the_mark) {
06654
06655
06656
06657
06658 return 0;
06659 }
06660
06661 if (parkinglot_activate(parkinglot)) {
06662
06663
06664
06665
06666 force_reload_load = 1;
06667 ast_log(LOG_WARNING, "Parking lot %s not open for business.\n", parkinglot->name);
06668 } else {
06669 ast_debug(1, "Parking lot %s now open for business. (parkpos %d-%d)\n",
06670 parkinglot->name, parkinglot->cfg.parking_start,
06671 parkinglot->cfg.parking_stop);
06672 }
06673
06674 return 0;
06675 }
06676
06677 static int load_config(int reload)
06678 {
06679 struct ast_flags config_flags = {
06680 reload && !force_reload_load ? CONFIG_FLAG_FILEUNCHANGED : 0 };
06681 struct ast_config *cfg;
06682 struct parking_dp_map old_usage_map = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
06683 struct parking_dp_map new_usage_map = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
06684
06685
06686 force_reload_load = 0;
06687
06688 if (!default_parkinglot) {
06689
06690 default_parkinglot = build_parkinglot(DEFAULT_PARKINGLOT, NULL);
06691 if (!default_parkinglot) {
06692 ast_log(LOG_ERROR, "Configuration of default default parking lot failed.\n");
06693 return -1;
06694 }
06695 ast_debug(1, "Configuration of default default parking lot done.\n");
06696 }
06697
06698 cfg = ast_config_load2("features.conf", "features", config_flags);
06699 if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
06700
06701 ast_debug(1, "features.conf did not change.\n");
06702 return 0;
06703 }
06704 if (cfg == CONFIG_STATUS_FILEMISSING
06705 || cfg == CONFIG_STATUS_FILEINVALID) {
06706 ast_log(LOG_WARNING, "Could not load features.conf\n");
06707 return 0;
06708 }
06709
06710
06711 if (build_dialplan_useage_map(&old_usage_map, 0)) {
06712 destroy_dialplan_usage_map(&old_usage_map);
06713
06714
06715 force_reload_load = 1;
06716 return -1;
06717 }
06718
06719 ao2_t_callback(parkinglots, OBJ_NODATA, parkinglot_markall_cb, NULL,
06720 "callback to mark all parking lots");
06721 process_config(cfg);
06722 ast_config_destroy(cfg);
06723 ao2_t_callback(parkinglots, OBJ_NODATA | OBJ_UNLINK, parkinglot_is_marked_cb, NULL,
06724 "callback to remove marked parking lots");
06725
06726
06727 if (build_dialplan_useage_map(&new_usage_map, 1)) {
06728
06729
06730
06731
06732
06733 destroy_dialplan_usage_map(&old_usage_map);
06734 destroy_dialplan_usage_map(&new_usage_map);
06735 return -1;
06736 }
06737
06738
06739 remove_dead_dialplan_useage(&old_usage_map, &new_usage_map);
06740
06741 destroy_dialplan_usage_map(&old_usage_map);
06742 destroy_dialplan_usage_map(&new_usage_map);
06743
06744 ao2_t_callback(parkinglots, OBJ_NODATA, parkinglot_activate_cb, NULL,
06745 "callback to activate all parking lots");
06746
06747 return 0;
06748 }
06749
06750
06751
06752
06753
06754
06755
06756
06757
06758
06759 static char *handle_feature_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
06760 {
06761 int i;
06762 struct ast_call_feature *feature;
06763 struct ao2_iterator iter;
06764 struct ast_parkinglot *curlot;
06765 #define HFS_FORMAT "%-25s %-7s %-7s\n"
06766
06767 switch (cmd) {
06768
06769 case CLI_INIT:
06770 e->command = "features show";
06771 e->usage =
06772 "Usage: features show\n"
06773 " Lists configured features\n";
06774 return NULL;
06775 case CLI_GENERATE:
06776 return NULL;
06777 }
06778
06779 ast_cli(a->fd, HFS_FORMAT, "Builtin Feature", "Default", "Current");
06780 ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
06781
06782 ast_cli(a->fd, HFS_FORMAT, "Pickup", "*8", ast_pickup_ext());
06783
06784 ast_rwlock_rdlock(&features_lock);
06785 for (i = 0; i < FEATURES_COUNT; i++)
06786 ast_cli(a->fd, HFS_FORMAT, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
06787 ast_rwlock_unlock(&features_lock);
06788
06789 ast_cli(a->fd, "\n");
06790 ast_cli(a->fd, HFS_FORMAT, "Dynamic Feature", "Default", "Current");
06791 ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
06792 if (AST_RWLIST_EMPTY(&feature_list)) {
06793 ast_cli(a->fd, "(none)\n");
06794 } else {
06795 AST_RWLIST_RDLOCK(&feature_list);
06796 AST_RWLIST_TRAVERSE(&feature_list, feature, feature_entry) {
06797 ast_cli(a->fd, HFS_FORMAT, feature->sname, "no def", feature->exten);
06798 }
06799 AST_RWLIST_UNLOCK(&feature_list);
06800 }
06801
06802 ast_cli(a->fd, "\nFeature Groups:\n");
06803 ast_cli(a->fd, "---------------\n");
06804 if (AST_RWLIST_EMPTY(&feature_groups)) {
06805 ast_cli(a->fd, "(none)\n");
06806 } else {
06807 struct feature_group *fg;
06808 struct feature_group_exten *fge;
06809
06810 AST_RWLIST_RDLOCK(&feature_groups);
06811 AST_RWLIST_TRAVERSE(&feature_groups, fg, entry) {
06812 ast_cli(a->fd, "===> Group: %s\n", fg->gname);
06813 AST_LIST_TRAVERSE(&fg->features, fge, entry) {
06814 ast_cli(a->fd, "===> --> %s (%s)\n", fge->feature->sname, fge->exten);
06815 }
06816 }
06817 AST_RWLIST_UNLOCK(&feature_groups);
06818 }
06819
06820 iter = ao2_iterator_init(parkinglots, 0);
06821 while ((curlot = ao2_iterator_next(&iter))) {
06822 ast_cli(a->fd, "\nCall parking (Parking lot: %s)\n", curlot->name);
06823 ast_cli(a->fd, "------------\n");
06824 ast_cli(a->fd,"%-22s: %s\n", "Parking extension", curlot->cfg.parkext);
06825 ast_cli(a->fd,"%-22s: %s\n", "Parking context", curlot->cfg.parking_con);
06826 ast_cli(a->fd,"%-22s: %d-%d\n", "Parked call extensions",
06827 curlot->cfg.parking_start, curlot->cfg.parking_stop);
06828 ast_cli(a->fd,"%-22s: %d ms\n", "Parkingtime", curlot->cfg.parkingtime);
06829 ast_cli(a->fd,"%-22s: %s\n", "MusicOnHold class", curlot->cfg.mohclass);
06830 ast_cli(a->fd,"%-22s: %s\n", "Enabled", AST_CLI_YESNO(!curlot->disabled));
06831 ast_cli(a->fd,"\n");
06832 ao2_ref(curlot, -1);
06833 }
06834 ao2_iterator_destroy(&iter);
06835
06836 return CLI_SUCCESS;
06837 }
06838
06839 int ast_features_reload(void)
06840 {
06841 struct ast_context *con;
06842 int res;
06843
06844 ast_mutex_lock(&features_reload_lock);
06845
06846
06847
06848
06849
06850
06851
06852
06853
06854 con = ast_context_find(parking_con_dial);
06855 if (con) {
06856 ast_context_destroy(con, registrar);
06857 }
06858
06859 res = load_config(1);
06860 ast_mutex_unlock(&features_reload_lock);
06861
06862 return res;
06863 }
06864
06865 static char *handle_features_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
06866 {
06867 switch (cmd) {
06868 case CLI_INIT:
06869 e->command = "features reload";
06870 e->usage =
06871 "Usage: features reload\n"
06872 " Reloads configured call features from features.conf\n";
06873 return NULL;
06874 case CLI_GENERATE:
06875 return NULL;
06876 }
06877 ast_features_reload();
06878
06879 return CLI_SUCCESS;
06880 }
06881
06882
06883
06884
06885
06886
06887
06888
06889
06890
06891
06892
06893 static int do_bridge_masquerade(struct ast_channel *chan, struct ast_channel *tmpchan)
06894 {
06895 const char *context;
06896 const char *exten;
06897 int priority;
06898
06899 ast_moh_stop(chan);
06900 ast_channel_lock_both(chan, tmpchan);
06901 context = ast_strdupa(chan->context);
06902 exten = ast_strdupa(chan->exten);
06903 priority = chan->priority;
06904 ast_setstate(tmpchan, chan->_state);
06905 tmpchan->readformat = chan->readformat;
06906 tmpchan->writeformat = chan->writeformat;
06907 ast_channel_unlock(chan);
06908 ast_channel_unlock(tmpchan);
06909
06910
06911 if (ast_channel_masquerade(tmpchan, chan)) {
06912 return -1;
06913 }
06914 ast_do_masquerade(tmpchan);
06915
06916
06917 ast_explicit_goto(tmpchan, context, exten, priority + 1);
06918
06919 return 0;
06920 }
06921
06922
06923
06924
06925
06926
06927
06928
06929
06930
06931
06932
06933
06934
06935 static int action_bridge(struct mansession *s, const struct message *m)
06936 {
06937 const char *channela = astman_get_header(m, "Channel1");
06938 const char *channelb = astman_get_header(m, "Channel2");
06939 const char *playtone = astman_get_header(m, "Tone");
06940 struct ast_channel *chana = NULL, *chanb = NULL, *chans[2];
06941 struct ast_channel *tmpchana = NULL, *tmpchanb = NULL;
06942 struct ast_bridge_thread_obj *tobj = NULL;
06943 char buf[256];
06944
06945
06946 if (ast_strlen_zero(channela) || ast_strlen_zero(channelb)) {
06947 astman_send_error(s, m, "Missing channel parameter in request");
06948 return 0;
06949 }
06950
06951
06952 chana = ast_channel_get_by_name_prefix(channela, strlen(channela));
06953 if (!chana) {
06954 snprintf(buf, sizeof(buf), "Channel1 does not exists: %s", channela);
06955 astman_send_error(s, m, buf);
06956 return 0;
06957 }
06958
06959
06960 if (chana->_state != AST_STATE_UP)
06961 ast_answer(chana);
06962
06963
06964 if (!(tmpchana = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
06965 NULL, NULL, chana->linkedid, 0, "Bridge/%s", chana->name))) {
06966 astman_send_error(s, m, "Unable to create temporary channel!");
06967 chana = ast_channel_unref(chana);
06968 return 0;
06969 }
06970
06971 if (do_bridge_masquerade(chana, tmpchana)) {
06972 snprintf(buf, sizeof(buf), "Unable to masquerade channel %s!", channela);
06973 astman_send_error(s, m, buf);
06974 ast_hangup(tmpchana);
06975 chana = ast_channel_unref(chana);
06976 return 0;
06977 }
06978
06979 chana = ast_channel_unref(chana);
06980
06981
06982 chanb = ast_channel_get_by_name_prefix(channelb, strlen(channelb));
06983 if (!chanb) {
06984 snprintf(buf, sizeof(buf), "Channel2 does not exists: %s", channelb);
06985 astman_send_error(s, m, buf);
06986 ast_hangup(tmpchana);
06987 return 0;
06988 }
06989
06990
06991 if (chanb->_state != AST_STATE_UP)
06992 ast_answer(chanb);
06993
06994
06995 if (!(tmpchanb = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
06996 NULL, NULL, chanb->linkedid, 0, "Bridge/%s", chanb->name))) {
06997 astman_send_error(s, m, "Unable to create temporary channels!");
06998 ast_hangup(tmpchana);
06999 chanb = ast_channel_unref(chanb);
07000 return 0;
07001 }
07002
07003 if (do_bridge_masquerade(chanb, tmpchanb)) {
07004 snprintf(buf, sizeof(buf), "Unable to masquerade channel %s!", channelb);
07005 astman_send_error(s, m, buf);
07006 ast_hangup(tmpchana);
07007 ast_hangup(tmpchanb);
07008 chanb = ast_channel_unref(chanb);
07009 return 0;
07010 }
07011
07012 chanb = ast_channel_unref(chanb);
07013
07014
07015 if (ast_channel_make_compatible(tmpchana, tmpchanb)) {
07016 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for manager bridge\n", tmpchana->name, tmpchanb->name);
07017 astman_send_error(s, m, "Could not make channels compatible for manager bridge");
07018 ast_hangup(tmpchana);
07019 ast_hangup(tmpchanb);
07020 return 0;
07021 }
07022
07023
07024 if (!(tobj = ast_calloc(1, sizeof(*tobj)))) {
07025 ast_log(LOG_WARNING, "Unable to spawn a new bridge thread on %s and %s: %s\n", tmpchana->name, tmpchanb->name, strerror(errno));
07026 astman_send_error(s, m, "Unable to spawn a new bridge thread");
07027 ast_hangup(tmpchana);
07028 ast_hangup(tmpchanb);
07029 return 0;
07030 }
07031
07032 tobj->chan = tmpchana;
07033 tobj->peer = tmpchanb;
07034 tobj->return_to_pbx = 1;
07035
07036 if (ast_true(playtone)) {
07037 if (!ast_strlen_zero(xfersound) && !ast_streamfile(tmpchanb, xfersound, tmpchanb->language)) {
07038 if (ast_waitstream(tmpchanb, "") < 0)
07039 ast_log(LOG_WARNING, "Failed to play a courtesy tone on chan %s\n", tmpchanb->name);
07040 }
07041 }
07042
07043 chans[0] = tmpchana;
07044 chans[1] = tmpchanb;
07045
07046 ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeAction", 2, chans,
07047 "Response: Success\r\n"
07048 "Channel1: %s\r\n"
07049 "Channel2: %s\r\n", tmpchana->name, tmpchanb->name);
07050
07051 bridge_call_thread_launch(tobj);
07052
07053 astman_send_ack(s, m, "Launched bridge thread with success");
07054
07055 return 0;
07056 }
07057
07058
07059
07060
07061
07062
07063
07064
07065
07066
07067
07068
07069 static char *handle_parkedcalls(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
07070 {
07071 struct parkeduser *cur;
07072 int numparked = 0;
07073 struct ao2_iterator iter;
07074 struct ast_parkinglot *curlot;
07075
07076 switch (cmd) {
07077 case CLI_INIT:
07078 e->command = "parkedcalls show";
07079 e->usage =
07080 "Usage: parkedcalls show\n"
07081 " List currently parked calls\n";
07082 return NULL;
07083 case CLI_GENERATE:
07084 return NULL;
07085 }
07086
07087 if (a->argc > e->args)
07088 return CLI_SHOWUSAGE;
07089
07090 ast_cli(a->fd, "%-10s %-25s (%-15s %-12s %4s) %s\n", "Num", "Channel",
07091 "Context", "Extension", "Pri", "Timeout");
07092
07093 iter = ao2_iterator_init(parkinglots, 0);
07094 while ((curlot = ao2_iterator_next(&iter))) {
07095 int lotparked = 0;
07096
07097
07098 ast_cli(a->fd, "*** Parking lot: %s (%d)\n", curlot->name,
07099 ao2_ref(curlot, 0) - 2 - (curlot == default_parkinglot));
07100
07101 AST_LIST_LOCK(&curlot->parkings);
07102 AST_LIST_TRAVERSE(&curlot->parkings, cur, list) {
07103 ast_cli(a->fd, "%-10.10s %-25s (%-15s %-12s %4d) %6lds\n",
07104 cur->parkingexten, cur->chan->name, cur->context, cur->exten,
07105 cur->priority,
07106 (long) (cur->start.tv_sec + (cur->parkingtime / 1000) - time(NULL)));
07107 ++lotparked;
07108 }
07109 AST_LIST_UNLOCK(&curlot->parkings);
07110 if (lotparked) {
07111 numparked += lotparked;
07112 ast_cli(a->fd, " %d parked call%s in parking lot %s\n", lotparked,
07113 ESS(lotparked), curlot->name);
07114 }
07115
07116 ao2_ref(curlot, -1);
07117 }
07118 ao2_iterator_destroy(&iter);
07119
07120 ast_cli(a->fd, "---\n%d parked call%s in total.\n", numparked, ESS(numparked));
07121
07122 return CLI_SUCCESS;
07123 }
07124
07125 static struct ast_cli_entry cli_features[] = {
07126 AST_CLI_DEFINE(handle_feature_show, "Lists configured features"),
07127 AST_CLI_DEFINE(handle_features_reload, "Reloads configured features"),
07128 AST_CLI_DEFINE(handle_parkedcalls, "List currently parked calls"),
07129 };
07130
07131
07132
07133
07134
07135
07136
07137
07138
07139 static int manager_parking_status(struct mansession *s, const struct message *m)
07140 {
07141 struct parkeduser *cur;
07142 const char *id = astman_get_header(m, "ActionID");
07143 char idText[256] = "";
07144 struct ao2_iterator iter;
07145 struct ast_parkinglot *curlot;
07146 int numparked = 0;
07147
07148 if (!ast_strlen_zero(id))
07149 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
07150
07151 astman_send_ack(s, m, "Parked calls will follow");
07152
07153 iter = ao2_iterator_init(parkinglots, 0);
07154 while ((curlot = ao2_iterator_next(&iter))) {
07155 AST_LIST_LOCK(&curlot->parkings);
07156 AST_LIST_TRAVERSE(&curlot->parkings, cur, list) {
07157 astman_append(s, "Event: ParkedCall\r\n"
07158 "Parkinglot: %s\r\n"
07159 "Exten: %d\r\n"
07160 "Channel: %s\r\n"
07161 "From: %s\r\n"
07162 "Timeout: %ld\r\n"
07163 "CallerIDNum: %s\r\n"
07164 "CallerIDName: %s\r\n"
07165 "ConnectedLineNum: %s\r\n"
07166 "ConnectedLineName: %s\r\n"
07167 "%s"
07168 "\r\n",
07169 curlot->name,
07170 cur->parkingnum, cur->chan->name, cur->peername,
07171 (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
07172 S_COR(cur->chan->caller.id.number.valid, cur->chan->caller.id.number.str, ""),
07173 S_COR(cur->chan->caller.id.name.valid, cur->chan->caller.id.name.str, ""),
07174 S_COR(cur->chan->connected.id.number.valid, cur->chan->connected.id.number.str, ""),
07175 S_COR(cur->chan->connected.id.name.valid, cur->chan->connected.id.name.str, ""),
07176 idText);
07177 ++numparked;
07178 }
07179 AST_LIST_UNLOCK(&curlot->parkings);
07180 ao2_ref(curlot, -1);
07181 }
07182 ao2_iterator_destroy(&iter);
07183
07184 astman_append(s,
07185 "Event: ParkedCallsComplete\r\n"
07186 "Total: %d\r\n"
07187 "%s"
07188 "\r\n",
07189 numparked, idText);
07190
07191 return RESULT_SUCCESS;
07192 }
07193
07194
07195
07196
07197
07198
07199
07200
07201
07202
07203
07204
07205 static int manager_park(struct mansession *s, const struct message *m)
07206 {
07207 const char *channel = astman_get_header(m, "Channel");
07208 const char *channel2 = astman_get_header(m, "Channel2");
07209 const char *timeout = astman_get_header(m, "Timeout");
07210 const char *parkinglotname = astman_get_header(m, "Parkinglot");
07211 char buf[BUFSIZ];
07212 int res = 0;
07213 struct ast_channel *ch1, *ch2;
07214 struct ast_park_call_args args = {
07215
07216
07217
07218
07219
07220
07221
07222
07223
07224
07225
07226
07227
07228
07229
07230
07231
07232
07233
07234 .flags = AST_PARK_OPT_SILENCE,
07235 };
07236
07237 if (ast_strlen_zero(channel)) {
07238 astman_send_error(s, m, "Channel not specified");
07239 return 0;
07240 }
07241
07242 if (ast_strlen_zero(channel2)) {
07243 astman_send_error(s, m, "Channel2 not specified");
07244 return 0;
07245 }
07246
07247 if (!ast_strlen_zero(timeout)) {
07248 if (sscanf(timeout, "%30d", &args.timeout) != 1) {
07249 astman_send_error(s, m, "Invalid timeout value.");
07250 return 0;
07251 }
07252 }
07253
07254 if (!(ch1 = ast_channel_get_by_name(channel))) {
07255 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
07256 astman_send_error(s, m, buf);
07257 return 0;
07258 }
07259
07260 if (!(ch2 = ast_channel_get_by_name(channel2))) {
07261 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
07262 astman_send_error(s, m, buf);
07263 ast_channel_unref(ch1);
07264 return 0;
07265 }
07266
07267 if (!ast_strlen_zero(parkinglotname)) {
07268 args.parkinglot = find_parkinglot(parkinglotname);
07269 }
07270
07271 res = masq_park_call(ch1, ch2, &args);
07272 if (!res) {
07273 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
07274 astman_send_ack(s, m, "Park successful");
07275 } else {
07276 astman_send_error(s, m, "Park failure");
07277 }
07278
07279 if (args.parkinglot) {
07280 parkinglot_unref(args.parkinglot);
07281 }
07282 ch1 = ast_channel_unref(ch1);
07283 ch2 = ast_channel_unref(ch2);
07284
07285 return 0;
07286 }
07287
07288
07289
07290
07291
07292
07293
07294 static const struct ast_datastore_info pickup_active = {
07295 .type = "pickup-active",
07296 };
07297
07298 int ast_can_pickup(struct ast_channel *chan)
07299 {
07300 if (!chan->pbx && !chan->masq && !ast_test_flag(chan, AST_FLAG_ZOMBIE)
07301 && (chan->_state == AST_STATE_RINGING
07302 || chan->_state == AST_STATE_RING
07303
07304
07305
07306
07307
07308
07309 || chan->_state == AST_STATE_DOWN)
07310 && !ast_channel_datastore_find(chan, &pickup_active, NULL)) {
07311 return 1;
07312 }
07313 return 0;
07314 }
07315
07316 static int find_channel_by_group(void *obj, void *arg, void *data, int flags)
07317 {
07318 struct ast_channel *target = obj;
07319 struct ast_channel *chan = data;
07320
07321 ast_channel_lock(target);
07322 if (chan != target && (chan->pickupgroup & target->callgroup)
07323 && ast_can_pickup(target)) {
07324
07325 return CMP_MATCH | CMP_STOP;
07326 }
07327 ast_channel_unlock(target);
07328
07329 return 0;
07330 }
07331
07332
07333
07334
07335
07336
07337
07338
07339
07340 int ast_pickup_call(struct ast_channel *chan)
07341 {
07342 struct ast_channel *target;
07343 int res = -1;
07344 ast_debug(1, "pickup attempt by %s\n", chan->name);
07345
07346
07347 target = ast_channel_callback(find_channel_by_group, NULL, chan, 0);
07348 if (target) {
07349 ast_log(LOG_NOTICE, "pickup %s attempt by %s\n", target->name, chan->name);
07350
07351 res = ast_do_pickup(chan, target);
07352 ast_channel_unlock(target);
07353 if (!res) {
07354 if (!ast_strlen_zero(pickupsound)) {
07355 pbx_builtin_setvar_helper(target, "BRIDGE_PLAY_SOUND", pickupsound);
07356 }
07357 } else {
07358 ast_log(LOG_WARNING, "pickup %s failed by %s\n", target->name, chan->name);
07359 }
07360 target = ast_channel_unref(target);
07361 }
07362
07363 if (res < 0) {
07364 ast_debug(1, "No call pickup possible... for %s\n", chan->name);
07365 if (!ast_strlen_zero(pickupfailsound)) {
07366 ast_answer(chan);
07367 ast_stream_and_wait(chan, pickupfailsound, "");
07368 }
07369 }
07370
07371 return res;
07372 }
07373
07374 int ast_do_pickup(struct ast_channel *chan, struct ast_channel *target)
07375 {
07376 struct ast_party_connected_line connected_caller;
07377 struct ast_channel *chans[2] = { chan, target };
07378 struct ast_datastore *ds_pickup;
07379 const char *chan_name;
07380 const char *target_name;
07381 int res = -1;
07382
07383 target_name = ast_strdupa(target->name);
07384 ast_debug(1, "Call pickup on '%s' by '%s'\n", target_name, chan->name);
07385
07386
07387 ds_pickup = ast_datastore_alloc(&pickup_active, NULL);
07388 if (!ds_pickup) {
07389 ast_log(LOG_WARNING,
07390 "Unable to create channel datastore on '%s' for call pickup\n", target_name);
07391 return -1;
07392 }
07393 ast_channel_datastore_add(target, ds_pickup);
07394
07395 ast_party_connected_line_init(&connected_caller);
07396 ast_party_connected_line_copy(&connected_caller, &target->connected);
07397 ast_channel_unlock(target);
07398 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
07399 if (ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) {
07400 ast_channel_update_connected_line(chan, &connected_caller, NULL);
07401 }
07402 ast_party_connected_line_free(&connected_caller);
07403
07404 ast_channel_lock(chan);
07405 chan_name = ast_strdupa(chan->name);
07406 ast_connected_line_copy_from_caller(&connected_caller, &chan->caller);
07407 ast_channel_unlock(chan);
07408 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
07409
07410 ast_cel_report_event(target, AST_CEL_PICKUP, NULL, NULL, chan);
07411
07412 if (ast_answer(chan)) {
07413 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name);
07414 goto pickup_failed;
07415 }
07416
07417 if (ast_queue_control(chan, AST_CONTROL_ANSWER)) {
07418 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan_name);
07419 goto pickup_failed;
07420 }
07421
07422 ast_channel_queue_connected_line_update(chan, &connected_caller, NULL);
07423
07424
07425 ast_set_flag(chan, AST_FLAG_ANSWERED_ELSEWHERE);
07426
07427 if (ast_channel_masquerade(target, chan)) {
07428 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan_name,
07429 target_name);
07430 goto pickup_failed;
07431 }
07432
07433
07434 ast_manager_event_multichan(EVENT_FLAG_CALL, "Pickup", 2, chans,
07435 "Channel: %s\r\n"
07436 "TargetChannel: %s\r\n",
07437 chan_name, target_name);
07438
07439
07440 ast_do_masquerade(target);
07441 res = 0;
07442
07443 pickup_failed:
07444 ast_channel_lock(target);
07445 if (!ast_channel_datastore_remove(target, ds_pickup)) {
07446 ast_datastore_free(ds_pickup);
07447 }
07448 ast_party_connected_line_free(&connected_caller);
07449
07450 return res;
07451 }
07452
07453 static char *app_bridge = "Bridge";
07454
07455 enum {
07456 BRIDGE_OPT_PLAYTONE = (1 << 0),
07457 OPT_CALLEE_HANGUP = (1 << 1),
07458 OPT_CALLER_HANGUP = (1 << 2),
07459 OPT_DURATION_LIMIT = (1 << 3),
07460 OPT_DURATION_STOP = (1 << 4),
07461 OPT_CALLEE_TRANSFER = (1 << 5),
07462 OPT_CALLER_TRANSFER = (1 << 6),
07463 OPT_CALLEE_MONITOR = (1 << 7),
07464 OPT_CALLER_MONITOR = (1 << 8),
07465 OPT_CALLEE_PARK = (1 << 9),
07466 OPT_CALLER_PARK = (1 << 10),
07467 OPT_CALLEE_KILL = (1 << 11),
07468 };
07469
07470 enum {
07471 OPT_ARG_DURATION_LIMIT = 0,
07472 OPT_ARG_DURATION_STOP,
07473
07474 OPT_ARG_ARRAY_SIZE,
07475 };
07476
07477 AST_APP_OPTIONS(bridge_exec_options, BEGIN_OPTIONS
07478 AST_APP_OPTION('p', BRIDGE_OPT_PLAYTONE),
07479 AST_APP_OPTION('h', OPT_CALLEE_HANGUP),
07480 AST_APP_OPTION('H', OPT_CALLER_HANGUP),
07481 AST_APP_OPTION('k', OPT_CALLEE_PARK),
07482 AST_APP_OPTION('K', OPT_CALLER_PARK),
07483 AST_APP_OPTION_ARG('L', OPT_DURATION_LIMIT, OPT_ARG_DURATION_LIMIT),
07484 AST_APP_OPTION_ARG('S', OPT_DURATION_STOP, OPT_ARG_DURATION_STOP),
07485 AST_APP_OPTION('t', OPT_CALLEE_TRANSFER),
07486 AST_APP_OPTION('T', OPT_CALLER_TRANSFER),
07487 AST_APP_OPTION('w', OPT_CALLEE_MONITOR),
07488 AST_APP_OPTION('W', OPT_CALLER_MONITOR),
07489 AST_APP_OPTION('x', OPT_CALLEE_KILL),
07490 END_OPTIONS );
07491
07492 int ast_bridge_timelimit(struct ast_channel *chan, struct ast_bridge_config *config,
07493 char *parse, struct timeval *calldurationlimit)
07494 {
07495 char *stringp = ast_strdupa(parse);
07496 char *limit_str, *warning_str, *warnfreq_str;
07497 const char *var;
07498 int play_to_caller = 0, play_to_callee = 0;
07499 int delta;
07500
07501 limit_str = strsep(&stringp, ":");
07502 warning_str = strsep(&stringp, ":");
07503 warnfreq_str = strsep(&stringp, ":");
07504
07505 config->timelimit = atol(limit_str);
07506 if (warning_str)
07507 config->play_warning = atol(warning_str);
07508 if (warnfreq_str)
07509 config->warning_freq = atol(warnfreq_str);
07510
07511 if (!config->timelimit) {
07512 ast_log(LOG_WARNING, "Bridge does not accept L(%s), hanging up.\n", limit_str);
07513 config->timelimit = config->play_warning = config->warning_freq = 0;
07514 config->warning_sound = NULL;
07515 return -1;
07516 } else if ( (delta = config->play_warning - config->timelimit) > 0) {
07517 int w = config->warning_freq;
07518
07519
07520
07521
07522
07523
07524
07525
07526
07527
07528
07529
07530
07531
07532
07533 if (w == 0) {
07534 config->play_warning = 0;
07535 } else {
07536 config->play_warning -= w * ( 1 + (delta-1)/w );
07537 if (config->play_warning < 1)
07538 config->play_warning = config->warning_freq = 0;
07539 }
07540 }
07541
07542 ast_channel_lock(chan);
07543
07544 var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLER");
07545 play_to_caller = var ? ast_true(var) : 1;
07546
07547 var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLEE");
07548 play_to_callee = var ? ast_true(var) : 0;
07549
07550 if (!play_to_caller && !play_to_callee)
07551 play_to_caller = 1;
07552
07553 var = pbx_builtin_getvar_helper(chan, "LIMIT_WARNING_FILE");
07554 config->warning_sound = !ast_strlen_zero(var) ? ast_strdup(var) : ast_strdup("timeleft");
07555
07556
07557
07558
07559
07560
07561
07562 var = pbx_builtin_getvar_helper(chan, "LIMIT_TIMEOUT_FILE");
07563 config->end_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL;
07564
07565 var = pbx_builtin_getvar_helper(chan, "LIMIT_CONNECT_FILE");
07566 config->start_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL;
07567
07568 ast_channel_unlock(chan);
07569
07570
07571 calldurationlimit->tv_sec = 0;
07572 calldurationlimit->tv_usec = 0;
07573
07574
07575 if (!config->play_warning && !config->start_sound && !config->end_sound && config->timelimit) {
07576 calldurationlimit->tv_sec = config->timelimit / 1000;
07577 calldurationlimit->tv_usec = (config->timelimit % 1000) * 1000;
07578 ast_verb(3, "Setting call duration limit to %.3lf seconds.\n",
07579 calldurationlimit->tv_sec + calldurationlimit->tv_usec / 1000000.0);
07580 config->timelimit = play_to_caller = play_to_callee =
07581 config->play_warning = config->warning_freq = 0;
07582 } else {
07583 ast_verb(4, "Limit Data for this call:\n");
07584 ast_verb(4, "timelimit = %ld ms (%.3lf s)\n", config->timelimit, config->timelimit / 1000.0);
07585 ast_verb(4, "play_warning = %ld ms (%.3lf s)\n", config->play_warning, config->play_warning / 1000.0);
07586 ast_verb(4, "play_to_caller = %s\n", play_to_caller ? "yes" : "no");
07587 ast_verb(4, "play_to_callee = %s\n", play_to_callee ? "yes" : "no");
07588 ast_verb(4, "warning_freq = %ld ms (%.3lf s)\n", config->warning_freq, config->warning_freq / 1000.0);
07589 ast_verb(4, "start_sound = %s\n", S_OR(config->start_sound, ""));
07590 ast_verb(4, "warning_sound = %s\n", config->warning_sound);
07591 ast_verb(4, "end_sound = %s\n", S_OR(config->end_sound, ""));
07592 }
07593 if (play_to_caller)
07594 ast_set_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
07595 if (play_to_callee)
07596 ast_set_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
07597 return 0;
07598 }
07599
07600
07601
07602
07603
07604
07605
07606
07607
07608
07609
07610 static int bridge_exec(struct ast_channel *chan, const char *data)
07611 {
07612 struct ast_channel *current_dest_chan, *final_dest_chan, *chans[2];
07613 char *tmp_data = NULL;
07614 struct ast_flags opts = { 0, };
07615 struct ast_bridge_config bconfig = { { 0, }, };
07616 char *opt_args[OPT_ARG_ARRAY_SIZE];
07617 struct timeval calldurationlimit = { 0, };
07618
07619 AST_DECLARE_APP_ARGS(args,
07620 AST_APP_ARG(dest_chan);
07621 AST_APP_ARG(options);
07622 );
07623
07624 if (ast_strlen_zero(data)) {
07625 ast_log(LOG_WARNING, "Bridge require at least 1 argument specifying the other end of the bridge\n");
07626 return -1;
07627 }
07628
07629 tmp_data = ast_strdupa(data);
07630 AST_STANDARD_APP_ARGS(args, tmp_data);
07631 if (!ast_strlen_zero(args.options))
07632 ast_app_parse_options(bridge_exec_options, &opts, opt_args, args.options);
07633
07634
07635 if (!strcmp(chan->name, args.dest_chan)) {
07636 ast_log(LOG_WARNING, "Unable to bridge channel %s with itself\n", chan->name);
07637 ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
07638 "Response: Failed\r\n"
07639 "Reason: Unable to bridge channel to itself\r\n"
07640 "Channel1: %s\r\n"
07641 "Channel2: %s\r\n",
07642 chan->name, args.dest_chan);
07643 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "LOOP");
07644 return 0;
07645 }
07646
07647
07648 if (!(current_dest_chan = ast_channel_get_by_name_prefix(args.dest_chan,
07649 strlen(args.dest_chan)))) {
07650 ast_log(LOG_WARNING, "Bridge failed because channel %s does not exist\n",
07651 args.dest_chan);
07652 ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
07653 "Response: Failed\r\n"
07654 "Reason: Channel2 does not exist\r\n"
07655 "Channel1: %s\r\n"
07656 "Channel2: %s\r\n", chan->name, args.dest_chan);
07657 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "NONEXISTENT");
07658 return 0;
07659 }
07660
07661
07662 if (!(final_dest_chan = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
07663 NULL, NULL, current_dest_chan->linkedid, 0, "Bridge/%s", current_dest_chan->name))) {
07664 ast_log(LOG_WARNING, "Cannot create placeholder channel for chan %s\n", args.dest_chan);
07665 ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
07666 "Response: Failed\r\n"
07667 "Reason: Cannot create placeholder channel\r\n"
07668 "Channel1: %s\r\n"
07669 "Channel2: %s\r\n", chan->name, args.dest_chan);
07670 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "FAILURE");
07671 ast_channel_unref(current_dest_chan);
07672 return 0;
07673 }
07674
07675 if (ast_test_flag(&opts, OPT_DURATION_LIMIT)
07676 && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_LIMIT])
07677 && ast_bridge_timelimit(chan, &bconfig, opt_args[OPT_ARG_DURATION_LIMIT], &calldurationlimit)) {
07678 ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
07679 "Response: Failed\r\n"
07680 "Reason: Cannot setup bridge time limit\r\n"
07681 "Channel1: %s\r\n"
07682 "Channel2: %s\r\n", chan->name, args.dest_chan);
07683 ast_hangup(final_dest_chan);
07684 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "FAILURE");
07685 current_dest_chan = ast_channel_unref(current_dest_chan);
07686 goto done;
07687 }
07688
07689 if (do_bridge_masquerade(current_dest_chan, final_dest_chan)) {
07690 ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
07691 "Response: Failed\r\n"
07692 "Reason: Cannot masquerade channels\r\n"
07693 "Channel1: %s\r\n"
07694 "Channel2: %s\r\n", chan->name, args.dest_chan);
07695 ast_hangup(final_dest_chan);
07696 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "FAILURE");
07697 current_dest_chan = ast_channel_unref(current_dest_chan);
07698 goto done;
07699 }
07700
07701
07702 if (final_dest_chan->_state != AST_STATE_UP) {
07703 ast_answer(final_dest_chan);
07704 }
07705
07706 chans[0] = current_dest_chan;
07707 chans[1] = final_dest_chan;
07708
07709
07710
07711 if (ast_channel_make_compatible(chan, final_dest_chan) < 0) {
07712 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, final_dest_chan->name);
07713 ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeExec", 2, chans,
07714 "Response: Failed\r\n"
07715 "Reason: Could not make channels compatible for bridge\r\n"
07716 "Channel1: %s\r\n"
07717 "Channel2: %s\r\n", chan->name, final_dest_chan->name);
07718
07719
07720 ast_hangup(final_dest_chan);
07721
07722 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "INCOMPATIBLE");
07723 current_dest_chan = ast_channel_unref(current_dest_chan);
07724 goto done;
07725 }
07726
07727
07728 ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeExec", 2, chans,
07729 "Response: Success\r\n"
07730 "Channel1: %s\r\n"
07731 "Channel2: %s\r\n", chan->name, final_dest_chan->name);
07732
07733 current_dest_chan = ast_channel_unref(current_dest_chan);
07734
07735
07736 if (ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE) && !ast_strlen_zero(xfersound)) {
07737 if (!ast_streamfile(final_dest_chan, xfersound, final_dest_chan->language)) {
07738 if (ast_waitstream(final_dest_chan, "") < 0)
07739 ast_log(LOG_WARNING, "Failed to play courtesy tone on %s\n", final_dest_chan->name);
07740 }
07741 }
07742
07743 if (ast_test_flag(&opts, OPT_CALLEE_TRANSFER))
07744 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_REDIRECT);
07745 if (ast_test_flag(&opts, OPT_CALLER_TRANSFER))
07746 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_REDIRECT);
07747 if (ast_test_flag(&opts, OPT_CALLEE_HANGUP))
07748 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
07749 if (ast_test_flag(&opts, OPT_CALLER_HANGUP))
07750 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
07751 if (ast_test_flag(&opts, OPT_CALLEE_MONITOR))
07752 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_AUTOMON);
07753 if (ast_test_flag(&opts, OPT_CALLER_MONITOR))
07754 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_AUTOMON);
07755 if (ast_test_flag(&opts, OPT_CALLEE_PARK))
07756 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_PARKCALL);
07757 if (ast_test_flag(&opts, OPT_CALLER_PARK))
07758 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_PARKCALL);
07759
07760
07761
07762
07763
07764 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT);
07765 ast_bridge_call(chan, final_dest_chan, &bconfig);
07766
07767
07768 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "SUCCESS");
07769
07770
07771 if (!ast_check_hangup(final_dest_chan)) {
07772 if (!ast_test_flag(&opts, OPT_CALLEE_KILL)) {
07773 ast_debug(1, "starting new PBX in %s,%s,%d for chan %s\n",
07774 final_dest_chan->context, final_dest_chan->exten,
07775 final_dest_chan->priority, final_dest_chan->name);
07776
07777 if (ast_pbx_start(final_dest_chan)) {
07778 ast_log(LOG_WARNING, "FAILED continuing PBX on dest chan %s\n", final_dest_chan->name);
07779 ast_hangup(final_dest_chan);
07780 } else {
07781 ast_debug(1, "SUCCESS continuing PBX on chan %s\n", final_dest_chan->name);
07782 }
07783 } else {
07784 ast_hangup(final_dest_chan);
07785 }
07786 } else {
07787 ast_debug(1, "chan %s was hungup\n", final_dest_chan->name);
07788 ast_hangup(final_dest_chan);
07789 }
07790 done:
07791 ast_free((char *) bconfig.warning_sound);
07792 ast_free((char *) bconfig.end_sound);
07793 ast_free((char *) bconfig.start_sound);
07794
07795 return 0;
07796 }
07797
07798 #if defined(TEST_FRAMEWORK)
07799
07800
07801
07802
07803
07804
07805
07806
07807
07808 static void create_spaces_str(struct ast_str **str, struct parking_dp_space_map *spaces)
07809 {
07810 const char *comma;
07811 struct parking_dp_spaces *cur;
07812
07813 ast_str_reset(*str);
07814 comma = "";
07815 AST_LIST_TRAVERSE(spaces, cur, node) {
07816 if (cur->start == cur->stop) {
07817 ast_str_append(str, 0, "%s%d", comma, cur->start);
07818 } else {
07819 ast_str_append(str, 0, "%s%d-%d", comma, cur->start, cur->stop);
07820 }
07821 comma = ",";
07822 }
07823 }
07824 #endif
07825
07826 #if defined(TEST_FRAMEWORK)
07827
07828
07829
07830
07831
07832
07833
07834
07835
07836
07837
07838
07839 static int check_spaces(struct ast_test *test, struct parking_dp_space_map *spaces, const char *expected, const char *what)
07840 {
07841 int cmp;
07842 struct ast_str *str = ast_str_alloca(1024);
07843
07844 create_spaces_str(&str, spaces);
07845 cmp = strcmp(expected, ast_str_buffer(str));
07846 if (cmp) {
07847 ast_test_status_update(test,
07848 "Unexpected parking space map for %s. Expect:'%s' Got:'%s'\n",
07849 what, expected, ast_str_buffer(str));
07850 }
07851 return cmp;
07852 }
07853 #endif
07854
07855 #if defined(TEST_FRAMEWORK)
07856
07857
07858
07859
07860
07861
07862
07863
07864
07865 static void test_add_dead_space(const char *context, int space)
07866 {
07867 struct parking_dp_space_map *dead_spaces = (struct parking_dp_space_map *) context;
07868
07869 usage_context_add_spaces(dead_spaces, space, space, NULL, 0);
07870 }
07871 #endif
07872
07873 #if defined(TEST_FRAMEWORK)
07874 struct test_map {
07875 const char *ramp;
07876 int start;
07877 int stop;
07878 const char *expect;
07879 };
07880
07881
07882
07883
07884
07885
07886
07887
07888
07889
07890
07891
07892
07893
07894 static struct parking_dp_context *test_build_maps(struct ast_test *test,
07895 struct ast_parkinglot *lot, const char *table_name, const struct test_map *table,
07896 size_t num_entries)
07897 {
07898 struct parking_dp_context *ctx_node;
07899 int cur_index = 0;
07900 char what[40];
07901
07902 snprintf(what, sizeof(what), "%s[%d]", table_name, cur_index);
07903 ast_copy_string(lot->cfg.parkext, table->ramp, sizeof(lot->cfg.parkext));
07904 lot->cfg.parking_start = table->start;
07905 lot->cfg.parking_stop = table->stop;
07906 ctx_node = build_dialplan_useage_context(lot);
07907 if (!ctx_node) {
07908 ast_test_status_update(test, "Failed to create parking lot context map for %s\n",
07909 what);
07910 return NULL;
07911 }
07912 if (check_spaces(test, &ctx_node->spaces, table->expect, what)) {
07913 destroy_dialplan_usage_context(ctx_node);
07914 return NULL;
07915 }
07916 while (--num_entries) {
07917 ++cur_index;
07918 ++table;
07919 snprintf(what, sizeof(what), "%s[%d]", table_name, cur_index);
07920 ast_copy_string(lot->cfg.parkext, table->ramp, sizeof(lot->cfg.parkext));
07921 lot->cfg.parking_start = table->start;
07922 lot->cfg.parking_stop = table->stop;
07923 if (dialplan_usage_add_parkinglot_data(ctx_node, lot, 1)) {
07924 ast_test_status_update(test, "Failed to add parking lot data for %s\n", what);
07925 destroy_dialplan_usage_context(ctx_node);
07926 return NULL;
07927 }
07928 if (check_spaces(test, &ctx_node->spaces, table->expect, what)) {
07929 destroy_dialplan_usage_context(ctx_node);
07930 return NULL;
07931 }
07932 }
07933 return ctx_node;
07934 }
07935
07936 static const struct test_map test_old_ctx[] = {
07937
07938 { "702", 14, 15, "14-15" },
07939 { "700", 10, 11, "10-11,14-15" },
07940 { "701", 18, 19, "10-11,14-15,18-19" },
07941 { "703", 12, 13, "10-15,18-19" },
07942 { "704", 16, 17, "10-19" },
07943
07944
07945 { "704", 9, 19, "9-19" },
07946 { "704", 9, 20, "9-20" },
07947 { "704", 8, 21, "8-21" },
07948
07949
07950 { "705", 23, 25, "8-21,23-25" },
07951 { "706", 28, 31, "8-21,23-25,28-31" },
07952 { "707", 33, 34, "8-21,23-25,28-31,33-34" },
07953 { "708", 38, 40, "8-21,23-25,28-31,33-34,38-40" },
07954 { "709", 42, 43, "8-21,23-25,28-31,33-34,38-40,42-43" },
07955 };
07956
07957 static const struct test_map test_new_ctx[] = {
07958 { "702", 4, 5, "4-5" },
07959 { "704", 24, 26, "4-5,24-26" },
07960 { "709", 29, 30, "4-5,24-26,29-30" },
07961 { "710", 32, 35, "4-5,24-26,29-30,32-35" },
07962 { "711", 37, 39, "4-5,24-26,29-30,32-35,37-39" },
07963 };
07964 #endif
07965
07966 #if defined(TEST_FRAMEWORK)
07967
07968
07969
07970
07971
07972
07973
07974
07975
07976 static int test_dialplan_usage_map(struct ast_test *test)
07977 {
07978 struct parking_dp_context *old_ctx;
07979 struct parking_dp_context *new_ctx;
07980 struct ast_parkinglot *lot;
07981 struct parking_dp_spaces *spaces;
07982 struct parking_dp_space_map dead_spaces = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
07983 int res;
07984
07985 ast_test_status_update(test, "Test parking dialplan usage map code\n");
07986
07987 lot = create_parkinglot("test_lot");
07988 if (!lot) {
07989 return -1;
07990 }
07991 ast_copy_string(lot->cfg.parking_con, "test-ctx", sizeof(lot->cfg.parking_con));
07992 lot->cfg.parkext_exclusive = 1;
07993
07994 ast_test_status_update(test,
07995 "Build old_ctx map\n");
07996 ast_log(LOG_NOTICE, "6 Ramp and space conflict warnings are expected.\n");
07997 old_ctx = test_build_maps(test, lot, "test_old_ctx", test_old_ctx,
07998 ARRAY_LEN(test_old_ctx));
07999 if (!old_ctx) {
08000 ao2_ref(lot, -1);
08001 return -1;
08002 }
08003
08004 ast_test_status_update(test, "Build new_ctx map\n");
08005 new_ctx = test_build_maps(test, lot, "test_new_ctx", test_new_ctx,
08006 ARRAY_LEN(test_new_ctx));
08007 if (!new_ctx) {
08008 res = -1;
08009 goto fail_old_ctx;
08010 }
08011
08012 ast_test_status_update(test, "Test removing dead parking spaces\n");
08013 remove_dead_spaces_usage((void *) &dead_spaces, &old_ctx->spaces,
08014 &new_ctx->spaces, test_add_dead_space);
08015 if (check_spaces(test, &dead_spaces, "8-21,23,28,31,40,42-43", "dead_spaces")) {
08016 res = -1;
08017 goto fail_dead_spaces;
08018 }
08019
08020 res = 0;
08021
08022 fail_dead_spaces:
08023 while ((spaces = AST_LIST_REMOVE_HEAD(&dead_spaces, node))) {
08024 ast_free(spaces);
08025 }
08026 destroy_dialplan_usage_context(new_ctx);
08027
08028 fail_old_ctx:
08029 destroy_dialplan_usage_context(old_ctx);
08030 ao2_ref(lot, -1);
08031 return res;
08032 }
08033 #endif
08034
08035 #if defined(TEST_FRAMEWORK)
08036 static int fake_fixup(struct ast_channel *clonechan, struct ast_channel *original)
08037 {
08038 return 0;
08039 }
08040 #endif
08041
08042 #if defined(TEST_FRAMEWORK)
08043 static struct ast_channel *create_test_channel(const struct ast_channel_tech *fake_tech)
08044 {
08045 struct ast_channel *test_channel1;
08046
08047 if (!(test_channel1 = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
08048 NULL, NULL, 0, 0, "TestChannel1"))) {
08049 ast_log(LOG_WARNING, "Whoa, test channel creation failed.\n");
08050 return NULL;
08051 }
08052
08053
08054 test_channel1->nativeformats = AST_FORMAT_GSM;
08055 test_channel1->writeformat = AST_FORMAT_GSM;
08056 test_channel1->rawwriteformat = AST_FORMAT_GSM;
08057 test_channel1->readformat = AST_FORMAT_GSM;
08058 test_channel1->rawreadformat = AST_FORMAT_GSM;
08059 test_channel1->tech = fake_tech;
08060
08061 return test_channel1;
08062 }
08063 #endif
08064
08065 #if defined(TEST_FRAMEWORK)
08066 static int unpark_test_channel(struct ast_channel *toremove, struct ast_park_call_args *args)
08067 {
08068 struct ast_context *con;
08069 struct parkeduser *pu_toremove;
08070 int res = 0;
08071
08072 args->pu->notquiteyet = 1;
08073
08074 AST_LIST_LOCK(&args->pu->parkinglot->parkings);
08075 AST_LIST_TRAVERSE_SAFE_BEGIN(&args->pu->parkinglot->parkings, pu_toremove, list) {
08076 if (pu_toremove == args->pu) {
08077 AST_LIST_REMOVE_CURRENT(list);
08078 break;
08079 }
08080 }
08081 AST_LIST_TRAVERSE_SAFE_END;
08082 AST_LIST_UNLOCK(&args->pu->parkinglot->parkings);
08083
08084 if (!pu_toremove) {
08085 ast_log(LOG_WARNING, "Whoa, could not find parking test call!\n");
08086 return -1;
08087 }
08088
08089 con = ast_context_find(args->pu->parkinglot->cfg.parking_con);
08090 if (con) {
08091 if (ast_context_remove_extension2(con, args->pu->parkingexten, 1, NULL, 0)) {
08092 ast_log(LOG_WARNING, "Whoa, failed to remove the parking extension!\n");
08093 res = -1;
08094 } else {
08095 notify_metermaids(args->pu->parkingexten,
08096 pu_toremove->parkinglot->cfg.parking_con, AST_DEVICE_NOT_INUSE);
08097 }
08098 } else {
08099 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
08100 res = -1;
08101 }
08102
08103 parkinglot_unref(pu_toremove->parkinglot);
08104 ast_free(pu_toremove);
08105 args->pu = NULL;
08106
08107 if (!res && toremove) {
08108 ast_hangup(toremove);
08109 }
08110 return res;
08111 }
08112 #endif
08113
08114 #if defined(TEST_FRAMEWORK)
08115 AST_TEST_DEFINE(features_test)
08116 {
08117 struct ast_channel *test_channel1 = NULL;
08118 struct ast_channel *parked_chan = NULL;
08119 struct ast_parkinglot *dynlot;
08120 struct ast_park_call_args args = {
08121 .timeout = DEFAULT_PARK_TIME,
08122 };
08123
08124 int res = 0;
08125
08126 static const struct ast_channel_tech fake_tech = {
08127 .fixup = fake_fixup,
08128 };
08129
08130 static const char unique_lot_1[] = "myuniquetestparkinglot314";
08131 static const char unique_lot_2[] = "myuniquetestparkinglot3141592654";
08132 static const char unique_context_1[] = "myuniquetestcontext314";
08133 static const char unique_context_2[] = "myuniquetestcontext3141592654";
08134 static const char parkinglot_parkext[] = "750";
08135 static const char parkinglot_range[] = "751-760";
08136
08137 switch (cmd) {
08138 case TEST_INIT:
08139 info->name = "features_test";
08140 info->category = "/main/features/";
08141 info->summary = "Features unit test";
08142 info->description =
08143 "Tests whether parking respects PARKINGLOT settings";
08144 return AST_TEST_NOT_RUN;
08145 case TEST_EXECUTE:
08146 break;
08147 }
08148
08149 if (test_dialplan_usage_map(test)) {
08150 res = -1;
08151 goto exit_features_test;
08152 }
08153
08154
08155 parkeddynamic = 1;
08156
08157 ast_test_status_update(test, "Test parking functionality with defaults\n");
08158 if (!(test_channel1 = create_test_channel(&fake_tech))) {
08159 res = -1;
08160 goto exit_features_test;
08161 }
08162 if (park_call_full(test_channel1, NULL, &args)) {
08163 res = -1;
08164 goto exit_features_test;
08165 }
08166 if (unpark_test_channel(test_channel1, &args)) {
08167 res = -1;
08168 goto exit_features_test;
08169 }
08170
08171
08172 ast_test_status_update(test, "Check that certain parking options are respected\n");
08173 if (!(test_channel1 = create_test_channel(&fake_tech))) {
08174 res = -1;
08175 goto exit_features_test;
08176 }
08177 pbx_builtin_setvar_helper(test_channel1, "PARKINGLOT", unique_lot_1);
08178 pbx_builtin_setvar_helper(test_channel1, "PARKINGDYNCONTEXT", unique_context_1);
08179 pbx_builtin_setvar_helper(test_channel1, "PARKINGDYNEXTEN", parkinglot_parkext);
08180 pbx_builtin_setvar_helper(test_channel1, "PARKINGDYNPOS", parkinglot_range);
08181 if (park_call_full(test_channel1, NULL, &args)) {
08182 res = -1;
08183 goto exit_features_test;
08184 }
08185
08186 dynlot = args.pu->parkinglot;
08187 if (args.pu->parkingnum != 751
08188 || strcmp(dynlot->name, unique_lot_1)
08189 || strcmp(dynlot->cfg.parking_con, unique_context_1)
08190 || strcmp(dynlot->cfg.parkext, parkinglot_parkext)
08191 || dynlot->cfg.parking_start != 751
08192 || dynlot->cfg.parking_stop != 760) {
08193 ast_test_status_update(test, "Parking settings were not respected\n");
08194 ast_test_status_update(test, "Dyn-name:%s\n", dynlot->name);
08195 ast_test_status_update(test, "Dyn-context:%s\n", dynlot->cfg.parking_con);
08196 ast_test_status_update(test, "Dyn-parkext:%s\n", dynlot->cfg.parkext);
08197 ast_test_status_update(test, "Dyn-parkpos:%d-%d\n", dynlot->cfg.parking_start,
08198 dynlot->cfg.parking_stop);
08199 ast_test_status_update(test, "Parked in space:%d\n", args.pu->parkingnum);
08200 if (!unpark_test_channel(test_channel1, &args)) {
08201 test_channel1 = NULL;
08202 }
08203 res = -1;
08204 goto exit_features_test;
08205 } else {
08206 ast_test_status_update(test, "Parking settings for non-masquerading park verified\n");
08207 }
08208 if (unpark_test_channel(test_channel1, &args)) {
08209 res = -1;
08210 goto exit_features_test;
08211 }
08212
08213
08214 ast_test_status_update(test, "Check #2 that certain parking options are respected\n");
08215 if (!(test_channel1 = create_test_channel(&fake_tech))) {
08216 res = -1;
08217 goto exit_features_test;
08218 }
08219 pbx_builtin_setvar_helper(test_channel1, "PARKINGLOT", unique_lot_2);
08220 pbx_builtin_setvar_helper(test_channel1, "PARKINGDYNCONTEXT", unique_context_2);
08221 pbx_builtin_setvar_helper(test_channel1, "PARKINGDYNEXTEN", parkinglot_parkext);
08222 pbx_builtin_setvar_helper(test_channel1, "PARKINGDYNPOS", parkinglot_range);
08223 if (masq_park_call(test_channel1, NULL, &args)) {
08224 res = -1;
08225 goto exit_features_test;
08226 }
08227
08228 ast_hangup(test_channel1);
08229 test_channel1 = NULL;
08230
08231 dynlot = args.pu->parkinglot;
08232 if (args.pu->parkingnum != 751
08233 || strcmp(dynlot->name, unique_lot_2)
08234 || strcmp(dynlot->cfg.parking_con, unique_context_2)
08235 || strcmp(dynlot->cfg.parkext, parkinglot_parkext)
08236 || dynlot->cfg.parking_start != 751
08237 || dynlot->cfg.parking_stop != 760) {
08238 ast_test_status_update(test, "Parking settings were not respected\n");
08239 ast_test_status_update(test, "Dyn-name:%s\n", dynlot->name);
08240 ast_test_status_update(test, "Dyn-context:%s\n", dynlot->cfg.parking_con);
08241 ast_test_status_update(test, "Dyn-parkext:%s\n", dynlot->cfg.parkext);
08242 ast_test_status_update(test, "Dyn-parkpos:%d-%d\n", dynlot->cfg.parking_start,
08243 dynlot->cfg.parking_stop);
08244 ast_test_status_update(test, "Parked in space:%d\n", args.pu->parkingnum);
08245 res = -1;
08246 } else {
08247 ast_test_status_update(test, "Parking settings for masquerading park verified\n");
08248 }
08249
08250
08251 parked_chan = ast_channel_get_by_name("TestChannel1");
08252 if (unpark_test_channel(parked_chan, &args)) {
08253 if (parked_chan) {
08254 ast_hangup(parked_chan);
08255 }
08256 res = -1;
08257 }
08258 parked_chan = ast_channel_unref(parked_chan);
08259
08260
08261 exit_features_test:
08262
08263 if (test_channel1) {
08264 ast_hangup(test_channel1);
08265 }
08266
08267 force_reload_load = 1;
08268 ast_features_reload();
08269 return res ? AST_TEST_FAIL : AST_TEST_PASS;
08270 }
08271 #endif
08272
08273
08274 static void features_shutdown(void)
08275 {
08276 ast_cli_unregister_multiple(cli_features, ARRAY_LEN(cli_features));
08277 ast_devstate_prov_del("Park");
08278 ast_manager_unregister("Bridge");
08279 ast_manager_unregister("Park");
08280 ast_manager_unregister("Parkinglots");
08281 ast_manager_unregister("ParkedCalls");
08282 ast_unregister_application(parkcall);
08283 ast_unregister_application(parkedcall);
08284 ast_unregister_application(app_bridge);
08285 #if defined(TEST_FRAMEWORK)
08286 AST_TEST_UNREGISTER(features_test);
08287 #endif
08288
08289 pthread_cancel(parking_thread);
08290 pthread_kill(parking_thread, SIGURG);
08291 pthread_join(parking_thread, NULL);
08292 ast_context_destroy(NULL, registrar);
08293 ao2_ref(parkinglots, -1);
08294 }
08295
08296 int ast_features_init(void)
08297 {
08298 int res;
08299
08300 parkinglots = ao2_container_alloc(7, parkinglot_hash_cb, parkinglot_cmp_cb);
08301 if (!parkinglots) {
08302 return -1;
08303 }
08304
08305 res = load_config(0);
08306 if (res) {
08307 return res;
08308 }
08309 ast_cli_register_multiple(cli_features, ARRAY_LEN(cli_features));
08310 if (ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL)) {
08311 return -1;
08312 }
08313 ast_register_application2(app_bridge, bridge_exec, NULL, NULL, NULL);
08314 res = ast_register_application2(parkedcall, parked_call_exec, NULL, NULL, NULL);
08315 if (!res)
08316 res = ast_register_application2(parkcall, park_call_exec, NULL, NULL, NULL);
08317 if (!res) {
08318 ast_manager_register_xml("ParkedCalls", 0, manager_parking_status);
08319 ast_manager_register_xml("Park", EVENT_FLAG_CALL, manager_park);
08320 ast_manager_register_xml("Bridge", EVENT_FLAG_CALL, action_bridge);
08321 }
08322
08323 res |= ast_devstate_prov_add("Park", metermaidstate);
08324 #if defined(TEST_FRAMEWORK)
08325 res |= AST_TEST_REGISTER(features_test);
08326 #endif
08327
08328 ast_register_atexit(features_shutdown);
08329
08330 return res;
08331 }