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