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