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