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