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 #include "asterisk.h"
00027
00028 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 303138 $")
00029
00030 #include "asterisk/_private.h"
00031
00032 #include <pthread.h>
00033 #include <signal.h>
00034 #include <sys/time.h>
00035 #include <sys/signal.h>
00036 #include <netinet/in.h>
00037
00038 #include "asterisk/lock.h"
00039 #include "asterisk/file.h"
00040 #include "asterisk/channel.h"
00041 #include "asterisk/pbx.h"
00042 #include "asterisk/causes.h"
00043 #include "asterisk/module.h"
00044 #include "asterisk/translate.h"
00045 #include "asterisk/app.h"
00046 #include "asterisk/say.h"
00047 #include "asterisk/features.h"
00048 #include "asterisk/musiconhold.h"
00049 #include "asterisk/config.h"
00050 #include "asterisk/cli.h"
00051 #include "asterisk/manager.h"
00052 #include "asterisk/utils.h"
00053 #include "asterisk/adsi.h"
00054 #include "asterisk/devicestate.h"
00055 #include "asterisk/monitor.h"
00056 #include "asterisk/audiohook.h"
00057 #include "asterisk/global_datastores.h"
00058 #include "asterisk/astobj2.h"
00059 #include "asterisk/cel.h"
00060 #include "asterisk/test.h"
00061
00062
00063
00064
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 #define DEFAULT_PARK_TIME 45000
00345 #define DEFAULT_PARK_EXTENSION "700"
00346 #define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000
00347 #define DEFAULT_FEATURE_DIGIT_TIMEOUT 1000
00348 #define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000
00349 #define DEFAULT_ATXFER_DROP_CALL 0
00350 #define DEFAULT_ATXFER_LOOP_DELAY 10000
00351 #define DEFAULT_ATXFER_CALLBACK_RETRIES 2
00352
00353 #define AST_MAX_WATCHERS 256
00354 #define MAX_DIAL_FEATURE_OPTIONS 30
00355
00356 struct feature_group_exten {
00357 AST_LIST_ENTRY(feature_group_exten) entry;
00358 AST_DECLARE_STRING_FIELDS(
00359 AST_STRING_FIELD(exten);
00360 );
00361 struct ast_call_feature *feature;
00362 };
00363
00364 struct feature_group {
00365 AST_LIST_ENTRY(feature_group) entry;
00366 AST_DECLARE_STRING_FIELDS(
00367 AST_STRING_FIELD(gname);
00368 );
00369 AST_LIST_HEAD_NOLOCK(, feature_group_exten) features;
00370 };
00371
00372 static AST_RWLIST_HEAD_STATIC(feature_groups, feature_group);
00373
00374 static char *parkedcall = "ParkedCall";
00375
00376 static char pickup_ext[AST_MAX_EXTENSION];
00377
00378
00379
00380
00381 struct parkeduser {
00382 struct ast_channel *chan;
00383 struct timeval start;
00384 int parkingnum;
00385 char parkingexten[AST_MAX_EXTENSION];
00386 char context[AST_MAX_CONTEXT];
00387 char exten[AST_MAX_EXTENSION];
00388 int priority;
00389 int parkingtime;
00390 unsigned int notquiteyet:1;
00391 unsigned int options_specified:1;
00392 char peername[1024];
00393 unsigned char moh_trys;
00394 struct ast_parkinglot *parkinglot;
00395 AST_LIST_ENTRY(parkeduser) list;
00396 };
00397
00398
00399 struct ast_parkinglot {
00400 char name[AST_MAX_CONTEXT];
00401 char parkext[AST_MAX_EXTENSION];
00402 char parking_con[AST_MAX_EXTENSION];
00403 char parking_con_dial[AST_MAX_EXTENSION];
00404 int parking_start;
00405 int parking_stop;
00406 int parking_offset;
00407 int parkfindnext;
00408 int parkingtime;
00409 char mohclass[MAX_MUSICCLASS];
00410 int parkaddhints;
00411 int parkedcalltransfers;
00412 int parkedcallreparking;
00413 int parkedcallhangup;
00414 int parkedcallrecording;
00415 unsigned short the_mark:1;
00416 AST_LIST_HEAD(parkinglot_parklist, parkeduser) parkings;
00417 };
00418
00419
00420 static struct ao2_container *parkinglots;
00421
00422 struct ast_parkinglot *default_parkinglot;
00423 char parking_ext[AST_MAX_EXTENSION];
00424
00425 static char courtesytone[256];
00426 static int parkedplay = 0;
00427 static int parkeddynamic = 0;
00428 static char xfersound[256];
00429 static char xferfailsound[256];
00430 static char pickupsound[256];
00431 static char pickupfailsound[256];
00432
00433 static int adsipark;
00434
00435 static int transferdigittimeout;
00436 static int featuredigittimeout;
00437 static int comebacktoorigin = 1;
00438
00439 static int atxfernoanswertimeout;
00440 static unsigned int atxferdropcall;
00441 static unsigned int atxferloopdelay;
00442 static unsigned int atxfercallbackretries;
00443
00444 static char *registrar = "features";
00445
00446
00447 static char *parkcall = PARK_APP_NAME;
00448
00449 static struct ast_app *monitor_app = NULL;
00450 static int monitor_ok = 1;
00451
00452 static struct ast_app *mixmonitor_app = NULL;
00453 static int mixmonitor_ok = 1;
00454
00455 static struct ast_app *stopmixmonitor_app = NULL;
00456 static int stopmixmonitor_ok = 1;
00457
00458 static pthread_t parking_thread;
00459 struct ast_dial_features {
00460 struct ast_flags features_caller;
00461 struct ast_flags features_callee;
00462 int is_caller;
00463 };
00464
00465 #if defined(ATXFER_NULL_TECH)
00466 static struct ast_frame *null_read(struct ast_channel *chan)
00467 {
00468
00469 return NULL;
00470 }
00471
00472 static struct ast_frame *null_exception(struct ast_channel *chan)
00473 {
00474
00475 return NULL;
00476 }
00477
00478 static int null_write(struct ast_channel *chan, struct ast_frame *frame)
00479 {
00480
00481 return -1;
00482 }
00483
00484 static int null_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
00485 {
00486
00487 return 0;
00488 }
00489
00490 static int null_hangup(struct ast_channel *chan)
00491 {
00492 chan->tech_pvt = NULL;
00493 return 0;
00494 }
00495
00496 static const struct ast_channel_tech null_tech = {
00497 .type = "NULL",
00498 .description = "NULL channel driver for atxfer",
00499 .capabilities = -1,
00500 .read = null_read,
00501 .exception = null_exception,
00502 .write = null_write,
00503 .fixup = null_fixup,
00504 .hangup = null_hangup,
00505 };
00506 #endif
00507
00508 #if defined(ATXFER_NULL_TECH)
00509
00510
00511
00512
00513
00514
00515
00516
00517 static void set_null_chan_tech(struct ast_channel *chan)
00518 {
00519 int idx;
00520
00521 ast_channel_lock(chan);
00522
00523
00524 if (chan->tech->hangup) {
00525 chan->tech->hangup(chan);
00526 }
00527 if (chan->tech_pvt) {
00528 ast_log(LOG_WARNING, "Channel '%s' may not have been hung up properly\n",
00529 chan->name);
00530 ast_free(chan->tech_pvt);
00531 chan->tech_pvt = NULL;
00532 }
00533
00534
00535 chan->tech = &null_tech;
00536 for (idx = 0; idx < AST_MAX_FDS; ++idx) {
00537 switch (idx) {
00538 case AST_ALERT_FD:
00539 case AST_TIMING_FD:
00540 case AST_GENERATOR_FD:
00541
00542 break;
00543 default:
00544 ast_channel_set_fd(chan, idx, -1);
00545 break;
00546 }
00547 }
00548 ast_queue_frame(chan, &ast_null_frame);
00549
00550 ast_channel_unlock(chan);
00551 }
00552 #endif
00553
00554 #if defined(ATXFER_NULL_TECH)
00555
00556
00557
00558
00559
00560
00561
00562
00563 static void set_new_chan_name(struct ast_channel *chan)
00564 {
00565 static int seq_num_last;
00566 int seq_num;
00567 int len;
00568 char *chan_name;
00569 char dummy[1];
00570
00571
00572 ast_channel_lock(chan);
00573 seq_num = ast_atomic_fetchadd_int(&seq_num_last, +1);
00574 len = snprintf(dummy, sizeof(dummy), "%s<XFER_%x>", chan->name, seq_num) + 1;
00575 chan_name = alloca(len);
00576 snprintf(chan_name, len, "%s<XFER_%x>", chan->name, seq_num);
00577 ast_channel_unlock(chan);
00578
00579 ast_change_name(chan, chan_name);
00580 }
00581 #endif
00582
00583 static void *dial_features_duplicate(void *data)
00584 {
00585 struct ast_dial_features *df = data, *df_copy;
00586
00587 if (!(df_copy = ast_calloc(1, sizeof(*df)))) {
00588 return NULL;
00589 }
00590
00591 memcpy(df_copy, df, sizeof(*df));
00592
00593 return df_copy;
00594 }
00595
00596 static void dial_features_destroy(void *data)
00597 {
00598 struct ast_dial_features *df = data;
00599 if (df) {
00600 ast_free(df);
00601 }
00602 }
00603
00604 static const struct ast_datastore_info dial_features_info = {
00605 .type = "dial-features",
00606 .destroy = dial_features_destroy,
00607 .duplicate = dial_features_duplicate,
00608 };
00609
00610
00611 static struct ast_parkinglot *parkinglot_addref(struct ast_parkinglot *parkinglot);
00612 static void parkinglot_unref(struct ast_parkinglot *parkinglot);
00613 static void parkinglot_destroy(void *obj);
00614 int manage_parkinglot(struct ast_parkinglot *curlot, const struct pollfd *pfds, const int nfds, struct pollfd **new_pfds, int *new_nfds, int *fs);
00615 struct ast_parkinglot *find_parkinglot(const char *name);
00616 static struct ast_parkinglot *create_parkinglot(const char *name);
00617 static struct ast_parkinglot *copy_parkinglot(const char *name, const struct ast_parkinglot *parkinglot);
00618
00619 static int find_parkinglot_by_position_cb(void *obj, void *args, int flags)
00620 {
00621 struct ast_parkinglot *parkinglot = obj;
00622 int *parkpos = args;
00623
00624 if (*parkpos >= parkinglot->parking_start && *parkpos <= parkinglot->parking_stop) {
00625 return CMP_MATCH | CMP_STOP;
00626 }
00627
00628 return 0;
00629 }
00630
00631 static int find_parkinglot_by_exten_cb(void *obj, void *args, int flags)
00632 {
00633 struct ast_parkinglot *parkinglot = obj;
00634 const char *parkext = args;
00635
00636 if (!strcmp(parkinglot->parkext, parkext)) {
00637 return CMP_MATCH | CMP_STOP;
00638 }
00639
00640 return 0;
00641 }
00642
00643 int ast_parking_ext_valid(const char *exten_str, struct ast_channel *chan, const char *context)
00644 {
00645 struct ast_exten *exten;
00646 struct pbx_find_info q = { .stacklen = 0 };
00647 const char *app_at_exten;
00648
00649 exten = pbx_find_extension(chan, NULL, &q, context, exten_str, 1, NULL, NULL, E_MATCH);
00650 if (!exten) {
00651 return 0;
00652 }
00653
00654 app_at_exten = ast_get_extension_app(exten);
00655 if (!app_at_exten || strcmp(PARK_APP_NAME, app_at_exten)) {
00656 return 0;
00657 }
00658
00659 return 1;
00660 }
00661
00662 const char *ast_pickup_ext(void)
00663 {
00664 return pickup_ext;
00665 }
00666
00667 struct ast_bridge_thread_obj
00668 {
00669 struct ast_bridge_config bconfig;
00670 struct ast_channel *chan;
00671 struct ast_channel *peer;
00672 unsigned int return_to_pbx:1;
00673 };
00674
00675 static int parkinglot_hash_cb(const void *obj, const int flags)
00676 {
00677 const struct ast_parkinglot *parkinglot = obj;
00678
00679 return ast_str_case_hash(parkinglot->name);
00680 }
00681
00682 static int parkinglot_cmp_cb(void *obj, void *arg, int flags)
00683 {
00684 struct ast_parkinglot *parkinglot = obj, *parkinglot2 = arg;
00685
00686 return !strcasecmp(parkinglot->name, parkinglot2->name) ? CMP_MATCH | CMP_STOP : 0;
00687 }
00688
00689
00690
00691
00692
00693 static void set_c_e_p(struct ast_channel *chan, const char *context, const char *ext, int pri)
00694 {
00695 ast_copy_string(chan->context, context, sizeof(chan->context));
00696 ast_copy_string(chan->exten, ext, sizeof(chan->exten));
00697 chan->priority = pri;
00698 }
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708 static void check_goto_on_transfer(struct ast_channel *chan)
00709 {
00710 struct ast_channel *xferchan;
00711 const char *val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR");
00712 char *x, *goto_on_transfer;
00713 struct ast_frame *f;
00714
00715 if (ast_strlen_zero(val))
00716 return;
00717
00718 goto_on_transfer = ast_strdupa(val);
00719
00720 if (!(xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", chan->linkedid, 0, "%s", chan->name)))
00721 return;
00722
00723 for (x = goto_on_transfer; x && *x; x++) {
00724 if (*x == '^')
00725 *x = '|';
00726 }
00727
00728 xferchan->readformat = chan->readformat;
00729 xferchan->writeformat = chan->writeformat;
00730 ast_channel_masquerade(xferchan, chan);
00731 ast_parseable_goto(xferchan, goto_on_transfer);
00732 xferchan->_state = AST_STATE_UP;
00733 ast_clear_flag(xferchan, AST_FLAGS_ALL);
00734 xferchan->_softhangup = 0;
00735 if ((f = ast_read(xferchan))) {
00736 ast_frfree(f);
00737 f = NULL;
00738 ast_pbx_start(xferchan);
00739 } else {
00740 ast_hangup(xferchan);
00741 }
00742 }
00743
00744 static struct ast_channel *feature_request_and_dial(struct ast_channel *caller,
00745 const char *caller_name, struct ast_channel *requestor,
00746 struct ast_channel *transferee, const char *type, int format, void *data,
00747 int timeout, int *outstate, const char *language);
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757 static void *bridge_call_thread(void *data)
00758 {
00759 struct ast_bridge_thread_obj *tobj = data;
00760 int res;
00761
00762 tobj->chan->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge";
00763 tobj->chan->data = tobj->peer->name;
00764 tobj->peer->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge";
00765 tobj->peer->data = tobj->chan->name;
00766
00767 ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
00768
00769 if (tobj->return_to_pbx) {
00770 if (!ast_check_hangup(tobj->peer)) {
00771 ast_log(LOG_VERBOSE, "putting peer %s into PBX again\n", tobj->peer->name);
00772 res = ast_pbx_start(tobj->peer);
00773 if (res != AST_PBX_SUCCESS)
00774 ast_log(LOG_WARNING, "FAILED continuing PBX on peer %s\n", tobj->peer->name);
00775 } else
00776 ast_hangup(tobj->peer);
00777 if (!ast_check_hangup(tobj->chan)) {
00778 ast_log(LOG_VERBOSE, "putting chan %s into PBX again\n", tobj->chan->name);
00779 res = ast_pbx_start(tobj->chan);
00780 if (res != AST_PBX_SUCCESS)
00781 ast_log(LOG_WARNING, "FAILED continuing PBX on chan %s\n", tobj->chan->name);
00782 } else
00783 ast_hangup(tobj->chan);
00784 } else {
00785 ast_hangup(tobj->chan);
00786 ast_hangup(tobj->peer);
00787 }
00788
00789 ast_free(tobj);
00790
00791 return NULL;
00792 }
00793
00794
00795
00796
00797
00798
00799
00800 static void bridge_call_thread_launch(void *data)
00801 {
00802 pthread_t thread;
00803 pthread_attr_t attr;
00804 struct sched_param sched;
00805
00806 pthread_attr_init(&attr);
00807 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00808 ast_pthread_create(&thread, &attr, bridge_call_thread, data);
00809 pthread_attr_destroy(&attr);
00810 memset(&sched, 0, sizeof(sched));
00811 pthread_setschedparam(thread, SCHED_RR, &sched);
00812 }
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822 static int adsi_announce_park(struct ast_channel *chan, char *parkingexten)
00823 {
00824 int res;
00825 int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
00826 char tmp[256];
00827 char *message[5] = {NULL, NULL, NULL, NULL, NULL};
00828
00829 snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten);
00830 message[0] = tmp;
00831 res = ast_adsi_load_session(chan, NULL, 0, 1);
00832 if (res == -1)
00833 return res;
00834 return ast_adsi_print(chan, message, justify, 1);
00835 }
00836
00837
00838 static const char *findparkinglotname(struct ast_channel *chan)
00839 {
00840 const char *temp, *parkinglot = NULL;
00841
00842
00843 if (!ast_strlen_zero(chan->parkinglot))
00844 parkinglot = chan->parkinglot;
00845
00846
00847
00848 if ((temp = pbx_builtin_getvar_helper(chan, "PARKINGLOT")))
00849 return temp;
00850
00851 return parkinglot;
00852 }
00853
00854
00855 static void notify_metermaids(const char *exten, char *context, enum ast_device_state state)
00856 {
00857 ast_debug(4, "Notification of state change to metermaids %s@%s\n to state '%s'",
00858 exten, context, ast_devstate2str(state));
00859
00860 ast_devstate_changed(state, "park:%s@%s", exten, context);
00861 }
00862
00863
00864 static enum ast_device_state metermaidstate(const char *data)
00865 {
00866 char *context;
00867 char *exten;
00868
00869 context = ast_strdupa(data);
00870
00871 exten = strsep(&context, "@");
00872 if (!context)
00873 return AST_DEVICE_INVALID;
00874
00875 ast_debug(4, "Checking state of exten %s in context %s\n", exten, context);
00876
00877 if (!ast_exists_extension(NULL, context, exten, 1, NULL))
00878 return AST_DEVICE_NOT_INUSE;
00879
00880 return AST_DEVICE_INUSE;
00881 }
00882
00883
00884 enum ast_park_call_options {
00885
00886 AST_PARK_OPT_RINGING = (1 << 0),
00887
00888
00889 AST_PARK_OPT_RANDOMIZE = (1 << 1),
00890
00891 AST_PARK_OPT_SILENCE = (1 << 2),
00892 };
00893
00894 struct ast_park_call_args {
00895
00896
00897
00898 int timeout;
00899
00900
00901 int *extout;
00902 const char *orig_chan_name;
00903 const char *return_con;
00904 const char *return_ext;
00905 int return_pri;
00906 uint32_t flags;
00907
00908 struct parkeduser *pu;
00909 struct ast_parkinglot *parkinglot;
00910 };
00911
00912 static struct parkeduser *park_space_reserve(struct ast_channel *chan, struct ast_channel *peer, struct ast_park_call_args *args)
00913 {
00914 struct parkeduser *pu;
00915 int i, parking_space = -1, parking_range;
00916 const char *parkinglotname = NULL;
00917 const char *parkingexten;
00918 struct ast_parkinglot *parkinglot = NULL;
00919
00920 if (args->parkinglot) {
00921 parkinglot = args->parkinglot;
00922 parkinglotname = parkinglot->name;
00923 } else if (peer) {
00924 parkinglotname = findparkinglotname(peer);
00925 } else {
00926 parkinglotname = findparkinglotname(chan);
00927 }
00928
00929 if (!args->parkinglot) {
00930 if (parkinglotname) {
00931 parkinglot = find_parkinglot(parkinglotname);
00932 } else {
00933 ast_debug(4, "This could be an indication channel driver needs updating, using default lot.\n");
00934 parkinglot = parkinglot_addref(default_parkinglot);
00935 }
00936 ast_debug(1, "Found chanvar Parkinglot: %s\n", parkinglot->name);
00937 }
00938
00939
00940 if (!parkinglot && parkeddynamic && !ast_strlen_zero(parkinglotname)) {
00941 const char *dyn_context, *dyn_range;
00942 const char *parkinglotname_copy = NULL;
00943 struct ast_parkinglot *parkinglot_copy = NULL;
00944 int dyn_start, dyn_end;
00945
00946 ast_channel_lock(chan);
00947 parkinglotname_copy = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNAMIC"), ""));
00948 dyn_context = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNCONTEXT"), ""));
00949 dyn_range = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNPOS"), ""));
00950 ast_channel_unlock(chan);
00951
00952 if (!ast_strlen_zero(parkinglotname_copy)) {
00953 parkinglot_copy = find_parkinglot(parkinglotname_copy);
00954 }
00955 if (!parkinglot_copy) {
00956 parkinglot_copy = parkinglot_addref(default_parkinglot);
00957 ast_debug(1, "Using default parking lot for copy\n");
00958 }
00959 if (!(parkinglot = copy_parkinglot(parkinglotname, parkinglot_copy))) {
00960 ast_log(LOG_ERROR, "Could not build dynamic parking lot!\n");
00961 } else {
00962 if (!ast_strlen_zero(dyn_context)) {
00963 ast_copy_string(parkinglot->parking_con, dyn_context, sizeof(parkinglot->parking_con));
00964 }
00965 if (!ast_strlen_zero(dyn_range)) {
00966 if (sscanf(dyn_range, "%30d-%30d", &dyn_start, &dyn_end) != 2) {
00967 ast_log(LOG_WARNING, "Format for parking positions is a-b, where a and b are numbers\n");
00968 } else {
00969 parkinglot->parking_start = dyn_start;
00970 parkinglot->parking_stop = dyn_end;
00971 }
00972 }
00973 ao2_link(parkinglots, parkinglot);
00974 }
00975
00976 if (parkinglot_copy) {
00977
00978 parkinglot_unref(parkinglot_copy);
00979 parkinglot_copy = NULL;
00980 }
00981 }
00982
00983 if (!parkinglot) {
00984 parkinglot = parkinglot_addref(default_parkinglot);
00985 }
00986
00987 ast_debug(1, "Parkinglot: %s\n", parkinglot->name);
00988
00989
00990 if (!(pu = ast_calloc(1, sizeof(*pu)))) {
00991 parkinglot_unref(parkinglot);
00992 return NULL;
00993 }
00994
00995
00996 AST_LIST_LOCK(&parkinglot->parkings);
00997
00998 ast_channel_lock(chan);
00999 parkingexten = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGEXTEN"), ""));
01000 ast_channel_unlock(chan);
01001 if (!ast_strlen_zero(parkingexten)) {
01002
01003
01004
01005
01006
01007
01008 if (sscanf(parkingexten, "%30d", &parking_space) != 1 || parking_space < 0) {
01009 AST_LIST_UNLOCK(&parkinglot->parkings);
01010 parkinglot_unref(parkinglot);
01011 free(pu);
01012 ast_log(LOG_WARNING, "PARKINGEXTEN does not indicate a valid parking slot: '%s'.\n", parkingexten);
01013 return NULL;
01014 }
01015 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space);
01016
01017 if (ast_exists_extension(NULL, parkinglot->parking_con, pu->parkingexten, 1, NULL)) {
01018 ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parkinglot->parking_con);
01019 AST_LIST_UNLOCK(&parkinglot->parkings);
01020 parkinglot_unref(parkinglot);
01021 ast_free(pu);
01022 return NULL;
01023 }
01024 } else {
01025 int start;
01026 struct parkeduser *cur = NULL;
01027
01028
01029 parking_range = parkinglot->parking_stop - parkinglot->parking_start + 1;
01030
01031 if (ast_test_flag(args, AST_PARK_OPT_RANDOMIZE)) {
01032 start = ast_random() % (parkinglot->parking_stop - parkinglot->parking_start + 1);
01033 } else {
01034 start = parkinglot->parking_start;
01035 }
01036
01037 for (i = start; 1; i++) {
01038 if (i == parkinglot->parking_stop + 1) {
01039 i = parkinglot->parking_start - 1;
01040 break;
01041 }
01042
01043 AST_LIST_TRAVERSE(&parkinglot->parkings, cur, list) {
01044 if (cur->parkingnum == i) {
01045 break;
01046 }
01047 }
01048 if (!cur) {
01049 parking_space = i;
01050 break;
01051 }
01052 }
01053
01054 if (i == start - 1 && cur) {
01055 ast_log(LOG_WARNING, "No more parking spaces\n");
01056 ast_free(pu);
01057 AST_LIST_UNLOCK(&parkinglot->parkings);
01058 parkinglot_unref(parkinglot);
01059 return NULL;
01060 }
01061
01062 if (parkinglot->parkfindnext)
01063 parkinglot->parking_offset = parking_space - parkinglot->parking_start + 1;
01064 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space);
01065 }
01066
01067 pu->notquiteyet = 1;
01068 pu->parkingnum = parking_space;
01069 pu->parkinglot = parkinglot;
01070 AST_LIST_INSERT_TAIL(&parkinglot->parkings, pu, list);
01071
01072 return pu;
01073 }
01074
01075
01076 static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, struct ast_park_call_args *args)
01077 {
01078 struct ast_context *con;
01079 int parkingnum_copy;
01080 struct parkeduser *pu = args->pu;
01081 const char *event_from;
01082
01083 if (pu == NULL)
01084 args->pu = pu = park_space_reserve(chan, peer, args);
01085 if (pu == NULL)
01086 return 1;
01087
01088 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", pu->parkingnum);
01089
01090 chan->appl = "Parked Call";
01091 chan->data = NULL;
01092
01093 pu->chan = chan;
01094
01095
01096 if (chan != peer) {
01097 if (ast_test_flag(args, AST_PARK_OPT_RINGING)) {
01098 ast_indicate(pu->chan, AST_CONTROL_RINGING);
01099 } else {
01100 ast_indicate_data(pu->chan, AST_CONTROL_HOLD,
01101 S_OR(pu->parkinglot->mohclass, NULL),
01102 !ast_strlen_zero(pu->parkinglot->mohclass) ? strlen(pu->parkinglot->mohclass) + 1 : 0);
01103 }
01104 }
01105
01106 pu->start = ast_tvnow();
01107 pu->parkingtime = (args->timeout > 0) ? args->timeout : pu->parkinglot->parkingtime;
01108 parkingnum_copy = pu->parkingnum;
01109 if (args->extout)
01110 *(args->extout) = pu->parkingnum;
01111
01112 if (peer) {
01113
01114
01115
01116
01117
01118 if (!strcasecmp(peer->tech->type, "Local")) {
01119 struct ast_channel *tmpchan, *base_peer;
01120 char other_side[AST_CHANNEL_NAME];
01121 char *c;
01122 ast_copy_string(other_side, S_OR(args->orig_chan_name, peer->name), sizeof(other_side));
01123 if ((c = strrchr(other_side, ';'))) {
01124 *++c = '1';
01125 }
01126 if ((tmpchan = ast_channel_get_by_name(other_side))) {
01127 ast_channel_lock(tmpchan);
01128 if ((base_peer = ast_bridged_channel(tmpchan))) {
01129 ast_copy_string(pu->peername, base_peer->name, sizeof(pu->peername));
01130 }
01131 ast_channel_unlock(tmpchan);
01132 tmpchan = ast_channel_unref(tmpchan);
01133 }
01134 } else {
01135 ast_copy_string(pu->peername, S_OR(args->orig_chan_name, peer->name), sizeof(pu->peername));
01136 }
01137 }
01138
01139
01140
01141
01142 pu->options_specified = (!ast_strlen_zero(args->return_con) || !ast_strlen_zero(args->return_ext) || args->return_pri);
01143
01144
01145
01146
01147
01148 ast_copy_string(pu->context,
01149 S_OR(args->return_con, S_OR(chan->macrocontext, chan->context)),
01150 sizeof(pu->context));
01151 ast_copy_string(pu->exten,
01152 S_OR(args->return_ext, S_OR(chan->macroexten, chan->exten)),
01153 sizeof(pu->exten));
01154 pu->priority = args->return_pri ? args->return_pri :
01155 (chan->macropriority ? chan->macropriority : chan->priority);
01156
01157
01158
01159 if (peer != chan)
01160 pu->notquiteyet = 0;
01161
01162
01163 pthread_kill(parking_thread, SIGURG);
01164 ast_verb(2, "Parked %s on %d (lot %s). Will timeout back to extension [%s] %s, %d in %d seconds\n", pu->chan->name, pu->parkingnum, pu->parkinglot->name, pu->context, pu->exten, pu->priority, (pu->parkingtime/1000));
01165
01166 ast_cel_report_event(pu->chan, AST_CEL_PARK_START, NULL, pu->parkinglot->name, peer);
01167
01168 if (peer) {
01169 event_from = peer->name;
01170 } else {
01171 event_from = pbx_builtin_getvar_helper(chan, "BLINDTRANSFER");
01172 }
01173
01174 ast_manager_event(pu->chan, EVENT_FLAG_CALL, "ParkedCall",
01175 "Exten: %s\r\n"
01176 "Channel: %s\r\n"
01177 "Parkinglot: %s\r\n"
01178 "From: %s\r\n"
01179 "Timeout: %ld\r\n"
01180 "CallerIDNum: %s\r\n"
01181 "CallerIDName: %s\r\n"
01182 "Uniqueid: %s\r\n",
01183 pu->parkingexten, pu->chan->name, pu->parkinglot->name, event_from ? event_from : "",
01184 (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL),
01185 S_COR(pu->chan->caller.id.number.valid, pu->chan->caller.id.number.str, "<unknown>"),
01186 S_COR(pu->chan->caller.id.name.valid, pu->chan->caller.id.name.str, "<unknown>"),
01187 pu->chan->uniqueid
01188 );
01189
01190 if (peer && adsipark && ast_adsi_available(peer)) {
01191 adsi_announce_park(peer, pu->parkingexten);
01192 ast_adsi_unload_session(peer);
01193 }
01194
01195 con = ast_context_find_or_create(NULL, NULL, pu->parkinglot->parking_con, registrar);
01196 if (!con)
01197 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", pu->parkinglot->parking_con);
01198 if (con) {
01199 if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, ast_strdup(pu->parkingexten), ast_free_ptr, registrar))
01200 notify_metermaids(pu->parkingexten, pu->parkinglot->parking_con, AST_DEVICE_INUSE);
01201 }
01202
01203 AST_LIST_UNLOCK(&pu->parkinglot->parkings);
01204
01205
01206 if (peer && !ast_test_flag(args, AST_PARK_OPT_SILENCE) && (ast_strlen_zero(args->orig_chan_name) || !strcasecmp(peer->name, args->orig_chan_name))) {
01207
01208 ast_set_flag(peer, AST_FLAG_MASQ_NOSTREAM);
01209
01210 ast_say_digits(peer, pu->parkingnum, "", peer->language);
01211 ast_clear_flag(peer, AST_FLAG_MASQ_NOSTREAM);
01212 }
01213 if (peer == chan) {
01214
01215 ast_indicate_data(pu->chan, AST_CONTROL_HOLD,
01216 S_OR(pu->parkinglot->mohclass, NULL),
01217 !ast_strlen_zero(pu->parkinglot->mohclass) ? strlen(pu->parkinglot->mohclass) + 1 : 0);
01218 pu->notquiteyet = 0;
01219 pthread_kill(parking_thread, SIGURG);
01220 }
01221 return 0;
01222 }
01223
01224
01225 int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeout, const char *parkexten, int *extout)
01226 {
01227 struct ast_parkinglot *found_lot = ao2_callback(parkinglots, 0, find_parkinglot_by_exten_cb, (void *) parkexten);
01228
01229 struct ast_park_call_args args = {
01230 .timeout = timeout,
01231 .extout = extout,
01232 .parkinglot = found_lot,
01233 };
01234
01235 return park_call_full(chan, peer, &args);
01236 }
01237
01238
01239
01240
01241
01242 static int masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout, int play_announcement, struct ast_park_call_args *args)
01243 {
01244 struct ast_channel *chan;
01245 struct ast_frame *f;
01246 struct ast_park_call_args park_args = {0,};
01247
01248 if (!args) {
01249 args = &park_args;
01250 args->timeout = timeout;
01251 args->extout = extout;
01252 }
01253
01254 if ((args->pu = park_space_reserve(rchan, peer, args)) == NULL) {
01255 if (peer) {
01256 ast_stream_and_wait(peer, "pbx-parkingfailed", "");
01257 }
01258 return AST_FEATURE_RETURN_PARKFAILED;
01259 }
01260
01261
01262 if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->linkedid, rchan->amaflags, "Parked/%s",rchan->name))) {
01263 ast_log(LOG_WARNING, "Unable to create parked channel\n");
01264 return -1;
01265 }
01266
01267
01268 chan->readformat = rchan->readformat;
01269 chan->writeformat = rchan->writeformat;
01270 ast_channel_masquerade(chan, rchan);
01271
01272
01273 set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority);
01274
01275
01276 ast_copy_string(chan->macrocontext,rchan->macrocontext,sizeof(chan->macrocontext));
01277 ast_copy_string(chan->macroexten,rchan->macroexten,sizeof(chan->macroexten));
01278 chan->macropriority = rchan->macropriority;
01279
01280
01281 if ((f = ast_read(chan)))
01282 ast_frfree(f);
01283
01284 if (peer == rchan) {
01285 peer = chan;
01286 }
01287
01288 if (peer && (!play_announcement && args == &park_args)) {
01289 args->orig_chan_name = ast_strdupa(peer->name);
01290 }
01291
01292
01293 park_call_full(chan, peer, args);
01294
01295 return 0;
01296 }
01297
01298
01299 int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
01300 {
01301 return masq_park_call(rchan, peer, timeout, extout, 0, NULL);
01302 }
01303
01304 static int masq_park_call_announce(struct ast_channel *rchan, struct ast_channel *peer, struct ast_park_call_args *args)
01305 {
01306 return masq_park_call(rchan, peer, 0, NULL, 1, args);
01307 }
01308
01309 #ifdef TEST_FRAMEWORK
01310 static int fake_fixup(struct ast_channel *clonechan, struct ast_channel *original)
01311 {
01312 return 0;
01313 }
01314
01315 static struct ast_channel *create_test_channel(const struct ast_channel_tech *fake_tech)
01316 {
01317 struct ast_channel *test_channel1;
01318 if (!(test_channel1 = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
01319 NULL, NULL, 0, 0, "TestChannel1"))) {
01320 return NULL;
01321 }
01322
01323
01324 test_channel1->nativeformats = AST_FORMAT_GSM;
01325 test_channel1->writeformat = AST_FORMAT_GSM;
01326 test_channel1->rawwriteformat = AST_FORMAT_GSM;
01327 test_channel1->readformat = AST_FORMAT_GSM;
01328 test_channel1->rawreadformat = AST_FORMAT_GSM;
01329 test_channel1->tech = fake_tech;
01330
01331 return test_channel1;
01332 }
01333
01334 static int unpark_test_channel(struct ast_channel *toremove, struct ast_park_call_args *args)
01335 {
01336 struct ast_context *con;
01337 struct parkeduser *pu_toremove;
01338 args->pu->notquiteyet = 1;
01339 AST_LIST_LOCK(&args->pu->parkinglot->parkings);
01340 AST_LIST_TRAVERSE_SAFE_BEGIN(&args->pu->parkinglot->parkings, pu_toremove, list) {
01341 con = ast_context_find(args->pu->parkinglot->parking_con);
01342 if (con) {
01343 if (ast_context_remove_extension2(con, args->pu->parkingexten, 1, NULL, 0)) {
01344 ast_log(LOG_WARNING, "Whoa, failed to remove the parking extension!\n");
01345 return -1;
01346 } else {
01347 notify_metermaids(args->pu->parkingexten, pu_toremove->parkinglot->parking_con, AST_DEVICE_NOT_INUSE);
01348 }
01349 } else {
01350 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01351 return -1;
01352 }
01353 if (pu_toremove == args->pu) {
01354 AST_LIST_REMOVE_CURRENT(list);
01355 break;
01356 }
01357 }
01358 AST_LIST_TRAVERSE_SAFE_END;
01359 AST_LIST_UNLOCK(&args->pu->parkinglot->parkings);
01360
01361
01362 ast_free(args->pu);
01363 args->pu = NULL;
01364
01365 ast_hangup(toremove);
01366 return 0;
01367 }
01368
01369 AST_TEST_DEFINE(features_test)
01370 {
01371 int saved_parkeddynamic;
01372 struct ast_channel *test_channel1 = NULL;
01373 struct ast_channel *parked_chan = NULL;
01374 struct ast_parkinglot *dynlot = NULL;
01375 struct ast_park_call_args args = {
01376 .timeout = DEFAULT_PARK_TIME,
01377 };
01378
01379 int res = -1;
01380
01381 static const struct ast_channel_tech fake_tech = {
01382 .fixup = fake_fixup,
01383 };
01384
01385 static const char unique_parkinglot[] = "myuniquetestparkinglot3141592654";
01386 static const char parkinglot_range[] = "750-760";
01387
01388 switch (cmd) {
01389 case TEST_INIT:
01390 info->name = "features_test";
01391 info->category = "/main/features/";
01392 info->summary = "Features unit test";
01393 info->description =
01394 "Tests whether parking respects PARKINGLOT settings";
01395 return AST_TEST_NOT_RUN;
01396 case TEST_EXECUTE:
01397 break;
01398 }
01399
01400
01401 saved_parkeddynamic = parkeddynamic;
01402 parkeddynamic = 1;
01403
01404 if (!(test_channel1 = create_test_channel(&fake_tech))) {
01405 goto exit_features_test;
01406 }
01407
01408 ast_test_status_update(test, "Test parking functionality with defaults\n");
01409 if (park_call_full(test_channel1, NULL, &args)) {
01410 goto exit_features_test;
01411 }
01412 if (unpark_test_channel(test_channel1, &args)) {
01413 goto exit_features_test;
01414 }
01415
01416 ast_test_status_update(test, "Check that certain parking options are respected\n");
01417 if (!(test_channel1 = create_test_channel(&fake_tech))) {
01418 goto exit_features_test;
01419 }
01420 pbx_builtin_setvar_helper(test_channel1, "PARKINGLOT", unique_parkinglot);
01421 pbx_builtin_setvar_helper(test_channel1, "PARKINGDYNPOS", parkinglot_range);
01422 if (park_call_full(test_channel1, NULL, &args)) {
01423 goto exit_features_test;
01424 }
01425
01426 dynlot = args.pu->parkinglot;
01427 if (!args.pu->parkingnum == 750 || strcasecmp(args.pu->parkinglot->name, unique_parkinglot)) {
01428 ast_test_status_update(test, "Parking settings were not respected\n");
01429 goto exit_features_test;
01430 } else {
01431 ast_test_status_update(test, "Parking settings for non-masquerading park verified\n");
01432 }
01433 if (unpark_test_channel(test_channel1, &args)) {
01434 goto exit_features_test;
01435 }
01436
01437 ast_test_status_update(test, "Check #2 that certain parking options are respected\n");
01438 if (!(test_channel1 = create_test_channel(&fake_tech))) {
01439 goto exit_features_test;
01440 }
01441 pbx_builtin_setvar_helper(test_channel1, "PARKINGLOT", unique_parkinglot);
01442 pbx_builtin_setvar_helper(test_channel1, "PARKINGDYNPOS", parkinglot_range);
01443 if (masq_park_call(test_channel1, NULL, 0, NULL, 0, &args) == AST_FEATURE_RETURN_PARKFAILED) {
01444 goto exit_features_test;
01445 }
01446
01447 ast_hangup(test_channel1);
01448 test_channel1 = NULL;
01449 if (!args.pu->parkingnum == 750 || strcasecmp(args.pu->parkinglot->name, unique_parkinglot)) {
01450 ast_test_status_update(test, "Parking settings were not respected\n");
01451 goto exit_features_test;
01452 } else {
01453 ast_test_status_update(test, "Parking settings for masquerading park verified\n");
01454 }
01455
01456 parked_chan = ast_channel_get_by_name("TestChannel1");
01457 if (unpark_test_channel(parked_chan, &args)) {
01458 goto exit_features_test;
01459 }
01460
01461 res = 0;
01462
01463 exit_features_test:
01464
01465 if (test_channel1) {
01466 ast_hangup(test_channel1);
01467 }
01468
01469
01470 ao2_unlink(parkinglots, dynlot);
01471 parkeddynamic = saved_parkeddynamic;
01472 return res ? AST_TEST_FAIL : AST_TEST_PASS;
01473 }
01474 #endif
01475
01476
01477
01478
01479
01480
01481
01482
01483 static void set_peers(struct ast_channel **caller, struct ast_channel **callee,
01484 struct ast_channel *peer, struct ast_channel *chan, int sense)
01485 {
01486 if (sense == FEATURE_SENSE_PEER) {
01487 *caller = peer;
01488 *callee = chan;
01489 } else {
01490 *callee = peer;
01491 *caller = chan;
01492 }
01493 }
01494
01495 static int parkcall_helper(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, struct ast_park_call_args *args)
01496 {
01497 int res = 0;
01498
01499 if (args) {
01500 ast_debug(1, "Parkinglot specified for builtin_parkcall: %s\n", args->parkinglot->name);
01501 }
01502
01503
01504
01505
01506
01507
01508
01509
01510
01511 if (chan->_state != AST_STATE_UP)
01512 res = ast_answer(chan);
01513 if (!res)
01514 res = ast_safe_sleep(chan, 1000);
01515
01516 if (!res) {
01517 struct ast_channel *parker;
01518 struct ast_channel *parkee;
01519 set_peers(&parker, &parkee, peer, chan, sense);
01520 res = masq_park_call_announce(parkee, parker, args);
01521
01522 }
01523
01524 return res;
01525 }
01526
01527
01528
01529
01530
01531
01532
01533
01534
01535
01536
01537
01538
01539 static int builtin_parkcall(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
01540 {
01541 return parkcall_helper(chan, peer, config, code, sense, NULL);
01542 }
01543
01544
01545
01546
01547 static int play_message_in_bridged_call(struct ast_channel *caller_chan, struct ast_channel *callee_chan, const char *audiofile)
01548 {
01549
01550 if (ast_autoservice_start(callee_chan))
01551 return -1;
01552 ast_autoservice_ignore(callee_chan, AST_FRAME_DTMF_END);
01553 if (ast_stream_and_wait(caller_chan, audiofile, "")) {
01554 ast_log(LOG_WARNING, "Failed to play automon message!\n");
01555 ast_autoservice_stop(callee_chan);
01556 return -1;
01557 }
01558 if (ast_autoservice_stop(callee_chan))
01559 return -1;
01560
01561 if (ast_autoservice_start(caller_chan))
01562 return -1;
01563 ast_autoservice_ignore(caller_chan, AST_FRAME_DTMF_END);
01564 if (ast_stream_and_wait(callee_chan, audiofile, "")) {
01565 ast_log(LOG_WARNING, "Failed to play automon message !\n");
01566 ast_autoservice_stop(caller_chan);
01567 return -1;
01568 }
01569 if (ast_autoservice_stop(caller_chan))
01570 return -1;
01571 return(0);
01572 }
01573
01574
01575
01576
01577
01578
01579
01580
01581
01582
01583
01584
01585
01586
01587
01588 static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
01589 {
01590 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
01591 int x = 0;
01592 size_t len;
01593 struct ast_channel *caller_chan, *callee_chan;
01594 const char *automon_message_start = NULL;
01595 const char *automon_message_stop = NULL;
01596
01597 if (!monitor_ok) {
01598 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
01599 return -1;
01600 }
01601
01602 if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) {
01603 monitor_ok = 0;
01604 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
01605 return -1;
01606 }
01607
01608 set_peers(&caller_chan, &callee_chan, peer, chan, sense);
01609 if (caller_chan) {
01610 automon_message_start = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_START");
01611 automon_message_stop = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_STOP");
01612 }
01613
01614 if (!ast_strlen_zero(courtesytone)) {
01615 if(play_message_in_bridged_call(caller_chan, callee_chan, courtesytone) == -1) {
01616 return -1;
01617 }
01618 }
01619
01620 if (callee_chan->monitor) {
01621 ast_verb(4, "User hit '%s' to stop recording call.\n", code);
01622 if (!ast_strlen_zero(automon_message_stop)) {
01623 play_message_in_bridged_call(caller_chan, callee_chan, automon_message_stop);
01624 }
01625 callee_chan->monitor->stop(callee_chan, 1);
01626 return AST_FEATURE_RETURN_SUCCESS;
01627 }
01628
01629 if (caller_chan && callee_chan) {
01630 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT");
01631 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
01632 const char *touch_monitor_prefix = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_PREFIX");
01633
01634 if (!touch_format)
01635 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
01636
01637 if (!touch_monitor)
01638 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
01639
01640 if (!touch_monitor_prefix)
01641 touch_monitor_prefix = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_PREFIX");
01642
01643 if (touch_monitor) {
01644 len = strlen(touch_monitor) + 50;
01645 args = alloca(len);
01646 touch_filename = alloca(len);
01647 snprintf(touch_filename, len, "%s-%ld-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), touch_monitor);
01648 snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename);
01649 } else {
01650 caller_chan_id = ast_strdupa(S_COR(caller_chan->caller.id.number.valid,
01651 caller_chan->caller.id.number.str, caller_chan->name));
01652 callee_chan_id = ast_strdupa(S_COR(callee_chan->caller.id.number.valid,
01653 callee_chan->caller.id.number.str, callee_chan->name));
01654 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
01655 args = alloca(len);
01656 touch_filename = alloca(len);
01657 snprintf(touch_filename, len, "%s-%ld-%s-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), caller_chan_id, callee_chan_id);
01658 snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename);
01659 }
01660
01661 for(x = 0; x < strlen(args); x++) {
01662 if (args[x] == '/')
01663 args[x] = '-';
01664 }
01665
01666 ast_verb(4, "User hit '%s' to record call. filename: %s\n", code, args);
01667
01668 pbx_exec(callee_chan, monitor_app, args);
01669 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
01670 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
01671
01672 if (!ast_strlen_zero(automon_message_start)) {
01673 play_message_in_bridged_call(caller_chan, callee_chan, automon_message_start);
01674 }
01675
01676 return AST_FEATURE_RETURN_SUCCESS;
01677 }
01678
01679 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");
01680 return -1;
01681 }
01682
01683 static int builtin_automixmonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
01684 {
01685 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
01686 int x = 0;
01687 size_t len;
01688 struct ast_channel *caller_chan, *callee_chan;
01689 const char *mixmonitor_spy_type = "MixMonitor";
01690 int count = 0;
01691
01692 if (!mixmonitor_ok) {
01693 ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n");
01694 return -1;
01695 }
01696
01697 if (!(mixmonitor_app = pbx_findapp("MixMonitor"))) {
01698 mixmonitor_ok = 0;
01699 ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n");
01700 return -1;
01701 }
01702
01703 set_peers(&caller_chan, &callee_chan, peer, chan, sense);
01704
01705 if (!ast_strlen_zero(courtesytone)) {
01706 if (ast_autoservice_start(callee_chan))
01707 return -1;
01708 ast_autoservice_ignore(callee_chan, AST_FRAME_DTMF_END);
01709 if (ast_stream_and_wait(caller_chan, courtesytone, "")) {
01710 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
01711 ast_autoservice_stop(callee_chan);
01712 return -1;
01713 }
01714 if (ast_autoservice_stop(callee_chan))
01715 return -1;
01716 }
01717
01718 ast_channel_lock(callee_chan);
01719 count = ast_channel_audiohook_count_by_source(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY);
01720 ast_channel_unlock(callee_chan);
01721
01722
01723 if (count > 0) {
01724
01725 ast_verb(3, "User hit '%s' to stop recording call.\n", code);
01726
01727
01728 ast_channel_lock(callee_chan);
01729 count = ast_channel_audiohook_count_by_source_running(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY);
01730 ast_channel_unlock(callee_chan);
01731 if (count > 0) {
01732 if (!stopmixmonitor_ok) {
01733 ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n");
01734 return -1;
01735 }
01736 if (!(stopmixmonitor_app = pbx_findapp("StopMixMonitor"))) {
01737 stopmixmonitor_ok = 0;
01738 ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n");
01739 return -1;
01740 } else {
01741 pbx_exec(callee_chan, stopmixmonitor_app, "");
01742 return AST_FEATURE_RETURN_SUCCESS;
01743 }
01744 }
01745
01746 ast_log(LOG_WARNING,"Stopped MixMonitors are attached to the channel.\n");
01747 }
01748
01749 if (caller_chan && callee_chan) {
01750 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR_FORMAT");
01751 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR");
01752
01753 if (!touch_format)
01754 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR_FORMAT");
01755
01756 if (!touch_monitor)
01757 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR");
01758
01759 if (touch_monitor) {
01760 len = strlen(touch_monitor) + 50;
01761 args = alloca(len);
01762 touch_filename = alloca(len);
01763 snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor);
01764 snprintf(args, len, "%s.%s,b", touch_filename, (touch_format) ? touch_format : "wav");
01765 } else {
01766 caller_chan_id = ast_strdupa(S_COR(caller_chan->caller.id.number.valid,
01767 caller_chan->caller.id.number.str, caller_chan->name));
01768 callee_chan_id = ast_strdupa(S_COR(callee_chan->caller.id.number.valid,
01769 callee_chan->caller.id.number.str, callee_chan->name));
01770 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
01771 args = alloca(len);
01772 touch_filename = alloca(len);
01773 snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id);
01774 snprintf(args, len, "%s.%s,b", touch_filename, S_OR(touch_format, "wav"));
01775 }
01776
01777 for( x = 0; x < strlen(args); x++) {
01778 if (args[x] == '/')
01779 args[x] = '-';
01780 }
01781
01782 ast_verb(3, "User hit '%s' to record call. filename: %s\n", code, touch_filename);
01783
01784 pbx_exec(callee_chan, mixmonitor_app, args);
01785 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename);
01786 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename);
01787 return AST_FEATURE_RETURN_SUCCESS;
01788
01789 }
01790
01791 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");
01792 return -1;
01793
01794 }
01795
01796 static int builtin_disconnect(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
01797 {
01798 ast_verb(4, "User hit '%s' to disconnect call.\n", code);
01799 return AST_FEATURE_RETURN_HANGUP;
01800 }
01801
01802 static int finishup(struct ast_channel *chan)
01803 {
01804 ast_indicate(chan, AST_CONTROL_UNHOLD);
01805
01806 return ast_autoservice_stop(chan);
01807 }
01808
01809
01810
01811
01812
01813
01814
01815
01816
01817 static const char *real_ctx(struct ast_channel *transferer, struct ast_channel *transferee)
01818 {
01819 const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT");
01820 if (ast_strlen_zero(s)) {
01821 s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT");
01822 }
01823 if (ast_strlen_zero(s)) {
01824 s = transferer->macrocontext;
01825 }
01826 if (ast_strlen_zero(s)) {
01827 s = transferer->context;
01828 }
01829 return s;
01830 }
01831
01832
01833
01834
01835
01836
01837
01838
01839
01840
01841
01842
01843
01844
01845
01846 static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
01847 {
01848 struct ast_channel *transferer;
01849 struct ast_channel *transferee;
01850 const char *transferer_real_context;
01851 struct ast_parkinglot *found_lot = NULL;
01852 char xferto[256];
01853 int res, parkstatus = 0;
01854
01855 set_peers(&transferer, &transferee, peer, chan, sense);
01856 transferer_real_context = real_ctx(transferer, transferee);
01857
01858 ast_autoservice_start(transferee);
01859 ast_autoservice_ignore(transferee, AST_FRAME_DTMF_END);
01860 ast_indicate(transferee, AST_CONTROL_HOLD);
01861
01862 memset(xferto, 0, sizeof(xferto));
01863
01864
01865 res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY);
01866 if (res < 0) {
01867 finishup(transferee);
01868 return -1;
01869 }
01870 if (res > 0)
01871 xferto[0] = (char) res;
01872
01873 ast_stopstream(transferer);
01874 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
01875 if (res < 0) {
01876 finishup(transferee);
01877 return res;
01878 }
01879
01880 found_lot = ao2_callback(parkinglots, 0, find_parkinglot_by_exten_cb, &xferto);
01881 if (found_lot) {
01882 struct ast_park_call_args args = {
01883 .parkinglot = found_lot,
01884 };
01885 res = finishup(transferee);
01886 if (res)
01887 res = -1;
01888 else if (!(parkstatus = masq_park_call_announce(transferee, transferer, &args))) {
01889
01890
01891
01892
01893 return 0;
01894 } else {
01895 ast_log(LOG_WARNING, "Unable to park call %s, parkstatus = %d\n", transferee->name, parkstatus);
01896 }
01897
01898 } else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1,
01899 S_COR(transferer->caller.id.number.valid, transferer->caller.id.number.str, NULL))) {
01900 ast_cel_report_event(transferer, AST_CEL_BLINDTRANSFER, NULL, xferto, transferee);
01901 pbx_builtin_setvar_helper(transferer, "BLINDTRANSFER", transferee->name);
01902 pbx_builtin_setvar_helper(transferee, "BLINDTRANSFER", transferer->name);
01903 res=finishup(transferee);
01904 if (!transferer->cdr) {
01905 transferer->cdr=ast_cdr_alloc();
01906 if (transferer->cdr) {
01907 ast_cdr_init(transferer->cdr, transferer);
01908 ast_cdr_start(transferer->cdr);
01909 }
01910 }
01911 if (transferer->cdr) {
01912 struct ast_cdr *swap = transferer->cdr;
01913 ast_log(LOG_DEBUG,"transferer=%s; transferee=%s; lastapp=%s; lastdata=%s; chan=%s; dstchan=%s\n",
01914 transferer->name, transferee->name, transferer->cdr->lastapp, transferer->cdr->lastdata,
01915 transferer->cdr->channel, transferer->cdr->dstchannel);
01916 ast_log(LOG_DEBUG,"TRANSFEREE; lastapp=%s; lastdata=%s, chan=%s; dstchan=%s\n",
01917 transferee->cdr->lastapp, transferee->cdr->lastdata, transferee->cdr->channel, transferee->cdr->dstchannel);
01918 ast_log(LOG_DEBUG,"transferer_real_context=%s; xferto=%s\n", transferer_real_context, xferto);
01919
01920 transferer->cdr = transferee->cdr;
01921 transferee->cdr = swap;
01922 }
01923 if (!transferee->pbx) {
01924
01925 ast_verb(3, "Transferring %s to '%s' (context %s) priority 1\n"
01926 ,transferee->name, xferto, transferer_real_context);
01927 if (ast_async_goto(transferee, transferer_real_context, xferto, 1))
01928 ast_log(LOG_WARNING, "Async goto failed :-(\n");
01929 } else {
01930
01931 ast_set_flag(transferee, AST_FLAG_BRIDGE_HANGUP_DONT);
01932 ast_log(LOG_DEBUG,"ABOUT TO AST_ASYNC_GOTO, have a pbx... set HANGUP_DONT on chan=%s\n", transferee->name);
01933 if (ast_channel_connected_line_macro(transferee, transferer, &transferer->connected, 1, 0)) {
01934 ast_channel_update_connected_line(transferer, &transferer->connected, NULL);
01935 }
01936 set_c_e_p(transferee, transferer_real_context, xferto, 0);
01937 }
01938 check_goto_on_transfer(transferer);
01939 return res;
01940 } else {
01941 ast_verb(3, "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context);
01942 }
01943 if (parkstatus != AST_FEATURE_RETURN_PARKFAILED && ast_stream_and_wait(transferer, xferfailsound, AST_DIGIT_ANY) < 0) {
01944 finishup(transferee);
01945 return -1;
01946 }
01947 ast_stopstream(transferer);
01948 res = finishup(transferee);
01949 if (res) {
01950 ast_verb(2, "Hungup during autoservice stop on '%s'\n", transferee->name);
01951 return res;
01952 }
01953 return AST_FEATURE_RETURN_SUCCESS;
01954 }
01955
01956
01957
01958
01959
01960
01961
01962
01963 static int check_compat(struct ast_channel *c, struct ast_channel *newchan)
01964 {
01965 if (ast_channel_make_compatible(c, newchan) < 0) {
01966 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n",
01967 c->name, newchan->name);
01968 ast_hangup(newchan);
01969 return -1;
01970 }
01971 return 0;
01972 }
01973
01974
01975
01976
01977
01978
01979
01980
01981
01982
01983
01984
01985
01986
01987 static void atxfer_fail_cleanup(struct ast_channel *transferee, struct ast_channel *transferer, struct ast_party_connected_line *connected_line)
01988 {
01989 finishup(transferee);
01990
01991
01992
01993
01994
01995
01996
01997 if (ast_channel_connected_line_macro(transferee, transferer, connected_line, 1, 0)) {
01998 ast_channel_update_connected_line(transferer, connected_line, NULL);
01999 }
02000 ast_party_connected_line_free(connected_line);
02001 }
02002
02003
02004
02005
02006
02007
02008
02009
02010
02011
02012
02013
02014
02015
02016
02017
02018 static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
02019 {
02020 struct ast_channel *transferer;
02021 struct ast_channel *transferee;
02022 const char *transferer_real_context;
02023 char xferto[256] = "";
02024 int res;
02025 int outstate=0;
02026 struct ast_channel *newchan;
02027 struct ast_channel *xferchan;
02028 struct ast_bridge_thread_obj *tobj;
02029 struct ast_bridge_config bconfig;
02030 int l;
02031 struct ast_party_connected_line connected_line;
02032 struct ast_datastore *features_datastore;
02033 struct ast_dial_features *dialfeatures = NULL;
02034 struct ast_parkinglot *parkinglot;
02035 char *transferer_tech;
02036 char *transferer_name;
02037 char *transferer_name_orig;
02038 char *dash;
02039
02040 ast_debug(1, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense);
02041 set_peers(&transferer, &transferee, peer, chan, sense);
02042 transferer_real_context = real_ctx(transferer, transferee);
02043
02044
02045 ast_autoservice_start(transferee);
02046 ast_indicate(transferee, AST_CONTROL_HOLD);
02047
02048
02049 res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY);
02050 if (res < 0) {
02051 finishup(transferee);
02052 return -1;
02053 }
02054 if (res > 0)
02055 xferto[0] = (char) res;
02056
02057
02058 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
02059 if (res < 0) {
02060 finishup(transferee);
02061 return -1;
02062 }
02063 l = strlen(xferto);
02064 if (res == 0) {
02065 if (l) {
02066 ast_log(LOG_WARNING, "Extension '%s' does not exist in context '%s'\n",
02067 xferto, transferer_real_context);
02068 } else {
02069
02070 ast_log(LOG_WARNING, "No digits dialed for atxfer.\n");
02071 }
02072 ast_stream_and_wait(transferer, "pbx-invalid", "");
02073 finishup(transferee);
02074 return AST_FEATURE_RETURN_SUCCESS;
02075 }
02076
02077
02078
02079 parkinglot = ao2_callback(parkinglots, 0, find_parkinglot_by_exten_cb, &xferto);
02080 if (parkinglot) {
02081 struct ast_park_call_args args = {
02082 .parkinglot = parkinglot,
02083 };
02084 finishup(transferee);
02085 return parkcall_helper(chan, peer, config, code, sense, &args);
02086 }
02087
02088
02089 snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context);
02090
02091
02092
02093 if (transferee) {
02094 const char *chan1_attended_sound = pbx_builtin_getvar_helper(transferer, "ATTENDED_TRANSFER_COMPLETE_SOUND");
02095 const char *chan2_attended_sound = pbx_builtin_getvar_helper(transferee, "ATTENDED_TRANSFER_COMPLETE_SOUND");
02096
02097 if (!ast_strlen_zero(chan1_attended_sound)) {
02098 pbx_builtin_setvar_helper(transferer, "BRIDGE_PLAY_SOUND", chan1_attended_sound);
02099 }
02100 if (!ast_strlen_zero(chan2_attended_sound)) {
02101 pbx_builtin_setvar_helper(transferee, "BRIDGE_PLAY_SOUND", chan2_attended_sound);
02102 }
02103 }
02104
02105
02106 transferer_name_orig = ast_strdupa(transferer->name);
02107 transferer_name = ast_strdupa(transferer_name_orig);
02108 transferer_tech = strsep(&transferer_name, "/");
02109 dash = strrchr(transferer_name, '-');
02110 if (dash) {
02111
02112 *dash = '\0';
02113 }
02114
02115
02116 if (ast_autoservice_stop(transferee) < 0) {
02117 ast_indicate(transferee, AST_CONTROL_UNHOLD);
02118 return -1;
02119 }
02120
02121
02122 ast_party_connected_line_init(&connected_line);
02123 ast_channel_lock(transferer);
02124 ast_party_connected_line_copy(&connected_line, &transferer->connected);
02125 ast_channel_unlock(transferer);
02126 connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
02127
02128
02129 newchan = feature_request_and_dial(transferer, transferer_name_orig, transferer,
02130 transferee, "Local", ast_best_codec(transferer->nativeformats), xferto,
02131 atxfernoanswertimeout, &outstate, transferer->language);
02132 ast_debug(2, "Dial party C result: newchan:%d, outstate:%d\n", !!newchan, outstate);
02133
02134 if (!ast_check_hangup(transferer)) {
02135 int hangup_dont = 0;
02136
02137
02138 ast_debug(1, "Actually doing an attended transfer.\n");
02139
02140
02141 ast_autoservice_start(transferee);
02142
02143 ast_indicate(transferer, -1);
02144 if (!newchan) {
02145
02146 switch (outstate) {
02147 case AST_CONTROL_UNHOLD:
02148 case AST_CONTROL_BUSY:
02149 case AST_CONTROL_CONGESTION:
02150 if (ast_stream_and_wait(transferer, xfersound, "")) {
02151 ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
02152 }
02153 break;
02154 default:
02155 if (ast_stream_and_wait(transferer, xferfailsound, "")) {
02156 ast_log(LOG_WARNING, "Failed to play transfer failed sound!\n");
02157 }
02158 break;
02159 }
02160 atxfer_fail_cleanup(transferee, transferer, &connected_line);
02161 return AST_FEATURE_RETURN_SUCCESS;
02162 }
02163
02164 if (check_compat(transferer, newchan)) {
02165 if (ast_stream_and_wait(transferer, xferfailsound, "")) {
02166 ast_log(LOG_WARNING, "Failed to play transfer failed sound!\n");
02167 }
02168 atxfer_fail_cleanup(transferee, transferer, &connected_line);
02169 return AST_FEATURE_RETURN_SUCCESS;
02170 }
02171 memset(&bconfig,0,sizeof(struct ast_bridge_config));
02172 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
02173 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
02174
02175
02176
02177
02178 if (ast_test_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT)) {
02179 hangup_dont = 1;
02180 }
02181
02182 ast_bridge_call(transferer, newchan, &bconfig);
02183 if (hangup_dont) {
02184 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT);
02185 }
02186
02187 if (ast_check_hangup(newchan) || !ast_check_hangup(transferer)) {
02188 ast_hangup(newchan);
02189 if (ast_stream_and_wait(transferer, xfersound, "")) {
02190 ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
02191 }
02192 atxfer_fail_cleanup(transferee, transferer, &connected_line);
02193 return AST_FEATURE_RETURN_SUCCESS;
02194 }
02195
02196
02197 if (check_compat(transferee, newchan)) {
02198 finishup(transferee);
02199 ast_party_connected_line_free(&connected_line);
02200 return -1;
02201 }
02202
02203 ast_indicate(transferee, AST_CONTROL_UNHOLD);
02204 if ((ast_autoservice_stop(transferee) < 0)
02205 || (ast_waitfordigit(transferee, 100) < 0)
02206 || (ast_waitfordigit(newchan, 100) < 0)
02207 || ast_check_hangup(transferee)
02208 || ast_check_hangup(newchan)) {
02209 ast_hangup(newchan);
02210 ast_party_connected_line_free(&connected_line);
02211 return -1;
02212 }
02213 } else if (!ast_check_hangup(transferee)) {
02214
02215 ast_debug(1, "Actually doing a blonde transfer.\n");
02216
02217 if (!newchan && !atxferdropcall) {
02218
02219 unsigned int tries = 0;
02220
02221 if (ast_strlen_zero(transferer_name) || ast_strlen_zero(transferer_tech)) {
02222 ast_log(LOG_WARNING,
02223 "Transferer channel name: '%s' cannot be used for callback.\n",
02224 transferer_name_orig);
02225 ast_indicate(transferee, AST_CONTROL_UNHOLD);
02226 ast_party_connected_line_free(&connected_line);
02227 return -1;
02228 }
02229
02230 tries = 0;
02231 for (;;) {
02232
02233 ast_debug(1, "We're trying to callback %s/%s\n",
02234 transferer_tech, transferer_name);
02235 newchan = feature_request_and_dial(transferer, transferer_name_orig,
02236 transferee, transferee, transferer_tech,
02237 ast_best_codec(transferee->nativeformats), transferer_name,
02238 atxfernoanswertimeout, &outstate, transferer->language);
02239 ast_debug(2, "Dial party B result: newchan:%d, outstate:%d\n",
02240 !!newchan, outstate);
02241 if (newchan || ast_check_hangup(transferee)) {
02242 break;
02243 }
02244
02245 ++tries;
02246 if (atxfercallbackretries <= tries) {
02247
02248 break;
02249 }
02250
02251 if (atxferloopdelay) {
02252
02253 ast_debug(1, "Sleeping for %d ms before retrying atxfer.\n",
02254 atxferloopdelay);
02255 ast_safe_sleep(transferee, atxferloopdelay);
02256 if (ast_check_hangup(transferee)) {
02257 ast_party_connected_line_free(&connected_line);
02258 return -1;
02259 }
02260 }
02261
02262
02263 ast_debug(1, "We're retrying to call %s/%s\n", "Local", xferto);
02264 newchan = feature_request_and_dial(transferer, transferer_name_orig,
02265 transferer, transferee, "Local",
02266 ast_best_codec(transferee->nativeformats), xferto,
02267 atxfernoanswertimeout, &outstate, transferer->language);
02268 ast_debug(2, "Redial party C result: newchan:%d, outstate:%d\n",
02269 !!newchan, outstate);
02270 if (newchan || ast_check_hangup(transferee)) {
02271 break;
02272 }
02273 }
02274 }
02275 ast_indicate(transferee, AST_CONTROL_UNHOLD);
02276 if (!newchan) {
02277
02278 ast_party_connected_line_free(&connected_line);
02279 return -1;
02280 }
02281
02282
02283 if (ast_check_hangup(newchan)) {
02284 ast_hangup(newchan);
02285 ast_party_connected_line_free(&connected_line);
02286 return -1;
02287 }
02288 if (check_compat(transferee, newchan)) {
02289 ast_party_connected_line_free(&connected_line);
02290 return -1;
02291 }
02292 } else {
02293
02294
02295
02296
02297 ast_debug(1, "Everyone is hungup.\n");
02298 if (newchan) {
02299 ast_hangup(newchan);
02300 }
02301 ast_party_connected_line_free(&connected_line);
02302 return -1;
02303 }
02304
02305
02306 ast_cel_report_event(transferee, AST_CEL_ATTENDEDTRANSFER, NULL, NULL, newchan);
02307
02308 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", transferee->linkedid, 0, "Transfered/%s", transferee->name);
02309 if (!xferchan) {
02310 ast_hangup(newchan);
02311 ast_party_connected_line_free(&connected_line);
02312 return -1;
02313 }
02314
02315
02316 xferchan->visible_indication = AST_CONTROL_RINGING;
02317
02318
02319 xferchan->readformat = transferee->readformat;
02320 xferchan->writeformat = transferee->writeformat;
02321
02322 ast_channel_masquerade(xferchan, transferee);
02323 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
02324 xferchan->_state = AST_STATE_UP;
02325 ast_clear_flag(xferchan, AST_FLAGS_ALL);
02326
02327
02328 ast_do_masquerade(xferchan);
02329
02330 newchan->_state = AST_STATE_UP;
02331 ast_clear_flag(newchan, AST_FLAGS_ALL);
02332 tobj = ast_calloc(1, sizeof(*tobj));
02333 if (!tobj) {
02334 ast_hangup(xferchan);
02335 ast_hangup(newchan);
02336 ast_party_connected_line_free(&connected_line);
02337 return -1;
02338 }
02339
02340 ast_channel_lock(newchan);
02341 if ((features_datastore = ast_channel_datastore_find(newchan, &dial_features_info, NULL))) {
02342 dialfeatures = features_datastore->data;
02343 }
02344 ast_channel_unlock(newchan);
02345
02346 if (dialfeatures) {
02347
02348
02349 ast_copy_flags(&(config->features_callee), &(dialfeatures->features_caller), AST_FLAGS_ALL);
02350 dialfeatures = NULL;
02351 }
02352
02353 ast_channel_lock(xferchan);
02354 if ((features_datastore = ast_channel_datastore_find(xferchan, &dial_features_info, NULL))) {
02355 dialfeatures = features_datastore->data;
02356 }
02357 ast_channel_unlock(xferchan);
02358
02359 if (dialfeatures) {
02360 ast_copy_flags(&(config->features_caller), &(dialfeatures->features_caller), AST_FLAGS_ALL);
02361 }
02362
02363 tobj->chan = newchan;
02364 tobj->peer = xferchan;
02365 tobj->bconfig = *config;
02366
02367 if (tobj->bconfig.end_bridge_callback_data_fixup) {
02368 tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan);
02369 }
02370
02371
02372
02373
02374
02375
02376
02377
02378
02379
02380
02381
02382
02383
02384
02385
02386
02387
02388
02389
02390
02391
02392
02393
02394
02395
02396
02397
02398
02399
02400
02401 ast_channel_lock(transferer);
02402
02403
02404
02405
02406 ast_party_connected_line_copy(&connected_line, &transferer->connected);
02407 ast_channel_unlock(transferer);
02408 connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
02409 if (ast_channel_connected_line_macro(newchan, xferchan, &connected_line, 1, 0)) {
02410 ast_channel_update_connected_line(xferchan, &connected_line, NULL);
02411 }
02412
02413
02414 ast_channel_lock(xferchan);
02415 ast_connected_line_copy_from_caller(&connected_line, &xferchan->caller);
02416 ast_channel_unlock(xferchan);
02417 connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
02418 if (ast_channel_connected_line_macro(xferchan, newchan, &connected_line, 0, 0)) {
02419 ast_channel_update_connected_line(newchan, &connected_line, NULL);
02420 }
02421
02422 if (ast_stream_and_wait(newchan, xfersound, ""))
02423 ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
02424 bridge_call_thread_launch(tobj);
02425
02426 ast_party_connected_line_free(&connected_line);
02427 return -1;
02428 }
02429
02430
02431 #define FEATURES_COUNT ARRAY_LEN(builtin_features)
02432
02433 AST_RWLOCK_DEFINE_STATIC(features_lock);
02434
02435 static struct ast_call_feature builtin_features[] = {
02436 { AST_FEATURE_REDIRECT, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
02437 { AST_FEATURE_REDIRECT, "Attended Transfer", "atxfer", "", "", builtin_atxfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
02438 { AST_FEATURE_AUTOMON, "One Touch Monitor", "automon", "", "", builtin_automonitor, AST_FEATURE_FLAG_NEEDSDTMF, "" },
02439 { AST_FEATURE_DISCONNECT, "Disconnect Call", "disconnect", "*", "*", builtin_disconnect, AST_FEATURE_FLAG_NEEDSDTMF, "" },
02440 { AST_FEATURE_PARKCALL, "Park Call", "parkcall", "", "", builtin_parkcall, AST_FEATURE_FLAG_NEEDSDTMF, "" },
02441 { AST_FEATURE_AUTOMIXMON, "One Touch MixMonitor", "automixmon", "", "", builtin_automixmonitor, AST_FEATURE_FLAG_NEEDSDTMF, "" },
02442 };
02443
02444
02445 static AST_RWLIST_HEAD_STATIC(feature_list, ast_call_feature);
02446
02447
02448 void ast_register_feature(struct ast_call_feature *feature)
02449 {
02450 if (!feature) {
02451 ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
02452 return;
02453 }
02454
02455 AST_RWLIST_WRLOCK(&feature_list);
02456 AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry);
02457 AST_RWLIST_UNLOCK(&feature_list);
02458
02459 ast_verb(2, "Registered Feature '%s'\n",feature->sname);
02460 }
02461
02462
02463
02464
02465
02466
02467
02468
02469 static struct feature_group *register_group(const char *fgname)
02470 {
02471 struct feature_group *fg;
02472
02473 if (!fgname) {
02474 ast_log(LOG_NOTICE, "You didn't pass a new group name!\n");
02475 return NULL;
02476 }
02477
02478 if (!(fg = ast_calloc_with_stringfields(1, struct feature_group, 128))) {
02479 return NULL;
02480 }
02481
02482 ast_string_field_set(fg, gname, fgname);
02483
02484 AST_LIST_INSERT_HEAD(&feature_groups, fg, entry);
02485
02486 ast_verb(2, "Registered group '%s'\n", fg->gname);
02487
02488 return fg;
02489 }
02490
02491
02492
02493
02494
02495
02496
02497
02498
02499
02500 static void register_group_feature(struct feature_group *fg, const char *exten, struct ast_call_feature *feature)
02501 {
02502 struct feature_group_exten *fge;
02503
02504 if (!fg) {
02505 ast_log(LOG_NOTICE, "You didn't pass a group!\n");
02506 return;
02507 }
02508
02509 if (!feature) {
02510 ast_log(LOG_NOTICE, "You didn't pass a feature!\n");
02511 return;
02512 }
02513
02514 if (!(fge = ast_calloc_with_stringfields(1, struct feature_group_exten, 128))) {
02515 return;
02516 }
02517
02518 ast_string_field_set(fge, exten, S_OR(exten, feature->exten));
02519
02520 fge->feature = feature;
02521
02522 AST_LIST_INSERT_HEAD(&fg->features, fge, entry);
02523
02524 ast_verb(2, "Registered feature '%s' for group '%s' at exten '%s'\n",
02525 feature->sname, fg->gname, fge->exten);
02526 }
02527
02528 void ast_unregister_feature(struct ast_call_feature *feature)
02529 {
02530 if (!feature) {
02531 return;
02532 }
02533
02534 AST_RWLIST_WRLOCK(&feature_list);
02535 AST_RWLIST_REMOVE(&feature_list, feature, feature_entry);
02536 AST_RWLIST_UNLOCK(&feature_list);
02537
02538 ast_free(feature);
02539 }
02540
02541
02542 static void ast_unregister_features(void)
02543 {
02544 struct ast_call_feature *feature;
02545
02546 AST_RWLIST_WRLOCK(&feature_list);
02547 while ((feature = AST_RWLIST_REMOVE_HEAD(&feature_list, feature_entry))) {
02548 ast_free(feature);
02549 }
02550 AST_RWLIST_UNLOCK(&feature_list);
02551 }
02552
02553
02554 static struct ast_call_feature *find_dynamic_feature(const char *name)
02555 {
02556 struct ast_call_feature *tmp;
02557
02558 AST_RWLIST_TRAVERSE(&feature_list, tmp, feature_entry) {
02559 if (!strcasecmp(tmp->sname, name)) {
02560 break;
02561 }
02562 }
02563
02564 return tmp;
02565 }
02566
02567
02568 static void ast_unregister_groups(void)
02569 {
02570 struct feature_group *fg;
02571 struct feature_group_exten *fge;
02572
02573 AST_RWLIST_WRLOCK(&feature_groups);
02574 while ((fg = AST_LIST_REMOVE_HEAD(&feature_groups, entry))) {
02575 while ((fge = AST_LIST_REMOVE_HEAD(&fg->features, entry))) {
02576 ast_string_field_free_memory(fge);
02577 ast_free(fge);
02578 }
02579
02580 ast_string_field_free_memory(fg);
02581 ast_free(fg);
02582 }
02583 AST_RWLIST_UNLOCK(&feature_groups);
02584 }
02585
02586
02587
02588
02589
02590
02591
02592 static struct feature_group *find_group(const char *name)
02593 {
02594 struct feature_group *fg = NULL;
02595
02596 AST_LIST_TRAVERSE(&feature_groups, fg, entry) {
02597 if (!strcasecmp(fg->gname, name))
02598 break;
02599 }
02600
02601 return fg;
02602 }
02603
02604 void ast_rdlock_call_features(void)
02605 {
02606 ast_rwlock_rdlock(&features_lock);
02607 }
02608
02609 void ast_unlock_call_features(void)
02610 {
02611 ast_rwlock_unlock(&features_lock);
02612 }
02613
02614 struct ast_call_feature *ast_find_call_feature(const char *name)
02615 {
02616 int x;
02617 for (x = 0; x < FEATURES_COUNT; x++) {
02618 if (!strcasecmp(name, builtin_features[x].sname))
02619 return &builtin_features[x];
02620 }
02621 return NULL;
02622 }
02623
02624
02625
02626
02627
02628
02629
02630
02631
02632
02633 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)
02634 {
02635 struct ast_app *app;
02636 struct ast_call_feature *feature = data;
02637 struct ast_channel *work, *idle;
02638 int res;
02639
02640 if (!feature) {
02641 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
02642 return -1;
02643 }
02644
02645 if (sense == FEATURE_SENSE_CHAN) {
02646 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
02647 return AST_FEATURE_RETURN_KEEPTRYING;
02648 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
02649 work = chan;
02650 idle = peer;
02651 } else {
02652 work = peer;
02653 idle = chan;
02654 }
02655 } else {
02656 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
02657 return AST_FEATURE_RETURN_KEEPTRYING;
02658 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
02659 work = peer;
02660 idle = chan;
02661 } else {
02662 work = chan;
02663 idle = peer;
02664 }
02665 }
02666
02667 if (!(app = pbx_findapp(feature->app))) {
02668 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
02669 return -2;
02670 }
02671
02672 ast_autoservice_start(idle);
02673 ast_autoservice_ignore(idle, AST_FRAME_DTMF_END);
02674
02675 if(work && idle) {
02676 pbx_builtin_setvar_helper(work, "DYNAMIC_PEERNAME", idle->name);
02677 pbx_builtin_setvar_helper(idle, "DYNAMIC_PEERNAME", work->name);
02678 pbx_builtin_setvar_helper(work, "DYNAMIC_FEATURENAME", feature->sname);
02679 pbx_builtin_setvar_helper(idle, "DYNAMIC_FEATURENAME", feature->sname);
02680 }
02681
02682 if (!ast_strlen_zero(feature->moh_class))
02683 ast_moh_start(idle, feature->moh_class, NULL);
02684
02685 res = pbx_exec(work, app, feature->app_args);
02686
02687 if (!ast_strlen_zero(feature->moh_class))
02688 ast_moh_stop(idle);
02689
02690 ast_autoservice_stop(idle);
02691
02692 if (res) {
02693 return AST_FEATURE_RETURN_SUCCESSBREAK;
02694 }
02695 return AST_FEATURE_RETURN_SUCCESS;
02696 }
02697
02698 static void unmap_features(void)
02699 {
02700 int x;
02701
02702 ast_rwlock_wrlock(&features_lock);
02703 for (x = 0; x < FEATURES_COUNT; x++)
02704 strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
02705 ast_rwlock_unlock(&features_lock);
02706 }
02707
02708 static int remap_feature(const char *name, const char *value)
02709 {
02710 int x, res = -1;
02711
02712 ast_rwlock_wrlock(&features_lock);
02713 for (x = 0; x < FEATURES_COUNT; x++) {
02714 if (strcasecmp(builtin_features[x].sname, name))
02715 continue;
02716
02717 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
02718 res = 0;
02719 break;
02720 }
02721 ast_rwlock_unlock(&features_lock);
02722
02723 return res;
02724 }
02725
02726
02727
02728
02729
02730
02731
02732
02733
02734
02735
02736 static int feature_interpret_helper(struct ast_channel *chan, struct ast_channel *peer,
02737 struct ast_bridge_config *config, const char *code, int sense, char *dynamic_features_buf,
02738 struct ast_flags *features, int operation, struct ast_call_feature *feature)
02739 {
02740 int x;
02741 struct feature_group *fg = NULL;
02742 struct feature_group_exten *fge;
02743 struct ast_call_feature *tmpfeature;
02744 char *tmp, *tok;
02745 int res = AST_FEATURE_RETURN_PASSDIGITS;
02746 int feature_detected = 0;
02747
02748 if (!(peer && chan && config) && operation) {
02749 return -1;
02750 }
02751
02752 ast_rwlock_rdlock(&features_lock);
02753 for (x = 0; x < FEATURES_COUNT; x++) {
02754 if ((ast_test_flag(features, builtin_features[x].feature_mask)) &&
02755 !ast_strlen_zero(builtin_features[x].exten)) {
02756
02757 if (!strcmp(builtin_features[x].exten, code)) {
02758 ast_debug(3, "Feature detected: fname=%s sname=%s exten=%s\n", builtin_features[x].fname, builtin_features[x].sname, builtin_features[x].exten);
02759 if (operation) {
02760 res = builtin_features[x].operation(chan, peer, config, code, sense, NULL);
02761 }
02762 memcpy(feature, &builtin_features[x], sizeof(feature));
02763 feature_detected = 1;
02764 break;
02765 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
02766 if (res == AST_FEATURE_RETURN_PASSDIGITS)
02767 res = AST_FEATURE_RETURN_STOREDIGITS;
02768 }
02769 }
02770 }
02771 ast_rwlock_unlock(&features_lock);
02772
02773 if (ast_strlen_zero(dynamic_features_buf) || feature_detected) {
02774 return res;
02775 }
02776
02777 tmp = dynamic_features_buf;
02778
02779 while ((tok = strsep(&tmp, "#"))) {
02780 AST_RWLIST_RDLOCK(&feature_groups);
02781
02782 fg = find_group(tok);
02783
02784 if (fg) {
02785 AST_LIST_TRAVERSE(&fg->features, fge, entry) {
02786 if (!strcmp(fge->exten, code)) {
02787 if (operation) {
02788 res = fge->feature->operation(chan, peer, config, code, sense, fge->feature);
02789 }
02790 memcpy(feature, fge->feature, sizeof(feature));
02791 if (res != AST_FEATURE_RETURN_KEEPTRYING) {
02792 AST_RWLIST_UNLOCK(&feature_groups);
02793 break;
02794 }
02795 res = AST_FEATURE_RETURN_PASSDIGITS;
02796 } else if (!strncmp(fge->exten, code, strlen(code))) {
02797 res = AST_FEATURE_RETURN_STOREDIGITS;
02798 }
02799 }
02800 if (fge) {
02801 break;
02802 }
02803 }
02804
02805 AST_RWLIST_UNLOCK(&feature_groups);
02806
02807 AST_RWLIST_RDLOCK(&feature_list);
02808
02809 if (!(tmpfeature = find_dynamic_feature(tok))) {
02810 AST_RWLIST_UNLOCK(&feature_list);
02811 continue;
02812 }
02813
02814
02815 if (!strcmp(tmpfeature->exten, code)) {
02816 ast_verb(3, " Feature Found: %s exten: %s\n",tmpfeature->sname, tok);
02817 if (operation) {
02818 res = tmpfeature->operation(chan, peer, config, code, sense, tmpfeature);
02819 }
02820 memcpy(feature, tmpfeature, sizeof(feature));
02821 if (res != AST_FEATURE_RETURN_KEEPTRYING) {
02822 AST_RWLIST_UNLOCK(&feature_list);
02823 break;
02824 }
02825 res = AST_FEATURE_RETURN_PASSDIGITS;
02826 } else if (!strncmp(tmpfeature->exten, code, strlen(code)))
02827 res = AST_FEATURE_RETURN_STOREDIGITS;
02828
02829 AST_RWLIST_UNLOCK(&feature_list);
02830 }
02831
02832 return res;
02833 }
02834
02835
02836
02837
02838
02839
02840
02841
02842
02843 static int feature_interpret(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense) {
02844
02845 char dynamic_features_buf[128];
02846 const char *peer_dynamic_features, *chan_dynamic_features;
02847 struct ast_flags features;
02848 struct ast_call_feature feature;
02849 if (sense == FEATURE_SENSE_CHAN) {
02850 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
02851 }
02852 else {
02853 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);
02854 }
02855
02856 ast_channel_lock(peer);
02857 peer_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES"),""));
02858 ast_channel_unlock(peer);
02859
02860 ast_channel_lock(chan);
02861 chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),""));
02862 ast_channel_unlock(chan);
02863
02864 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,""));
02865
02866 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);
02867
02868 return feature_interpret_helper(chan, peer, config, code, sense, dynamic_features_buf, &features, 1, &feature);
02869 }
02870
02871
02872 int ast_feature_detect(struct ast_channel *chan, struct ast_flags *features, const char *code, struct ast_call_feature *feature) {
02873
02874 return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, 0, feature);
02875 }
02876
02877 static void set_config_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
02878 {
02879 int x;
02880
02881 ast_clear_flag(config, AST_FLAGS_ALL);
02882
02883 ast_rwlock_rdlock(&features_lock);
02884 for (x = 0; x < FEATURES_COUNT; x++) {
02885 if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF))
02886 continue;
02887
02888 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
02889 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
02890
02891 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
02892 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
02893 }
02894 ast_rwlock_unlock(&features_lock);
02895
02896 if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
02897 const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
02898
02899 if (dynamic_features) {
02900 char *tmp = ast_strdupa(dynamic_features);
02901 char *tok;
02902 struct ast_call_feature *feature;
02903
02904
02905 while ((tok = strsep(&tmp, "#"))) {
02906 struct feature_group *fg;
02907
02908 AST_RWLIST_RDLOCK(&feature_groups);
02909 AST_RWLIST_TRAVERSE(&feature_groups, fg, entry) {
02910 struct feature_group_exten *fge;
02911
02912 AST_LIST_TRAVERSE(&fg->features, fge, entry) {
02913 if (ast_test_flag(fge->feature, AST_FEATURE_FLAG_BYCALLER)) {
02914 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
02915 }
02916 if (ast_test_flag(fge->feature, AST_FEATURE_FLAG_BYCALLEE)) {
02917 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
02918 }
02919 }
02920 }
02921 AST_RWLIST_UNLOCK(&feature_groups);
02922
02923 AST_RWLIST_RDLOCK(&feature_list);
02924 if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
02925 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) {
02926 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
02927 }
02928 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) {
02929 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
02930 }
02931 }
02932 AST_RWLIST_UNLOCK(&feature_list);
02933 }
02934 }
02935 }
02936 }
02937
02938
02939
02940
02941
02942
02943
02944
02945
02946
02947
02948
02949
02950
02951
02952
02953
02954
02955
02956
02957
02958
02959
02960
02961
02962
02963
02964
02965
02966
02967
02968
02969
02970
02971
02972 static struct ast_channel *feature_request_and_dial(struct ast_channel *caller,
02973 const char *caller_name, struct ast_channel *requestor,
02974 struct ast_channel *transferee, const char *type, int format, void *data,
02975 int timeout, int *outstate, const char *language)
02976 {
02977 int state = 0;
02978 int cause = 0;
02979 int to;
02980 int caller_hungup;
02981 int transferee_hungup;
02982 struct ast_channel *chan;
02983 struct ast_channel *monitor_chans[3];
02984 struct ast_channel *active_channel;
02985 int res;
02986 int ready = 0;
02987 struct timeval started;
02988 int x, len = 0;
02989 char *disconnect_code = NULL, *dialed_code = NULL;
02990 struct ast_frame *f;
02991 AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames;
02992
02993 caller_hungup = ast_check_hangup(caller);
02994
02995 if (!(chan = ast_request(type, format, requestor, data, &cause))) {
02996 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
02997 switch (cause) {
02998 case AST_CAUSE_BUSY:
02999 state = AST_CONTROL_BUSY;
03000 break;
03001 case AST_CAUSE_CONGESTION:
03002 state = AST_CONTROL_CONGESTION;
03003 break;
03004 default:
03005 state = 0;
03006 break;
03007 }
03008 goto done;
03009 }
03010
03011 ast_string_field_set(chan, language, language);
03012 ast_channel_inherit_variables(caller, chan);
03013 pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller_name);
03014
03015 ast_channel_lock(chan);
03016 ast_connected_line_copy_from_caller(&chan->connected, &requestor->caller);
03017 ast_channel_unlock(chan);
03018
03019 if (ast_call(chan, data, timeout)) {
03020 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
03021 switch (chan->hangupcause) {
03022 case AST_CAUSE_BUSY:
03023 state = AST_CONTROL_BUSY;
03024 break;
03025 case AST_CAUSE_CONGESTION:
03026 state = AST_CONTROL_CONGESTION;
03027 break;
03028 default:
03029 state = 0;
03030 break;
03031 }
03032 goto done;
03033 }
03034
03035
03036 ast_rwlock_rdlock(&features_lock);
03037 for (x = 0; x < FEATURES_COUNT; x++) {
03038 if (strcasecmp(builtin_features[x].sname, "disconnect"))
03039 continue;
03040
03041 disconnect_code = builtin_features[x].exten;
03042 len = strlen(disconnect_code) + 1;
03043 dialed_code = alloca(len);
03044 memset(dialed_code, 0, len);
03045 break;
03046 }
03047 ast_rwlock_unlock(&features_lock);
03048 x = 0;
03049 started = ast_tvnow();
03050 to = timeout;
03051 AST_LIST_HEAD_INIT_NOLOCK(&deferred_frames);
03052
03053 ast_poll_channel_add(caller, chan);
03054
03055 transferee_hungup = 0;
03056 while (!ast_check_hangup(transferee) && (chan->_state != AST_STATE_UP)) {
03057 int num_chans = 0;
03058
03059 monitor_chans[num_chans++] = transferee;
03060 monitor_chans[num_chans++] = chan;
03061 if (!caller_hungup) {
03062 if (ast_check_hangup(caller)) {
03063 caller_hungup = 1;
03064
03065 #if defined(ATXFER_NULL_TECH)
03066
03067 set_new_chan_name(caller);
03068
03069
03070
03071
03072
03073 set_null_chan_tech(caller);
03074 #endif
03075 } else {
03076
03077 monitor_chans[num_chans++] = caller;
03078 }
03079 }
03080
03081
03082 if (ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
03083 state = AST_CONTROL_UNHOLD;
03084 ast_log(LOG_NOTICE, "We exceeded our AT-timeout for %s\n", chan->name);
03085 break;
03086 }
03087
03088 active_channel = ast_waitfor_n(monitor_chans, num_chans, &to);
03089 if (!active_channel)
03090 continue;
03091
03092 f = NULL;
03093 if (transferee == active_channel) {
03094 struct ast_frame *dup_f;
03095
03096 f = ast_read(transferee);
03097 if (f == NULL) {
03098 transferee_hungup = 1;
03099 state = 0;
03100 break;
03101 }
03102 if (ast_is_deferrable_frame(f)) {
03103 dup_f = ast_frisolate(f);
03104 if (dup_f) {
03105 if (dup_f == f) {
03106 f = NULL;
03107 }
03108 AST_LIST_INSERT_HEAD(&deferred_frames, dup_f, frame_list);
03109 }
03110 }
03111 } else if (chan == active_channel) {
03112 if (!ast_strlen_zero(chan->call_forward)) {
03113 state = 0;
03114 chan = ast_call_forward(caller, chan, NULL, format, NULL, &state);
03115 if (!chan) {
03116 break;
03117 }
03118 continue;
03119 }
03120 f = ast_read(chan);
03121 if (f == NULL) {
03122 switch (chan->hangupcause) {
03123 case AST_CAUSE_BUSY:
03124 state = AST_CONTROL_BUSY;
03125 break;
03126 case AST_CAUSE_CONGESTION:
03127 state = AST_CONTROL_CONGESTION;
03128 break;
03129 default:
03130 state = 0;
03131 break;
03132 }
03133 break;
03134 }
03135
03136 if (f->frametype == AST_FRAME_CONTROL) {
03137 if (f->subclass.integer == AST_CONTROL_RINGING) {
03138 ast_verb(3, "%s is ringing\n", chan->name);
03139 ast_indicate(caller, AST_CONTROL_RINGING);
03140 } else if (f->subclass.integer == AST_CONTROL_BUSY) {
03141 state = f->subclass.integer;
03142 ast_verb(3, "%s is busy\n", chan->name);
03143 ast_indicate(caller, AST_CONTROL_BUSY);
03144 ast_frfree(f);
03145 break;
03146 } else if (f->subclass.integer == AST_CONTROL_CONGESTION) {
03147 state = f->subclass.integer;
03148 ast_verb(3, "%s is congested\n", chan->name);
03149 ast_indicate(caller, AST_CONTROL_CONGESTION);
03150 ast_frfree(f);
03151 break;
03152 } else if (f->subclass.integer == AST_CONTROL_ANSWER) {
03153
03154 state = f->subclass.integer;
03155 ast_frfree(f);
03156 ready=1;
03157 break;
03158 } else if (f->subclass.integer == AST_CONTROL_CONNECTED_LINE) {
03159 if (caller_hungup) {
03160 struct ast_party_connected_line connected;
03161
03162
03163 ast_party_connected_line_set_init(&connected, &caller->connected);
03164 res = ast_connected_line_parse_data(f->data.ptr, f->datalen,
03165 &connected);
03166 if (!res) {
03167 ast_channel_set_connected_line(caller, &connected, NULL);
03168 }
03169 ast_party_connected_line_free(&connected);
03170 } else {
03171 ast_autoservice_start(transferee);
03172 if (ast_channel_connected_line_macro(chan, caller, f, 1, 1)) {
03173 ast_indicate_data(caller, AST_CONTROL_CONNECTED_LINE,
03174 f->data.ptr, f->datalen);
03175 }
03176 ast_autoservice_stop(transferee);
03177 }
03178 } else if (f->subclass.integer == AST_CONTROL_REDIRECTING) {
03179 if (!caller_hungup) {
03180 ast_autoservice_start(transferee);
03181 if (ast_channel_redirecting_macro(chan, caller, f, 1, 1)) {
03182 ast_indicate_data(caller, AST_CONTROL_REDIRECTING,
03183 f->data.ptr, f->datalen);
03184 }
03185 ast_autoservice_stop(transferee);
03186 }
03187 } else if (f->subclass.integer != -1 && f->subclass.integer != AST_CONTROL_PROGRESS) {
03188 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass.integer);
03189 }
03190
03191 } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) {
03192 ast_write(caller, f);
03193 }
03194 } else if (caller == active_channel) {
03195 f = ast_read(caller);
03196 if (f) {
03197 if (f->frametype == AST_FRAME_DTMF) {
03198 dialed_code[x++] = f->subclass.integer;
03199 dialed_code[x] = '\0';
03200 if (strlen(dialed_code) == len) {
03201 x = 0;
03202 } else if (x && strncmp(dialed_code, disconnect_code, x)) {
03203 x = 0;
03204 dialed_code[x] = '\0';
03205 }
03206 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
03207
03208 state = AST_CONTROL_UNHOLD;
03209 ast_frfree(f);
03210 break;
03211 }
03212 } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) {
03213 ast_write(chan, f);
03214 }
03215 }
03216 }
03217 if (f)
03218 ast_frfree(f);
03219 }
03220
03221 ast_poll_channel_del(caller, chan);
03222
03223
03224
03225
03226
03227 ast_channel_lock(transferee);
03228 transferee_hungup = (transferee_hungup || ast_check_hangup(transferee));
03229 while ((f = AST_LIST_REMOVE_HEAD(&deferred_frames, frame_list))) {
03230 if (!transferee_hungup) {
03231 ast_queue_frame_head(transferee, f);
03232 }
03233 ast_frfree(f);
03234 }
03235 ast_channel_unlock(transferee);
03236
03237 done:
03238 ast_indicate(caller, -1);
03239 if (chan && ready) {
03240 if (chan->_state == AST_STATE_UP)
03241 state = AST_CONTROL_ANSWER;
03242 } else if (chan) {
03243 ast_hangup(chan);
03244 chan = NULL;
03245 }
03246
03247 if (outstate)
03248 *outstate = state;
03249
03250 return chan;
03251 }
03252
03253 void ast_channel_log(char *title, struct ast_channel *chan);
03254
03255 void ast_channel_log(char *title, struct ast_channel *chan)
03256 {
03257 ast_log(LOG_NOTICE, "______ %s (%lx)______\n", title, (unsigned long)chan);
03258 ast_log(LOG_NOTICE, "CHAN: name: %s; appl: %s; data: %s; contxt: %s; exten: %s; pri: %d;\n",
03259 chan->name, chan->appl, chan->data, chan->context, chan->exten, chan->priority);
03260 ast_log(LOG_NOTICE, "CHAN: acctcode: %s; dialcontext: %s; amaflags: %x; maccontxt: %s; macexten: %s; macpri: %d;\n",
03261 chan->accountcode, chan->dialcontext, chan->amaflags, chan->macrocontext, chan->macroexten, chan->macropriority);
03262 ast_log(LOG_NOTICE, "CHAN: masq: %p; masqr: %p; _bridge: %p; uniqueID: %s; linkedID:%s\n",
03263 chan->masq, chan->masqr,
03264 chan->_bridge, chan->uniqueid, chan->linkedid);
03265 if (chan->masqr)
03266 ast_log(LOG_NOTICE, "CHAN: masquerading as: %s; cdr: %p;\n",
03267 chan->masqr->name, chan->masqr->cdr);
03268 if (chan->_bridge)
03269 ast_log(LOG_NOTICE, "CHAN: Bridged to %s\n", chan->_bridge->name);
03270
03271 ast_log(LOG_NOTICE, "===== done ====\n");
03272 }
03273
03274
03275
03276
03277 static struct ast_cdr *pick_unlocked_cdr(struct ast_cdr *cdr)
03278 {
03279 struct ast_cdr *cdr_orig = cdr;
03280 while (cdr) {
03281 if (!ast_test_flag(cdr,AST_CDR_FLAG_LOCKED))
03282 return cdr;
03283 cdr = cdr->next;
03284 }
03285 return cdr_orig;
03286 }
03287
03288 static void set_bridge_features_on_config(struct ast_bridge_config *config, const char *features)
03289 {
03290 const char *feature;
03291
03292 if (ast_strlen_zero(features)) {
03293 return;
03294 }
03295
03296 for (feature = features; *feature; feature++) {
03297 switch (*feature) {
03298 case 'T' :
03299 case 't' :
03300 ast_set_flag(&(config->features_caller), AST_FEATURE_REDIRECT);
03301 break;
03302 case 'K' :
03303 case 'k' :
03304 ast_set_flag(&(config->features_caller), AST_FEATURE_PARKCALL);
03305 break;
03306 case 'H' :
03307 case 'h' :
03308 ast_set_flag(&(config->features_caller), AST_FEATURE_DISCONNECT);
03309 break;
03310 case 'W' :
03311 case 'w' :
03312 ast_set_flag(&(config->features_caller), AST_FEATURE_AUTOMON);
03313 break;
03314 default :
03315 ast_log(LOG_WARNING, "Skipping unknown feature code '%c'\n", *feature);
03316 }
03317 }
03318 }
03319
03320 static void add_features_datastores(struct ast_channel *caller, struct ast_channel *callee, struct ast_bridge_config *config)
03321 {
03322 struct ast_datastore *ds_callee_features = NULL, *ds_caller_features = NULL;
03323 struct ast_dial_features *callee_features = NULL, *caller_features = NULL;
03324
03325 ast_channel_lock(caller);
03326 ds_caller_features = ast_channel_datastore_find(caller, &dial_features_info, NULL);
03327 ast_channel_unlock(caller);
03328 if (!ds_caller_features) {
03329 if (!(ds_caller_features = ast_datastore_alloc(&dial_features_info, NULL))) {
03330 ast_log(LOG_WARNING, "Unable to create channel datastore for caller features. Aborting!\n");
03331 return;
03332 }
03333 if (!(caller_features = ast_calloc(1, sizeof(*caller_features)))) {
03334 ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n");
03335 ast_datastore_free(ds_caller_features);
03336 return;
03337 }
03338 ds_caller_features->inheritance = DATASTORE_INHERIT_FOREVER;
03339 caller_features->is_caller = 1;
03340 ast_copy_flags(&(caller_features->features_callee), &(config->features_callee), AST_FLAGS_ALL);
03341 ast_copy_flags(&(caller_features->features_caller), &(config->features_caller), AST_FLAGS_ALL);
03342 ds_caller_features->data = caller_features;
03343 ast_channel_lock(caller);
03344 ast_channel_datastore_add(caller, ds_caller_features);
03345 ast_channel_unlock(caller);
03346 } else {
03347
03348
03349 return;
03350 }
03351
03352 ast_channel_lock(callee);
03353 ds_callee_features = ast_channel_datastore_find(callee, &dial_features_info, NULL);
03354 ast_channel_unlock(callee);
03355 if (!ds_callee_features) {
03356 if (!(ds_callee_features = ast_datastore_alloc(&dial_features_info, NULL))) {
03357 ast_log(LOG_WARNING, "Unable to create channel datastore for callee features. Aborting!\n");
03358 return;
03359 }
03360 if (!(callee_features = ast_calloc(1, sizeof(*callee_features)))) {
03361 ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n");
03362 ast_datastore_free(ds_callee_features);
03363 return;
03364 }
03365 ds_callee_features->inheritance = DATASTORE_INHERIT_FOREVER;
03366 callee_features->is_caller = 0;
03367 ast_copy_flags(&(callee_features->features_callee), &(config->features_caller), AST_FLAGS_ALL);
03368 ast_copy_flags(&(callee_features->features_caller), &(config->features_callee), AST_FLAGS_ALL);
03369 ds_callee_features->data = callee_features;
03370 ast_channel_lock(callee);
03371 ast_channel_datastore_add(callee, ds_callee_features);
03372 ast_channel_unlock(callee);
03373 }
03374
03375 return;
03376 }
03377
03378
03379
03380
03381
03382
03383
03384
03385
03386
03387 int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast_bridge_config *config)
03388 {
03389
03390
03391 struct ast_frame *f;
03392 struct ast_channel *who;
03393 char chan_featurecode[FEATURE_MAX_LEN + 1]="";
03394 char peer_featurecode[FEATURE_MAX_LEN + 1]="";
03395 char orig_channame[AST_MAX_EXTENSION];
03396 char orig_peername[AST_MAX_EXTENSION];
03397 int res;
03398 int diff;
03399 int hasfeatures=0;
03400 int hadfeatures=0;
03401 int autoloopflag;
03402 int we_disabled_peer_cdr = 0;
03403 struct ast_option_header *aoh;
03404 struct ast_cdr *bridge_cdr = NULL;
03405 struct ast_cdr *orig_peer_cdr = NULL;
03406 struct ast_cdr *chan_cdr = chan->cdr;
03407 struct ast_cdr *peer_cdr = peer->cdr;
03408 struct ast_cdr *new_chan_cdr = NULL;
03409 struct ast_cdr *new_peer_cdr = NULL;
03410
03411 if (chan && peer) {
03412 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
03413 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
03414 } else if (chan) {
03415 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
03416 }
03417
03418 set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES"));
03419 add_features_datastores(chan, peer, config);
03420
03421
03422
03423
03424 if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) {
03425 ast_indicate(peer, AST_CONTROL_RINGING);
03426 }
03427
03428 if (monitor_ok) {
03429 const char *monitor_exec;
03430 struct ast_channel *src = NULL;
03431 if (!monitor_app) {
03432 if (!(monitor_app = pbx_findapp("Monitor")))
03433 monitor_ok=0;
03434 }
03435 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR")))
03436 src = chan;
03437 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
03438 src = peer;
03439 if (monitor_app && src) {
03440 char *tmp = ast_strdupa(monitor_exec);
03441 pbx_exec(src, monitor_app, tmp);
03442 }
03443 }
03444
03445 set_config_flags(chan, peer, config);
03446
03447
03448 if (chan->_state != AST_STATE_UP) {
03449 if (ast_raw_answer(chan, 1)) {
03450 return -1;
03451 }
03452 }
03453
03454 #ifdef FOR_DEBUG
03455
03456 ast_channel_log("Pre-bridge CHAN Channel info", chan);
03457 ast_channel_log("Pre-bridge PEER Channel info", peer);
03458 #endif
03459
03460 ast_channel_set_linkgroup(chan,peer);
03461
03462
03463 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
03464 char tmp[256];
03465 if (!ast_strlen_zero(chan->cdr->userfield)) {
03466 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield);
03467 ast_cdr_appenduserfield(chan, tmp);
03468 } else
03469 ast_cdr_setuserfield(chan, peer->cdr->userfield);
03470
03471 ast_set_flag(peer->cdr, AST_CDR_FLAG_POST_DISABLED);
03472 we_disabled_peer_cdr = 1;
03473 }
03474 ast_copy_string(orig_channame,chan->name,sizeof(orig_channame));
03475 ast_copy_string(orig_peername,peer->name,sizeof(orig_peername));
03476 orig_peer_cdr = peer_cdr;
03477
03478 if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) {
03479
03480 if (chan_cdr) {
03481 ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN);
03482 ast_cdr_update(chan);
03483 bridge_cdr = ast_cdr_dup_unique_swap(chan_cdr);
03484
03485
03486 bridge_cdr->next = chan_cdr->next;
03487 chan_cdr->next = NULL;
03488 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp));
03489 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata));
03490 if (peer_cdr && !ast_strlen_zero(peer_cdr->userfield)) {
03491 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield));
03492 }
03493 ast_cdr_setaccount(peer, chan->accountcode);
03494
03495 } else {
03496
03497 bridge_cdr = ast_cdr_alloc();
03498 ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel));
03499 ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel));
03500 ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid));
03501 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp));
03502 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata));
03503 ast_cdr_setcid(bridge_cdr, chan);
03504 bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ? AST_CDR_ANSWERED : AST_CDR_NULL;
03505 bridge_cdr->amaflags = chan->amaflags ? chan->amaflags : ast_default_amaflags;
03506 ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode));
03507
03508 ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst));
03509 ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext));
03510 if (peer_cdr) {
03511 bridge_cdr->start = peer_cdr->start;
03512 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield));
03513 } else {
03514 ast_cdr_start(bridge_cdr);
03515 }
03516 }
03517 ast_debug(4,"bridge answer set, chan answer set\n");
03518
03519
03520
03521
03522
03523
03524
03525
03526
03527
03528
03529
03530
03531
03532
03533 if (peer_cdr && !ast_tvzero(peer_cdr->answer) && ast_tvcmp(peer_cdr->answer, bridge_cdr->start) >= 0) {
03534 ast_cdr_setanswer(bridge_cdr, peer_cdr->answer);
03535 ast_cdr_setdisposition(bridge_cdr, peer_cdr->disposition);
03536 if (chan_cdr) {
03537 ast_cdr_setanswer(chan_cdr, peer_cdr->answer);
03538 ast_cdr_setdisposition(chan_cdr, peer_cdr->disposition);
03539 }
03540 } else {
03541 ast_cdr_answer(bridge_cdr);
03542 if (chan_cdr) {
03543 ast_cdr_answer(chan_cdr);
03544 }
03545 }
03546 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT) && (chan_cdr || peer_cdr)) {
03547 if (chan_cdr) {
03548 ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED);
03549 }
03550 if (peer_cdr) {
03551 ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED);
03552 }
03553 }
03554
03555
03556
03557
03558 ast_clear_flag(bridge_cdr, AST_CDR_FLAG_DIALED);
03559 }
03560 ast_cel_report_event(chan, AST_CEL_BRIDGE_START, NULL, NULL, NULL);
03561 for (;;) {
03562 struct ast_channel *other;
03563
03564 res = ast_channel_bridge(chan, peer, config, &f, &who);
03565
03566
03567
03568
03569
03570
03571
03572
03573 if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) {
03574
03575 diff = ast_tvdiff_ms(ast_tvnow(), config->feature_start_time);
03576 if (res == AST_BRIDGE_RETRY) {
03577
03578
03579
03580 config->feature_timer = -1;
03581 } else {
03582 config->feature_timer -= diff;
03583 }
03584
03585 if (hasfeatures) {
03586 if (config->feature_timer <= 0) {
03587
03588
03589 ast_debug(1, "Timed out for feature!\n");
03590 if (!ast_strlen_zero(peer_featurecode)) {
03591 ast_dtmf_stream(chan, peer, peer_featurecode, 0, 0);
03592 memset(peer_featurecode, 0, sizeof(peer_featurecode));
03593 }
03594 if (!ast_strlen_zero(chan_featurecode)) {
03595 ast_dtmf_stream(peer, chan, chan_featurecode, 0, 0);
03596 memset(chan_featurecode, 0, sizeof(chan_featurecode));
03597 }
03598 if (f)
03599 ast_frfree(f);
03600 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
03601 if (!hasfeatures) {
03602
03603 config->feature_timer = 0;
03604 }
03605 hadfeatures = hasfeatures;
03606
03607 continue;
03608 } else if (!f) {
03609
03610
03611
03612 continue;
03613 }
03614 } else {
03615 if (config->feature_timer <=0) {
03616
03617 config->feature_timer = 0;
03618 who = chan;
03619 if (f)
03620 ast_frfree(f);
03621 f = NULL;
03622 res = 0;
03623 }
03624 }
03625 }
03626 if (res < 0) {
03627 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) {
03628 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
03629 }
03630 goto before_you_go;
03631 }
03632
03633 if (!f || (f->frametype == AST_FRAME_CONTROL &&
03634 (f->subclass.integer == AST_CONTROL_HANGUP || f->subclass.integer == AST_CONTROL_BUSY ||
03635 f->subclass.integer == AST_CONTROL_CONGESTION))) {
03636 res = -1;
03637 break;
03638 }
03639
03640 other = (who == chan) ? peer : chan;
03641 if (f->frametype == AST_FRAME_CONTROL) {
03642 switch (f->subclass.integer) {
03643 case AST_CONTROL_RINGING:
03644 case AST_CONTROL_FLASH:
03645 case -1:
03646 ast_indicate(other, f->subclass.integer);
03647 break;
03648 case AST_CONTROL_CONNECTED_LINE:
03649 if (!ast_channel_connected_line_macro(who, other, f, who != chan, 1)) {
03650 break;
03651 }
03652 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen);
03653 break;
03654 case AST_CONTROL_REDIRECTING:
03655 if (!ast_channel_redirecting_macro(who, other, f, who != chan, 1)) {
03656 break;
03657 }
03658 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen);
03659 break;
03660 case AST_CONTROL_AOC:
03661 case AST_CONTROL_HOLD:
03662 case AST_CONTROL_UNHOLD:
03663 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen);
03664 break;
03665 case AST_CONTROL_OPTION:
03666 aoh = f->data.ptr;
03667
03668 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) {
03669 ast_channel_setoption(other, ntohs(aoh->option), aoh->data,
03670 f->datalen - sizeof(struct ast_option_header), 0);
03671 }
03672 break;
03673 }
03674 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
03675
03676 } else if (f->frametype == AST_FRAME_DTMF) {
03677 char *featurecode;
03678 int sense;
03679
03680 hadfeatures = hasfeatures;
03681
03682 if (who == chan) {
03683 sense = FEATURE_SENSE_CHAN;
03684 featurecode = chan_featurecode;
03685 } else {
03686 sense = FEATURE_SENSE_PEER;
03687 featurecode = peer_featurecode;
03688 }
03689
03690
03691
03692
03693 featurecode[strlen(featurecode)] = f->subclass.integer;
03694
03695 ast_frfree(f);
03696 f = NULL;
03697 config->feature_timer = 0;
03698 res = feature_interpret(chan, peer, config, featurecode, sense);
03699 switch(res) {
03700 case AST_FEATURE_RETURN_PASSDIGITS:
03701 ast_dtmf_stream(other, who, featurecode, 0, 0);
03702
03703 case AST_FEATURE_RETURN_SUCCESS:
03704 memset(featurecode, 0, sizeof(chan_featurecode));
03705 break;
03706 }
03707 if (res >= AST_FEATURE_RETURN_PASSDIGITS) {
03708 res = 0;
03709 } else {
03710 break;
03711 }
03712 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
03713 if (hadfeatures && !hasfeatures) {
03714
03715 config->feature_timer = 0;
03716 } else if (hasfeatures) {
03717 if (config->timelimit) {
03718
03719 ast_set_flag(config, AST_FEATURE_WARNING_ACTIVE);
03720 }
03721 config->feature_start_time = ast_tvnow();
03722 config->feature_timer = featuredigittimeout;
03723 ast_debug(1, "Set feature timer to %ld ms\n", config->feature_timer);
03724 }
03725 }
03726 if (f)
03727 ast_frfree(f);
03728
03729 }
03730 ast_cel_report_event(chan, AST_CEL_BRIDGE_END, NULL, NULL, NULL);
03731 before_you_go:
03732
03733 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) {
03734 ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT);
03735 if (bridge_cdr) {
03736 ast_cdr_discard(bridge_cdr);
03737
03738 }
03739 return res;
03740 }
03741
03742 if (config->end_bridge_callback) {
03743 config->end_bridge_callback(config->end_bridge_callback_data);
03744 }
03745
03746
03747
03748
03749
03750 if (!ast_test_flag(&(config->features_caller),AST_FEATURE_NO_H_EXTEN)
03751 && ast_exists_extension(chan, chan->context, "h", 1,
03752 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
03753 struct ast_cdr *swapper = NULL;
03754 char savelastapp[AST_MAX_EXTENSION];
03755 char savelastdata[AST_MAX_EXTENSION];
03756 char save_exten[AST_MAX_EXTENSION];
03757 int save_prio;
03758 int found = 0;
03759 int spawn_error = 0;
03760
03761 autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP);
03762 ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP);
03763 if (bridge_cdr && ast_opt_end_cdr_before_h_exten) {
03764 ast_cdr_end(bridge_cdr);
03765 }
03766
03767
03768 ast_channel_lock(chan);
03769 if (bridge_cdr) {
03770 swapper = chan->cdr;
03771 ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp));
03772 ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata));
03773 chan->cdr = bridge_cdr;
03774 }
03775 ast_copy_string(save_exten, chan->exten, sizeof(save_exten));
03776 save_prio = chan->priority;
03777 ast_copy_string(chan->exten, "h", sizeof(chan->exten));
03778 chan->priority = 1;
03779 ast_channel_unlock(chan);
03780 while ((spawn_error = ast_spawn_extension(chan, chan->context, chan->exten,
03781 chan->priority,
03782 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
03783 &found, 1)) == 0) {
03784 chan->priority++;
03785 }
03786 if (spawn_error
03787 && (!ast_exists_extension(chan, chan->context, chan->exten, chan->priority,
03788 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))
03789 || ast_check_hangup(chan))) {
03790
03791 spawn_error = 0;
03792 }
03793 if (found && spawn_error) {
03794
03795 ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name);
03796 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name);
03797 }
03798
03799 ast_channel_lock(chan);
03800 ast_copy_string(chan->exten, save_exten, sizeof(chan->exten));
03801 chan->priority = save_prio;
03802 if (bridge_cdr) {
03803 if (chan->cdr == bridge_cdr) {
03804 chan->cdr = swapper;
03805 } else {
03806 bridge_cdr = NULL;
03807 }
03808 }
03809 if (!spawn_error) {
03810 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN);
03811 }
03812 ast_channel_unlock(chan);
03813
03814 if (bridge_cdr) {
03815 ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp));
03816 ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata));
03817 }
03818 ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP);
03819 }
03820
03821
03822 new_chan_cdr = pick_unlocked_cdr(chan->cdr);
03823 if (bridge_cdr && new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED))
03824 ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED);
03825
03826
03827 if (bridge_cdr) {
03828 ast_cdr_end(bridge_cdr);
03829 ast_cdr_detach(bridge_cdr);
03830 }
03831
03832
03833
03834
03835
03836
03837
03838
03839
03840
03841
03842
03843
03844
03845
03846
03847
03848
03849
03850
03851
03852
03853
03854
03855
03856 if (new_chan_cdr) {
03857 struct ast_channel *chan_ptr = NULL;
03858
03859 if (strcasecmp(orig_channame, chan->name) != 0) {
03860
03861 if ((chan_ptr = ast_channel_get_by_name(orig_channame))) {
03862 ast_channel_lock(chan_ptr);
03863 if (!ast_bridged_channel(chan_ptr)) {
03864 struct ast_cdr *cur;
03865 for (cur = chan_ptr->cdr; cur; cur = cur->next) {
03866 if (cur == chan_cdr) {
03867 break;
03868 }
03869 }
03870 if (cur) {
03871 ast_cdr_specialized_reset(chan_cdr, 0);
03872 }
03873 }
03874 ast_channel_unlock(chan_ptr);
03875 chan_ptr = ast_channel_unref(chan_ptr);
03876 }
03877
03878 ast_cdr_specialized_reset(new_chan_cdr, 0);
03879 } else {
03880 ast_cdr_specialized_reset(chan->cdr, 0);
03881 }
03882 }
03883
03884 {
03885 struct ast_channel *chan_ptr = NULL;
03886 new_peer_cdr = pick_unlocked_cdr(peer->cdr);
03887 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))
03888 ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED);
03889 if (strcasecmp(orig_peername, peer->name) != 0) {
03890
03891 if ((chan_ptr = ast_channel_get_by_name(orig_peername))) {
03892 ast_channel_lock(chan_ptr);
03893 if (!ast_bridged_channel(chan_ptr)) {
03894 struct ast_cdr *cur;
03895 for (cur = chan_ptr->cdr; cur; cur = cur->next) {
03896 if (cur == peer_cdr) {
03897 break;
03898 }
03899 }
03900 if (cur) {
03901 ast_cdr_specialized_reset(peer_cdr, 0);
03902 }
03903 }
03904 ast_channel_unlock(chan_ptr);
03905 chan_ptr = ast_channel_unref(chan_ptr);
03906 }
03907
03908 if (new_peer_cdr) {
03909 ast_cdr_specialized_reset(new_peer_cdr, 0);
03910 }
03911 } else {
03912 if (we_disabled_peer_cdr) {
03913 ast_clear_flag(peer->cdr, AST_CDR_FLAG_POST_DISABLED);
03914 }
03915 ast_cdr_specialized_reset(peer->cdr, 0);
03916 }
03917 }
03918
03919 return res;
03920 }
03921
03922
03923 static void post_manager_event(const char *s, struct parkeduser *pu)
03924 {
03925 manager_event(EVENT_FLAG_CALL, s,
03926 "Exten: %s\r\n"
03927 "Channel: %s\r\n"
03928 "Parkinglot: %s\r\n"
03929 "CallerIDNum: %s\r\n"
03930 "CallerIDName: %s\r\n"
03931 "UniqueID: %s\r\n\r\n",
03932 pu->parkingexten,
03933 pu->chan->name,
03934 pu->parkinglot->name,
03935 S_COR(pu->chan->caller.id.number.valid, pu->chan->caller.id.number.str, "<unknown>"),
03936 S_COR(pu->chan->caller.id.name.valid, pu->chan->caller.id.name.str, "<unknown>"),
03937 pu->chan->uniqueid
03938 );
03939 }
03940
03941 static char *callback_dialoptions(struct ast_flags *features_callee, struct ast_flags *features_caller, char *options, size_t len)
03942 {
03943 int i = 0;
03944 enum {
03945 OPT_CALLEE_REDIRECT = 't',
03946 OPT_CALLER_REDIRECT = 'T',
03947 OPT_CALLEE_AUTOMON = 'w',
03948 OPT_CALLER_AUTOMON = 'W',
03949 OPT_CALLEE_DISCONNECT = 'h',
03950 OPT_CALLER_DISCONNECT = 'H',
03951 OPT_CALLEE_PARKCALL = 'k',
03952 OPT_CALLER_PARKCALL = 'K',
03953 };
03954
03955 memset(options, 0, len);
03956 if (ast_test_flag(features_caller, AST_FEATURE_REDIRECT) && i < len) {
03957 options[i++] = OPT_CALLER_REDIRECT;
03958 }
03959 if (ast_test_flag(features_caller, AST_FEATURE_AUTOMON) && i < len) {
03960 options[i++] = OPT_CALLER_AUTOMON;
03961 }
03962 if (ast_test_flag(features_caller, AST_FEATURE_DISCONNECT) && i < len) {
03963 options[i++] = OPT_CALLER_DISCONNECT;
03964 }
03965 if (ast_test_flag(features_caller, AST_FEATURE_PARKCALL) && i < len) {
03966 options[i++] = OPT_CALLER_PARKCALL;
03967 }
03968
03969 if (ast_test_flag(features_callee, AST_FEATURE_REDIRECT) && i < len) {
03970 options[i++] = OPT_CALLEE_REDIRECT;
03971 }
03972 if (ast_test_flag(features_callee, AST_FEATURE_AUTOMON) && i < len) {
03973 options[i++] = OPT_CALLEE_AUTOMON;
03974 }
03975 if (ast_test_flag(features_callee, AST_FEATURE_DISCONNECT) && i < len) {
03976 options[i++] = OPT_CALLEE_DISCONNECT;
03977 }
03978 if (ast_test_flag(features_callee, AST_FEATURE_PARKCALL) && i < len) {
03979 options[i++] = OPT_CALLEE_PARKCALL;
03980 }
03981
03982 return options;
03983 }
03984
03985
03986 int manage_parkinglot(struct ast_parkinglot *curlot, const struct pollfd *pfds, const int nfds, struct pollfd **new_pfds, int *new_nfds, int *ms)
03987 {
03988 struct parkeduser *pu;
03989 int res = 0;
03990 char parkingslot[AST_MAX_EXTENSION];
03991
03992
03993 AST_LIST_LOCK(&curlot->parkings);
03994 AST_LIST_TRAVERSE_SAFE_BEGIN(&curlot->parkings, pu, list) {
03995 struct ast_channel *chan = pu->chan;
03996 int tms;
03997 int x;
03998 struct ast_context *con;
03999
04000 if (pu->notquiteyet) {
04001 continue;
04002 }
04003 tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
04004 if (tms > pu->parkingtime) {
04005
04006 ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
04007
04008 if (pu->peername[0]) {
04009 char *peername = ast_strdupa(pu->peername);
04010 char *dash = strrchr(peername, '-');
04011 char *peername_flat;
04012 int i;
04013
04014 if (dash) {
04015 *dash = '\0';
04016 }
04017
04018 peername_flat = ast_strdupa(peername);
04019 for (i = 0; peername_flat[i]; i++) {
04020 if (peername_flat[i] == '/') {
04021 peername_flat[i]= '_';
04022 }
04023 }
04024
04025 con = ast_context_find_or_create(NULL, NULL, pu->parkinglot->parking_con_dial, registrar);
04026 if (!con) {
04027 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", pu->parkinglot->parking_con_dial);
04028 } else {
04029 char returnexten[AST_MAX_EXTENSION];
04030 struct ast_datastore *features_datastore;
04031 struct ast_dial_features *dialfeatures = NULL;
04032
04033 ast_channel_lock(chan);
04034
04035 if ((features_datastore = ast_channel_datastore_find(chan, &dial_features_info, NULL)))
04036 dialfeatures = features_datastore->data;
04037
04038 ast_channel_unlock(chan);
04039
04040 if (!strncmp(peername, "Parked/", 7)) {
04041 peername += 7;
04042 }
04043
04044 if (dialfeatures) {
04045 char buf[MAX_DIAL_FEATURE_OPTIONS] = {0,};
04046 snprintf(returnexten, sizeof(returnexten), "%s,30,%s", peername, callback_dialoptions(&(dialfeatures->features_callee), &(dialfeatures->features_caller), buf, sizeof(buf)));
04047 } else {
04048 ast_log(LOG_NOTICE, "Dial features not found on %s, using default!\n", chan->name);
04049 snprintf(returnexten, sizeof(returnexten), "%s,30,t", peername);
04050 }
04051
04052 ast_add_extension2(con, 1, peername_flat, 1, NULL, NULL, "Dial", ast_strdup(returnexten), ast_free_ptr, registrar);
04053 }
04054 if (pu->options_specified == 1) {
04055
04056 set_c_e_p(chan, pu->context, pu->exten, pu->priority);
04057 } else {
04058 if (comebacktoorigin) {
04059 set_c_e_p(chan, pu->parkinglot->parking_con_dial, peername_flat, 1);
04060 } else {
04061 snprintf(parkingslot, sizeof(parkingslot), "%d", pu->parkingnum);
04062 pbx_builtin_setvar_helper(chan, "PARKINGSLOT", parkingslot);
04063 set_c_e_p(chan, "parkedcallstimeout", peername_flat, 1);
04064 }
04065 }
04066 } else {
04067
04068
04069 set_c_e_p(chan, pu->context, pu->exten, pu->priority);
04070 }
04071 post_manager_event("ParkedCallTimeOut", pu);
04072 ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "ParkedCallTimeOut", NULL);
04073
04074 ast_verb(2, "Timeout for %s parked on %d (%s). Returning to %s,%s,%d\n", pu->chan->name, pu->parkingnum, pu->parkinglot->name, pu->chan->context, pu->chan->exten, pu->chan->priority);
04075
04076 if (ast_pbx_start(chan)) {
04077 ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name);
04078 ast_hangup(chan);
04079 }
04080
04081 con = ast_context_find(pu->parkinglot->parking_con);
04082 if (con) {
04083 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0))
04084 ast_log(LOG_WARNING, "Whoa, failed to remove the parking extension!\n");
04085 else
04086 notify_metermaids(pu->parkingexten, curlot->parking_con, AST_DEVICE_NOT_INUSE);
04087 } else
04088 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
04089 AST_LIST_REMOVE_CURRENT(list);
04090 free(pu);
04091 } else {
04092 for (x = 0; x < AST_MAX_FDS; x++) {
04093 struct ast_frame *f;
04094 int y;
04095
04096 if (chan->fds[x] == -1) {
04097 continue;
04098 }
04099
04100 for (y = 0; y < nfds; y++) {
04101 if (pfds[y].fd == chan->fds[x]) {
04102
04103 break;
04104 }
04105 }
04106 if (y == nfds) {
04107
04108 continue;
04109 }
04110
04111 if (!(pfds[y].revents & (POLLIN | POLLERR | POLLPRI))) {
04112
04113 continue;
04114 }
04115
04116 if (pfds[y].revents & POLLERR) {
04117 ast_set_flag(chan, AST_FLAG_EXCEPTION);
04118 } else {
04119 ast_clear_flag(chan, AST_FLAG_EXCEPTION);
04120 }
04121 chan->fdno = x;
04122
04123
04124 f = ast_read(pu->chan);
04125
04126 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer == AST_CONTROL_HANGUP))) {
04127 if (f)
04128 ast_frfree(f);
04129 post_manager_event("ParkedCallGiveUp", pu);
04130 ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "ParkedCallGiveUp", NULL);
04131
04132
04133 ast_verb(2, "%s got tired of being parked\n", chan->name);
04134 ast_hangup(chan);
04135
04136 con = ast_context_find(curlot->parking_con);
04137 if (con) {
04138 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0))
04139 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
04140 else
04141 notify_metermaids(pu->parkingexten, curlot->parking_con, AST_DEVICE_NOT_INUSE);
04142 } else
04143 ast_log(LOG_WARNING, "Whoa, no parking context for parking lot %s?\n", curlot->name);
04144 AST_LIST_REMOVE_CURRENT(list);
04145 parkinglot_unref(pu->parkinglot);
04146 free(pu);
04147 break;
04148 } else {
04149
04150 ast_frfree(f);
04151 if (pu->moh_trys < 3 && !chan->generatordata) {
04152 ast_debug(1, "MOH on parked call stopped by outside source. Restarting on channel %s.\n", chan->name);
04153 ast_indicate_data(chan, AST_CONTROL_HOLD,
04154 S_OR(curlot->mohclass, NULL),
04155 (!ast_strlen_zero(curlot->mohclass) ? strlen(curlot->mohclass) + 1 : 0));
04156 pu->moh_trys++;
04157 }
04158 goto std;
04159 }
04160 }
04161 if (x >= AST_MAX_FDS) {
04162 std: for (x = 0; x < AST_MAX_FDS; x++) {
04163 if (chan->fds[x] > -1) {
04164 void *tmp = ast_realloc(*new_pfds, (*new_nfds + 1) * sizeof(struct pollfd));
04165 if (!tmp) {
04166 continue;
04167 }
04168 *new_pfds = tmp;
04169 (*new_pfds)[*new_nfds].fd = chan->fds[x];
04170 (*new_pfds)[*new_nfds].events = POLLIN | POLLERR | POLLPRI;
04171 (*new_pfds)[*new_nfds].revents = 0;
04172 (*new_nfds)++;
04173 }
04174 }
04175
04176 if (tms < *ms || *ms < 0) {
04177 *ms = tms;
04178 }
04179 }
04180 }
04181 }
04182 AST_LIST_TRAVERSE_SAFE_END;
04183 AST_LIST_UNLOCK(&curlot->parkings);
04184
04185 return res;
04186 }
04187
04188
04189
04190
04191
04192
04193
04194
04195
04196 static void *do_parking_thread(void *ignore)
04197 {
04198 struct pollfd *pfds = NULL, *new_pfds = NULL;
04199 int nfds = 0, new_nfds = 0;
04200
04201 for (;;) {
04202 struct ao2_iterator iter;
04203 struct ast_parkinglot *curlot;
04204 int ms = -1;
04205 iter = ao2_iterator_init(parkinglots, 0);
04206
04207 while ((curlot = ao2_iterator_next(&iter))) {
04208 manage_parkinglot(curlot, pfds, nfds, &new_pfds, &new_nfds, &ms);
04209 ao2_ref(curlot, -1);
04210 }
04211 ao2_iterator_destroy(&iter);
04212
04213
04214 ast_free(pfds);
04215 pfds = new_pfds;
04216 nfds = new_nfds;
04217 new_pfds = NULL;
04218 new_nfds = 0;
04219
04220
04221 ast_poll(pfds, nfds, ms);
04222 pthread_testcancel();
04223 }
04224
04225 return NULL;
04226 }
04227
04228
04229 struct ast_parkinglot *find_parkinglot(const char *name)
04230 {
04231 struct ast_parkinglot *parkinglot;
04232
04233 if (ast_strlen_zero(name)) {
04234 return NULL;
04235 }
04236
04237 parkinglot = ao2_find(parkinglots, (void *) name, 0);
04238 if (parkinglot) {
04239 ast_debug(1, "Found Parkinglot: %s\n", parkinglot->name);
04240 }
04241
04242 return parkinglot;
04243 }
04244
04245
04246 struct ast_parkinglot *copy_parkinglot(const char *name, const struct ast_parkinglot *parkinglot) {
04247 struct ast_parkinglot *copylot;
04248
04249 if (ast_strlen_zero(name)) {
04250 return NULL;
04251 }
04252 if ((copylot = find_parkinglot(name))) {
04253 if (copylot) {
04254 ao2_ref(copylot, -1);
04255 }
04256 return NULL;
04257 }
04258
04259 copylot = create_parkinglot(name);
04260 ast_debug(1, "Building parking lot %s\n", name);
04261
04262 memcpy(copylot, parkinglot, sizeof(struct ast_parkinglot));
04263 ast_copy_string(copylot->name, name, sizeof(copylot->name));
04264 AST_LIST_HEAD_INIT(©lot->parkings);
04265
04266 return copylot;
04267 }
04268
04269 AST_APP_OPTIONS(park_call_options, BEGIN_OPTIONS
04270 AST_APP_OPTION('r', AST_PARK_OPT_RINGING),
04271 AST_APP_OPTION('R', AST_PARK_OPT_RANDOMIZE),
04272 AST_APP_OPTION('s', AST_PARK_OPT_SILENCE),
04273 END_OPTIONS );
04274
04275
04276 static int park_call_exec(struct ast_channel *chan, const char *data)
04277 {
04278
04279
04280
04281 char *orig_chan_name = ast_strdupa(chan->name);
04282 char orig_exten[AST_MAX_EXTENSION];
04283 int orig_priority = chan->priority;
04284
04285
04286
04287 int res = 0;
04288
04289 char *parse = NULL;
04290 AST_DECLARE_APP_ARGS(app_args,
04291 AST_APP_ARG(timeout);
04292 AST_APP_ARG(return_con);
04293 AST_APP_ARG(return_ext);
04294 AST_APP_ARG(return_pri);
04295 AST_APP_ARG(options);
04296 );
04297
04298 parse = ast_strdupa(data);
04299 AST_STANDARD_APP_ARGS(app_args, parse);
04300
04301 ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten));
04302
04303
04304
04305 strcpy(chan->exten, "s");
04306 chan->priority = 1;
04307
04308
04309 if (chan->_state != AST_STATE_UP)
04310 res = ast_answer(chan);
04311
04312
04313 if (!res)
04314 res = ast_safe_sleep(chan, 1000);
04315
04316
04317 if (!res) {
04318 struct ast_park_call_args args = {
04319 .orig_chan_name = orig_chan_name,
04320 };
04321 struct ast_flags flags = { 0 };
04322
04323 if (parse) {
04324 if (!ast_strlen_zero(app_args.timeout)) {
04325 if (sscanf(app_args.timeout, "%30d", &args.timeout) != 1) {
04326 ast_log(LOG_WARNING, "Invalid timeout '%s' provided\n", app_args.timeout);
04327 args.timeout = 0;
04328 }
04329 }
04330 if (!ast_strlen_zero(app_args.return_con)) {
04331 args.return_con = app_args.return_con;
04332 }
04333 if (!ast_strlen_zero(app_args.return_ext)) {
04334 args.return_ext = app_args.return_ext;
04335 }
04336 if (!ast_strlen_zero(app_args.return_pri)) {
04337 if (sscanf(app_args.return_pri, "%30d", &args.return_pri) != 1) {
04338 ast_log(LOG_WARNING, "Invalid priority '%s' specified\n", app_args.return_pri);
04339 args.return_pri = 0;
04340 }
04341 }
04342 }
04343
04344 ast_app_parse_options(park_call_options, &flags, NULL, app_args.options);
04345 args.flags = flags.flags;
04346
04347 args.parkinglot = ao2_callback(parkinglots, 0, find_parkinglot_by_exten_cb, &orig_exten);
04348 res = masq_park_call_announce(chan, chan, &args);
04349
04350 if (res == 1) {
04351 ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten));
04352 chan->priority = orig_priority;
04353 res = 0;
04354 } else if (!res) {
04355 res = 1;
04356 }
04357 }
04358
04359 return res;
04360 }
04361
04362
04363 static int park_exec_full(struct ast_channel *chan, const char *data)
04364 {
04365 int res = 0;
04366 struct ast_channel *peer=NULL;
04367 struct parkeduser *pu;
04368 struct ast_context *con;
04369 int park = 0;
04370 struct ast_bridge_config config;
04371 struct ast_parkinglot *parkinglot;
04372
04373 if (data) {
04374 park = atoi((char *) data);
04375 }
04376
04377 parkinglot = ao2_callback(parkinglots, 0, find_parkinglot_by_position_cb, (void *) &park);
04378 if (!parkinglot)
04379 parkinglot = default_parkinglot;
04380
04381 AST_LIST_LOCK(&parkinglot->parkings);
04382 AST_LIST_TRAVERSE_SAFE_BEGIN(&parkinglot->parkings, pu, list) {
04383 if (!pu->notquiteyet && (!data || pu->parkingnum == park)) {
04384 if (pu->chan->pbx) {
04385 AST_LIST_UNLOCK(&parkinglot->parkings);
04386 return -1;
04387 }
04388 AST_LIST_REMOVE_CURRENT(list);
04389 break;
04390 }
04391 }
04392 AST_LIST_TRAVERSE_SAFE_END;
04393 AST_LIST_UNLOCK(&parkinglot->parkings);
04394
04395 if (pu) {
04396 peer = pu->chan;
04397 con = ast_context_find(parkinglot->parking_con);
04398 if (con) {
04399 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0))
04400 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
04401 else
04402 notify_metermaids(pu->parkingexten, parkinglot->parking_con, AST_DEVICE_NOT_INUSE);
04403 } else
04404 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
04405
04406 ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "UnParkedCall", chan);
04407 ast_manager_event(pu->chan, EVENT_FLAG_CALL, "UnParkedCall",
04408 "Exten: %s\r\n"
04409 "Channel: %s\r\n"
04410 "From: %s\r\n"
04411 "CallerIDNum: %s\r\n"
04412 "CallerIDName: %s\r\n",
04413 pu->parkingexten, pu->chan->name, chan->name,
04414 S_COR(pu->chan->caller.id.number.valid, pu->chan->caller.id.number.str, "<unknown>"),
04415 S_COR(pu->chan->caller.id.name.valid, pu->chan->caller.id.name.str, "<unknown>")
04416 );
04417
04418 ast_free(pu);
04419 }
04420
04421 if (chan->_state != AST_STATE_UP)
04422 ast_answer(chan);
04423
04424
04425
04426
04427
04428 if (peer) {
04429 struct ast_datastore *features_datastore;
04430 struct ast_dial_features *dialfeatures = NULL;
04431
04432
04433
04434 if (!ast_strlen_zero(courtesytone)) {
04435 int error = 0;
04436 ast_indicate(peer, AST_CONTROL_UNHOLD);
04437 if (parkedplay == 0) {
04438 error = ast_stream_and_wait(chan, courtesytone, "");
04439 } else if (parkedplay == 1) {
04440 error = ast_stream_and_wait(peer, courtesytone, "");
04441 } else if (parkedplay == 2) {
04442 if (!ast_streamfile(chan, courtesytone, chan->language) &&
04443 !ast_streamfile(peer, courtesytone, chan->language)) {
04444
04445 res = ast_waitstream(chan, "");
04446 if (res >= 0)
04447 res = ast_waitstream(peer, "");
04448 if (res < 0)
04449 error = 1;
04450 }
04451 }
04452 if (error) {
04453 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
04454 ast_hangup(peer);
04455 return -1;
04456 }
04457 } else
04458 ast_indicate(peer, AST_CONTROL_UNHOLD);
04459
04460 res = ast_channel_make_compatible(chan, peer);
04461 if (res < 0) {
04462 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
04463 ast_hangup(peer);
04464 return -1;
04465 }
04466
04467
04468 ast_verb(3, "Channel %s connected to parked call %d\n", chan->name, park);
04469
04470 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
04471 ast_cdr_setdestchan(chan->cdr, peer->name);
04472 memset(&config, 0, sizeof(struct ast_bridge_config));
04473
04474
04475 ast_channel_lock(peer);
04476 if ((features_datastore = ast_channel_datastore_find(peer, &dial_features_info, NULL))) {
04477 dialfeatures = features_datastore->data;
04478 }
04479 ast_channel_unlock(peer);
04480
04481
04482
04483
04484
04485 if (dialfeatures) {
04486 ast_copy_flags(&(config.features_callee), &(dialfeatures->features_caller), AST_FLAGS_ALL);
04487 }
04488
04489 if ((parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
04490 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
04491 }
04492 if ((parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
04493 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
04494 }
04495 if ((parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
04496 ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL);
04497 }
04498 if ((parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
04499 ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL);
04500 }
04501 if ((parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
04502 ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT);
04503 }
04504 if ((parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
04505 ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT);
04506 }
04507 if ((parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
04508 ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
04509 }
04510 if ((parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
04511 ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
04512 }
04513
04514 parkinglot_unref(parkinglot);
04515 res = ast_bridge_call(chan, peer, &config);
04516
04517 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
04518 ast_cdr_setdestchan(chan->cdr, peer->name);
04519
04520
04521 ast_hangup(peer);
04522 return -1;
04523 } else {
04524
04525 if (ast_stream_and_wait(chan, "pbx-invalidpark", ""))
04526 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
04527 ast_verb(3, "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
04528 res = -1;
04529 }
04530
04531 return -1;
04532 }
04533
04534 static int park_exec(struct ast_channel *chan, const char *data)
04535 {
04536 return park_exec_full(chan, data);
04537 }
04538
04539
04540
04541 static void parkinglot_unref(struct ast_parkinglot *parkinglot)
04542 {
04543 int refcount = ao2_ref(parkinglot, -1);
04544 ast_debug(3, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount - 1);
04545 }
04546
04547 static struct ast_parkinglot *parkinglot_addref(struct ast_parkinglot *parkinglot)
04548 {
04549 int refcount = ao2_ref(parkinglot, +1);
04550 ast_debug(3, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount + 1);
04551 return parkinglot;
04552 }
04553
04554
04555 static struct ast_parkinglot *create_parkinglot(const char *name)
04556 {
04557 struct ast_parkinglot *newlot = (struct ast_parkinglot *) NULL;
04558
04559 if (!name)
04560 return NULL;
04561
04562 newlot = ao2_alloc(sizeof(*newlot), parkinglot_destroy);
04563 if (!newlot)
04564 return NULL;
04565
04566 ast_copy_string(newlot->name, name, sizeof(newlot->name));
04567 AST_LIST_HEAD_INIT(&newlot->parkings);
04568
04569 return newlot;
04570 }
04571
04572
04573 static void parkinglot_destroy(void *obj)
04574 {
04575 struct ast_parkinglot *ruin = obj;
04576 struct ast_context *con;
04577 con = ast_context_find(ruin->parking_con);
04578 if (con)
04579 ast_context_destroy(con, registrar);
04580 }
04581
04582
04583
04584
04585
04586
04587
04588 static void park_add_hints(char *context, int start, int stop)
04589 {
04590 int numext;
04591 char device[AST_MAX_EXTENSION];
04592 char exten[10];
04593
04594 for (numext = start; numext <= stop; numext++) {
04595 snprintf(exten, sizeof(exten), "%d", numext);
04596 snprintf(device, sizeof(device), "park:%s@%s", exten, context);
04597 ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
04598 }
04599 }
04600
04601
04602 static struct ast_parkinglot *build_parkinglot(char *name, struct ast_variable *var)
04603 {
04604 struct ast_parkinglot *parkinglot;
04605 struct ast_context *con = NULL;
04606
04607 struct ast_variable *confvar = var;
04608 int error = 0;
04609 int start = 0, end = 0;
04610 int oldparkinglot = 0;
04611
04612 parkinglot = find_parkinglot(name);
04613 if (parkinglot)
04614 oldparkinglot = 1;
04615 else
04616 parkinglot = create_parkinglot(name);
04617
04618 if (!parkinglot)
04619 return NULL;
04620
04621 ao2_lock(parkinglot);
04622
04623 ast_debug(1, "Building parking lot %s\n", name);
04624
04625
04626 while(confvar) {
04627 if (!strcasecmp(confvar->name, "context")) {
04628 ast_copy_string(parkinglot->parking_con, confvar->value, sizeof(parkinglot->parking_con));
04629 } else if (!strcasecmp(confvar->name, "parkext")) {
04630 ast_copy_string(parkinglot->parkext, confvar->value, sizeof(parkinglot->parkext));
04631 } else if (!strcasecmp(confvar->name, "parkingtime")) {
04632 if ((sscanf(confvar->value, "%30d", &parkinglot->parkingtime) != 1) || (parkinglot->parkingtime < 1)) {
04633 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", confvar->value);
04634 parkinglot->parkingtime = DEFAULT_PARK_TIME;
04635 } else
04636 parkinglot->parkingtime = parkinglot->parkingtime * 1000;
04637 } else if (!strcasecmp(confvar->name, "parkpos")) {
04638 if (sscanf(confvar->value, "%30d-%30d", &start, &end) != 2) {
04639 ast_log(LOG_WARNING, "Format for parking positions is a-b, where a and b are numbers at line %d of parking.conf\n", confvar->lineno);
04640 error = 1;
04641 } else {
04642 parkinglot->parking_start = start;
04643 parkinglot->parking_stop = end;
04644 }
04645 } else if (!strcasecmp(confvar->name, "findslot")) {
04646 parkinglot->parkfindnext = (!strcasecmp(confvar->value, "next"));
04647 } else if (!strcasecmp(confvar->name, "parkedcalltransfers")) {
04648 ast_log(LOG_DEBUG, "Setting parking lot %s %s to %s\n", name, confvar->name, confvar->value);
04649 if (!strcasecmp(confvar->value, "both"))
04650 parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH;
04651 else if (!strcasecmp(confvar->value, "caller"))
04652 parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYCALLER;
04653 else if (!strcasecmp(confvar->value, "callee"))
04654 parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYCALLEE;
04655 } else if (!strcasecmp(confvar->name, "parkedcallreparking")) {
04656 ast_log(LOG_DEBUG, "Setting parking lot %s %s to %s\n", name, confvar->name, confvar->value);
04657 if (!strcasecmp(confvar->value, "both"))
04658 parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYBOTH;
04659 else if (!strcasecmp(confvar->value, "caller"))
04660 parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYCALLER;
04661 else if (!strcasecmp(confvar->value, "callee"))
04662 parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYCALLEE;
04663 } else if (!strcasecmp(confvar->name, "parkedcallhangup")) {
04664 ast_log(LOG_DEBUG, "Setting parking lot %s %s to %s\n", name, confvar->name, confvar->value);
04665 if (!strcasecmp(confvar->value, "both"))
04666 parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYBOTH;
04667 else if (!strcasecmp(confvar->value, "caller"))
04668 parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYCALLER;
04669 else if (!strcasecmp(confvar->value, "callee"))
04670 parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYCALLEE;
04671 } else if (!strcasecmp(confvar->name, "parkedcallrecording")) {
04672 ast_log(LOG_DEBUG, "Setting parking lot %s %s to %s\n", name, confvar->name, confvar->value);
04673 if (!strcasecmp(confvar->value, "both"))
04674 parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYBOTH;
04675 else if (!strcasecmp(confvar->value, "caller"))
04676 parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYCALLER;
04677 else if (!strcasecmp(confvar->value, "callee"))
04678 parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYCALLEE;
04679 }
04680 confvar = confvar->next;
04681 }
04682
04683 if (parkinglot->parkingtime == 0) {
04684 parkinglot->parkingtime = DEFAULT_PARK_TIME;
04685 }
04686 if (ast_strlen_zero(parkinglot->parkext)) {
04687 ast_debug(2, "no parkext specified for %s - setting it to %s\n", parkinglot->name, DEFAULT_PARK_EXTENSION);
04688 ast_copy_string(parkinglot->parkext, DEFAULT_PARK_EXTENSION, sizeof(parkinglot->parkext));
04689 }
04690
04691 if (!var) {
04692 ast_copy_string(parkinglot->parking_con, "parkedcalls", sizeof(parkinglot->parking_con));
04693 ast_copy_string(parkinglot->parking_con_dial, "park-dial", sizeof(parkinglot->parking_con_dial));
04694 ast_copy_string(parkinglot->mohclass, "default", sizeof(parkinglot->mohclass));
04695 }
04696
04697
04698 if (ast_strlen_zero(parkinglot->parking_con)) {
04699 ast_log(LOG_WARNING, "Parking lot %s lacks context\n", name);
04700 error = 1;
04701 }
04702
04703
04704 if (!error && !(con = ast_context_find_or_create(NULL, NULL, parkinglot->parking_con, registrar))) {
04705 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parkinglot->parking_con);
04706 error = 1;
04707 }
04708
04709
04710 if (!error && !oldparkinglot) {
04711 if (!ast_strlen_zero(parkinglot->parkext)) {
04712 if (ast_add_extension2(con, 1, parkinglot->parkext, 1, NULL, NULL, parkcall, strdup(""), ast_free_ptr, registrar) == -1)
04713 error = 1;
04714 }
04715 }
04716
04717
04718 if (parkinglot->parkaddhints)
04719 park_add_hints(parkinglot->parking_con, parkinglot->parking_start, parkinglot->parking_stop);
04720
04721 ao2_unlock(parkinglot);
04722
04723 if (error) {
04724 ast_log(LOG_WARNING, "Parking %s not open for business. Configuration error.\n", name);
04725 parkinglot_destroy(parkinglot);
04726 parkinglot_unref(parkinglot);
04727 return NULL;
04728 }
04729 ast_debug(1, "Parking %s now open for business. (start exten %d end %d)\n", name, start, end);
04730 parkinglot->the_mark = 0;
04731
04732
04733 if (!oldparkinglot) {
04734 ao2_link(parkinglots, parkinglot);
04735 }
04736 parkinglot_unref(parkinglot);
04737
04738 return parkinglot;
04739 }
04740
04741 static int load_config(void)
04742 {
04743 int start = 0, end = 0;
04744 int res;
04745 int i;
04746 struct ast_context *con = NULL;
04747 struct ast_config *cfg = NULL;
04748 struct ast_variable *var = NULL;
04749 struct feature_group *fg = NULL;
04750 struct ast_flags config_flags = { 0 };
04751 char *ctg;
04752 static const char * const categories[] = {
04753
04754
04755
04756 "general",
04757 "featuremap",
04758 "applicationmap"
04759 };
04760
04761 default_parkinglot = build_parkinglot(DEFAULT_PARKINGLOT, NULL);
04762 if (default_parkinglot) {
04763 ao2_lock(default_parkinglot);
04764 ast_copy_string(default_parkinglot->parkext, DEFAULT_PARK_EXTENSION, sizeof(default_parkinglot->parkext));
04765 default_parkinglot->parking_start = 701;
04766 default_parkinglot->parking_stop = 750;
04767 default_parkinglot->parking_offset = 0;
04768 default_parkinglot->parkfindnext = 0;
04769 default_parkinglot->parkingtime = DEFAULT_PARK_TIME;
04770 ao2_unlock(default_parkinglot);
04771 }
04772
04773 if (default_parkinglot) {
04774 ast_debug(1, "Configuration of default parkinglot done.\n");
04775 } else {
04776 ast_log(LOG_ERROR, "Configuration of default parkinglot failed.\n");
04777 return -1;
04778 }
04779
04780
04781 strcpy(default_parkinglot->parkext, DEFAULT_PARK_EXTENSION);
04782 strcpy(pickup_ext, "*8");
04783 courtesytone[0] = '\0';
04784 strcpy(xfersound, "beep");
04785 strcpy(xferfailsound, "pbx-invalid");
04786 pickupsound[0] = '\0';
04787 pickupfailsound[0] = '\0';
04788 adsipark = 0;
04789 comebacktoorigin = 1;
04790 parkeddynamic = 0;
04791
04792 default_parkinglot->parkaddhints = 0;
04793 default_parkinglot->parkedcalltransfers = 0;
04794 default_parkinglot->parkedcallreparking = 0;
04795 default_parkinglot->parkedcallrecording = 0;
04796 default_parkinglot->parkedcallhangup = 0;
04797
04798 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
04799 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
04800 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
04801 atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY;
04802 atxferdropcall = DEFAULT_ATXFER_DROP_CALL;
04803 atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES;
04804
04805 cfg = ast_config_load2("features.conf", "features", config_flags);
04806 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
04807 ast_log(LOG_WARNING,"Could not load features.conf\n");
04808 return 0;
04809 }
04810 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
04811 if (!strcasecmp(var->name, "parkext")) {
04812 ast_copy_string(default_parkinglot->parkext, var->value, sizeof(default_parkinglot->parkext));
04813 } else if (!strcasecmp(var->name, "context")) {
04814 ast_copy_string(default_parkinglot->parking_con, var->value, sizeof(default_parkinglot->parking_con));
04815 } else if (!strcasecmp(var->name, "parkingtime")) {
04816 if ((sscanf(var->value, "%30d", &default_parkinglot->parkingtime) != 1) || (default_parkinglot->parkingtime < 1)) {
04817 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
04818 default_parkinglot->parkingtime = DEFAULT_PARK_TIME;
04819 } else
04820 default_parkinglot->parkingtime = default_parkinglot->parkingtime * 1000;
04821 } else if (!strcasecmp(var->name, "parkpos")) {
04822 if (sscanf(var->value, "%30d-%30d", &start, &end) != 2) {
04823 ast_log(LOG_WARNING, "Format for parking positions is a-b, where a and b are numbers at line %d of features.conf\n", var->lineno);
04824 } else if (default_parkinglot) {
04825 default_parkinglot->parking_start = start;
04826 default_parkinglot->parking_stop = end;
04827 } else {
04828 ast_log(LOG_WARNING, "No default parking lot!\n");
04829 }
04830 } else if (!strcasecmp(var->name, "findslot")) {
04831 default_parkinglot->parkfindnext = (!strcasecmp(var->value, "next"));
04832 } else if (!strcasecmp(var->name, "parkinghints")) {
04833 default_parkinglot->parkaddhints = ast_true(var->value);
04834 } else if (!strcasecmp(var->name, "parkedcalltransfers")) {
04835 if (!strcasecmp(var->value, "both"))
04836 default_parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH;
04837 else if (!strcasecmp(var->value, "caller"))
04838 default_parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYCALLER;
04839 else if (!strcasecmp(var->value, "callee"))
04840 default_parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYCALLEE;
04841 } else if (!strcasecmp(var->name, "parkedcallreparking")) {
04842 if (!strcasecmp(var->value, "both"))
04843 default_parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYBOTH;
04844 else if (!strcasecmp(var->value, "caller"))
04845 default_parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYCALLER;
04846 else if (!strcasecmp(var->value, "callee"))
04847 default_parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYCALLEE;
04848 } else if (!strcasecmp(var->name, "parkedcallhangup")) {
04849 if (!strcasecmp(var->value, "both"))
04850 default_parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYBOTH;
04851 else if (!strcasecmp(var->value, "caller"))
04852 default_parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYCALLER;
04853 else if (!strcasecmp(var->value, "callee"))
04854 default_parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYCALLEE;
04855 } else if (!strcasecmp(var->name, "parkedcallrecording")) {
04856 if (!strcasecmp(var->value, "both"))
04857 default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYBOTH;
04858 else if (!strcasecmp(var->value, "caller"))
04859 default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYCALLER;
04860 else if (!strcasecmp(var->value, "callee"))
04861 default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYCALLEE;
04862 } else if (!strcasecmp(var->name, "parkeddynamic")) {
04863 parkeddynamic = ast_true(var->value);
04864 } else if (!strcasecmp(var->name, "adsipark")) {
04865 adsipark = ast_true(var->value);
04866 } else if (!strcasecmp(var->name, "transferdigittimeout")) {
04867 if ((sscanf(var->value, "%30d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
04868 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
04869 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
04870 } else
04871 transferdigittimeout = transferdigittimeout * 1000;
04872 } else if (!strcasecmp(var->name, "featuredigittimeout")) {
04873 if ((sscanf(var->value, "%30d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
04874 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
04875 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
04876 }
04877 } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) {
04878 if ((sscanf(var->value, "%30d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) {
04879 ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value);
04880 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
04881 } else
04882 atxfernoanswertimeout = atxfernoanswertimeout * 1000;
04883 } else if (!strcasecmp(var->name, "atxferloopdelay")) {
04884 if ((sscanf(var->value, "%30u", &atxferloopdelay) != 1)) {
04885 ast_log(LOG_WARNING, "%s is not a valid atxferloopdelay\n", var->value);
04886 atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY;
04887 } else
04888 atxferloopdelay *= 1000;
04889 } else if (!strcasecmp(var->name, "atxferdropcall")) {
04890 atxferdropcall = ast_true(var->value);
04891 } else if (!strcasecmp(var->name, "atxfercallbackretries")) {
04892 if ((sscanf(var->value, "%30u", &atxfercallbackretries) != 1)) {
04893 ast_log(LOG_WARNING, "%s is not a valid atxfercallbackretries\n", var->value);
04894 atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES;
04895 }
04896 } else if (!strcasecmp(var->name, "courtesytone")) {
04897 ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
04898 } else if (!strcasecmp(var->name, "parkedplay")) {
04899 if (!strcasecmp(var->value, "both"))
04900 parkedplay = 2;
04901 else if (!strcasecmp(var->value, "parked"))
04902 parkedplay = 1;
04903 else
04904 parkedplay = 0;
04905 } else if (!strcasecmp(var->name, "xfersound")) {
04906 ast_copy_string(xfersound, var->value, sizeof(xfersound));
04907 } else if (!strcasecmp(var->name, "xferfailsound")) {
04908 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
04909 } else if (!strcasecmp(var->name, "pickupexten")) {
04910 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
04911 } else if (!strcasecmp(var->name, "pickupsound")) {
04912 ast_copy_string(pickupsound, var->value, sizeof(pickupsound));
04913 } else if (!strcasecmp(var->name, "pickupfailsound")) {
04914 ast_copy_string(pickupfailsound, var->value, sizeof(pickupfailsound));
04915 } else if (!strcasecmp(var->name, "comebacktoorigin")) {
04916 comebacktoorigin = ast_true(var->value);
04917 } else if (!strcasecmp(var->name, "parkedmusicclass")) {
04918 ast_copy_string(default_parkinglot->mohclass, var->value, sizeof(default_parkinglot->mohclass));
04919 }
04920 }
04921
04922 unmap_features();
04923 for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) {
04924 if (remap_feature(var->name, var->value))
04925 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
04926 }
04927
04928
04929 ast_unregister_features();
04930 for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) {
04931 char *tmp_val = ast_strdupa(var->value);
04932 char *activateon;
04933 struct ast_call_feature *feature;
04934 AST_DECLARE_APP_ARGS(args,
04935 AST_APP_ARG(exten);
04936 AST_APP_ARG(activatedby);
04937 AST_APP_ARG(app);
04938 AST_APP_ARG(app_args);
04939 AST_APP_ARG(moh_class);
04940 );
04941
04942 AST_STANDARD_APP_ARGS(args, tmp_val);
04943 if (strchr(args.app, '(')) {
04944
04945 args.moh_class = args.app_args;
04946 args.app_args = strchr(args.app, '(');
04947 *args.app_args++ = '\0';
04948 if (args.app_args[strlen(args.app_args) - 1] == ')') {
04949 args.app_args[strlen(args.app_args) - 1] = '\0';
04950 }
04951 }
04952
04953 activateon = strsep(&args.activatedby, "/");
04954
04955
04956 if (ast_strlen_zero(args.app) || ast_strlen_zero(args.exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) {
04957 ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",
04958 args.app, args.exten, activateon, var->name);
04959 continue;
04960 }
04961
04962 AST_RWLIST_RDLOCK(&feature_list);
04963 if ((feature = find_dynamic_feature(var->name))) {
04964 AST_RWLIST_UNLOCK(&feature_list);
04965 ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name);
04966 continue;
04967 }
04968 AST_RWLIST_UNLOCK(&feature_list);
04969
04970 if (!(feature = ast_calloc(1, sizeof(*feature)))) {
04971 continue;
04972 }
04973
04974 ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN);
04975 ast_copy_string(feature->app, args.app, FEATURE_APP_LEN);
04976 ast_copy_string(feature->exten, args.exten, FEATURE_EXTEN_LEN);
04977
04978 if (args.app_args) {
04979 ast_copy_string(feature->app_args, args.app_args, FEATURE_APP_ARGS_LEN);
04980 }
04981
04982 if (args.moh_class) {
04983 ast_copy_string(feature->moh_class, args.moh_class, FEATURE_MOH_LEN);
04984 }
04985
04986 ast_copy_string(feature->exten, args.exten, sizeof(feature->exten));
04987 feature->operation = feature_exec_app;
04988 ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF);
04989
04990
04991 if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller"))
04992 ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF);
04993 else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee"))
04994 ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER);
04995 else {
04996 ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s',"
04997 " must be 'self', or 'peer'\n", var->name);
04998 continue;
04999 }
05000
05001 if (ast_strlen_zero(args.activatedby))
05002 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
05003 else if (!strcasecmp(args.activatedby, "caller"))
05004 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER);
05005 else if (!strcasecmp(args.activatedby, "callee"))
05006 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE);
05007 else if (!strcasecmp(args.activatedby, "both"))
05008 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
05009 else {
05010 ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s',"
05011 " must be 'caller', or 'callee', or 'both'\n", var->name);
05012 continue;
05013 }
05014
05015 ast_register_feature(feature);
05016
05017 ast_verb(2, "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, args.app, args.app_args, args.exten);
05018 }
05019
05020 ast_unregister_groups();
05021 AST_RWLIST_WRLOCK(&feature_groups);
05022
05023 ctg = NULL;
05024 while ((ctg = ast_category_browse(cfg, ctg))) {
05025
05026 if (!strncasecmp(ctg, "parkinglot_", strlen("parkinglot_"))) {
05027 ast_debug(2, "Found configuration section %s, assume parking context\n", ctg);
05028 if(!build_parkinglot(ctg, ast_variable_browse(cfg, ctg)))
05029 ast_log(LOG_ERROR, "Could not build parking lot %s. Configuration error.\n", ctg);
05030 else
05031 ast_debug(1, "Configured parking context %s\n", ctg);
05032 continue;
05033 }
05034
05035 for (i = 0; i < ARRAY_LEN(categories); i++) {
05036 if (!strcasecmp(categories[i], ctg))
05037 break;
05038 }
05039
05040 if (i < ARRAY_LEN(categories))
05041 continue;
05042
05043 if (!(fg = register_group(ctg)))
05044 continue;
05045
05046 for (var = ast_variable_browse(cfg, ctg); var; var = var->next) {
05047 struct ast_call_feature *feature;
05048
05049 AST_RWLIST_RDLOCK(&feature_list);
05050 if (!(feature = find_dynamic_feature(var->name)) &&
05051 !(feature = ast_find_call_feature(var->name))) {
05052 AST_RWLIST_UNLOCK(&feature_list);
05053 ast_log(LOG_WARNING, "Feature '%s' was not found.\n", var->name);
05054 continue;
05055 }
05056 AST_RWLIST_UNLOCK(&feature_list);
05057
05058 register_group_feature(fg, var->value, feature);
05059 }
05060 }
05061
05062 AST_RWLIST_UNLOCK(&feature_groups);
05063
05064 ast_config_destroy(cfg);
05065
05066 if (!(con = ast_context_find_or_create(NULL, NULL, default_parkinglot->parking_con, registrar))) {
05067 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", default_parkinglot->parking_con);
05068 return -1;
05069 }
05070 res = ast_add_extension2(con, 1, default_parkinglot->parkext, 1, NULL, NULL, parkcall, NULL, NULL, registrar);
05071 if (default_parkinglot->parkaddhints)
05072 park_add_hints(default_parkinglot->parking_con, default_parkinglot->parking_start, default_parkinglot->parking_stop);
05073 if (!res)
05074 notify_metermaids(default_parkinglot->parkext, default_parkinglot->parking_con, AST_DEVICE_INUSE);
05075 return res;
05076
05077 }
05078
05079
05080
05081
05082
05083
05084
05085
05086
05087
05088 static char *handle_feature_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05089 {
05090 int i;
05091 struct ast_call_feature *feature;
05092 struct ao2_iterator iter;
05093 struct ast_parkinglot *curlot;
05094 #define HFS_FORMAT "%-25s %-7s %-7s\n"
05095
05096 switch (cmd) {
05097
05098 case CLI_INIT:
05099 e->command = "features show";
05100 e->usage =
05101 "Usage: features show\n"
05102 " Lists configured features\n";
05103 return NULL;
05104 case CLI_GENERATE:
05105 return NULL;
05106 }
05107
05108 ast_cli(a->fd, HFS_FORMAT, "Builtin Feature", "Default", "Current");
05109 ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
05110
05111 ast_cli(a->fd, HFS_FORMAT, "Pickup", "*8", ast_pickup_ext());
05112
05113 ast_rwlock_rdlock(&features_lock);
05114 for (i = 0; i < FEATURES_COUNT; i++)
05115 ast_cli(a->fd, HFS_FORMAT, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
05116 ast_rwlock_unlock(&features_lock);
05117
05118 ast_cli(a->fd, "\n");
05119 ast_cli(a->fd, HFS_FORMAT, "Dynamic Feature", "Default", "Current");
05120 ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
05121 if (AST_RWLIST_EMPTY(&feature_list)) {
05122 ast_cli(a->fd, "(none)\n");
05123 } else {
05124 AST_RWLIST_RDLOCK(&feature_list);
05125 AST_RWLIST_TRAVERSE(&feature_list, feature, feature_entry) {
05126 ast_cli(a->fd, HFS_FORMAT, feature->sname, "no def", feature->exten);
05127 }
05128 AST_RWLIST_UNLOCK(&feature_list);
05129 }
05130
05131 ast_cli(a->fd, "\nFeature Groups:\n");
05132 ast_cli(a->fd, "---------------\n");
05133 if (AST_RWLIST_EMPTY(&feature_groups)) {
05134 ast_cli(a->fd, "(none)\n");
05135 } else {
05136 struct feature_group *fg;
05137 struct feature_group_exten *fge;
05138
05139 AST_RWLIST_RDLOCK(&feature_groups);
05140 AST_RWLIST_TRAVERSE(&feature_groups, fg, entry) {
05141 ast_cli(a->fd, "===> Group: %s\n", fg->gname);
05142 AST_LIST_TRAVERSE(&fg->features, fge, entry) {
05143 ast_cli(a->fd, "===> --> %s (%s)\n", fge->feature->sname, fge->exten);
05144 }
05145 }
05146 AST_RWLIST_UNLOCK(&feature_groups);
05147 }
05148
05149 iter = ao2_iterator_init(parkinglots, 0);
05150 while ((curlot = ao2_iterator_next(&iter))) {
05151 ast_cli(a->fd, "\nCall parking (Parking lot: %s)\n", curlot->name);
05152 ast_cli(a->fd, "------------\n");
05153 ast_cli(a->fd,"%-22s: %s\n", "Parking extension", curlot->parkext);
05154 ast_cli(a->fd,"%-22s: %s\n", "Parking context", curlot->parking_con);
05155 ast_cli(a->fd,"%-22s: %d-%d\n", "Parked call extensions", curlot->parking_start, curlot->parking_stop);
05156 ast_cli(a->fd,"%-22s: %d\n", "Parkingtime", curlot->parkingtime);
05157 ast_cli(a->fd,"%-22s: %s\n", "MusicOnHold class", curlot->mohclass);
05158 ast_cli(a->fd,"\n");
05159 ao2_ref(curlot, -1);
05160 }
05161 ao2_iterator_destroy(&iter);
05162
05163 return CLI_SUCCESS;
05164 }
05165
05166 static int parkinglot_markall_cb(void *obj, void *arg, int flags)
05167 {
05168 struct ast_parkinglot *parkinglot = obj;
05169 parkinglot->the_mark = 1;
05170 return 0;
05171 }
05172
05173 static int parkinglot_is_marked_cb(void *obj, void *arg, int flags)
05174 {
05175 struct ast_parkinglot *parkinglot = obj;
05176 return parkinglot->the_mark ? CMP_MATCH : 0;
05177 }
05178
05179 int ast_features_reload(void)
05180 {
05181 int res;
05182
05183 ao2_t_callback(parkinglots, OBJ_NODATA, parkinglot_markall_cb, NULL, "callback to mark all parkinglots");
05184 res = load_config();
05185 ao2_t_callback(parkinglots, OBJ_NODATA | OBJ_UNLINK, parkinglot_is_marked_cb, NULL, "callback to remove all marked parkinglots");
05186
05187 return res;
05188 }
05189
05190 static char *handle_features_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05191 {
05192 switch (cmd) {
05193 case CLI_INIT:
05194 e->command = "features reload";
05195 e->usage =
05196 "Usage: features reload\n"
05197 " Reloads configured call features from features.conf\n";
05198 return NULL;
05199 case CLI_GENERATE:
05200 return NULL;
05201 }
05202 ast_features_reload();
05203
05204 return CLI_SUCCESS;
05205 }
05206
05207
05208
05209
05210
05211
05212
05213
05214
05215 static void do_bridge_masquerade(struct ast_channel *chan, struct ast_channel *tmpchan)
05216 {
05217 ast_moh_stop(chan);
05218 ast_channel_lock_both(chan, tmpchan);
05219 ast_setstate(tmpchan, chan->_state);
05220 tmpchan->readformat = chan->readformat;
05221 tmpchan->writeformat = chan->writeformat;
05222 ast_channel_masquerade(tmpchan, chan);
05223 ast_channel_unlock(chan);
05224 ast_channel_unlock(tmpchan);
05225
05226
05227 ast_do_masquerade(tmpchan);
05228
05229
05230 ast_explicit_goto(tmpchan, chan->context, chan->exten, chan->priority + 1);
05231 }
05232
05233
05234
05235
05236
05237
05238
05239
05240
05241
05242
05243
05244
05245
05246
05247 static int action_bridge(struct mansession *s, const struct message *m)
05248 {
05249 const char *channela = astman_get_header(m, "Channel1");
05250 const char *channelb = astman_get_header(m, "Channel2");
05251 const char *playtone = astman_get_header(m, "Tone");
05252 struct ast_channel *chana = NULL, *chanb = NULL, *chans[2];
05253 struct ast_channel *tmpchana = NULL, *tmpchanb = NULL;
05254 struct ast_bridge_thread_obj *tobj = NULL;
05255
05256
05257 if (ast_strlen_zero(channela) || ast_strlen_zero(channelb)) {
05258 astman_send_error(s, m, "Missing channel parameter in request");
05259 return 0;
05260 }
05261
05262
05263 chana = ast_channel_get_by_name_prefix(channela, strlen(channela));
05264
05265
05266 if (!chana) {
05267 char buf[256];
05268 snprintf(buf, sizeof(buf), "Channel1 does not exists: %s", channela);
05269 astman_send_error(s, m, buf);
05270 return 0;
05271 }
05272
05273
05274 if (chana->_state != AST_STATE_UP)
05275 ast_answer(chana);
05276
05277
05278 if (!(tmpchana = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
05279 NULL, NULL, chana->linkedid, 0, "Bridge/%s", chana->name))) {
05280 astman_send_error(s, m, "Unable to create temporary channel!");
05281 chana = ast_channel_unref(chana);
05282 return 1;
05283 }
05284
05285 do_bridge_masquerade(chana, tmpchana);
05286
05287 chana = ast_channel_unref(chana);
05288
05289
05290 chanb = ast_channel_get_by_name_prefix(channelb, strlen(channelb));
05291
05292 if (!chanb) {
05293 char buf[256];
05294 snprintf(buf, sizeof(buf), "Channel2 does not exists: %s", channelb);
05295 ast_hangup(tmpchana);
05296 astman_send_error(s, m, buf);
05297 return 0;
05298 }
05299
05300
05301 if (chanb->_state != AST_STATE_UP)
05302 ast_answer(chanb);
05303
05304
05305 if (!(tmpchanb = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
05306 NULL, NULL, chanb->linkedid, 0, "Bridge/%s", chanb->name))) {
05307 astman_send_error(s, m, "Unable to create temporary channels!");
05308 ast_hangup(tmpchana);
05309 chanb = ast_channel_unref(chanb);
05310 return 1;
05311 }
05312
05313 do_bridge_masquerade(chanb, tmpchanb);
05314
05315 chanb = ast_channel_unref(chanb);
05316
05317
05318 if (ast_channel_make_compatible(tmpchana, tmpchanb)) {
05319 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for manager bridge\n", tmpchana->name, tmpchanb->name);
05320 astman_send_error(s, m, "Could not make channels compatible for manager bridge");
05321 ast_hangup(tmpchana);
05322 ast_hangup(tmpchanb);
05323 return 1;
05324 }
05325
05326
05327 if (!(tobj = ast_calloc(1, sizeof(*tobj)))) {
05328 ast_log(LOG_WARNING, "Unable to spawn a new bridge thread on %s and %s: %s\n", tmpchana->name, tmpchanb->name, strerror(errno));
05329 astman_send_error(s, m, "Unable to spawn a new bridge thread");
05330 ast_hangup(tmpchana);
05331 ast_hangup(tmpchanb);
05332 return 1;
05333 }
05334
05335 tobj->chan = tmpchana;
05336 tobj->peer = tmpchanb;
05337 tobj->return_to_pbx = 1;
05338
05339 if (ast_true(playtone)) {
05340 if (!ast_strlen_zero(xfersound) && !ast_streamfile(tmpchanb, xfersound, tmpchanb->language)) {
05341 if (ast_waitstream(tmpchanb, "") < 0)
05342 ast_log(LOG_WARNING, "Failed to play a courtesy tone on chan %s\n", tmpchanb->name);
05343 }
05344 }
05345
05346 chans[0] = tmpchana;
05347 chans[1] = tmpchanb;
05348
05349 ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeAction", 2, chans,
05350 "Response: Success\r\n"
05351 "Channel1: %s\r\n"
05352 "Channel2: %s\r\n", tmpchana->name, tmpchanb->name);
05353
05354 bridge_call_thread_launch(tobj);
05355
05356 astman_send_ack(s, m, "Launched bridge thread with success");
05357
05358 return 0;
05359 }
05360
05361
05362
05363
05364
05365
05366
05367
05368
05369
05370
05371
05372 static char *handle_parkedcalls(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05373 {
05374 struct parkeduser *cur;
05375 int numparked = 0;
05376 struct ao2_iterator iter;
05377 struct ast_parkinglot *curlot;
05378
05379 switch (cmd) {
05380 case CLI_INIT:
05381 e->command = "parkedcalls show";
05382 e->usage =
05383 "Usage: parkedcalls show\n"
05384 " List currently parked calls\n";
05385 return NULL;
05386 case CLI_GENERATE:
05387 return NULL;
05388 }
05389
05390 if (a->argc > e->args)
05391 return CLI_SHOWUSAGE;
05392
05393 ast_cli(a->fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
05394 , "Context", "Extension", "Pri", "Timeout");
05395
05396 iter = ao2_iterator_init(parkinglots, 0);
05397 while ((curlot = ao2_iterator_next(&iter))) {
05398 int lotparked = 0;
05399
05400 ast_cli(a->fd, "*** Parking lot: %s (%d)\n", curlot->name, ao2_ref(curlot, 0) - 2);
05401
05402 AST_LIST_LOCK(&curlot->parkings);
05403 AST_LIST_TRAVERSE(&curlot->parkings, cur, list) {
05404 ast_cli(a->fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n"
05405 ,cur->parkingexten, cur->chan->name, cur->context, cur->exten
05406 ,cur->priority,
05407 (long)(cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL)) );
05408 numparked++;
05409 numparked += lotparked;
05410 }
05411 AST_LIST_UNLOCK(&curlot->parkings);
05412 if (lotparked)
05413 ast_cli(a->fd, " %d parked call%s in parking lot %s\n", lotparked, ESS(lotparked), curlot->name);
05414
05415 ao2_ref(curlot, -1);
05416 }
05417
05418 ast_cli(a->fd, "---\n%d parked call%s in total.\n", numparked, ESS(numparked));
05419
05420 return CLI_SUCCESS;
05421 }
05422
05423 static struct ast_cli_entry cli_features[] = {
05424 AST_CLI_DEFINE(handle_feature_show, "Lists configured features"),
05425 AST_CLI_DEFINE(handle_features_reload, "Reloads configured features"),
05426 AST_CLI_DEFINE(handle_parkedcalls, "List currently parked calls"),
05427 };
05428
05429
05430
05431
05432
05433
05434
05435
05436
05437 static int manager_parking_status(struct mansession *s, const struct message *m)
05438 {
05439 struct parkeduser *cur;
05440 const char *id = astman_get_header(m, "ActionID");
05441 char idText[256] = "";
05442 struct ao2_iterator iter;
05443 struct ast_parkinglot *curlot;
05444
05445 if (!ast_strlen_zero(id))
05446 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
05447
05448 astman_send_ack(s, m, "Parked calls will follow");
05449
05450 iter = ao2_iterator_init(parkinglots, 0);
05451 while ((curlot = ao2_iterator_next(&iter))) {
05452
05453 AST_LIST_LOCK(&curlot->parkings);
05454 AST_LIST_TRAVERSE(&curlot->parkings, cur, list) {
05455 astman_append(s, "Event: ParkedCall\r\n"
05456 "Exten: %d\r\n"
05457 "Channel: %s\r\n"
05458 "From: %s\r\n"
05459 "Timeout: %ld\r\n"
05460 "CallerIDNum: %s\r\n"
05461 "CallerIDName: %s\r\n"
05462 "%s"
05463 "\r\n",
05464 cur->parkingnum, cur->chan->name, cur->peername,
05465 (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
05466 S_COR(cur->chan->caller.id.number.valid, cur->chan->caller.id.number.str, ""),
05467 S_COR(cur->chan->caller.id.name.valid, cur->chan->caller.id.name.str, ""),
05468 idText);
05469 }
05470 AST_LIST_UNLOCK(&curlot->parkings);
05471 ao2_ref(curlot, -1);
05472 }
05473
05474 astman_append(s,
05475 "Event: ParkedCallsComplete\r\n"
05476 "%s"
05477 "\r\n",idText);
05478
05479
05480 return RESULT_SUCCESS;
05481 }
05482
05483
05484
05485
05486
05487
05488
05489
05490
05491 static int manager_park(struct mansession *s, const struct message *m)
05492 {
05493 const char *channel = astman_get_header(m, "Channel");
05494 const char *channel2 = astman_get_header(m, "Channel2");
05495 const char *timeout = astman_get_header(m, "Timeout");
05496 const char *parkinglotname = astman_get_header(m, "Parkinglot");
05497 char buf[BUFSIZ];
05498 int res = 0;
05499 struct ast_channel *ch1, *ch2;
05500 struct ast_park_call_args args = {0,};
05501
05502 if (ast_strlen_zero(channel)) {
05503 astman_send_error(s, m, "Channel not specified");
05504 return 0;
05505 }
05506
05507 if (ast_strlen_zero(channel2)) {
05508 astman_send_error(s, m, "Channel2 not specified");
05509 return 0;
05510 }
05511
05512 if (!(ch1 = ast_channel_get_by_name(channel))) {
05513 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
05514 astman_send_error(s, m, buf);
05515 return 0;
05516 }
05517
05518 if (!(ch2 = ast_channel_get_by_name(channel2))) {
05519 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
05520 astman_send_error(s, m, buf);
05521 ast_channel_unref(ch1);
05522 return 0;
05523 }
05524
05525 if (!ast_strlen_zero(timeout)) {
05526 sscanf(timeout, "%30d", &args.timeout);
05527 }
05528 if (!ast_strlen_zero(parkinglotname)) {
05529 args.parkinglot = find_parkinglot(parkinglotname);
05530 }
05531
05532 ast_channel_lock(ch1);
05533 while (ast_channel_trylock(ch2)) {
05534 CHANNEL_DEADLOCK_AVOIDANCE(ch1);
05535 }
05536
05537 res = masq_park_call(ch1, ch2, 0, NULL, 0, &args);
05538 if (!res) {
05539 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
05540 astman_send_ack(s, m, "Park successful");
05541 } else {
05542 astman_send_error(s, m, "Park failure");
05543 }
05544
05545 ast_channel_unlock(ch1);
05546 ast_channel_unlock(ch2);
05547
05548 ch1 = ast_channel_unref(ch1);
05549 ch2 = ast_channel_unref(ch2);
05550
05551 return 0;
05552 }
05553
05554 static int find_channel_by_group(void *obj, void *arg, void *data, int flags)
05555 {
05556 struct ast_channel *c = data;
05557 struct ast_channel *chan = obj;
05558
05559 int i = !chan->pbx &&
05560
05561
05562
05563 (c != chan) &&
05564 (chan->pickupgroup & c->callgroup) &&
05565 ((chan->_state == AST_STATE_RINGING) || (chan->_state == AST_STATE_RING));
05566
05567 return i ? CMP_MATCH | CMP_STOP : 0;
05568 }
05569
05570
05571
05572
05573
05574
05575
05576
05577
05578 int ast_pickup_call(struct ast_channel *chan)
05579 {
05580 struct ast_channel *cur, *chans[2] = { chan, };
05581 struct ast_party_connected_line connected_caller;
05582 int res;
05583 const char *chan_name;
05584 const char *cur_name;
05585
05586 if (!(cur = ast_channel_callback(find_channel_by_group, NULL, chan, 0))) {
05587 ast_debug(1, "No call pickup possible...\n");
05588 if (!ast_strlen_zero(pickupfailsound)) {
05589 ast_stream_and_wait(chan, pickupfailsound, "");
05590 }
05591 return -1;
05592 }
05593
05594 chans[1] = cur;
05595
05596 ast_channel_lock_both(cur, chan);
05597
05598 cur_name = ast_strdupa(cur->name);
05599 chan_name = ast_strdupa(chan->name);
05600
05601 ast_debug(1, "Call pickup on chan '%s' by '%s'\n", cur_name, chan_name);
05602
05603 connected_caller = cur->connected;
05604 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
05605 if (ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) {
05606 ast_channel_update_connected_line(chan, &connected_caller, NULL);
05607 }
05608
05609 ast_party_connected_line_collect_caller(&connected_caller, &chan->caller);
05610 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
05611 ast_channel_queue_connected_line_update(chan, &connected_caller, NULL);
05612
05613 ast_channel_unlock(cur);
05614 ast_channel_unlock(chan);
05615
05616 if (ast_answer(chan)) {
05617 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name);
05618 }
05619
05620 if (ast_queue_control(chan, AST_CONTROL_ANSWER)) {
05621 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan_name);
05622 }
05623
05624 if ((res = ast_channel_masquerade(cur, chan))) {
05625 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan_name, cur_name);
05626 }
05627
05628 if (!ast_strlen_zero(pickupsound)) {
05629 ast_stream_and_wait(cur, pickupsound, "");
05630 }
05631
05632
05633 ast_manager_event_multichan(EVENT_FLAG_CALL, "Pickup", 2, chans,
05634 "Channel: %s\r\nTargetChannel: %s\r\n", chan->name, cur->name);
05635
05636 cur = ast_channel_unref(cur);
05637
05638 return res;
05639 }
05640
05641 static char *app_bridge = "Bridge";
05642
05643 enum {
05644 BRIDGE_OPT_PLAYTONE = (1 << 0),
05645 OPT_CALLEE_HANGUP = (1 << 1),
05646 OPT_CALLER_HANGUP = (1 << 2),
05647 OPT_DURATION_LIMIT = (1 << 3),
05648 OPT_DURATION_STOP = (1 << 4),
05649 OPT_CALLEE_TRANSFER = (1 << 5),
05650 OPT_CALLER_TRANSFER = (1 << 6),
05651 OPT_CALLEE_MONITOR = (1 << 7),
05652 OPT_CALLER_MONITOR = (1 << 8),
05653 OPT_CALLEE_PARK = (1 << 9),
05654 OPT_CALLER_PARK = (1 << 10),
05655 OPT_CALLEE_KILL = (1 << 11),
05656 };
05657
05658 enum {
05659 OPT_ARG_DURATION_LIMIT = 0,
05660 OPT_ARG_DURATION_STOP,
05661
05662 OPT_ARG_ARRAY_SIZE,
05663 };
05664
05665 AST_APP_OPTIONS(bridge_exec_options, BEGIN_OPTIONS
05666 AST_APP_OPTION('p', BRIDGE_OPT_PLAYTONE),
05667 AST_APP_OPTION('h', OPT_CALLEE_HANGUP),
05668 AST_APP_OPTION('H', OPT_CALLER_HANGUP),
05669 AST_APP_OPTION('k', OPT_CALLEE_PARK),
05670 AST_APP_OPTION('K', OPT_CALLER_PARK),
05671 AST_APP_OPTION_ARG('L', OPT_DURATION_LIMIT, OPT_ARG_DURATION_LIMIT),
05672 AST_APP_OPTION_ARG('S', OPT_DURATION_STOP, OPT_ARG_DURATION_STOP),
05673 AST_APP_OPTION('t', OPT_CALLEE_TRANSFER),
05674 AST_APP_OPTION('T', OPT_CALLER_TRANSFER),
05675 AST_APP_OPTION('w', OPT_CALLEE_MONITOR),
05676 AST_APP_OPTION('W', OPT_CALLER_MONITOR),
05677 AST_APP_OPTION('x', OPT_CALLEE_KILL),
05678 END_OPTIONS );
05679
05680 int ast_bridge_timelimit(struct ast_channel *chan, struct ast_bridge_config *config,
05681 char *parse, struct timeval *calldurationlimit)
05682 {
05683 char *stringp = ast_strdupa(parse);
05684 char *limit_str, *warning_str, *warnfreq_str;
05685 const char *var;
05686 int play_to_caller = 0, play_to_callee = 0;
05687 int delta;
05688
05689 limit_str = strsep(&stringp, ":");
05690 warning_str = strsep(&stringp, ":");
05691 warnfreq_str = strsep(&stringp, ":");
05692
05693 config->timelimit = atol(limit_str);
05694 if (warning_str)
05695 config->play_warning = atol(warning_str);
05696 if (warnfreq_str)
05697 config->warning_freq = atol(warnfreq_str);
05698
05699 if (!config->timelimit) {
05700 ast_log(LOG_WARNING, "Bridge does not accept L(%s), hanging up.\n", limit_str);
05701 config->timelimit = config->play_warning = config->warning_freq = 0;
05702 config->warning_sound = NULL;
05703 return -1;
05704 } else if ( (delta = config->play_warning - config->timelimit) > 0) {
05705 int w = config->warning_freq;
05706
05707
05708
05709
05710
05711
05712
05713
05714
05715
05716
05717
05718
05719 if (w == 0) {
05720 config->play_warning = 0;
05721 } else {
05722 config->play_warning -= w * ( 1 + (delta-1)/w );
05723 if (config->play_warning < 1)
05724 config->play_warning = config->warning_freq = 0;
05725 }
05726 }
05727
05728 ast_channel_lock(chan);
05729
05730 var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLER");
05731 play_to_caller = var ? ast_true(var) : 1;
05732
05733 var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLEE");
05734 play_to_callee = var ? ast_true(var) : 0;
05735
05736 if (!play_to_caller && !play_to_callee)
05737 play_to_caller = 1;
05738
05739 var = pbx_builtin_getvar_helper(chan, "LIMIT_WARNING_FILE");
05740 config->warning_sound = !ast_strlen_zero(var) ? ast_strdup(var) : ast_strdup("timeleft");
05741
05742
05743
05744
05745
05746
05747
05748 var = pbx_builtin_getvar_helper(chan, "LIMIT_TIMEOUT_FILE");
05749 config->end_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL;
05750
05751 var = pbx_builtin_getvar_helper(chan, "LIMIT_CONNECT_FILE");
05752 config->start_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL;
05753
05754 ast_channel_unlock(chan);
05755
05756
05757 calldurationlimit->tv_sec = 0;
05758 calldurationlimit->tv_usec = 0;
05759
05760
05761 if (!config->play_warning && !config->start_sound && !config->end_sound && config->timelimit) {
05762 calldurationlimit->tv_sec = config->timelimit / 1000;
05763 calldurationlimit->tv_usec = (config->timelimit % 1000) * 1000;
05764 ast_verb(3, "Setting call duration limit to %.3lf seconds.\n",
05765 calldurationlimit->tv_sec + calldurationlimit->tv_usec / 1000000.0);
05766 config->timelimit = play_to_caller = play_to_callee =
05767 config->play_warning = config->warning_freq = 0;
05768 } else {
05769 ast_verb(4, "Limit Data for this call:\n");
05770 ast_verb(4, "timelimit = %ld ms (%.3lf s)\n", config->timelimit, config->timelimit / 1000.0);
05771 ast_verb(4, "play_warning = %ld ms (%.3lf s)\n", config->play_warning, config->play_warning / 1000.0);
05772 ast_verb(4, "play_to_caller = %s\n", play_to_caller ? "yes" : "no");
05773 ast_verb(4, "play_to_callee = %s\n", play_to_callee ? "yes" : "no");
05774 ast_verb(4, "warning_freq = %ld ms (%.3lf s)\n", config->warning_freq, config->warning_freq / 1000.0);
05775 ast_verb(4, "start_sound = %s\n", S_OR(config->start_sound, ""));
05776 ast_verb(4, "warning_sound = %s\n", config->warning_sound);
05777 ast_verb(4, "end_sound = %s\n", S_OR(config->end_sound, ""));
05778 }
05779 if (play_to_caller)
05780 ast_set_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
05781 if (play_to_callee)
05782 ast_set_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
05783 return 0;
05784 }
05785
05786
05787
05788
05789
05790
05791
05792
05793
05794
05795
05796 static int bridge_exec(struct ast_channel *chan, const char *data)
05797 {
05798 struct ast_channel *current_dest_chan, *final_dest_chan, *chans[2];
05799 char *tmp_data = NULL;
05800 struct ast_flags opts = { 0, };
05801 struct ast_bridge_config bconfig = { { 0, }, };
05802 char *opt_args[OPT_ARG_ARRAY_SIZE];
05803 struct timeval calldurationlimit = { 0, };
05804
05805 AST_DECLARE_APP_ARGS(args,
05806 AST_APP_ARG(dest_chan);
05807 AST_APP_ARG(options);
05808 );
05809
05810 if (ast_strlen_zero(data)) {
05811 ast_log(LOG_WARNING, "Bridge require at least 1 argument specifying the other end of the bridge\n");
05812 return -1;
05813 }
05814
05815 tmp_data = ast_strdupa(data);
05816 AST_STANDARD_APP_ARGS(args, tmp_data);
05817 if (!ast_strlen_zero(args.options))
05818 ast_app_parse_options(bridge_exec_options, &opts, opt_args, args.options);
05819
05820
05821 if (!strcmp(chan->name, args.dest_chan)) {
05822 ast_log(LOG_WARNING, "Unable to bridge channel %s with itself\n", chan->name);
05823 ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
05824 "Response: Failed\r\n"
05825 "Reason: Unable to bridge channel to itself\r\n"
05826 "Channel1: %s\r\n"
05827 "Channel2: %s\r\n",
05828 chan->name, args.dest_chan);
05829 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "LOOP");
05830 return 0;
05831 }
05832
05833
05834 if (!(current_dest_chan = ast_channel_get_by_name_prefix(args.dest_chan,
05835 strlen(args.dest_chan)))) {
05836 ast_log(LOG_WARNING, "Bridge failed because channel %s does not exists or we "
05837 "cannot get its lock\n", args.dest_chan);
05838 ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
05839 "Response: Failed\r\n"
05840 "Reason: Cannot grab end point\r\n"
05841 "Channel1: %s\r\n"
05842 "Channel2: %s\r\n", chan->name, args.dest_chan);
05843 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "NONEXISTENT");
05844 return 0;
05845 }
05846
05847
05848 if (current_dest_chan->_state != AST_STATE_UP) {
05849 ast_answer(current_dest_chan);
05850 }
05851
05852
05853 if (!(final_dest_chan = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
05854 NULL, NULL, current_dest_chan->linkedid, 0, "Bridge/%s", current_dest_chan->name))) {
05855 ast_log(LOG_WARNING, "Cannot create placeholder channel for chan %s\n", args.dest_chan);
05856 ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
05857 "Response: Failed\r\n"
05858 "Reason: cannot create placeholder\r\n"
05859 "Channel1: %s\r\n"
05860 "Channel2: %s\r\n", chan->name, args.dest_chan);
05861 }
05862
05863 ast_channel_unlock(current_dest_chan);
05864
05865 do_bridge_masquerade(current_dest_chan, final_dest_chan);
05866
05867 chans[0] = current_dest_chan;
05868 chans[1] = final_dest_chan;
05869
05870
05871
05872 if (ast_channel_make_compatible(chan, final_dest_chan) < 0) {
05873 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, final_dest_chan->name);
05874 ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeExec", 2, chans,
05875 "Response: Failed\r\n"
05876 "Reason: Could not make channels compatible for bridge\r\n"
05877 "Channel1: %s\r\n"
05878 "Channel2: %s\r\n", chan->name, final_dest_chan->name);
05879 ast_hangup(final_dest_chan);
05880 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "INCOMPATIBLE");
05881 current_dest_chan = ast_channel_unref(current_dest_chan);
05882 return 0;
05883 }
05884
05885
05886 ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeExec", 2, chans,
05887 "Response: Success\r\n"
05888 "Channel1: %s\r\n"
05889 "Channel2: %s\r\n", chan->name, final_dest_chan->name);
05890
05891
05892 if (ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE) && !ast_strlen_zero(xfersound)) {
05893 if (!ast_streamfile(final_dest_chan, xfersound, final_dest_chan->language)) {
05894 if (ast_waitstream(final_dest_chan, "") < 0)
05895 ast_log(LOG_WARNING, "Failed to play courtesy tone on %s\n", final_dest_chan->name);
05896 }
05897 }
05898
05899 current_dest_chan = ast_channel_unref(current_dest_chan);
05900
05901 if (ast_test_flag(&opts, OPT_DURATION_LIMIT) && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_LIMIT])) {
05902 if (ast_bridge_timelimit(chan, &bconfig, opt_args[OPT_ARG_DURATION_LIMIT], &calldurationlimit))
05903 goto done;
05904 }
05905
05906 if (ast_test_flag(&opts, OPT_CALLEE_TRANSFER))
05907 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_REDIRECT);
05908 if (ast_test_flag(&opts, OPT_CALLER_TRANSFER))
05909 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_REDIRECT);
05910 if (ast_test_flag(&opts, OPT_CALLEE_HANGUP))
05911 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
05912 if (ast_test_flag(&opts, OPT_CALLER_HANGUP))
05913 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
05914 if (ast_test_flag(&opts, OPT_CALLEE_MONITOR))
05915 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_AUTOMON);
05916 if (ast_test_flag(&opts, OPT_CALLER_MONITOR))
05917 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_AUTOMON);
05918 if (ast_test_flag(&opts, OPT_CALLEE_PARK))
05919 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_PARKCALL);
05920 if (ast_test_flag(&opts, OPT_CALLER_PARK))
05921 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_PARKCALL);
05922
05923 ast_bridge_call(chan, final_dest_chan, &bconfig);
05924
05925
05926 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "SUCCESS");
05927 if (!ast_check_hangup(final_dest_chan) && !ast_test_flag(&opts, OPT_CALLEE_KILL)) {
05928 ast_debug(1, "starting new PBX in %s,%s,%d for chan %s\n",
05929 final_dest_chan->context, final_dest_chan->exten,
05930 final_dest_chan->priority, final_dest_chan->name);
05931
05932 if (ast_pbx_start(final_dest_chan) != AST_PBX_SUCCESS) {
05933 ast_log(LOG_WARNING, "FAILED continuing PBX on dest chan %s\n", final_dest_chan->name);
05934 ast_hangup(final_dest_chan);
05935 } else
05936 ast_debug(1, "SUCCESS continuing PBX on chan %s\n", final_dest_chan->name);
05937 } else {
05938 ast_debug(1, "hangup chan %s since the other endpoint has hung up or the x flag was passed\n", final_dest_chan->name);
05939 ast_hangup(final_dest_chan);
05940 }
05941 done:
05942 if (bconfig.warning_sound) {
05943 ast_free((char *)bconfig.warning_sound);
05944 }
05945 if (bconfig.end_sound) {
05946 ast_free((char *)bconfig.end_sound);
05947 }
05948 if (bconfig.start_sound) {
05949 ast_free((char *)bconfig.start_sound);
05950 }
05951
05952 return 0;
05953 }
05954
05955 int ast_features_init(void)
05956 {
05957 int res;
05958
05959 ast_register_application2(app_bridge, bridge_exec, NULL, NULL, NULL);
05960
05961 parkinglots = ao2_container_alloc(7, parkinglot_hash_cb, parkinglot_cmp_cb);
05962
05963 if ((res = load_config()))
05964 return res;
05965 ast_cli_register_multiple(cli_features, ARRAY_LEN(cli_features));
05966 ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
05967 res = ast_register_application2(parkedcall, park_exec, NULL, NULL, NULL);
05968 if (!res)
05969 res = ast_register_application2(parkcall, park_call_exec, NULL, NULL, NULL);
05970 if (!res) {
05971 ast_manager_register_xml("ParkedCalls", 0, manager_parking_status);
05972 ast_manager_register_xml("Park", EVENT_FLAG_CALL, manager_park);
05973 ast_manager_register_xml("Bridge", EVENT_FLAG_CALL, action_bridge);
05974 }
05975
05976 res |= ast_devstate_prov_add("Park", metermaidstate);
05977 #ifdef TEST_FRAMEWORK
05978 res |= AST_TEST_REGISTER(features_test);
05979 #endif
05980
05981 return res;
05982 }