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