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: 324704 $")
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 ast_channel_clear_softhangup(xferchan, AST_SOFTHANGUP_ALL);
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, format_t 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 -1;
01878 }
01879 if (res == 0) {
01880 if (xferto[0]) {
01881 ast_log(LOG_WARNING, "Extension '%s' does not exist in context '%s'\n",
01882 xferto, transferer_real_context);
01883 } else {
01884
01885 ast_log(LOG_WARNING, "No digits dialed.\n");
01886 }
01887 ast_stream_and_wait(transferer, "pbx-invalid", "");
01888 finishup(transferee);
01889 return AST_FEATURE_RETURN_SUCCESS;
01890 }
01891
01892 found_lot = ao2_callback(parkinglots, 0, find_parkinglot_by_exten_cb, &xferto);
01893 if (found_lot) {
01894 struct ast_park_call_args args = {
01895 .parkinglot = found_lot,
01896 };
01897 res = finishup(transferee);
01898 if (res) {
01899 } else if (!(parkstatus = masq_park_call_announce(transferee, transferer, &args))) {
01900
01901
01902
01903
01904 return 0;
01905 } else {
01906 ast_log(LOG_WARNING, "Unable to park call %s, parkstatus = %d\n", transferee->name, parkstatus);
01907 }
01908 ast_autoservice_start(transferee);
01909 } else {
01910 ast_cel_report_event(transferer, AST_CEL_BLINDTRANSFER, NULL, xferto, transferee);
01911 pbx_builtin_setvar_helper(transferer, "BLINDTRANSFER", transferee->name);
01912 pbx_builtin_setvar_helper(transferee, "BLINDTRANSFER", transferer->name);
01913 res=finishup(transferee);
01914 if (!transferer->cdr) {
01915 transferer->cdr=ast_cdr_alloc();
01916 if (transferer->cdr) {
01917 ast_cdr_init(transferer->cdr, transferer);
01918 ast_cdr_start(transferer->cdr);
01919 }
01920 }
01921 if (transferer->cdr) {
01922 struct ast_cdr *swap = transferer->cdr;
01923 ast_log(LOG_DEBUG,"transferer=%s; transferee=%s; lastapp=%s; lastdata=%s; chan=%s; dstchan=%s\n",
01924 transferer->name, transferee->name, transferer->cdr->lastapp, transferer->cdr->lastdata,
01925 transferer->cdr->channel, transferer->cdr->dstchannel);
01926 ast_log(LOG_DEBUG,"TRANSFEREE; lastapp=%s; lastdata=%s, chan=%s; dstchan=%s\n",
01927 transferee->cdr->lastapp, transferee->cdr->lastdata, transferee->cdr->channel, transferee->cdr->dstchannel);
01928 ast_log(LOG_DEBUG,"transferer_real_context=%s; xferto=%s\n", transferer_real_context, xferto);
01929
01930 transferer->cdr = transferee->cdr;
01931 transferee->cdr = swap;
01932 }
01933 if (!transferee->pbx) {
01934
01935 ast_verb(3, "Transferring %s to '%s' (context %s) priority 1\n"
01936 ,transferee->name, xferto, transferer_real_context);
01937 if (ast_async_goto(transferee, transferer_real_context, xferto, 1))
01938 ast_log(LOG_WARNING, "Async goto failed :-(\n");
01939 } else {
01940
01941 ast_set_flag(transferee, AST_FLAG_BRIDGE_HANGUP_DONT);
01942 ast_log(LOG_DEBUG,"ABOUT TO AST_ASYNC_GOTO, have a pbx... set HANGUP_DONT on chan=%s\n", transferee->name);
01943 if (ast_channel_connected_line_macro(transferee, transferer, &transferer->connected, 1, 0)) {
01944 ast_channel_update_connected_line(transferer, &transferer->connected, NULL);
01945 }
01946 set_c_e_p(transferee, transferer_real_context, xferto, 0);
01947 }
01948 check_goto_on_transfer(transferer);
01949 return res;
01950 }
01951 if (parkstatus != AST_FEATURE_RETURN_PARKFAILED
01952 && ast_stream_and_wait(transferer, xferfailsound, "")) {
01953 finishup(transferee);
01954 return -1;
01955 }
01956 ast_stopstream(transferer);
01957 res = finishup(transferee);
01958 if (res) {
01959 ast_verb(2, "Hungup during autoservice stop on '%s'\n", transferee->name);
01960 return res;
01961 }
01962 return AST_FEATURE_RETURN_SUCCESS;
01963 }
01964
01965
01966
01967
01968
01969
01970
01971
01972 static int check_compat(struct ast_channel *c, struct ast_channel *newchan)
01973 {
01974 if (ast_channel_make_compatible(c, newchan) < 0) {
01975 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n",
01976 c->name, newchan->name);
01977 ast_hangup(newchan);
01978 return -1;
01979 }
01980 return 0;
01981 }
01982
01983
01984
01985
01986
01987
01988
01989
01990
01991
01992
01993
01994
01995
01996 static void atxfer_fail_cleanup(struct ast_channel *transferee, struct ast_channel *transferer, struct ast_party_connected_line *connected_line)
01997 {
01998 finishup(transferee);
01999
02000
02001
02002
02003
02004
02005
02006 if (ast_channel_connected_line_macro(transferee, transferer, connected_line, 1, 0)) {
02007 ast_channel_update_connected_line(transferer, connected_line, NULL);
02008 }
02009 ast_party_connected_line_free(connected_line);
02010 }
02011
02012
02013
02014
02015
02016
02017
02018
02019
02020
02021
02022
02023
02024
02025
02026
02027 static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
02028 {
02029 struct ast_channel *transferer;
02030 struct ast_channel *transferee;
02031 const char *transferer_real_context;
02032 char xferto[256] = "";
02033 int res;
02034 int outstate=0;
02035 struct ast_channel *newchan;
02036 struct ast_channel *xferchan;
02037 struct ast_bridge_thread_obj *tobj;
02038 struct ast_bridge_config bconfig;
02039 int l;
02040 struct ast_party_connected_line connected_line;
02041 struct ast_datastore *features_datastore;
02042 struct ast_dial_features *dialfeatures = NULL;
02043 struct ast_parkinglot *parkinglot;
02044 char *transferer_tech;
02045 char *transferer_name;
02046 char *transferer_name_orig;
02047 char *dash;
02048
02049 ast_debug(1, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense);
02050 set_peers(&transferer, &transferee, peer, chan, sense);
02051 transferer_real_context = real_ctx(transferer, transferee);
02052
02053
02054 ast_autoservice_start(transferee);
02055 ast_indicate(transferee, AST_CONTROL_HOLD);
02056
02057
02058 res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY);
02059 if (res < 0) {
02060 finishup(transferee);
02061 return -1;
02062 }
02063 if (res > 0)
02064 xferto[0] = (char) res;
02065
02066
02067 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
02068 if (res < 0) {
02069 finishup(transferee);
02070 return -1;
02071 }
02072 l = strlen(xferto);
02073 if (res == 0) {
02074 if (l) {
02075 ast_log(LOG_WARNING, "Extension '%s' does not exist in context '%s'\n",
02076 xferto, transferer_real_context);
02077 } else {
02078
02079 ast_log(LOG_WARNING, "No digits dialed for atxfer.\n");
02080 }
02081 ast_stream_and_wait(transferer, "pbx-invalid", "");
02082 finishup(transferee);
02083 return AST_FEATURE_RETURN_SUCCESS;
02084 }
02085
02086
02087
02088 parkinglot = ao2_callback(parkinglots, 0, find_parkinglot_by_exten_cb, &xferto);
02089 if (parkinglot) {
02090 struct ast_park_call_args args = {
02091 .parkinglot = parkinglot,
02092 };
02093 finishup(transferee);
02094 return parkcall_helper(chan, peer, config, code, sense, &args);
02095 }
02096
02097
02098 snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context);
02099
02100
02101
02102 if (transferee) {
02103 const char *chan1_attended_sound = pbx_builtin_getvar_helper(transferer, "ATTENDED_TRANSFER_COMPLETE_SOUND");
02104 const char *chan2_attended_sound = pbx_builtin_getvar_helper(transferee, "ATTENDED_TRANSFER_COMPLETE_SOUND");
02105
02106 if (!ast_strlen_zero(chan1_attended_sound)) {
02107 pbx_builtin_setvar_helper(transferer, "BRIDGE_PLAY_SOUND", chan1_attended_sound);
02108 }
02109 if (!ast_strlen_zero(chan2_attended_sound)) {
02110 pbx_builtin_setvar_helper(transferee, "BRIDGE_PLAY_SOUND", chan2_attended_sound);
02111 }
02112 }
02113
02114
02115 transferer_name_orig = ast_strdupa(transferer->name);
02116 transferer_name = ast_strdupa(transferer_name_orig);
02117 transferer_tech = strsep(&transferer_name, "/");
02118 dash = strrchr(transferer_name, '-');
02119 if (dash) {
02120
02121 *dash = '\0';
02122 }
02123
02124
02125 if (ast_autoservice_stop(transferee) < 0) {
02126 ast_indicate(transferee, AST_CONTROL_UNHOLD);
02127 return -1;
02128 }
02129
02130
02131 ast_party_connected_line_init(&connected_line);
02132 ast_channel_lock(transferer);
02133 ast_party_connected_line_copy(&connected_line, &transferer->connected);
02134 ast_channel_unlock(transferer);
02135 connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
02136
02137
02138 newchan = feature_request_and_dial(transferer, transferer_name_orig, transferer,
02139 transferee, "Local", ast_best_codec(transferer->nativeformats), xferto,
02140 atxfernoanswertimeout, &outstate, transferer->language);
02141 ast_debug(2, "Dial party C result: newchan:%d, outstate:%d\n", !!newchan, outstate);
02142
02143 if (!ast_check_hangup(transferer)) {
02144 int hangup_dont = 0;
02145
02146
02147 ast_debug(1, "Actually doing an attended transfer.\n");
02148
02149
02150 ast_autoservice_start(transferee);
02151
02152 ast_indicate(transferer, -1);
02153 if (!newchan) {
02154
02155 switch (outstate) {
02156 case AST_CONTROL_UNHOLD:
02157 case AST_CONTROL_BUSY:
02158 case AST_CONTROL_CONGESTION:
02159 if (ast_stream_and_wait(transferer, xfersound, "")) {
02160 ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
02161 }
02162 break;
02163 default:
02164 if (ast_stream_and_wait(transferer, xferfailsound, "")) {
02165 ast_log(LOG_WARNING, "Failed to play transfer failed sound!\n");
02166 }
02167 break;
02168 }
02169 atxfer_fail_cleanup(transferee, transferer, &connected_line);
02170 return AST_FEATURE_RETURN_SUCCESS;
02171 }
02172
02173 if (check_compat(transferer, newchan)) {
02174 if (ast_stream_and_wait(transferer, xferfailsound, "")) {
02175 ast_log(LOG_WARNING, "Failed to play transfer failed sound!\n");
02176 }
02177 atxfer_fail_cleanup(transferee, transferer, &connected_line);
02178 return AST_FEATURE_RETURN_SUCCESS;
02179 }
02180 memset(&bconfig,0,sizeof(struct ast_bridge_config));
02181 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
02182 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
02183
02184
02185
02186
02187 if (ast_test_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT)) {
02188 hangup_dont = 1;
02189 }
02190
02191 ast_bridge_call(transferer, newchan, &bconfig);
02192 if (hangup_dont) {
02193 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT);
02194 }
02195
02196 if (ast_check_hangup(newchan) || !ast_check_hangup(transferer)) {
02197 ast_hangup(newchan);
02198 if (ast_stream_and_wait(transferer, xfersound, "")) {
02199 ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
02200 }
02201 atxfer_fail_cleanup(transferee, transferer, &connected_line);
02202 return AST_FEATURE_RETURN_SUCCESS;
02203 }
02204
02205
02206 if (check_compat(transferee, newchan)) {
02207 finishup(transferee);
02208 ast_party_connected_line_free(&connected_line);
02209 return -1;
02210 }
02211
02212 ast_indicate(transferee, AST_CONTROL_UNHOLD);
02213 if ((ast_autoservice_stop(transferee) < 0)
02214 || (ast_waitfordigit(transferee, 100) < 0)
02215 || (ast_waitfordigit(newchan, 100) < 0)
02216 || ast_check_hangup(transferee)
02217 || ast_check_hangup(newchan)) {
02218 ast_hangup(newchan);
02219 ast_party_connected_line_free(&connected_line);
02220 return -1;
02221 }
02222 } else if (!ast_check_hangup(transferee)) {
02223
02224 ast_debug(1, "Actually doing a blonde transfer.\n");
02225
02226 if (!newchan && !atxferdropcall) {
02227
02228 unsigned int tries = 0;
02229
02230 if (ast_strlen_zero(transferer_name) || ast_strlen_zero(transferer_tech)) {
02231 ast_log(LOG_WARNING,
02232 "Transferer channel name: '%s' cannot be used for callback.\n",
02233 transferer_name_orig);
02234 ast_indicate(transferee, AST_CONTROL_UNHOLD);
02235 ast_party_connected_line_free(&connected_line);
02236 return -1;
02237 }
02238
02239 tries = 0;
02240 for (;;) {
02241
02242 ast_debug(1, "We're trying to callback %s/%s\n",
02243 transferer_tech, transferer_name);
02244 newchan = feature_request_and_dial(transferer, transferer_name_orig,
02245 transferee, transferee, transferer_tech,
02246 ast_best_codec(transferee->nativeformats), transferer_name,
02247 atxfernoanswertimeout, &outstate, transferer->language);
02248 ast_debug(2, "Dial party B result: newchan:%d, outstate:%d\n",
02249 !!newchan, outstate);
02250 if (newchan || ast_check_hangup(transferee)) {
02251 break;
02252 }
02253
02254 ++tries;
02255 if (atxfercallbackretries <= tries) {
02256
02257 break;
02258 }
02259
02260 if (atxferloopdelay) {
02261
02262 ast_debug(1, "Sleeping for %d ms before retrying atxfer.\n",
02263 atxferloopdelay);
02264 ast_safe_sleep(transferee, atxferloopdelay);
02265 if (ast_check_hangup(transferee)) {
02266 ast_party_connected_line_free(&connected_line);
02267 return -1;
02268 }
02269 }
02270
02271
02272 ast_debug(1, "We're retrying to call %s/%s\n", "Local", xferto);
02273 newchan = feature_request_and_dial(transferer, transferer_name_orig,
02274 transferer, transferee, "Local",
02275 ast_best_codec(transferee->nativeformats), xferto,
02276 atxfernoanswertimeout, &outstate, transferer->language);
02277 ast_debug(2, "Redial party C result: newchan:%d, outstate:%d\n",
02278 !!newchan, outstate);
02279 if (newchan || ast_check_hangup(transferee)) {
02280 break;
02281 }
02282 }
02283 }
02284 ast_indicate(transferee, AST_CONTROL_UNHOLD);
02285 if (!newchan) {
02286
02287 ast_party_connected_line_free(&connected_line);
02288 return -1;
02289 }
02290
02291
02292 if (ast_check_hangup(newchan)) {
02293 ast_hangup(newchan);
02294 ast_party_connected_line_free(&connected_line);
02295 return -1;
02296 }
02297 if (check_compat(transferee, newchan)) {
02298 ast_party_connected_line_free(&connected_line);
02299 return -1;
02300 }
02301 } else {
02302
02303
02304
02305
02306 ast_debug(1, "Everyone is hungup.\n");
02307 if (newchan) {
02308 ast_hangup(newchan);
02309 }
02310 ast_party_connected_line_free(&connected_line);
02311 return -1;
02312 }
02313
02314
02315 ast_cel_report_event(transferee, AST_CEL_ATTENDEDTRANSFER, NULL, NULL, newchan);
02316
02317 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", transferee->linkedid, 0, "Transfered/%s", transferee->name);
02318 if (!xferchan) {
02319 ast_hangup(newchan);
02320 ast_party_connected_line_free(&connected_line);
02321 return -1;
02322 }
02323
02324
02325 xferchan->visible_indication = AST_CONTROL_RINGING;
02326
02327
02328 xferchan->readformat = transferee->readformat;
02329 xferchan->writeformat = transferee->writeformat;
02330
02331 ast_channel_masquerade(xferchan, transferee);
02332 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
02333 xferchan->_state = AST_STATE_UP;
02334 ast_clear_flag(xferchan, AST_FLAGS_ALL);
02335
02336
02337 ast_do_masquerade(xferchan);
02338
02339 newchan->_state = AST_STATE_UP;
02340 ast_clear_flag(newchan, AST_FLAGS_ALL);
02341 tobj = ast_calloc(1, sizeof(*tobj));
02342 if (!tobj) {
02343 ast_hangup(xferchan);
02344 ast_hangup(newchan);
02345 ast_party_connected_line_free(&connected_line);
02346 return -1;
02347 }
02348
02349 ast_channel_lock(newchan);
02350 if ((features_datastore = ast_channel_datastore_find(newchan, &dial_features_info, NULL))) {
02351 dialfeatures = features_datastore->data;
02352 }
02353 ast_channel_unlock(newchan);
02354
02355 if (dialfeatures) {
02356
02357
02358 ast_copy_flags(&(config->features_callee), &(dialfeatures->features_caller), AST_FLAGS_ALL);
02359 dialfeatures = NULL;
02360 }
02361
02362 ast_channel_lock(xferchan);
02363 if ((features_datastore = ast_channel_datastore_find(xferchan, &dial_features_info, NULL))) {
02364 dialfeatures = features_datastore->data;
02365 }
02366 ast_channel_unlock(xferchan);
02367
02368 if (dialfeatures) {
02369 ast_copy_flags(&(config->features_caller), &(dialfeatures->features_caller), AST_FLAGS_ALL);
02370 }
02371
02372 tobj->chan = newchan;
02373 tobj->peer = xferchan;
02374 tobj->bconfig = *config;
02375
02376 if (tobj->bconfig.end_bridge_callback_data_fixup) {
02377 tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan);
02378 }
02379
02380
02381
02382
02383
02384
02385
02386
02387
02388
02389
02390
02391
02392
02393
02394
02395
02396
02397
02398
02399
02400
02401
02402
02403
02404
02405
02406
02407
02408
02409
02410 ast_channel_lock(transferer);
02411
02412
02413
02414
02415 ast_party_connected_line_copy(&connected_line, &transferer->connected);
02416 ast_channel_unlock(transferer);
02417 connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
02418 if (ast_channel_connected_line_macro(newchan, xferchan, &connected_line, 1, 0)) {
02419 ast_channel_update_connected_line(xferchan, &connected_line, NULL);
02420 }
02421
02422
02423 ast_channel_lock(xferchan);
02424 ast_connected_line_copy_from_caller(&connected_line, &xferchan->caller);
02425 ast_channel_unlock(xferchan);
02426 connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
02427 if (ast_channel_connected_line_macro(xferchan, newchan, &connected_line, 0, 0)) {
02428 ast_channel_update_connected_line(newchan, &connected_line, NULL);
02429 }
02430
02431 if (ast_stream_and_wait(newchan, xfersound, ""))
02432 ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
02433 bridge_call_thread_launch(tobj);
02434
02435 ast_party_connected_line_free(&connected_line);
02436 return -1;
02437 }
02438
02439
02440 #define FEATURES_COUNT ARRAY_LEN(builtin_features)
02441
02442 AST_RWLOCK_DEFINE_STATIC(features_lock);
02443
02444 static struct ast_call_feature builtin_features[] = {
02445 { AST_FEATURE_REDIRECT, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
02446 { AST_FEATURE_REDIRECT, "Attended Transfer", "atxfer", "", "", builtin_atxfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
02447 { AST_FEATURE_AUTOMON, "One Touch Monitor", "automon", "", "", builtin_automonitor, AST_FEATURE_FLAG_NEEDSDTMF, "" },
02448 { AST_FEATURE_DISCONNECT, "Disconnect Call", "disconnect", "*", "*", builtin_disconnect, AST_FEATURE_FLAG_NEEDSDTMF, "" },
02449 { AST_FEATURE_PARKCALL, "Park Call", "parkcall", "", "", builtin_parkcall, AST_FEATURE_FLAG_NEEDSDTMF, "" },
02450 { AST_FEATURE_AUTOMIXMON, "One Touch MixMonitor", "automixmon", "", "", builtin_automixmonitor, AST_FEATURE_FLAG_NEEDSDTMF, "" },
02451 };
02452
02453
02454 static AST_RWLIST_HEAD_STATIC(feature_list, ast_call_feature);
02455
02456
02457 void ast_register_feature(struct ast_call_feature *feature)
02458 {
02459 if (!feature) {
02460 ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
02461 return;
02462 }
02463
02464 AST_RWLIST_WRLOCK(&feature_list);
02465 AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry);
02466 AST_RWLIST_UNLOCK(&feature_list);
02467
02468 ast_verb(2, "Registered Feature '%s'\n",feature->sname);
02469 }
02470
02471
02472
02473
02474
02475
02476
02477
02478 static struct feature_group *register_group(const char *fgname)
02479 {
02480 struct feature_group *fg;
02481
02482 if (!fgname) {
02483 ast_log(LOG_NOTICE, "You didn't pass a new group name!\n");
02484 return NULL;
02485 }
02486
02487 if (!(fg = ast_calloc_with_stringfields(1, struct feature_group, 128))) {
02488 return NULL;
02489 }
02490
02491 ast_string_field_set(fg, gname, fgname);
02492
02493 AST_LIST_INSERT_HEAD(&feature_groups, fg, entry);
02494
02495 ast_verb(2, "Registered group '%s'\n", fg->gname);
02496
02497 return fg;
02498 }
02499
02500
02501
02502
02503
02504
02505
02506
02507
02508
02509 static void register_group_feature(struct feature_group *fg, const char *exten, struct ast_call_feature *feature)
02510 {
02511 struct feature_group_exten *fge;
02512
02513 if (!fg) {
02514 ast_log(LOG_NOTICE, "You didn't pass a group!\n");
02515 return;
02516 }
02517
02518 if (!feature) {
02519 ast_log(LOG_NOTICE, "You didn't pass a feature!\n");
02520 return;
02521 }
02522
02523 if (!(fge = ast_calloc_with_stringfields(1, struct feature_group_exten, 128))) {
02524 return;
02525 }
02526
02527 ast_string_field_set(fge, exten, S_OR(exten, feature->exten));
02528
02529 fge->feature = feature;
02530
02531 AST_LIST_INSERT_HEAD(&fg->features, fge, entry);
02532
02533 ast_verb(2, "Registered feature '%s' for group '%s' at exten '%s'\n",
02534 feature->sname, fg->gname, fge->exten);
02535 }
02536
02537 void ast_unregister_feature(struct ast_call_feature *feature)
02538 {
02539 if (!feature) {
02540 return;
02541 }
02542
02543 AST_RWLIST_WRLOCK(&feature_list);
02544 AST_RWLIST_REMOVE(&feature_list, feature, feature_entry);
02545 AST_RWLIST_UNLOCK(&feature_list);
02546
02547 ast_free(feature);
02548 }
02549
02550
02551 static void ast_unregister_features(void)
02552 {
02553 struct ast_call_feature *feature;
02554
02555 AST_RWLIST_WRLOCK(&feature_list);
02556 while ((feature = AST_RWLIST_REMOVE_HEAD(&feature_list, feature_entry))) {
02557 ast_free(feature);
02558 }
02559 AST_RWLIST_UNLOCK(&feature_list);
02560 }
02561
02562
02563 static struct ast_call_feature *find_dynamic_feature(const char *name)
02564 {
02565 struct ast_call_feature *tmp;
02566
02567 AST_RWLIST_TRAVERSE(&feature_list, tmp, feature_entry) {
02568 if (!strcasecmp(tmp->sname, name)) {
02569 break;
02570 }
02571 }
02572
02573 return tmp;
02574 }
02575
02576
02577 static void ast_unregister_groups(void)
02578 {
02579 struct feature_group *fg;
02580 struct feature_group_exten *fge;
02581
02582 AST_RWLIST_WRLOCK(&feature_groups);
02583 while ((fg = AST_LIST_REMOVE_HEAD(&feature_groups, entry))) {
02584 while ((fge = AST_LIST_REMOVE_HEAD(&fg->features, entry))) {
02585 ast_string_field_free_memory(fge);
02586 ast_free(fge);
02587 }
02588
02589 ast_string_field_free_memory(fg);
02590 ast_free(fg);
02591 }
02592 AST_RWLIST_UNLOCK(&feature_groups);
02593 }
02594
02595
02596
02597
02598
02599
02600
02601 static struct feature_group *find_group(const char *name)
02602 {
02603 struct feature_group *fg = NULL;
02604
02605 AST_LIST_TRAVERSE(&feature_groups, fg, entry) {
02606 if (!strcasecmp(fg->gname, name))
02607 break;
02608 }
02609
02610 return fg;
02611 }
02612
02613 void ast_rdlock_call_features(void)
02614 {
02615 ast_rwlock_rdlock(&features_lock);
02616 }
02617
02618 void ast_unlock_call_features(void)
02619 {
02620 ast_rwlock_unlock(&features_lock);
02621 }
02622
02623 struct ast_call_feature *ast_find_call_feature(const char *name)
02624 {
02625 int x;
02626 for (x = 0; x < FEATURES_COUNT; x++) {
02627 if (!strcasecmp(name, builtin_features[x].sname))
02628 return &builtin_features[x];
02629 }
02630 return NULL;
02631 }
02632
02633
02634
02635
02636
02637
02638
02639
02640
02641
02642 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)
02643 {
02644 struct ast_app *app;
02645 struct ast_call_feature *feature = data;
02646 struct ast_channel *work, *idle;
02647 int res;
02648
02649 if (!feature) {
02650 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
02651 return -1;
02652 }
02653
02654 if (sense == FEATURE_SENSE_CHAN) {
02655 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
02656 return AST_FEATURE_RETURN_KEEPTRYING;
02657 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
02658 work = chan;
02659 idle = peer;
02660 } else {
02661 work = peer;
02662 idle = chan;
02663 }
02664 } else {
02665 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
02666 return AST_FEATURE_RETURN_KEEPTRYING;
02667 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
02668 work = peer;
02669 idle = chan;
02670 } else {
02671 work = chan;
02672 idle = peer;
02673 }
02674 }
02675
02676 if (!(app = pbx_findapp(feature->app))) {
02677 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
02678 return -2;
02679 }
02680
02681 ast_autoservice_start(idle);
02682 ast_autoservice_ignore(idle, AST_FRAME_DTMF_END);
02683
02684 if(work && idle) {
02685 pbx_builtin_setvar_helper(work, "DYNAMIC_PEERNAME", idle->name);
02686 pbx_builtin_setvar_helper(idle, "DYNAMIC_PEERNAME", work->name);
02687 pbx_builtin_setvar_helper(work, "DYNAMIC_FEATURENAME", feature->sname);
02688 pbx_builtin_setvar_helper(idle, "DYNAMIC_FEATURENAME", feature->sname);
02689 }
02690
02691 if (!ast_strlen_zero(feature->moh_class))
02692 ast_moh_start(idle, feature->moh_class, NULL);
02693
02694 res = pbx_exec(work, app, feature->app_args);
02695
02696 if (!ast_strlen_zero(feature->moh_class))
02697 ast_moh_stop(idle);
02698
02699 ast_autoservice_stop(idle);
02700
02701 if (res) {
02702 return AST_FEATURE_RETURN_SUCCESSBREAK;
02703 }
02704 return AST_FEATURE_RETURN_SUCCESS;
02705 }
02706
02707 static void unmap_features(void)
02708 {
02709 int x;
02710
02711 ast_rwlock_wrlock(&features_lock);
02712 for (x = 0; x < FEATURES_COUNT; x++)
02713 strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
02714 ast_rwlock_unlock(&features_lock);
02715 }
02716
02717 static int remap_feature(const char *name, const char *value)
02718 {
02719 int x, res = -1;
02720
02721 ast_rwlock_wrlock(&features_lock);
02722 for (x = 0; x < FEATURES_COUNT; x++) {
02723 if (strcasecmp(builtin_features[x].sname, name))
02724 continue;
02725
02726 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
02727 res = 0;
02728 break;
02729 }
02730 ast_rwlock_unlock(&features_lock);
02731
02732 return res;
02733 }
02734
02735
02736
02737
02738
02739
02740
02741
02742
02743
02744
02745 static int feature_interpret_helper(struct ast_channel *chan, struct ast_channel *peer,
02746 struct ast_bridge_config *config, const char *code, int sense, char *dynamic_features_buf,
02747 struct ast_flags *features, int operation, struct ast_call_feature *feature)
02748 {
02749 int x;
02750 struct feature_group *fg = NULL;
02751 struct feature_group_exten *fge;
02752 struct ast_call_feature *tmpfeature;
02753 char *tmp, *tok;
02754 int res = AST_FEATURE_RETURN_PASSDIGITS;
02755 int feature_detected = 0;
02756
02757 if (!(peer && chan && config) && operation) {
02758 return -1;
02759 }
02760
02761 ast_rwlock_rdlock(&features_lock);
02762 for (x = 0; x < FEATURES_COUNT; x++) {
02763 if ((ast_test_flag(features, builtin_features[x].feature_mask)) &&
02764 !ast_strlen_zero(builtin_features[x].exten)) {
02765
02766 if (!strcmp(builtin_features[x].exten, code)) {
02767 ast_debug(3, "Feature detected: fname=%s sname=%s exten=%s\n", builtin_features[x].fname, builtin_features[x].sname, builtin_features[x].exten);
02768 if (operation) {
02769 res = builtin_features[x].operation(chan, peer, config, code, sense, NULL);
02770 }
02771 memcpy(feature, &builtin_features[x], sizeof(feature));
02772 feature_detected = 1;
02773 break;
02774 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
02775 if (res == AST_FEATURE_RETURN_PASSDIGITS)
02776 res = AST_FEATURE_RETURN_STOREDIGITS;
02777 }
02778 }
02779 }
02780 ast_rwlock_unlock(&features_lock);
02781
02782 if (ast_strlen_zero(dynamic_features_buf) || feature_detected) {
02783 return res;
02784 }
02785
02786 tmp = dynamic_features_buf;
02787
02788 while ((tok = strsep(&tmp, "#"))) {
02789 AST_RWLIST_RDLOCK(&feature_groups);
02790
02791 fg = find_group(tok);
02792
02793 if (fg) {
02794 AST_LIST_TRAVERSE(&fg->features, fge, entry) {
02795 if (!strcmp(fge->exten, code)) {
02796 if (operation) {
02797 res = fge->feature->operation(chan, peer, config, code, sense, fge->feature);
02798 }
02799 memcpy(feature, fge->feature, sizeof(feature));
02800 if (res != AST_FEATURE_RETURN_KEEPTRYING) {
02801 AST_RWLIST_UNLOCK(&feature_groups);
02802 break;
02803 }
02804 res = AST_FEATURE_RETURN_PASSDIGITS;
02805 } else if (!strncmp(fge->exten, code, strlen(code))) {
02806 res = AST_FEATURE_RETURN_STOREDIGITS;
02807 }
02808 }
02809 if (fge) {
02810 break;
02811 }
02812 }
02813
02814 AST_RWLIST_UNLOCK(&feature_groups);
02815
02816 AST_RWLIST_RDLOCK(&feature_list);
02817
02818 if (!(tmpfeature = find_dynamic_feature(tok))) {
02819 AST_RWLIST_UNLOCK(&feature_list);
02820 continue;
02821 }
02822
02823
02824 if (!strcmp(tmpfeature->exten, code)) {
02825 ast_verb(3, " Feature Found: %s exten: %s\n",tmpfeature->sname, tok);
02826 if (operation) {
02827 res = tmpfeature->operation(chan, peer, config, code, sense, tmpfeature);
02828 }
02829 memcpy(feature, tmpfeature, sizeof(feature));
02830 if (res != AST_FEATURE_RETURN_KEEPTRYING) {
02831 AST_RWLIST_UNLOCK(&feature_list);
02832 break;
02833 }
02834 res = AST_FEATURE_RETURN_PASSDIGITS;
02835 } else if (!strncmp(tmpfeature->exten, code, strlen(code)))
02836 res = AST_FEATURE_RETURN_STOREDIGITS;
02837
02838 AST_RWLIST_UNLOCK(&feature_list);
02839 }
02840
02841 return res;
02842 }
02843
02844
02845
02846
02847
02848
02849
02850
02851
02852 static int feature_interpret(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense) {
02853
02854 char dynamic_features_buf[128];
02855 const char *peer_dynamic_features, *chan_dynamic_features;
02856 struct ast_flags features;
02857 struct ast_call_feature feature;
02858 if (sense == FEATURE_SENSE_CHAN) {
02859 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
02860 }
02861 else {
02862 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);
02863 }
02864
02865 ast_channel_lock(peer);
02866 peer_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES"),""));
02867 ast_channel_unlock(peer);
02868
02869 ast_channel_lock(chan);
02870 chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),""));
02871 ast_channel_unlock(chan);
02872
02873 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,""));
02874
02875 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);
02876
02877 return feature_interpret_helper(chan, peer, config, code, sense, dynamic_features_buf, &features, 1, &feature);
02878 }
02879
02880
02881 int ast_feature_detect(struct ast_channel *chan, struct ast_flags *features, const char *code, struct ast_call_feature *feature) {
02882
02883 return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, 0, feature);
02884 }
02885
02886 static void set_config_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
02887 {
02888 int x;
02889
02890 ast_clear_flag(config, AST_FLAGS_ALL);
02891
02892 ast_rwlock_rdlock(&features_lock);
02893 for (x = 0; x < FEATURES_COUNT; x++) {
02894 if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF))
02895 continue;
02896
02897 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
02898 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
02899
02900 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
02901 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
02902 }
02903 ast_rwlock_unlock(&features_lock);
02904
02905 if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
02906 const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
02907
02908 if (dynamic_features) {
02909 char *tmp = ast_strdupa(dynamic_features);
02910 char *tok;
02911 struct ast_call_feature *feature;
02912
02913
02914 while ((tok = strsep(&tmp, "#"))) {
02915 struct feature_group *fg;
02916
02917 AST_RWLIST_RDLOCK(&feature_groups);
02918 AST_RWLIST_TRAVERSE(&feature_groups, fg, entry) {
02919 struct feature_group_exten *fge;
02920
02921 AST_LIST_TRAVERSE(&fg->features, fge, entry) {
02922 if (ast_test_flag(fge->feature, AST_FEATURE_FLAG_BYCALLER)) {
02923 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
02924 }
02925 if (ast_test_flag(fge->feature, AST_FEATURE_FLAG_BYCALLEE)) {
02926 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
02927 }
02928 }
02929 }
02930 AST_RWLIST_UNLOCK(&feature_groups);
02931
02932 AST_RWLIST_RDLOCK(&feature_list);
02933 if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
02934 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) {
02935 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
02936 }
02937 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) {
02938 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
02939 }
02940 }
02941 AST_RWLIST_UNLOCK(&feature_list);
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
02973
02974
02975
02976
02977
02978
02979
02980
02981 static struct ast_channel *feature_request_and_dial(struct ast_channel *caller,
02982 const char *caller_name, struct ast_channel *requestor,
02983 struct ast_channel *transferee, const char *type, format_t format, void *data,
02984 int timeout, int *outstate, const char *language)
02985 {
02986 int state = 0;
02987 int cause = 0;
02988 int to;
02989 int caller_hungup;
02990 int transferee_hungup;
02991 struct ast_channel *chan;
02992 struct ast_channel *monitor_chans[3];
02993 struct ast_channel *active_channel;
02994 int res;
02995 int ready = 0;
02996 struct timeval started;
02997 int x, len = 0;
02998 char *disconnect_code = NULL, *dialed_code = NULL;
02999 struct ast_frame *f;
03000 AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames;
03001
03002 caller_hungup = ast_check_hangup(caller);
03003
03004 if (!(chan = ast_request(type, format, requestor, data, &cause))) {
03005 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
03006 switch (cause) {
03007 case AST_CAUSE_BUSY:
03008 state = AST_CONTROL_BUSY;
03009 break;
03010 case AST_CAUSE_CONGESTION:
03011 state = AST_CONTROL_CONGESTION;
03012 break;
03013 default:
03014 state = 0;
03015 break;
03016 }
03017 goto done;
03018 }
03019
03020 ast_string_field_set(chan, language, language);
03021 ast_channel_inherit_variables(caller, chan);
03022 pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller_name);
03023
03024 ast_channel_lock(chan);
03025 ast_connected_line_copy_from_caller(&chan->connected, &requestor->caller);
03026 ast_channel_unlock(chan);
03027
03028 if (ast_call(chan, data, timeout)) {
03029 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
03030 switch (chan->hangupcause) {
03031 case AST_CAUSE_BUSY:
03032 state = AST_CONTROL_BUSY;
03033 break;
03034 case AST_CAUSE_CONGESTION:
03035 state = AST_CONTROL_CONGESTION;
03036 break;
03037 default:
03038 state = 0;
03039 break;
03040 }
03041 goto done;
03042 }
03043
03044
03045 ast_rwlock_rdlock(&features_lock);
03046 for (x = 0; x < FEATURES_COUNT; x++) {
03047 if (strcasecmp(builtin_features[x].sname, "disconnect"))
03048 continue;
03049
03050 disconnect_code = builtin_features[x].exten;
03051 len = strlen(disconnect_code) + 1;
03052 dialed_code = alloca(len);
03053 memset(dialed_code, 0, len);
03054 break;
03055 }
03056 ast_rwlock_unlock(&features_lock);
03057 x = 0;
03058 started = ast_tvnow();
03059 to = timeout;
03060 AST_LIST_HEAD_INIT_NOLOCK(&deferred_frames);
03061
03062 ast_poll_channel_add(caller, chan);
03063
03064 transferee_hungup = 0;
03065 while (!ast_check_hangup(transferee) && (chan->_state != AST_STATE_UP)) {
03066 int num_chans = 0;
03067
03068 monitor_chans[num_chans++] = transferee;
03069 monitor_chans[num_chans++] = chan;
03070 if (!caller_hungup) {
03071 if (ast_check_hangup(caller)) {
03072 caller_hungup = 1;
03073
03074 #if defined(ATXFER_NULL_TECH)
03075
03076 set_new_chan_name(caller);
03077
03078
03079
03080
03081
03082 set_null_chan_tech(caller);
03083 #endif
03084 } else {
03085
03086 monitor_chans[num_chans++] = caller;
03087 }
03088 }
03089
03090
03091 if (ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
03092 state = AST_CONTROL_UNHOLD;
03093 ast_log(LOG_NOTICE, "We exceeded our AT-timeout for %s\n", chan->name);
03094 break;
03095 }
03096
03097 active_channel = ast_waitfor_n(monitor_chans, num_chans, &to);
03098 if (!active_channel)
03099 continue;
03100
03101 f = NULL;
03102 if (transferee == active_channel) {
03103 struct ast_frame *dup_f;
03104
03105 f = ast_read(transferee);
03106 if (f == NULL) {
03107 transferee_hungup = 1;
03108 state = 0;
03109 break;
03110 }
03111 if (ast_is_deferrable_frame(f)) {
03112 dup_f = ast_frisolate(f);
03113 if (dup_f) {
03114 if (dup_f == f) {
03115 f = NULL;
03116 }
03117 AST_LIST_INSERT_HEAD(&deferred_frames, dup_f, frame_list);
03118 }
03119 }
03120 } else if (chan == active_channel) {
03121 if (!ast_strlen_zero(chan->call_forward)) {
03122 state = 0;
03123 chan = ast_call_forward(caller, chan, NULL, format, NULL, &state);
03124 if (!chan) {
03125 break;
03126 }
03127 continue;
03128 }
03129 f = ast_read(chan);
03130 if (f == NULL) {
03131 switch (chan->hangupcause) {
03132 case AST_CAUSE_BUSY:
03133 state = AST_CONTROL_BUSY;
03134 break;
03135 case AST_CAUSE_CONGESTION:
03136 state = AST_CONTROL_CONGESTION;
03137 break;
03138 default:
03139 state = 0;
03140 break;
03141 }
03142 break;
03143 }
03144
03145 if (f->frametype == AST_FRAME_CONTROL) {
03146 if (f->subclass.integer == AST_CONTROL_RINGING) {
03147 ast_verb(3, "%s is ringing\n", chan->name);
03148 ast_indicate(caller, AST_CONTROL_RINGING);
03149 } else if (f->subclass.integer == AST_CONTROL_BUSY) {
03150 state = f->subclass.integer;
03151 ast_verb(3, "%s is busy\n", chan->name);
03152 ast_indicate(caller, AST_CONTROL_BUSY);
03153 ast_frfree(f);
03154 break;
03155 } else if (f->subclass.integer == AST_CONTROL_CONGESTION) {
03156 state = f->subclass.integer;
03157 ast_verb(3, "%s is congested\n", chan->name);
03158 ast_indicate(caller, AST_CONTROL_CONGESTION);
03159 ast_frfree(f);
03160 break;
03161 } else if (f->subclass.integer == AST_CONTROL_ANSWER) {
03162
03163 state = f->subclass.integer;
03164 ast_frfree(f);
03165 ready=1;
03166 break;
03167 } else if (f->subclass.integer == AST_CONTROL_CONNECTED_LINE) {
03168 if (caller_hungup) {
03169 struct ast_party_connected_line connected;
03170
03171
03172 ast_party_connected_line_set_init(&connected, &caller->connected);
03173 res = ast_connected_line_parse_data(f->data.ptr, f->datalen,
03174 &connected);
03175 if (!res) {
03176 ast_channel_set_connected_line(caller, &connected, NULL);
03177 }
03178 ast_party_connected_line_free(&connected);
03179 } else {
03180 ast_autoservice_start(transferee);
03181 if (ast_channel_connected_line_macro(chan, caller, f, 1, 1)) {
03182 ast_indicate_data(caller, AST_CONTROL_CONNECTED_LINE,
03183 f->data.ptr, f->datalen);
03184 }
03185 ast_autoservice_stop(transferee);
03186 }
03187 } else if (f->subclass.integer == AST_CONTROL_REDIRECTING) {
03188 if (!caller_hungup) {
03189 ast_autoservice_start(transferee);
03190 if (ast_channel_redirecting_macro(chan, caller, f, 1, 1)) {
03191 ast_indicate_data(caller, AST_CONTROL_REDIRECTING,
03192 f->data.ptr, f->datalen);
03193 }
03194 ast_autoservice_stop(transferee);
03195 }
03196 } else if (f->subclass.integer != -1 && f->subclass.integer != AST_CONTROL_PROGRESS) {
03197 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass.integer);
03198 }
03199
03200 } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) {
03201 ast_write(caller, f);
03202 }
03203 } else if (caller == active_channel) {
03204 f = ast_read(caller);
03205 if (f) {
03206 if (f->frametype == AST_FRAME_DTMF) {
03207 dialed_code[x++] = f->subclass.integer;
03208 dialed_code[x] = '\0';
03209 if (strlen(dialed_code) == len) {
03210 x = 0;
03211 } else if (x && strncmp(dialed_code, disconnect_code, x)) {
03212 x = 0;
03213 dialed_code[x] = '\0';
03214 }
03215 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
03216
03217 state = AST_CONTROL_UNHOLD;
03218 ast_frfree(f);
03219 break;
03220 }
03221 } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) {
03222 ast_write(chan, f);
03223 }
03224 }
03225 }
03226 if (f)
03227 ast_frfree(f);
03228 }
03229
03230 ast_poll_channel_del(caller, chan);
03231
03232
03233
03234
03235
03236 ast_channel_lock(transferee);
03237 transferee_hungup = (transferee_hungup || ast_check_hangup(transferee));
03238 while ((f = AST_LIST_REMOVE_HEAD(&deferred_frames, frame_list))) {
03239 if (!transferee_hungup) {
03240 ast_queue_frame_head(transferee, f);
03241 }
03242 ast_frfree(f);
03243 }
03244 ast_channel_unlock(transferee);
03245
03246 done:
03247 ast_indicate(caller, -1);
03248 if (chan && (ready || chan->_state == AST_STATE_UP)) {
03249 state = AST_CONTROL_ANSWER;
03250 } else if (chan) {
03251 ast_hangup(chan);
03252 chan = NULL;
03253 }
03254
03255 if (outstate)
03256 *outstate = state;
03257
03258 return chan;
03259 }
03260
03261 void ast_channel_log(char *title, struct ast_channel *chan);
03262
03263 void ast_channel_log(char *title, struct ast_channel *chan)
03264 {
03265 ast_log(LOG_NOTICE, "______ %s (%lx)______\n", title, (unsigned long)chan);
03266 ast_log(LOG_NOTICE, "CHAN: name: %s; appl: %s; data: %s; contxt: %s; exten: %s; pri: %d;\n",
03267 chan->name, chan->appl, chan->data, chan->context, chan->exten, chan->priority);
03268 ast_log(LOG_NOTICE, "CHAN: acctcode: %s; dialcontext: %s; amaflags: %x; maccontxt: %s; macexten: %s; macpri: %d;\n",
03269 chan->accountcode, chan->dialcontext, chan->amaflags, chan->macrocontext, chan->macroexten, chan->macropriority);
03270 ast_log(LOG_NOTICE, "CHAN: masq: %p; masqr: %p; _bridge: %p; uniqueID: %s; linkedID:%s\n",
03271 chan->masq, chan->masqr,
03272 chan->_bridge, chan->uniqueid, chan->linkedid);
03273 if (chan->masqr)
03274 ast_log(LOG_NOTICE, "CHAN: masquerading as: %s; cdr: %p;\n",
03275 chan->masqr->name, chan->masqr->cdr);
03276 if (chan->_bridge)
03277 ast_log(LOG_NOTICE, "CHAN: Bridged to %s\n", chan->_bridge->name);
03278
03279 ast_log(LOG_NOTICE, "===== done ====\n");
03280 }
03281
03282
03283
03284
03285 static struct ast_cdr *pick_unlocked_cdr(struct ast_cdr *cdr)
03286 {
03287 struct ast_cdr *cdr_orig = cdr;
03288 while (cdr) {
03289 if (!ast_test_flag(cdr,AST_CDR_FLAG_LOCKED))
03290 return cdr;
03291 cdr = cdr->next;
03292 }
03293 return cdr_orig;
03294 }
03295
03296 static void set_bridge_features_on_config(struct ast_bridge_config *config, const char *features)
03297 {
03298 const char *feature;
03299
03300 if (ast_strlen_zero(features)) {
03301 return;
03302 }
03303
03304 for (feature = features; *feature; feature++) {
03305 switch (*feature) {
03306 case 'T' :
03307 case 't' :
03308 ast_set_flag(&(config->features_caller), AST_FEATURE_REDIRECT);
03309 break;
03310 case 'K' :
03311 case 'k' :
03312 ast_set_flag(&(config->features_caller), AST_FEATURE_PARKCALL);
03313 break;
03314 case 'H' :
03315 case 'h' :
03316 ast_set_flag(&(config->features_caller), AST_FEATURE_DISCONNECT);
03317 break;
03318 case 'W' :
03319 case 'w' :
03320 ast_set_flag(&(config->features_caller), AST_FEATURE_AUTOMON);
03321 break;
03322 default :
03323 ast_log(LOG_WARNING, "Skipping unknown feature code '%c'\n", *feature);
03324 }
03325 }
03326 }
03327
03328 static void add_features_datastores(struct ast_channel *caller, struct ast_channel *callee, struct ast_bridge_config *config)
03329 {
03330 struct ast_datastore *ds_callee_features = NULL, *ds_caller_features = NULL;
03331 struct ast_dial_features *callee_features = NULL, *caller_features = NULL;
03332
03333 ast_channel_lock(caller);
03334 ds_caller_features = ast_channel_datastore_find(caller, &dial_features_info, NULL);
03335 ast_channel_unlock(caller);
03336 if (!ds_caller_features) {
03337 if (!(ds_caller_features = ast_datastore_alloc(&dial_features_info, NULL))) {
03338 ast_log(LOG_WARNING, "Unable to create channel datastore for caller features. Aborting!\n");
03339 return;
03340 }
03341 if (!(caller_features = ast_calloc(1, sizeof(*caller_features)))) {
03342 ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n");
03343 ast_datastore_free(ds_caller_features);
03344 return;
03345 }
03346 ds_caller_features->inheritance = DATASTORE_INHERIT_FOREVER;
03347 caller_features->is_caller = 1;
03348 ast_copy_flags(&(caller_features->features_callee), &(config->features_callee), AST_FLAGS_ALL);
03349 ast_copy_flags(&(caller_features->features_caller), &(config->features_caller), AST_FLAGS_ALL);
03350 ds_caller_features->data = caller_features;
03351 ast_channel_lock(caller);
03352 ast_channel_datastore_add(caller, ds_caller_features);
03353 ast_channel_unlock(caller);
03354 } else {
03355
03356
03357 return;
03358 }
03359
03360 ast_channel_lock(callee);
03361 ds_callee_features = ast_channel_datastore_find(callee, &dial_features_info, NULL);
03362 ast_channel_unlock(callee);
03363 if (!ds_callee_features) {
03364 if (!(ds_callee_features = ast_datastore_alloc(&dial_features_info, NULL))) {
03365 ast_log(LOG_WARNING, "Unable to create channel datastore for callee features. Aborting!\n");
03366 return;
03367 }
03368 if (!(callee_features = ast_calloc(1, sizeof(*callee_features)))) {
03369 ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n");
03370 ast_datastore_free(ds_callee_features);
03371 return;
03372 }
03373 ds_callee_features->inheritance = DATASTORE_INHERIT_FOREVER;
03374 callee_features->is_caller = 0;
03375 ast_copy_flags(&(callee_features->features_callee), &(config->features_caller), AST_FLAGS_ALL);
03376 ast_copy_flags(&(callee_features->features_caller), &(config->features_callee), AST_FLAGS_ALL);
03377 ds_callee_features->data = callee_features;
03378 ast_channel_lock(callee);
03379 ast_channel_datastore_add(callee, ds_callee_features);
03380 ast_channel_unlock(callee);
03381 }
03382
03383 return;
03384 }
03385
03386
03387
03388
03389
03390
03391
03392
03393
03394
03395 int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast_bridge_config *config)
03396 {
03397
03398
03399 struct ast_frame *f;
03400 struct ast_channel *who;
03401 char chan_featurecode[FEATURE_MAX_LEN + 1]="";
03402 char peer_featurecode[FEATURE_MAX_LEN + 1]="";
03403 char orig_channame[AST_MAX_EXTENSION];
03404 char orig_peername[AST_MAX_EXTENSION];
03405 int res;
03406 int diff;
03407 int hasfeatures=0;
03408 int hadfeatures=0;
03409 int autoloopflag;
03410 int we_disabled_peer_cdr = 0;
03411 struct ast_option_header *aoh;
03412 struct ast_cdr *bridge_cdr = NULL;
03413 struct ast_cdr *orig_peer_cdr = NULL;
03414 struct ast_cdr *chan_cdr = chan->cdr;
03415 struct ast_cdr *peer_cdr = peer->cdr;
03416 struct ast_cdr *new_chan_cdr = NULL;
03417 struct ast_cdr *new_peer_cdr = NULL;
03418
03419 if (chan && peer) {
03420 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
03421 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
03422 } else if (chan) {
03423 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
03424 }
03425
03426 set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES"));
03427 add_features_datastores(chan, peer, config);
03428
03429
03430
03431
03432 if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) {
03433 ast_indicate(peer, AST_CONTROL_RINGING);
03434 }
03435
03436 if (monitor_ok) {
03437 const char *monitor_exec;
03438 struct ast_channel *src = NULL;
03439 if (!monitor_app) {
03440 if (!(monitor_app = pbx_findapp("Monitor")))
03441 monitor_ok=0;
03442 }
03443 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR")))
03444 src = chan;
03445 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
03446 src = peer;
03447 if (monitor_app && src) {
03448 char *tmp = ast_strdupa(monitor_exec);
03449 pbx_exec(src, monitor_app, tmp);
03450 }
03451 }
03452
03453 set_config_flags(chan, peer, config);
03454
03455
03456 if (chan->_state != AST_STATE_UP) {
03457 if (ast_raw_answer(chan, 1)) {
03458 return -1;
03459 }
03460 }
03461
03462 #ifdef FOR_DEBUG
03463
03464 ast_channel_log("Pre-bridge CHAN Channel info", chan);
03465 ast_channel_log("Pre-bridge PEER Channel info", peer);
03466 #endif
03467
03468 ast_channel_set_linkgroup(chan,peer);
03469
03470
03471 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
03472 char tmp[256];
03473 if (!ast_strlen_zero(chan->cdr->userfield)) {
03474 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield);
03475 ast_cdr_appenduserfield(chan, tmp);
03476 } else
03477 ast_cdr_setuserfield(chan, peer->cdr->userfield);
03478
03479 ast_set_flag(peer->cdr, AST_CDR_FLAG_POST_DISABLED);
03480 we_disabled_peer_cdr = 1;
03481 }
03482 ast_copy_string(orig_channame,chan->name,sizeof(orig_channame));
03483 ast_copy_string(orig_peername,peer->name,sizeof(orig_peername));
03484 orig_peer_cdr = peer_cdr;
03485
03486 if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) {
03487
03488 if (chan_cdr) {
03489 ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN);
03490 ast_cdr_update(chan);
03491 bridge_cdr = ast_cdr_dup_unique_swap(chan_cdr);
03492
03493
03494 bridge_cdr->next = chan_cdr->next;
03495 chan_cdr->next = NULL;
03496 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp));
03497 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata));
03498 if (peer_cdr && !ast_strlen_zero(peer_cdr->userfield)) {
03499 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield));
03500 }
03501 ast_cdr_setaccount(peer, chan->accountcode);
03502
03503 } else {
03504
03505 bridge_cdr = ast_cdr_alloc();
03506 ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel));
03507 ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel));
03508 ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid));
03509 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp));
03510 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata));
03511 ast_cdr_setcid(bridge_cdr, chan);
03512 bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ? AST_CDR_ANSWERED : AST_CDR_NULL;
03513 bridge_cdr->amaflags = chan->amaflags ? chan->amaflags : ast_default_amaflags;
03514 ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode));
03515
03516 ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst));
03517 ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext));
03518 if (peer_cdr) {
03519 bridge_cdr->start = peer_cdr->start;
03520 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield));
03521 } else {
03522 ast_cdr_start(bridge_cdr);
03523 }
03524 }
03525 ast_debug(4,"bridge answer set, chan answer set\n");
03526
03527
03528
03529
03530
03531
03532
03533
03534
03535
03536
03537
03538
03539
03540
03541 if (peer_cdr && !ast_tvzero(peer_cdr->answer) && ast_tvcmp(peer_cdr->answer, bridge_cdr->start) >= 0) {
03542 ast_cdr_setanswer(bridge_cdr, peer_cdr->answer);
03543 ast_cdr_setdisposition(bridge_cdr, peer_cdr->disposition);
03544 if (chan_cdr) {
03545 ast_cdr_setanswer(chan_cdr, peer_cdr->answer);
03546 ast_cdr_setdisposition(chan_cdr, peer_cdr->disposition);
03547 }
03548 } else {
03549 ast_cdr_answer(bridge_cdr);
03550 if (chan_cdr) {
03551 ast_cdr_answer(chan_cdr);
03552 }
03553 }
03554 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT) && (chan_cdr || peer_cdr)) {
03555 if (chan_cdr) {
03556 ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED);
03557 }
03558 if (peer_cdr) {
03559 ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED);
03560 }
03561 }
03562
03563
03564
03565
03566 ast_clear_flag(bridge_cdr, AST_CDR_FLAG_DIALED);
03567 }
03568 ast_cel_report_event(chan, AST_CEL_BRIDGE_START, NULL, NULL, NULL);
03569 for (;;) {
03570 struct ast_channel *other;
03571
03572 res = ast_channel_bridge(chan, peer, config, &f, &who);
03573
03574
03575
03576
03577
03578
03579
03580
03581 if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) {
03582
03583 diff = ast_tvdiff_ms(ast_tvnow(), config->feature_start_time);
03584 if (res == AST_BRIDGE_RETRY) {
03585
03586
03587
03588 config->feature_timer = -1;
03589 } else {
03590 config->feature_timer -= diff;
03591 }
03592
03593 if (hasfeatures) {
03594 if (config->feature_timer <= 0) {
03595
03596
03597 ast_debug(1, "Timed out for feature!\n");
03598 if (!ast_strlen_zero(peer_featurecode)) {
03599 ast_dtmf_stream(chan, peer, peer_featurecode, 0, 0);
03600 memset(peer_featurecode, 0, sizeof(peer_featurecode));
03601 }
03602 if (!ast_strlen_zero(chan_featurecode)) {
03603 ast_dtmf_stream(peer, chan, chan_featurecode, 0, 0);
03604 memset(chan_featurecode, 0, sizeof(chan_featurecode));
03605 }
03606 if (f)
03607 ast_frfree(f);
03608 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
03609 if (!hasfeatures) {
03610
03611 config->feature_timer = 0;
03612 }
03613 hadfeatures = hasfeatures;
03614
03615 continue;
03616 } else if (!f) {
03617
03618
03619
03620 continue;
03621 }
03622 } else {
03623 if (config->feature_timer <=0) {
03624
03625 config->feature_timer = 0;
03626 who = chan;
03627 if (f)
03628 ast_frfree(f);
03629 f = NULL;
03630 res = 0;
03631 }
03632 }
03633 }
03634 if (res < 0) {
03635 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) {
03636 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
03637 }
03638 goto before_you_go;
03639 }
03640
03641 if (!f || (f->frametype == AST_FRAME_CONTROL &&
03642 (f->subclass.integer == AST_CONTROL_HANGUP || f->subclass.integer == AST_CONTROL_BUSY ||
03643 f->subclass.integer == AST_CONTROL_CONGESTION))) {
03644 res = -1;
03645 break;
03646 }
03647
03648 other = (who == chan) ? peer : chan;
03649 if (f->frametype == AST_FRAME_CONTROL) {
03650 switch (f->subclass.integer) {
03651 case AST_CONTROL_RINGING:
03652 case AST_CONTROL_FLASH:
03653 case -1:
03654 ast_indicate(other, f->subclass.integer);
03655 break;
03656 case AST_CONTROL_CONNECTED_LINE:
03657 if (!ast_channel_connected_line_macro(who, other, f, who != chan, 1)) {
03658 break;
03659 }
03660 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen);
03661 break;
03662 case AST_CONTROL_REDIRECTING:
03663 if (!ast_channel_redirecting_macro(who, other, f, who != chan, 1)) {
03664 break;
03665 }
03666 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen);
03667 break;
03668 case AST_CONTROL_AOC:
03669 case AST_CONTROL_HOLD:
03670 case AST_CONTROL_UNHOLD:
03671 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen);
03672 break;
03673 case AST_CONTROL_OPTION:
03674 aoh = f->data.ptr;
03675
03676
03677
03678
03679 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) {
03680 switch (ntohs(aoh->option)) {
03681 case AST_OPTION_TONE_VERIFY:
03682 case AST_OPTION_TDD:
03683 case AST_OPTION_RELAXDTMF:
03684 case AST_OPTION_AUDIO_MODE:
03685 case AST_OPTION_DIGIT_DETECT:
03686 case AST_OPTION_FAX_DETECT:
03687 ast_channel_setoption(other, ntohs(aoh->option), aoh->data,
03688 f->datalen - sizeof(struct ast_option_header), 0);
03689 }
03690 }
03691 break;
03692 }
03693 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
03694
03695 } else if (f->frametype == AST_FRAME_DTMF) {
03696 char *featurecode;
03697 int sense;
03698
03699 hadfeatures = hasfeatures;
03700
03701 if (who == chan) {
03702 sense = FEATURE_SENSE_CHAN;
03703 featurecode = chan_featurecode;
03704 } else {
03705 sense = FEATURE_SENSE_PEER;
03706 featurecode = peer_featurecode;
03707 }
03708
03709
03710
03711
03712 featurecode[strlen(featurecode)] = f->subclass.integer;
03713
03714 ast_frfree(f);
03715 f = NULL;
03716 config->feature_timer = 0;
03717 res = feature_interpret(chan, peer, config, featurecode, sense);
03718 switch(res) {
03719 case AST_FEATURE_RETURN_PASSDIGITS:
03720 ast_dtmf_stream(other, who, featurecode, 0, 0);
03721
03722 case AST_FEATURE_RETURN_SUCCESS:
03723 memset(featurecode, 0, sizeof(chan_featurecode));
03724 break;
03725 }
03726 if (res >= AST_FEATURE_RETURN_PASSDIGITS) {
03727 res = 0;
03728 } else {
03729 break;
03730 }
03731 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
03732 if (hadfeatures && !hasfeatures) {
03733
03734 config->feature_timer = 0;
03735 } else if (hasfeatures) {
03736 if (config->timelimit) {
03737
03738 ast_set_flag(config, AST_FEATURE_WARNING_ACTIVE);
03739 }
03740 config->feature_start_time = ast_tvnow();
03741 config->feature_timer = featuredigittimeout;
03742 ast_debug(1, "Set feature timer to %ld ms\n", config->feature_timer);
03743 }
03744 }
03745 if (f)
03746 ast_frfree(f);
03747
03748 }
03749 ast_cel_report_event(chan, AST_CEL_BRIDGE_END, NULL, NULL, NULL);
03750 before_you_go:
03751
03752 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) {
03753 ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT);
03754 if (bridge_cdr) {
03755 ast_cdr_discard(bridge_cdr);
03756
03757 }
03758 return res;
03759 }
03760
03761 if (config->end_bridge_callback) {
03762 config->end_bridge_callback(config->end_bridge_callback_data);
03763 }
03764
03765
03766
03767
03768
03769 if (!ast_test_flag(&(config->features_caller),AST_FEATURE_NO_H_EXTEN)
03770 && ast_exists_extension(chan, chan->context, "h", 1,
03771 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
03772 struct ast_cdr *swapper = NULL;
03773 char savelastapp[AST_MAX_EXTENSION];
03774 char savelastdata[AST_MAX_EXTENSION];
03775 char save_exten[AST_MAX_EXTENSION];
03776 int save_prio;
03777 int found = 0;
03778 int spawn_error = 0;
03779
03780 autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP);
03781 ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP);
03782 if (bridge_cdr && ast_opt_end_cdr_before_h_exten) {
03783 ast_cdr_end(bridge_cdr);
03784 }
03785
03786
03787 ast_channel_lock(chan);
03788 if (bridge_cdr) {
03789 swapper = chan->cdr;
03790 ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp));
03791 ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata));
03792 chan->cdr = bridge_cdr;
03793 }
03794 ast_copy_string(save_exten, chan->exten, sizeof(save_exten));
03795 save_prio = chan->priority;
03796 ast_copy_string(chan->exten, "h", sizeof(chan->exten));
03797 chan->priority = 1;
03798 ast_channel_unlock(chan);
03799 while ((spawn_error = ast_spawn_extension(chan, chan->context, chan->exten,
03800 chan->priority,
03801 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
03802 &found, 1)) == 0) {
03803 chan->priority++;
03804 }
03805 if (spawn_error
03806 && (!ast_exists_extension(chan, chan->context, chan->exten, chan->priority,
03807 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))
03808 || ast_check_hangup(chan))) {
03809
03810 spawn_error = 0;
03811 }
03812 if (found && spawn_error) {
03813
03814 ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name);
03815 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name);
03816 }
03817
03818 ast_channel_lock(chan);
03819 ast_copy_string(chan->exten, save_exten, sizeof(chan->exten));
03820 chan->priority = save_prio;
03821 if (bridge_cdr) {
03822 if (chan->cdr == bridge_cdr) {
03823 chan->cdr = swapper;
03824 } else {
03825 bridge_cdr = NULL;
03826 }
03827 }
03828 if (!spawn_error) {
03829 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN);
03830 }
03831 ast_channel_unlock(chan);
03832
03833 if (bridge_cdr) {
03834 ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp));
03835 ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata));
03836 }
03837 ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP);
03838 }
03839
03840
03841 new_chan_cdr = pick_unlocked_cdr(chan->cdr);
03842 if (bridge_cdr && new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED))
03843 ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED);
03844
03845
03846 if (bridge_cdr) {
03847 ast_cdr_end(bridge_cdr);
03848 ast_cdr_detach(bridge_cdr);
03849 }
03850
03851
03852
03853
03854
03855
03856
03857
03858
03859
03860
03861
03862
03863
03864
03865
03866
03867
03868
03869
03870
03871
03872
03873
03874
03875 if (new_chan_cdr) {
03876 struct ast_channel *chan_ptr = NULL;
03877
03878 if (strcasecmp(orig_channame, chan->name) != 0) {
03879
03880 if ((chan_ptr = ast_channel_get_by_name(orig_channame))) {
03881 ast_channel_lock(chan_ptr);
03882 if (!ast_bridged_channel(chan_ptr)) {
03883 struct ast_cdr *cur;
03884 for (cur = chan_ptr->cdr; cur; cur = cur->next) {
03885 if (cur == chan_cdr) {
03886 break;
03887 }
03888 }
03889 if (cur) {
03890 ast_cdr_specialized_reset(chan_cdr, 0);
03891 }
03892 }
03893 ast_channel_unlock(chan_ptr);
03894 chan_ptr = ast_channel_unref(chan_ptr);
03895 }
03896
03897 ast_cdr_specialized_reset(new_chan_cdr, 0);
03898 } else {
03899 ast_cdr_specialized_reset(chan->cdr, 0);
03900 }
03901 }
03902
03903 {
03904 struct ast_channel *chan_ptr = NULL;
03905 new_peer_cdr = pick_unlocked_cdr(peer->cdr);
03906 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))
03907 ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED);
03908 if (strcasecmp(orig_peername, peer->name) != 0) {
03909
03910 if ((chan_ptr = ast_channel_get_by_name(orig_peername))) {
03911 ast_channel_lock(chan_ptr);
03912 if (!ast_bridged_channel(chan_ptr)) {
03913 struct ast_cdr *cur;
03914 for (cur = chan_ptr->cdr; cur; cur = cur->next) {
03915 if (cur == peer_cdr) {
03916 break;
03917 }
03918 }
03919 if (cur) {
03920 ast_cdr_specialized_reset(peer_cdr, 0);
03921 }
03922 }
03923 ast_channel_unlock(chan_ptr);
03924 chan_ptr = ast_channel_unref(chan_ptr);
03925 }
03926
03927 if (new_peer_cdr) {
03928 ast_cdr_specialized_reset(new_peer_cdr, 0);
03929 }
03930 } else {
03931 if (we_disabled_peer_cdr) {
03932 ast_clear_flag(peer->cdr, AST_CDR_FLAG_POST_DISABLED);
03933 }
03934 ast_cdr_specialized_reset(peer->cdr, 0);
03935 }
03936 }
03937
03938 return res;
03939 }
03940
03941
03942 static void post_manager_event(const char *s, struct parkeduser *pu)
03943 {
03944 manager_event(EVENT_FLAG_CALL, s,
03945 "Exten: %s\r\n"
03946 "Channel: %s\r\n"
03947 "Parkinglot: %s\r\n"
03948 "CallerIDNum: %s\r\n"
03949 "CallerIDName: %s\r\n"
03950 "UniqueID: %s\r\n",
03951 pu->parkingexten,
03952 pu->chan->name,
03953 pu->parkinglot->name,
03954 S_COR(pu->chan->caller.id.number.valid, pu->chan->caller.id.number.str, "<unknown>"),
03955 S_COR(pu->chan->caller.id.name.valid, pu->chan->caller.id.name.str, "<unknown>"),
03956 pu->chan->uniqueid
03957 );
03958 }
03959
03960 static char *callback_dialoptions(struct ast_flags *features_callee, struct ast_flags *features_caller, char *options, size_t len)
03961 {
03962 int i = 0;
03963 enum {
03964 OPT_CALLEE_REDIRECT = 't',
03965 OPT_CALLER_REDIRECT = 'T',
03966 OPT_CALLEE_AUTOMON = 'w',
03967 OPT_CALLER_AUTOMON = 'W',
03968 OPT_CALLEE_DISCONNECT = 'h',
03969 OPT_CALLER_DISCONNECT = 'H',
03970 OPT_CALLEE_PARKCALL = 'k',
03971 OPT_CALLER_PARKCALL = 'K',
03972 };
03973
03974 memset(options, 0, len);
03975 if (ast_test_flag(features_caller, AST_FEATURE_REDIRECT) && i < len) {
03976 options[i++] = OPT_CALLER_REDIRECT;
03977 }
03978 if (ast_test_flag(features_caller, AST_FEATURE_AUTOMON) && i < len) {
03979 options[i++] = OPT_CALLER_AUTOMON;
03980 }
03981 if (ast_test_flag(features_caller, AST_FEATURE_DISCONNECT) && i < len) {
03982 options[i++] = OPT_CALLER_DISCONNECT;
03983 }
03984 if (ast_test_flag(features_caller, AST_FEATURE_PARKCALL) && i < len) {
03985 options[i++] = OPT_CALLER_PARKCALL;
03986 }
03987
03988 if (ast_test_flag(features_callee, AST_FEATURE_REDIRECT) && i < len) {
03989 options[i++] = OPT_CALLEE_REDIRECT;
03990 }
03991 if (ast_test_flag(features_callee, AST_FEATURE_AUTOMON) && i < len) {
03992 options[i++] = OPT_CALLEE_AUTOMON;
03993 }
03994 if (ast_test_flag(features_callee, AST_FEATURE_DISCONNECT) && i < len) {
03995 options[i++] = OPT_CALLEE_DISCONNECT;
03996 }
03997 if (ast_test_flag(features_callee, AST_FEATURE_PARKCALL) && i < len) {
03998 options[i++] = OPT_CALLEE_PARKCALL;
03999 }
04000
04001 return options;
04002 }
04003
04004
04005 int manage_parkinglot(struct ast_parkinglot *curlot, const struct pollfd *pfds, const int nfds, struct pollfd **new_pfds, int *new_nfds, int *ms)
04006 {
04007 struct parkeduser *pu;
04008 int res = 0;
04009 char parkingslot[AST_MAX_EXTENSION];
04010
04011
04012 AST_LIST_LOCK(&curlot->parkings);
04013 AST_LIST_TRAVERSE_SAFE_BEGIN(&curlot->parkings, pu, list) {
04014 struct ast_channel *chan = pu->chan;
04015 int tms;
04016 int x;
04017 struct ast_context *con;
04018
04019 if (pu->notquiteyet) {
04020 continue;
04021 }
04022 tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
04023 if (tms > pu->parkingtime) {
04024
04025 ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
04026
04027 if (pu->peername[0]) {
04028 char *peername = ast_strdupa(pu->peername);
04029 char *dash = strrchr(peername, '-');
04030 char *peername_flat;
04031 int i;
04032
04033 if (dash) {
04034 *dash = '\0';
04035 }
04036
04037 peername_flat = ast_strdupa(peername);
04038 for (i = 0; peername_flat[i]; i++) {
04039 if (peername_flat[i] == '/') {
04040 peername_flat[i]= '_';
04041 }
04042 }
04043
04044 con = ast_context_find_or_create(NULL, NULL, pu->parkinglot->parking_con_dial, registrar);
04045 if (!con) {
04046 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", pu->parkinglot->parking_con_dial);
04047 } else {
04048 char returnexten[AST_MAX_EXTENSION];
04049 struct ast_datastore *features_datastore;
04050 struct ast_dial_features *dialfeatures = NULL;
04051
04052 ast_channel_lock(chan);
04053
04054 if ((features_datastore = ast_channel_datastore_find(chan, &dial_features_info, NULL)))
04055 dialfeatures = features_datastore->data;
04056
04057 ast_channel_unlock(chan);
04058
04059 if (!strncmp(peername, "Parked/", 7)) {
04060 peername += 7;
04061 }
04062
04063 if (dialfeatures) {
04064 char buf[MAX_DIAL_FEATURE_OPTIONS] = {0,};
04065 snprintf(returnexten, sizeof(returnexten), "%s,30,%s", peername, callback_dialoptions(&(dialfeatures->features_callee), &(dialfeatures->features_caller), buf, sizeof(buf)));
04066 } else {
04067 ast_log(LOG_NOTICE, "Dial features not found on %s, using default!\n", chan->name);
04068 snprintf(returnexten, sizeof(returnexten), "%s,30,t", peername);
04069 }
04070
04071 ast_add_extension2(con, 1, peername_flat, 1, NULL, NULL, "Dial", ast_strdup(returnexten), ast_free_ptr, registrar);
04072 }
04073 if (pu->options_specified == 1) {
04074
04075 set_c_e_p(chan, pu->context, pu->exten, pu->priority);
04076 } else {
04077 if (comebacktoorigin) {
04078 set_c_e_p(chan, pu->parkinglot->parking_con_dial, peername_flat, 1);
04079 } else {
04080 snprintf(parkingslot, sizeof(parkingslot), "%d", pu->parkingnum);
04081 pbx_builtin_setvar_helper(chan, "PARKINGSLOT", parkingslot);
04082 set_c_e_p(chan, "parkedcallstimeout", peername_flat, 1);
04083 }
04084 }
04085 } else {
04086
04087
04088 set_c_e_p(chan, pu->context, pu->exten, pu->priority);
04089 }
04090 post_manager_event("ParkedCallTimeOut", pu);
04091 ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "ParkedCallTimeOut", NULL);
04092
04093 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);
04094
04095 if (ast_pbx_start(chan)) {
04096 ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name);
04097 ast_hangup(chan);
04098 }
04099
04100 con = ast_context_find(pu->parkinglot->parking_con);
04101 if (con) {
04102 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0))
04103 ast_log(LOG_WARNING, "Whoa, failed to remove the parking extension!\n");
04104 else
04105 notify_metermaids(pu->parkingexten, curlot->parking_con, AST_DEVICE_NOT_INUSE);
04106 } else
04107 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
04108 AST_LIST_REMOVE_CURRENT(list);
04109 free(pu);
04110 } else {
04111 for (x = 0; x < AST_MAX_FDS; x++) {
04112 struct ast_frame *f;
04113 int y;
04114
04115 if (chan->fds[x] == -1) {
04116 continue;
04117 }
04118
04119 for (y = 0; y < nfds; y++) {
04120 if (pfds[y].fd == chan->fds[x]) {
04121
04122 break;
04123 }
04124 }
04125 if (y == nfds) {
04126
04127 continue;
04128 }
04129
04130 if (!(pfds[y].revents & (POLLIN | POLLERR | POLLPRI))) {
04131
04132 continue;
04133 }
04134
04135 if (pfds[y].revents & POLLPRI) {
04136 ast_set_flag(chan, AST_FLAG_EXCEPTION);
04137 } else {
04138 ast_clear_flag(chan, AST_FLAG_EXCEPTION);
04139 }
04140 chan->fdno = x;
04141
04142
04143 f = ast_read(pu->chan);
04144
04145 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer == AST_CONTROL_HANGUP))) {
04146 if (f)
04147 ast_frfree(f);
04148 post_manager_event("ParkedCallGiveUp", pu);
04149 ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "ParkedCallGiveUp", NULL);
04150
04151
04152 ast_verb(2, "%s got tired of being parked\n", chan->name);
04153 ast_hangup(chan);
04154
04155 con = ast_context_find(curlot->parking_con);
04156 if (con) {
04157 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0))
04158 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
04159 else
04160 notify_metermaids(pu->parkingexten, curlot->parking_con, AST_DEVICE_NOT_INUSE);
04161 } else
04162 ast_log(LOG_WARNING, "Whoa, no parking context for parking lot %s?\n", curlot->name);
04163 AST_LIST_REMOVE_CURRENT(list);
04164 parkinglot_unref(pu->parkinglot);
04165 free(pu);
04166 break;
04167 } else {
04168
04169 ast_frfree(f);
04170 if (pu->moh_trys < 3 && !chan->generatordata) {
04171 ast_debug(1, "MOH on parked call stopped by outside source. Restarting on channel %s.\n", chan->name);
04172 ast_indicate_data(chan, AST_CONTROL_HOLD,
04173 S_OR(curlot->mohclass, NULL),
04174 (!ast_strlen_zero(curlot->mohclass) ? strlen(curlot->mohclass) + 1 : 0));
04175 pu->moh_trys++;
04176 }
04177 goto std;
04178 }
04179 }
04180 if (x >= AST_MAX_FDS) {
04181 std: for (x = 0; x < AST_MAX_FDS; x++) {
04182 if (chan->fds[x] > -1) {
04183 void *tmp = ast_realloc(*new_pfds, (*new_nfds + 1) * sizeof(struct pollfd));
04184 if (!tmp) {
04185 continue;
04186 }
04187 *new_pfds = tmp;
04188 (*new_pfds)[*new_nfds].fd = chan->fds[x];
04189 (*new_pfds)[*new_nfds].events = POLLIN | POLLERR | POLLPRI;
04190 (*new_pfds)[*new_nfds].revents = 0;
04191 (*new_nfds)++;
04192 }
04193 }
04194
04195 if (tms < *ms || *ms < 0) {
04196 *ms = tms;
04197 }
04198 }
04199 }
04200 }
04201 AST_LIST_TRAVERSE_SAFE_END;
04202 AST_LIST_UNLOCK(&curlot->parkings);
04203
04204 return res;
04205 }
04206
04207
04208
04209
04210
04211
04212
04213
04214
04215 static void *do_parking_thread(void *ignore)
04216 {
04217 struct pollfd *pfds = NULL, *new_pfds = NULL;
04218 int nfds = 0, new_nfds = 0;
04219
04220 for (;;) {
04221 struct ao2_iterator iter;
04222 struct ast_parkinglot *curlot;
04223 int ms = -1;
04224 iter = ao2_iterator_init(parkinglots, 0);
04225
04226 while ((curlot = ao2_iterator_next(&iter))) {
04227 manage_parkinglot(curlot, pfds, nfds, &new_pfds, &new_nfds, &ms);
04228 ao2_ref(curlot, -1);
04229 }
04230 ao2_iterator_destroy(&iter);
04231
04232
04233 ast_free(pfds);
04234 pfds = new_pfds;
04235 nfds = new_nfds;
04236 new_pfds = NULL;
04237 new_nfds = 0;
04238
04239
04240 ast_poll(pfds, nfds, ms);
04241 pthread_testcancel();
04242 }
04243
04244 return NULL;
04245 }
04246
04247
04248 struct ast_parkinglot *find_parkinglot(const char *name)
04249 {
04250 struct ast_parkinglot *parkinglot;
04251
04252 if (ast_strlen_zero(name)) {
04253 return NULL;
04254 }
04255
04256 parkinglot = ao2_find(parkinglots, (void *) name, 0);
04257 if (parkinglot) {
04258 ast_debug(1, "Found Parkinglot: %s\n", parkinglot->name);
04259 }
04260
04261 return parkinglot;
04262 }
04263
04264
04265 struct ast_parkinglot *copy_parkinglot(const char *name, const struct ast_parkinglot *parkinglot) {
04266 struct ast_parkinglot *copylot;
04267
04268 if (ast_strlen_zero(name)) {
04269 return NULL;
04270 }
04271 if ((copylot = find_parkinglot(name))) {
04272 if (copylot) {
04273 ao2_ref(copylot, -1);
04274 }
04275 return NULL;
04276 }
04277
04278 copylot = create_parkinglot(name);
04279 ast_debug(1, "Building parking lot %s\n", name);
04280
04281 memcpy(copylot, parkinglot, sizeof(struct ast_parkinglot));
04282 ast_copy_string(copylot->name, name, sizeof(copylot->name));
04283 AST_LIST_HEAD_INIT(©lot->parkings);
04284
04285 return copylot;
04286 }
04287
04288 AST_APP_OPTIONS(park_call_options, BEGIN_OPTIONS
04289 AST_APP_OPTION('r', AST_PARK_OPT_RINGING),
04290 AST_APP_OPTION('R', AST_PARK_OPT_RANDOMIZE),
04291 AST_APP_OPTION('s', AST_PARK_OPT_SILENCE),
04292 END_OPTIONS );
04293
04294
04295 static int park_call_exec(struct ast_channel *chan, const char *data)
04296 {
04297
04298
04299
04300 char *orig_chan_name = ast_strdupa(chan->name);
04301 char orig_exten[AST_MAX_EXTENSION];
04302 int orig_priority = chan->priority;
04303
04304
04305
04306 int res = 0;
04307
04308 char *parse = NULL;
04309 AST_DECLARE_APP_ARGS(app_args,
04310 AST_APP_ARG(timeout);
04311 AST_APP_ARG(return_con);
04312 AST_APP_ARG(return_ext);
04313 AST_APP_ARG(return_pri);
04314 AST_APP_ARG(options);
04315 );
04316
04317 parse = ast_strdupa(data);
04318 AST_STANDARD_APP_ARGS(app_args, parse);
04319
04320 ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten));
04321
04322
04323
04324 strcpy(chan->exten, "s");
04325 chan->priority = 1;
04326
04327
04328 if (chan->_state != AST_STATE_UP)
04329 res = ast_answer(chan);
04330
04331
04332 if (!res)
04333 res = ast_safe_sleep(chan, 1000);
04334
04335
04336 if (!res) {
04337 struct ast_park_call_args args = {
04338 .orig_chan_name = orig_chan_name,
04339 };
04340 struct ast_flags flags = { 0 };
04341
04342 if (parse) {
04343 if (!ast_strlen_zero(app_args.timeout)) {
04344 if (sscanf(app_args.timeout, "%30d", &args.timeout) != 1) {
04345 ast_log(LOG_WARNING, "Invalid timeout '%s' provided\n", app_args.timeout);
04346 args.timeout = 0;
04347 }
04348 }
04349 if (!ast_strlen_zero(app_args.return_con)) {
04350 args.return_con = app_args.return_con;
04351 }
04352 if (!ast_strlen_zero(app_args.return_ext)) {
04353 args.return_ext = app_args.return_ext;
04354 }
04355 if (!ast_strlen_zero(app_args.return_pri)) {
04356 if (sscanf(app_args.return_pri, "%30d", &args.return_pri) != 1) {
04357 ast_log(LOG_WARNING, "Invalid priority '%s' specified\n", app_args.return_pri);
04358 args.return_pri = 0;
04359 }
04360 }
04361 }
04362
04363 ast_app_parse_options(park_call_options, &flags, NULL, app_args.options);
04364 args.flags = flags.flags;
04365
04366 args.parkinglot = ao2_callback(parkinglots, 0, find_parkinglot_by_exten_cb, &orig_exten);
04367 res = masq_park_call_announce(chan, chan, &args);
04368
04369 if (res == 1) {
04370 ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten));
04371 chan->priority = orig_priority;
04372 res = 0;
04373 } else if (!res) {
04374 res = 1;
04375 }
04376 }
04377
04378 return res;
04379 }
04380
04381
04382 static int park_exec_full(struct ast_channel *chan, const char *data)
04383 {
04384 int res = 0;
04385 struct ast_channel *peer=NULL;
04386 struct parkeduser *pu;
04387 struct ast_context *con;
04388 int park = 0;
04389 struct ast_bridge_config config;
04390 struct ast_parkinglot *parkinglot;
04391
04392 if (data) {
04393 park = atoi((char *) data);
04394 }
04395
04396 parkinglot = ao2_callback(parkinglots, 0, find_parkinglot_by_position_cb, (void *) &park);
04397 if (!parkinglot)
04398 parkinglot = default_parkinglot;
04399
04400 AST_LIST_LOCK(&parkinglot->parkings);
04401 AST_LIST_TRAVERSE_SAFE_BEGIN(&parkinglot->parkings, pu, list) {
04402 if (!pu->notquiteyet && (!data || pu->parkingnum == park)) {
04403 if (pu->chan->pbx) {
04404 AST_LIST_UNLOCK(&parkinglot->parkings);
04405 return -1;
04406 }
04407 AST_LIST_REMOVE_CURRENT(list);
04408 break;
04409 }
04410 }
04411 AST_LIST_TRAVERSE_SAFE_END;
04412 AST_LIST_UNLOCK(&parkinglot->parkings);
04413
04414 if (pu) {
04415 peer = pu->chan;
04416 con = ast_context_find(parkinglot->parking_con);
04417 if (con) {
04418 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0))
04419 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
04420 else
04421 notify_metermaids(pu->parkingexten, parkinglot->parking_con, AST_DEVICE_NOT_INUSE);
04422 } else
04423 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
04424
04425 ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "UnParkedCall", chan);
04426 ast_manager_event(pu->chan, EVENT_FLAG_CALL, "UnParkedCall",
04427 "Exten: %s\r\n"
04428 "Channel: %s\r\n"
04429 "From: %s\r\n"
04430 "CallerIDNum: %s\r\n"
04431 "CallerIDName: %s\r\n",
04432 pu->parkingexten, pu->chan->name, chan->name,
04433 S_COR(pu->chan->caller.id.number.valid, pu->chan->caller.id.number.str, "<unknown>"),
04434 S_COR(pu->chan->caller.id.name.valid, pu->chan->caller.id.name.str, "<unknown>")
04435 );
04436
04437 ast_free(pu);
04438 }
04439
04440 if (chan->_state != AST_STATE_UP)
04441 ast_answer(chan);
04442
04443
04444
04445
04446
04447 if (peer) {
04448 struct ast_datastore *features_datastore;
04449 struct ast_dial_features *dialfeatures = NULL;
04450
04451
04452
04453 if (!ast_strlen_zero(courtesytone)) {
04454 int error = 0;
04455 ast_indicate(peer, AST_CONTROL_UNHOLD);
04456 if (parkedplay == 0) {
04457 error = ast_stream_and_wait(chan, courtesytone, "");
04458 } else if (parkedplay == 1) {
04459 error = ast_stream_and_wait(peer, courtesytone, "");
04460 } else if (parkedplay == 2) {
04461 if (!ast_streamfile(chan, courtesytone, chan->language) &&
04462 !ast_streamfile(peer, courtesytone, chan->language)) {
04463
04464 res = ast_waitstream(chan, "");
04465 if (res >= 0)
04466 res = ast_waitstream(peer, "");
04467 if (res < 0)
04468 error = 1;
04469 }
04470 }
04471 if (error) {
04472 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
04473 ast_hangup(peer);
04474 return -1;
04475 }
04476 } else
04477 ast_indicate(peer, AST_CONTROL_UNHOLD);
04478
04479 res = ast_channel_make_compatible(chan, peer);
04480 if (res < 0) {
04481 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
04482 ast_hangup(peer);
04483 return -1;
04484 }
04485
04486
04487 ast_verb(3, "Channel %s connected to parked call %d\n", chan->name, park);
04488
04489 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
04490 ast_cdr_setdestchan(chan->cdr, peer->name);
04491 memset(&config, 0, sizeof(struct ast_bridge_config));
04492
04493
04494 ast_channel_lock(peer);
04495 if ((features_datastore = ast_channel_datastore_find(peer, &dial_features_info, NULL))) {
04496 dialfeatures = features_datastore->data;
04497 }
04498 ast_channel_unlock(peer);
04499
04500
04501
04502
04503
04504 if (dialfeatures) {
04505 ast_copy_flags(&(config.features_callee), &(dialfeatures->features_caller), AST_FLAGS_ALL);
04506 }
04507
04508 if ((parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
04509 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
04510 }
04511 if ((parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
04512 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
04513 }
04514 if ((parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
04515 ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL);
04516 }
04517 if ((parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
04518 ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL);
04519 }
04520 if ((parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
04521 ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT);
04522 }
04523 if ((parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
04524 ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT);
04525 }
04526 if ((parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
04527 ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
04528 }
04529 if ((parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
04530 ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
04531 }
04532
04533 parkinglot_unref(parkinglot);
04534 res = ast_bridge_call(chan, peer, &config);
04535
04536 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
04537 ast_cdr_setdestchan(chan->cdr, peer->name);
04538
04539
04540 ast_hangup(peer);
04541 return -1;
04542 } else {
04543
04544 if (ast_stream_and_wait(chan, "pbx-invalidpark", ""))
04545 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
04546 ast_verb(3, "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
04547 res = -1;
04548 }
04549
04550 return -1;
04551 }
04552
04553 static int park_exec(struct ast_channel *chan, const char *data)
04554 {
04555 return park_exec_full(chan, data);
04556 }
04557
04558
04559
04560 static void parkinglot_unref(struct ast_parkinglot *parkinglot)
04561 {
04562 int refcount = ao2_ref(parkinglot, -1);
04563 ast_debug(3, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount - 1);
04564 }
04565
04566 static struct ast_parkinglot *parkinglot_addref(struct ast_parkinglot *parkinglot)
04567 {
04568 int refcount = ao2_ref(parkinglot, +1);
04569 ast_debug(3, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount + 1);
04570 return parkinglot;
04571 }
04572
04573
04574 static struct ast_parkinglot *create_parkinglot(const char *name)
04575 {
04576 struct ast_parkinglot *newlot = (struct ast_parkinglot *) NULL;
04577
04578 if (!name)
04579 return NULL;
04580
04581 newlot = ao2_alloc(sizeof(*newlot), parkinglot_destroy);
04582 if (!newlot)
04583 return NULL;
04584
04585 ast_copy_string(newlot->name, name, sizeof(newlot->name));
04586 AST_LIST_HEAD_INIT(&newlot->parkings);
04587
04588 return newlot;
04589 }
04590
04591
04592 static void parkinglot_destroy(void *obj)
04593 {
04594 struct ast_parkinglot *ruin = obj;
04595 struct ast_context *con;
04596 con = ast_context_find(ruin->parking_con);
04597 if (con)
04598 ast_context_destroy(con, registrar);
04599 }
04600
04601
04602
04603
04604
04605
04606
04607 static void park_add_hints(char *context, int start, int stop)
04608 {
04609 int numext;
04610 char device[AST_MAX_EXTENSION];
04611 char exten[10];
04612
04613 for (numext = start; numext <= stop; numext++) {
04614 snprintf(exten, sizeof(exten), "%d", numext);
04615 snprintf(device, sizeof(device), "park:%s@%s", exten, context);
04616 ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
04617 }
04618 }
04619
04620
04621 static struct ast_parkinglot *build_parkinglot(char *name, struct ast_variable *var)
04622 {
04623 struct ast_parkinglot *parkinglot;
04624 struct ast_context *con = NULL;
04625
04626 struct ast_variable *confvar = var;
04627 int error = 0;
04628 int start = 0, end = 0;
04629 int oldparkinglot = 0;
04630
04631 parkinglot = find_parkinglot(name);
04632 if (parkinglot)
04633 oldparkinglot = 1;
04634 else
04635 parkinglot = create_parkinglot(name);
04636
04637 if (!parkinglot)
04638 return NULL;
04639
04640 ao2_lock(parkinglot);
04641
04642 ast_debug(1, "Building parking lot %s\n", name);
04643
04644
04645 while(confvar) {
04646 if (!strcasecmp(confvar->name, "context")) {
04647 ast_copy_string(parkinglot->parking_con, confvar->value, sizeof(parkinglot->parking_con));
04648 } else if (!strcasecmp(confvar->name, "parkext")) {
04649 ast_copy_string(parkinglot->parkext, confvar->value, sizeof(parkinglot->parkext));
04650 } else if (!strcasecmp(confvar->name, "parkingtime")) {
04651 if ((sscanf(confvar->value, "%30d", &parkinglot->parkingtime) != 1) || (parkinglot->parkingtime < 1)) {
04652 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", confvar->value);
04653 parkinglot->parkingtime = DEFAULT_PARK_TIME;
04654 } else
04655 parkinglot->parkingtime = parkinglot->parkingtime * 1000;
04656 } else if (!strcasecmp(confvar->name, "parkpos")) {
04657 if (sscanf(confvar->value, "%30d-%30d", &start, &end) != 2) {
04658 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);
04659 error = 1;
04660 } else {
04661 parkinglot->parking_start = start;
04662 parkinglot->parking_stop = end;
04663 }
04664 } else if (!strcasecmp(confvar->name, "findslot")) {
04665 parkinglot->parkfindnext = (!strcasecmp(confvar->value, "next"));
04666 } else if (!strcasecmp(confvar->name, "parkedcalltransfers")) {
04667 ast_log(LOG_DEBUG, "Setting parking lot %s %s to %s\n", name, confvar->name, confvar->value);
04668 if (!strcasecmp(confvar->value, "both"))
04669 parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH;
04670 else if (!strcasecmp(confvar->value, "caller"))
04671 parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYCALLER;
04672 else if (!strcasecmp(confvar->value, "callee"))
04673 parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYCALLEE;
04674 } else if (!strcasecmp(confvar->name, "parkedcallreparking")) {
04675 ast_log(LOG_DEBUG, "Setting parking lot %s %s to %s\n", name, confvar->name, confvar->value);
04676 if (!strcasecmp(confvar->value, "both"))
04677 parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYBOTH;
04678 else if (!strcasecmp(confvar->value, "caller"))
04679 parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYCALLER;
04680 else if (!strcasecmp(confvar->value, "callee"))
04681 parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYCALLEE;
04682 } else if (!strcasecmp(confvar->name, "parkedcallhangup")) {
04683 ast_log(LOG_DEBUG, "Setting parking lot %s %s to %s\n", name, confvar->name, confvar->value);
04684 if (!strcasecmp(confvar->value, "both"))
04685 parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYBOTH;
04686 else if (!strcasecmp(confvar->value, "caller"))
04687 parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYCALLER;
04688 else if (!strcasecmp(confvar->value, "callee"))
04689 parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYCALLEE;
04690 } else if (!strcasecmp(confvar->name, "parkedcallrecording")) {
04691 ast_log(LOG_DEBUG, "Setting parking lot %s %s to %s\n", name, confvar->name, confvar->value);
04692 if (!strcasecmp(confvar->value, "both"))
04693 parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYBOTH;
04694 else if (!strcasecmp(confvar->value, "caller"))
04695 parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYCALLER;
04696 else if (!strcasecmp(confvar->value, "callee"))
04697 parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYCALLEE;
04698 }
04699 confvar = confvar->next;
04700 }
04701
04702 if (parkinglot->parkingtime == 0) {
04703 parkinglot->parkingtime = DEFAULT_PARK_TIME;
04704 }
04705 if (ast_strlen_zero(parkinglot->parkext)) {
04706 ast_debug(2, "no parkext specified for %s - setting it to %s\n", parkinglot->name, DEFAULT_PARK_EXTENSION);
04707 ast_copy_string(parkinglot->parkext, DEFAULT_PARK_EXTENSION, sizeof(parkinglot->parkext));
04708 }
04709
04710 if (!var) {
04711 ast_copy_string(parkinglot->parking_con, "parkedcalls", sizeof(parkinglot->parking_con));
04712 ast_copy_string(parkinglot->mohclass, "default", sizeof(parkinglot->mohclass));
04713 }
04714 ast_copy_string(parkinglot->parking_con_dial, "park-dial", sizeof(parkinglot->parking_con_dial));
04715
04716
04717 if (ast_strlen_zero(parkinglot->parking_con)) {
04718 ast_log(LOG_WARNING, "Parking lot %s lacks context\n", name);
04719 error = 1;
04720 }
04721
04722
04723 if (!error && !(con = ast_context_find_or_create(NULL, NULL, parkinglot->parking_con, registrar))) {
04724 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parkinglot->parking_con);
04725 error = 1;
04726 }
04727
04728
04729 if (!error && !oldparkinglot) {
04730 if (!ast_strlen_zero(parkinglot->parkext)) {
04731 if (ast_add_extension2(con, 1, parkinglot->parkext, 1, NULL, NULL, parkcall, strdup(""), ast_free_ptr, registrar) == -1)
04732 error = 1;
04733 }
04734 }
04735
04736
04737 if (parkinglot->parkaddhints)
04738 park_add_hints(parkinglot->parking_con, parkinglot->parking_start, parkinglot->parking_stop);
04739
04740 ao2_unlock(parkinglot);
04741
04742 if (error) {
04743 ast_log(LOG_WARNING, "Parking %s not open for business. Configuration error.\n", name);
04744 parkinglot_destroy(parkinglot);
04745 parkinglot_unref(parkinglot);
04746 return NULL;
04747 }
04748 ast_debug(1, "Parking %s now open for business. (start exten %d end %d)\n", name, start, end);
04749 parkinglot->the_mark = 0;
04750
04751
04752 if (!oldparkinglot) {
04753 ao2_link(parkinglots, parkinglot);
04754 }
04755 parkinglot_unref(parkinglot);
04756
04757 return parkinglot;
04758 }
04759
04760 static int load_config(void)
04761 {
04762 int start = 0, end = 0;
04763 int res;
04764 int i;
04765 struct ast_context *con = NULL;
04766 struct ast_config *cfg = NULL;
04767 struct ast_variable *var = NULL;
04768 struct feature_group *fg = NULL;
04769 struct ast_flags config_flags = { 0 };
04770 char *ctg;
04771 static const char * const categories[] = {
04772
04773
04774
04775 "general",
04776 "featuremap",
04777 "applicationmap"
04778 };
04779
04780 default_parkinglot = build_parkinglot(DEFAULT_PARKINGLOT, NULL);
04781 if (default_parkinglot) {
04782 ao2_lock(default_parkinglot);
04783 ast_copy_string(default_parkinglot->parkext, DEFAULT_PARK_EXTENSION, sizeof(default_parkinglot->parkext));
04784 default_parkinglot->parking_start = 701;
04785 default_parkinglot->parking_stop = 750;
04786 default_parkinglot->parking_offset = 0;
04787 default_parkinglot->parkfindnext = 0;
04788 default_parkinglot->parkingtime = DEFAULT_PARK_TIME;
04789 ao2_unlock(default_parkinglot);
04790 }
04791
04792 if (default_parkinglot) {
04793 ast_debug(1, "Configuration of default parkinglot done.\n");
04794 } else {
04795 ast_log(LOG_ERROR, "Configuration of default parkinglot failed.\n");
04796 return -1;
04797 }
04798
04799
04800 strcpy(default_parkinglot->parkext, DEFAULT_PARK_EXTENSION);
04801 strcpy(pickup_ext, "*8");
04802 courtesytone[0] = '\0';
04803 strcpy(xfersound, "beep");
04804 strcpy(xferfailsound, "beeperr");
04805 pickupsound[0] = '\0';
04806 pickupfailsound[0] = '\0';
04807 adsipark = 0;
04808 comebacktoorigin = 1;
04809 parkeddynamic = 0;
04810
04811 default_parkinglot->parkaddhints = 0;
04812 default_parkinglot->parkedcalltransfers = 0;
04813 default_parkinglot->parkedcallreparking = 0;
04814 default_parkinglot->parkedcallrecording = 0;
04815 default_parkinglot->parkedcallhangup = 0;
04816
04817 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
04818 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
04819 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
04820 atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY;
04821 atxferdropcall = DEFAULT_ATXFER_DROP_CALL;
04822 atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES;
04823
04824 cfg = ast_config_load2("features.conf", "features", config_flags);
04825 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
04826 ast_log(LOG_WARNING,"Could not load features.conf\n");
04827 return 0;
04828 }
04829 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
04830 if (!strcasecmp(var->name, "parkext")) {
04831 ast_copy_string(default_parkinglot->parkext, var->value, sizeof(default_parkinglot->parkext));
04832 } else if (!strcasecmp(var->name, "context")) {
04833 ast_copy_string(default_parkinglot->parking_con, var->value, sizeof(default_parkinglot->parking_con));
04834 } else if (!strcasecmp(var->name, "parkingtime")) {
04835 if ((sscanf(var->value, "%30d", &default_parkinglot->parkingtime) != 1) || (default_parkinglot->parkingtime < 1)) {
04836 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
04837 default_parkinglot->parkingtime = DEFAULT_PARK_TIME;
04838 } else
04839 default_parkinglot->parkingtime = default_parkinglot->parkingtime * 1000;
04840 } else if (!strcasecmp(var->name, "parkpos")) {
04841 if (sscanf(var->value, "%30d-%30d", &start, &end) != 2) {
04842 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);
04843 } else if (default_parkinglot) {
04844 default_parkinglot->parking_start = start;
04845 default_parkinglot->parking_stop = end;
04846 } else {
04847 ast_log(LOG_WARNING, "No default parking lot!\n");
04848 }
04849 } else if (!strcasecmp(var->name, "findslot")) {
04850 default_parkinglot->parkfindnext = (!strcasecmp(var->value, "next"));
04851 } else if (!strcasecmp(var->name, "parkinghints")) {
04852 default_parkinglot->parkaddhints = ast_true(var->value);
04853 } else if (!strcasecmp(var->name, "parkedcalltransfers")) {
04854 if (!strcasecmp(var->value, "both"))
04855 default_parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH;
04856 else if (!strcasecmp(var->value, "caller"))
04857 default_parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYCALLER;
04858 else if (!strcasecmp(var->value, "callee"))
04859 default_parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYCALLEE;
04860 } else if (!strcasecmp(var->name, "parkedcallreparking")) {
04861 if (!strcasecmp(var->value, "both"))
04862 default_parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYBOTH;
04863 else if (!strcasecmp(var->value, "caller"))
04864 default_parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYCALLER;
04865 else if (!strcasecmp(var->value, "callee"))
04866 default_parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYCALLEE;
04867 } else if (!strcasecmp(var->name, "parkedcallhangup")) {
04868 if (!strcasecmp(var->value, "both"))
04869 default_parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYBOTH;
04870 else if (!strcasecmp(var->value, "caller"))
04871 default_parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYCALLER;
04872 else if (!strcasecmp(var->value, "callee"))
04873 default_parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYCALLEE;
04874 } else if (!strcasecmp(var->name, "parkedcallrecording")) {
04875 if (!strcasecmp(var->value, "both"))
04876 default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYBOTH;
04877 else if (!strcasecmp(var->value, "caller"))
04878 default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYCALLER;
04879 else if (!strcasecmp(var->value, "callee"))
04880 default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYCALLEE;
04881 } else if (!strcasecmp(var->name, "parkeddynamic")) {
04882 parkeddynamic = ast_true(var->value);
04883 } else if (!strcasecmp(var->name, "adsipark")) {
04884 adsipark = ast_true(var->value);
04885 } else if (!strcasecmp(var->name, "transferdigittimeout")) {
04886 if ((sscanf(var->value, "%30d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
04887 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
04888 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
04889 } else
04890 transferdigittimeout = transferdigittimeout * 1000;
04891 } else if (!strcasecmp(var->name, "featuredigittimeout")) {
04892 if ((sscanf(var->value, "%30d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
04893 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
04894 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
04895 }
04896 } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) {
04897 if ((sscanf(var->value, "%30d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) {
04898 ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value);
04899 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
04900 } else
04901 atxfernoanswertimeout = atxfernoanswertimeout * 1000;
04902 } else if (!strcasecmp(var->name, "atxferloopdelay")) {
04903 if ((sscanf(var->value, "%30u", &atxferloopdelay) != 1)) {
04904 ast_log(LOG_WARNING, "%s is not a valid atxferloopdelay\n", var->value);
04905 atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY;
04906 } else
04907 atxferloopdelay *= 1000;
04908 } else if (!strcasecmp(var->name, "atxferdropcall")) {
04909 atxferdropcall = ast_true(var->value);
04910 } else if (!strcasecmp(var->name, "atxfercallbackretries")) {
04911 if ((sscanf(var->value, "%30u", &atxfercallbackretries) != 1)) {
04912 ast_log(LOG_WARNING, "%s is not a valid atxfercallbackretries\n", var->value);
04913 atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES;
04914 }
04915 } else if (!strcasecmp(var->name, "courtesytone")) {
04916 ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
04917 } else if (!strcasecmp(var->name, "parkedplay")) {
04918 if (!strcasecmp(var->value, "both"))
04919 parkedplay = 2;
04920 else if (!strcasecmp(var->value, "parked"))
04921 parkedplay = 1;
04922 else
04923 parkedplay = 0;
04924 } else if (!strcasecmp(var->name, "xfersound")) {
04925 ast_copy_string(xfersound, var->value, sizeof(xfersound));
04926 } else if (!strcasecmp(var->name, "xferfailsound")) {
04927 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
04928 } else if (!strcasecmp(var->name, "pickupexten")) {
04929 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
04930 } else if (!strcasecmp(var->name, "pickupsound")) {
04931 ast_copy_string(pickupsound, var->value, sizeof(pickupsound));
04932 } else if (!strcasecmp(var->name, "pickupfailsound")) {
04933 ast_copy_string(pickupfailsound, var->value, sizeof(pickupfailsound));
04934 } else if (!strcasecmp(var->name, "comebacktoorigin")) {
04935 comebacktoorigin = ast_true(var->value);
04936 } else if (!strcasecmp(var->name, "parkedmusicclass")) {
04937 ast_copy_string(default_parkinglot->mohclass, var->value, sizeof(default_parkinglot->mohclass));
04938 }
04939 }
04940
04941 unmap_features();
04942 for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) {
04943 if (remap_feature(var->name, var->value))
04944 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
04945 }
04946
04947
04948 ast_unregister_features();
04949 for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) {
04950 char *tmp_val = ast_strdupa(var->value);
04951 char *activateon;
04952 struct ast_call_feature *feature;
04953 AST_DECLARE_APP_ARGS(args,
04954 AST_APP_ARG(exten);
04955 AST_APP_ARG(activatedby);
04956 AST_APP_ARG(app);
04957 AST_APP_ARG(app_args);
04958 AST_APP_ARG(moh_class);
04959 );
04960
04961 AST_STANDARD_APP_ARGS(args, tmp_val);
04962 if (strchr(args.app, '(')) {
04963
04964 args.moh_class = args.app_args;
04965 args.app_args = strchr(args.app, '(');
04966 *args.app_args++ = '\0';
04967 if (args.app_args[strlen(args.app_args) - 1] == ')') {
04968 args.app_args[strlen(args.app_args) - 1] = '\0';
04969 }
04970 }
04971
04972 activateon = strsep(&args.activatedby, "/");
04973
04974
04975 if (ast_strlen_zero(args.app) || ast_strlen_zero(args.exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) {
04976 ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",
04977 args.app, args.exten, activateon, var->name);
04978 continue;
04979 }
04980
04981 AST_RWLIST_RDLOCK(&feature_list);
04982 if ((feature = find_dynamic_feature(var->name))) {
04983 AST_RWLIST_UNLOCK(&feature_list);
04984 ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name);
04985 continue;
04986 }
04987 AST_RWLIST_UNLOCK(&feature_list);
04988
04989 if (!(feature = ast_calloc(1, sizeof(*feature)))) {
04990 continue;
04991 }
04992
04993 ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN);
04994 ast_copy_string(feature->app, args.app, FEATURE_APP_LEN);
04995 ast_copy_string(feature->exten, args.exten, FEATURE_EXTEN_LEN);
04996
04997 if (args.app_args) {
04998 ast_copy_string(feature->app_args, args.app_args, FEATURE_APP_ARGS_LEN);
04999 }
05000
05001 if (args.moh_class) {
05002 ast_copy_string(feature->moh_class, args.moh_class, FEATURE_MOH_LEN);
05003 }
05004
05005 ast_copy_string(feature->exten, args.exten, sizeof(feature->exten));
05006 feature->operation = feature_exec_app;
05007 ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF);
05008
05009
05010 if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller"))
05011 ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF);
05012 else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee"))
05013 ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER);
05014 else {
05015 ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s',"
05016 " must be 'self', or 'peer'\n", var->name);
05017 continue;
05018 }
05019
05020 if (ast_strlen_zero(args.activatedby))
05021 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
05022 else if (!strcasecmp(args.activatedby, "caller"))
05023 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER);
05024 else if (!strcasecmp(args.activatedby, "callee"))
05025 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE);
05026 else if (!strcasecmp(args.activatedby, "both"))
05027 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
05028 else {
05029 ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s',"
05030 " must be 'caller', or 'callee', or 'both'\n", var->name);
05031 continue;
05032 }
05033
05034 ast_register_feature(feature);
05035
05036 ast_verb(2, "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, args.app, args.app_args, args.exten);
05037 }
05038
05039 ast_unregister_groups();
05040 AST_RWLIST_WRLOCK(&feature_groups);
05041
05042 ctg = NULL;
05043 while ((ctg = ast_category_browse(cfg, ctg))) {
05044
05045 if (!strncasecmp(ctg, "parkinglot_", strlen("parkinglot_"))) {
05046 ast_debug(2, "Found configuration section %s, assume parking context\n", ctg);
05047 if(!build_parkinglot(ctg, ast_variable_browse(cfg, ctg)))
05048 ast_log(LOG_ERROR, "Could not build parking lot %s. Configuration error.\n", ctg);
05049 else
05050 ast_debug(1, "Configured parking context %s\n", ctg);
05051 continue;
05052 }
05053
05054 for (i = 0; i < ARRAY_LEN(categories); i++) {
05055 if (!strcasecmp(categories[i], ctg))
05056 break;
05057 }
05058
05059 if (i < ARRAY_LEN(categories))
05060 continue;
05061
05062 if (!(fg = register_group(ctg)))
05063 continue;
05064
05065 for (var = ast_variable_browse(cfg, ctg); var; var = var->next) {
05066 struct ast_call_feature *feature;
05067
05068 AST_RWLIST_RDLOCK(&feature_list);
05069 if (!(feature = find_dynamic_feature(var->name)) &&
05070 !(feature = ast_find_call_feature(var->name))) {
05071 AST_RWLIST_UNLOCK(&feature_list);
05072 ast_log(LOG_WARNING, "Feature '%s' was not found.\n", var->name);
05073 continue;
05074 }
05075 AST_RWLIST_UNLOCK(&feature_list);
05076
05077 register_group_feature(fg, var->value, feature);
05078 }
05079 }
05080
05081 AST_RWLIST_UNLOCK(&feature_groups);
05082
05083 ast_config_destroy(cfg);
05084
05085 if (!(con = ast_context_find_or_create(NULL, NULL, default_parkinglot->parking_con, registrar))) {
05086 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", default_parkinglot->parking_con);
05087 return -1;
05088 }
05089 res = ast_add_extension2(con, 1, default_parkinglot->parkext, 1, NULL, NULL, parkcall, NULL, NULL, registrar);
05090 if (default_parkinglot->parkaddhints)
05091 park_add_hints(default_parkinglot->parking_con, default_parkinglot->parking_start, default_parkinglot->parking_stop);
05092 if (!res)
05093 notify_metermaids(default_parkinglot->parkext, default_parkinglot->parking_con, AST_DEVICE_INUSE);
05094 return res;
05095
05096 }
05097
05098
05099
05100
05101
05102
05103
05104
05105
05106
05107 static char *handle_feature_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05108 {
05109 int i;
05110 struct ast_call_feature *feature;
05111 struct ao2_iterator iter;
05112 struct ast_parkinglot *curlot;
05113 #define HFS_FORMAT "%-25s %-7s %-7s\n"
05114
05115 switch (cmd) {
05116
05117 case CLI_INIT:
05118 e->command = "features show";
05119 e->usage =
05120 "Usage: features show\n"
05121 " Lists configured features\n";
05122 return NULL;
05123 case CLI_GENERATE:
05124 return NULL;
05125 }
05126
05127 ast_cli(a->fd, HFS_FORMAT, "Builtin Feature", "Default", "Current");
05128 ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
05129
05130 ast_cli(a->fd, HFS_FORMAT, "Pickup", "*8", ast_pickup_ext());
05131
05132 ast_rwlock_rdlock(&features_lock);
05133 for (i = 0; i < FEATURES_COUNT; i++)
05134 ast_cli(a->fd, HFS_FORMAT, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
05135 ast_rwlock_unlock(&features_lock);
05136
05137 ast_cli(a->fd, "\n");
05138 ast_cli(a->fd, HFS_FORMAT, "Dynamic Feature", "Default", "Current");
05139 ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
05140 if (AST_RWLIST_EMPTY(&feature_list)) {
05141 ast_cli(a->fd, "(none)\n");
05142 } else {
05143 AST_RWLIST_RDLOCK(&feature_list);
05144 AST_RWLIST_TRAVERSE(&feature_list, feature, feature_entry) {
05145 ast_cli(a->fd, HFS_FORMAT, feature->sname, "no def", feature->exten);
05146 }
05147 AST_RWLIST_UNLOCK(&feature_list);
05148 }
05149
05150 ast_cli(a->fd, "\nFeature Groups:\n");
05151 ast_cli(a->fd, "---------------\n");
05152 if (AST_RWLIST_EMPTY(&feature_groups)) {
05153 ast_cli(a->fd, "(none)\n");
05154 } else {
05155 struct feature_group *fg;
05156 struct feature_group_exten *fge;
05157
05158 AST_RWLIST_RDLOCK(&feature_groups);
05159 AST_RWLIST_TRAVERSE(&feature_groups, fg, entry) {
05160 ast_cli(a->fd, "===> Group: %s\n", fg->gname);
05161 AST_LIST_TRAVERSE(&fg->features, fge, entry) {
05162 ast_cli(a->fd, "===> --> %s (%s)\n", fge->feature->sname, fge->exten);
05163 }
05164 }
05165 AST_RWLIST_UNLOCK(&feature_groups);
05166 }
05167
05168 iter = ao2_iterator_init(parkinglots, 0);
05169 while ((curlot = ao2_iterator_next(&iter))) {
05170 ast_cli(a->fd, "\nCall parking (Parking lot: %s)\n", curlot->name);
05171 ast_cli(a->fd, "------------\n");
05172 ast_cli(a->fd,"%-22s: %s\n", "Parking extension", curlot->parkext);
05173 ast_cli(a->fd,"%-22s: %s\n", "Parking context", curlot->parking_con);
05174 ast_cli(a->fd,"%-22s: %d-%d\n", "Parked call extensions", curlot->parking_start, curlot->parking_stop);
05175 ast_cli(a->fd,"%-22s: %d\n", "Parkingtime", curlot->parkingtime);
05176 ast_cli(a->fd,"%-22s: %s\n", "MusicOnHold class", curlot->mohclass);
05177 ast_cli(a->fd,"\n");
05178 ao2_ref(curlot, -1);
05179 }
05180 ao2_iterator_destroy(&iter);
05181
05182 return CLI_SUCCESS;
05183 }
05184
05185 static int parkinglot_markall_cb(void *obj, void *arg, int flags)
05186 {
05187 struct ast_parkinglot *parkinglot = obj;
05188 parkinglot->the_mark = 1;
05189 return 0;
05190 }
05191
05192 static int parkinglot_is_marked_cb(void *obj, void *arg, int flags)
05193 {
05194 struct ast_parkinglot *parkinglot = obj;
05195 return parkinglot->the_mark ? CMP_MATCH : 0;
05196 }
05197
05198 int ast_features_reload(void)
05199 {
05200 int res;
05201
05202 ao2_t_callback(parkinglots, OBJ_NODATA, parkinglot_markall_cb, NULL, "callback to mark all parkinglots");
05203 res = load_config();
05204 ao2_t_callback(parkinglots, OBJ_NODATA | OBJ_UNLINK, parkinglot_is_marked_cb, NULL, "callback to remove all marked parkinglots");
05205
05206 return res;
05207 }
05208
05209 static char *handle_features_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05210 {
05211 switch (cmd) {
05212 case CLI_INIT:
05213 e->command = "features reload";
05214 e->usage =
05215 "Usage: features reload\n"
05216 " Reloads configured call features from features.conf\n";
05217 return NULL;
05218 case CLI_GENERATE:
05219 return NULL;
05220 }
05221 ast_features_reload();
05222
05223 return CLI_SUCCESS;
05224 }
05225
05226
05227
05228
05229
05230
05231
05232
05233
05234 static void do_bridge_masquerade(struct ast_channel *chan, struct ast_channel *tmpchan)
05235 {
05236 ast_moh_stop(chan);
05237 ast_channel_lock_both(chan, tmpchan);
05238 ast_setstate(tmpchan, chan->_state);
05239 tmpchan->readformat = chan->readformat;
05240 tmpchan->writeformat = chan->writeformat;
05241 ast_channel_masquerade(tmpchan, chan);
05242 ast_channel_unlock(chan);
05243 ast_channel_unlock(tmpchan);
05244
05245
05246 ast_do_masquerade(tmpchan);
05247
05248
05249 ast_explicit_goto(tmpchan, chan->context, chan->exten, chan->priority + 1);
05250 }
05251
05252
05253
05254
05255
05256
05257
05258
05259
05260
05261
05262
05263
05264
05265
05266 static int action_bridge(struct mansession *s, const struct message *m)
05267 {
05268 const char *channela = astman_get_header(m, "Channel1");
05269 const char *channelb = astman_get_header(m, "Channel2");
05270 const char *playtone = astman_get_header(m, "Tone");
05271 struct ast_channel *chana = NULL, *chanb = NULL, *chans[2];
05272 struct ast_channel *tmpchana = NULL, *tmpchanb = NULL;
05273 struct ast_bridge_thread_obj *tobj = NULL;
05274
05275
05276 if (ast_strlen_zero(channela) || ast_strlen_zero(channelb)) {
05277 astman_send_error(s, m, "Missing channel parameter in request");
05278 return 0;
05279 }
05280
05281
05282 chana = ast_channel_get_by_name_prefix(channela, strlen(channela));
05283
05284
05285 if (!chana) {
05286 char buf[256];
05287 snprintf(buf, sizeof(buf), "Channel1 does not exists: %s", channela);
05288 astman_send_error(s, m, buf);
05289 return 0;
05290 }
05291
05292
05293 if (chana->_state != AST_STATE_UP)
05294 ast_answer(chana);
05295
05296
05297 if (!(tmpchana = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
05298 NULL, NULL, chana->linkedid, 0, "Bridge/%s", chana->name))) {
05299 astman_send_error(s, m, "Unable to create temporary channel!");
05300 chana = ast_channel_unref(chana);
05301 return 1;
05302 }
05303
05304 do_bridge_masquerade(chana, tmpchana);
05305
05306 chana = ast_channel_unref(chana);
05307
05308
05309 chanb = ast_channel_get_by_name_prefix(channelb, strlen(channelb));
05310
05311 if (!chanb) {
05312 char buf[256];
05313 snprintf(buf, sizeof(buf), "Channel2 does not exists: %s", channelb);
05314 ast_hangup(tmpchana);
05315 astman_send_error(s, m, buf);
05316 return 0;
05317 }
05318
05319
05320 if (chanb->_state != AST_STATE_UP)
05321 ast_answer(chanb);
05322
05323
05324 if (!(tmpchanb = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
05325 NULL, NULL, chanb->linkedid, 0, "Bridge/%s", chanb->name))) {
05326 astman_send_error(s, m, "Unable to create temporary channels!");
05327 ast_hangup(tmpchana);
05328 chanb = ast_channel_unref(chanb);
05329 return 1;
05330 }
05331
05332 do_bridge_masquerade(chanb, tmpchanb);
05333
05334 chanb = ast_channel_unref(chanb);
05335
05336
05337 if (ast_channel_make_compatible(tmpchana, tmpchanb)) {
05338 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for manager bridge\n", tmpchana->name, tmpchanb->name);
05339 astman_send_error(s, m, "Could not make channels compatible for manager bridge");
05340 ast_hangup(tmpchana);
05341 ast_hangup(tmpchanb);
05342 return 1;
05343 }
05344
05345
05346 if (!(tobj = ast_calloc(1, sizeof(*tobj)))) {
05347 ast_log(LOG_WARNING, "Unable to spawn a new bridge thread on %s and %s: %s\n", tmpchana->name, tmpchanb->name, strerror(errno));
05348 astman_send_error(s, m, "Unable to spawn a new bridge thread");
05349 ast_hangup(tmpchana);
05350 ast_hangup(tmpchanb);
05351 return 1;
05352 }
05353
05354 tobj->chan = tmpchana;
05355 tobj->peer = tmpchanb;
05356 tobj->return_to_pbx = 1;
05357
05358 if (ast_true(playtone)) {
05359 if (!ast_strlen_zero(xfersound) && !ast_streamfile(tmpchanb, xfersound, tmpchanb->language)) {
05360 if (ast_waitstream(tmpchanb, "") < 0)
05361 ast_log(LOG_WARNING, "Failed to play a courtesy tone on chan %s\n", tmpchanb->name);
05362 }
05363 }
05364
05365 chans[0] = tmpchana;
05366 chans[1] = tmpchanb;
05367
05368 ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeAction", 2, chans,
05369 "Response: Success\r\n"
05370 "Channel1: %s\r\n"
05371 "Channel2: %s\r\n", tmpchana->name, tmpchanb->name);
05372
05373 bridge_call_thread_launch(tobj);
05374
05375 astman_send_ack(s, m, "Launched bridge thread with success");
05376
05377 return 0;
05378 }
05379
05380
05381
05382
05383
05384
05385
05386
05387
05388
05389
05390
05391 static char *handle_parkedcalls(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05392 {
05393 struct parkeduser *cur;
05394 int numparked = 0;
05395 struct ao2_iterator iter;
05396 struct ast_parkinglot *curlot;
05397
05398 switch (cmd) {
05399 case CLI_INIT:
05400 e->command = "parkedcalls show";
05401 e->usage =
05402 "Usage: parkedcalls show\n"
05403 " List currently parked calls\n";
05404 return NULL;
05405 case CLI_GENERATE:
05406 return NULL;
05407 }
05408
05409 if (a->argc > e->args)
05410 return CLI_SHOWUSAGE;
05411
05412 ast_cli(a->fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
05413 , "Context", "Extension", "Pri", "Timeout");
05414
05415 iter = ao2_iterator_init(parkinglots, 0);
05416 while ((curlot = ao2_iterator_next(&iter))) {
05417 int lotparked = 0;
05418
05419 ast_cli(a->fd, "*** Parking lot: %s (%d)\n", curlot->name, ao2_ref(curlot, 0) - 2);
05420
05421 AST_LIST_LOCK(&curlot->parkings);
05422 AST_LIST_TRAVERSE(&curlot->parkings, cur, list) {
05423 ast_cli(a->fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n"
05424 ,cur->parkingexten, cur->chan->name, cur->context, cur->exten
05425 ,cur->priority,
05426 (long)(cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL)) );
05427 numparked++;
05428 numparked += lotparked;
05429 }
05430 AST_LIST_UNLOCK(&curlot->parkings);
05431 if (lotparked)
05432 ast_cli(a->fd, " %d parked call%s in parking lot %s\n", lotparked, ESS(lotparked), curlot->name);
05433
05434 ao2_ref(curlot, -1);
05435 }
05436
05437 ast_cli(a->fd, "---\n%d parked call%s in total.\n", numparked, ESS(numparked));
05438
05439 return CLI_SUCCESS;
05440 }
05441
05442 static struct ast_cli_entry cli_features[] = {
05443 AST_CLI_DEFINE(handle_feature_show, "Lists configured features"),
05444 AST_CLI_DEFINE(handle_features_reload, "Reloads configured features"),
05445 AST_CLI_DEFINE(handle_parkedcalls, "List currently parked calls"),
05446 };
05447
05448
05449
05450
05451
05452
05453
05454
05455
05456 static int manager_parking_status(struct mansession *s, const struct message *m)
05457 {
05458 struct parkeduser *cur;
05459 const char *id = astman_get_header(m, "ActionID");
05460 char idText[256] = "";
05461 struct ao2_iterator iter;
05462 struct ast_parkinglot *curlot;
05463
05464 if (!ast_strlen_zero(id))
05465 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
05466
05467 astman_send_ack(s, m, "Parked calls will follow");
05468
05469 iter = ao2_iterator_init(parkinglots, 0);
05470 while ((curlot = ao2_iterator_next(&iter))) {
05471
05472 AST_LIST_LOCK(&curlot->parkings);
05473 AST_LIST_TRAVERSE(&curlot->parkings, cur, list) {
05474 astman_append(s, "Event: ParkedCall\r\n"
05475 "Exten: %d\r\n"
05476 "Channel: %s\r\n"
05477 "From: %s\r\n"
05478 "Timeout: %ld\r\n"
05479 "CallerIDNum: %s\r\n"
05480 "CallerIDName: %s\r\n"
05481 "%s"
05482 "\r\n",
05483 cur->parkingnum, cur->chan->name, cur->peername,
05484 (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
05485 S_COR(cur->chan->caller.id.number.valid, cur->chan->caller.id.number.str, ""),
05486 S_COR(cur->chan->caller.id.name.valid, cur->chan->caller.id.name.str, ""),
05487 idText);
05488 }
05489 AST_LIST_UNLOCK(&curlot->parkings);
05490 ao2_ref(curlot, -1);
05491 }
05492
05493 astman_append(s,
05494 "Event: ParkedCallsComplete\r\n"
05495 "%s"
05496 "\r\n",idText);
05497
05498
05499 return RESULT_SUCCESS;
05500 }
05501
05502
05503
05504
05505
05506
05507
05508
05509
05510 static int manager_park(struct mansession *s, const struct message *m)
05511 {
05512 const char *channel = astman_get_header(m, "Channel");
05513 const char *channel2 = astman_get_header(m, "Channel2");
05514 const char *timeout = astman_get_header(m, "Timeout");
05515 const char *parkinglotname = astman_get_header(m, "Parkinglot");
05516 char buf[BUFSIZ];
05517 int res = 0;
05518 struct ast_channel *ch1, *ch2;
05519 struct ast_park_call_args args = {0,};
05520
05521 if (ast_strlen_zero(channel)) {
05522 astman_send_error(s, m, "Channel not specified");
05523 return 0;
05524 }
05525
05526 if (ast_strlen_zero(channel2)) {
05527 astman_send_error(s, m, "Channel2 not specified");
05528 return 0;
05529 }
05530
05531 if (!(ch1 = ast_channel_get_by_name(channel))) {
05532 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
05533 astman_send_error(s, m, buf);
05534 return 0;
05535 }
05536
05537 if (!(ch2 = ast_channel_get_by_name(channel2))) {
05538 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
05539 astman_send_error(s, m, buf);
05540 ast_channel_unref(ch1);
05541 return 0;
05542 }
05543
05544 if (!ast_strlen_zero(timeout)) {
05545 sscanf(timeout, "%30d", &args.timeout);
05546 }
05547 if (!ast_strlen_zero(parkinglotname)) {
05548 args.parkinglot = find_parkinglot(parkinglotname);
05549 }
05550
05551 ast_channel_lock(ch1);
05552 while (ast_channel_trylock(ch2)) {
05553 CHANNEL_DEADLOCK_AVOIDANCE(ch1);
05554 }
05555
05556 res = masq_park_call(ch1, ch2, 0, NULL, 0, &args);
05557 if (!res) {
05558 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
05559 astman_send_ack(s, m, "Park successful");
05560 } else {
05561 astman_send_error(s, m, "Park failure");
05562 }
05563
05564 ast_channel_unlock(ch1);
05565 ast_channel_unlock(ch2);
05566
05567 ch1 = ast_channel_unref(ch1);
05568 ch2 = ast_channel_unref(ch2);
05569
05570 return 0;
05571 }
05572
05573 static int find_channel_by_group(void *obj, void *arg, void *data, int flags)
05574 {
05575 struct ast_channel *c = data;
05576 struct ast_channel *chan = obj;
05577
05578 int i = !chan->pbx &&
05579
05580
05581
05582 (c != chan) &&
05583 (chan->pickupgroup & c->callgroup) &&
05584 ((chan->_state == AST_STATE_RINGING) || (chan->_state == AST_STATE_RING)) &&
05585 !c->masq;
05586
05587 return i ? CMP_MATCH | CMP_STOP : 0;
05588 }
05589
05590
05591
05592
05593
05594
05595
05596
05597
05598 int ast_pickup_call(struct ast_channel *chan)
05599 {
05600 struct ast_channel *cur, *chans[2] = { chan, };
05601 struct ast_party_connected_line connected_caller;
05602 int res;
05603 const char *chan_name;
05604 const char *cur_name;
05605
05606 if (!(cur = ast_channel_callback(find_channel_by_group, NULL, chan, 0))) {
05607 ast_debug(1, "No call pickup possible...\n");
05608 if (!ast_strlen_zero(pickupfailsound)) {
05609 ast_stream_and_wait(chan, pickupfailsound, "");
05610 }
05611 return -1;
05612 }
05613
05614 chans[1] = cur;
05615
05616 ast_channel_lock_both(cur, chan);
05617
05618 cur_name = ast_strdupa(cur->name);
05619 chan_name = ast_strdupa(chan->name);
05620
05621 ast_debug(1, "Call pickup on chan '%s' by '%s'\n", cur_name, chan_name);
05622
05623 connected_caller = cur->connected;
05624 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
05625 if (ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) {
05626 ast_channel_update_connected_line(chan, &connected_caller, NULL);
05627 }
05628
05629 ast_party_connected_line_collect_caller(&connected_caller, &chan->caller);
05630 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
05631 ast_channel_queue_connected_line_update(chan, &connected_caller, NULL);
05632
05633 ast_channel_unlock(cur);
05634 ast_channel_unlock(chan);
05635
05636 if (ast_answer(chan)) {
05637 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name);
05638 }
05639
05640 if (ast_queue_control(chan, AST_CONTROL_ANSWER)) {
05641 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan_name);
05642 }
05643
05644 if ((res = ast_channel_masquerade(cur, chan))) {
05645 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan_name, cur_name);
05646 }
05647
05648 if (!ast_strlen_zero(pickupsound)) {
05649 ast_stream_and_wait(cur, pickupsound, "");
05650 }
05651
05652
05653 ast_manager_event_multichan(EVENT_FLAG_CALL, "Pickup", 2, chans,
05654 "Channel: %s\r\nTargetChannel: %s\r\n", chan->name, cur->name);
05655
05656 cur = ast_channel_unref(cur);
05657
05658 return res;
05659 }
05660
05661 static char *app_bridge = "Bridge";
05662
05663 enum {
05664 BRIDGE_OPT_PLAYTONE = (1 << 0),
05665 OPT_CALLEE_HANGUP = (1 << 1),
05666 OPT_CALLER_HANGUP = (1 << 2),
05667 OPT_DURATION_LIMIT = (1 << 3),
05668 OPT_DURATION_STOP = (1 << 4),
05669 OPT_CALLEE_TRANSFER = (1 << 5),
05670 OPT_CALLER_TRANSFER = (1 << 6),
05671 OPT_CALLEE_MONITOR = (1 << 7),
05672 OPT_CALLER_MONITOR = (1 << 8),
05673 OPT_CALLEE_PARK = (1 << 9),
05674 OPT_CALLER_PARK = (1 << 10),
05675 OPT_CALLEE_KILL = (1 << 11),
05676 };
05677
05678 enum {
05679 OPT_ARG_DURATION_LIMIT = 0,
05680 OPT_ARG_DURATION_STOP,
05681
05682 OPT_ARG_ARRAY_SIZE,
05683 };
05684
05685 AST_APP_OPTIONS(bridge_exec_options, BEGIN_OPTIONS
05686 AST_APP_OPTION('p', BRIDGE_OPT_PLAYTONE),
05687 AST_APP_OPTION('h', OPT_CALLEE_HANGUP),
05688 AST_APP_OPTION('H', OPT_CALLER_HANGUP),
05689 AST_APP_OPTION('k', OPT_CALLEE_PARK),
05690 AST_APP_OPTION('K', OPT_CALLER_PARK),
05691 AST_APP_OPTION_ARG('L', OPT_DURATION_LIMIT, OPT_ARG_DURATION_LIMIT),
05692 AST_APP_OPTION_ARG('S', OPT_DURATION_STOP, OPT_ARG_DURATION_STOP),
05693 AST_APP_OPTION('t', OPT_CALLEE_TRANSFER),
05694 AST_APP_OPTION('T', OPT_CALLER_TRANSFER),
05695 AST_APP_OPTION('w', OPT_CALLEE_MONITOR),
05696 AST_APP_OPTION('W', OPT_CALLER_MONITOR),
05697 AST_APP_OPTION('x', OPT_CALLEE_KILL),
05698 END_OPTIONS );
05699
05700 int ast_bridge_timelimit(struct ast_channel *chan, struct ast_bridge_config *config,
05701 char *parse, struct timeval *calldurationlimit)
05702 {
05703 char *stringp = ast_strdupa(parse);
05704 char *limit_str, *warning_str, *warnfreq_str;
05705 const char *var;
05706 int play_to_caller = 0, play_to_callee = 0;
05707 int delta;
05708
05709 limit_str = strsep(&stringp, ":");
05710 warning_str = strsep(&stringp, ":");
05711 warnfreq_str = strsep(&stringp, ":");
05712
05713 config->timelimit = atol(limit_str);
05714 if (warning_str)
05715 config->play_warning = atol(warning_str);
05716 if (warnfreq_str)
05717 config->warning_freq = atol(warnfreq_str);
05718
05719 if (!config->timelimit) {
05720 ast_log(LOG_WARNING, "Bridge does not accept L(%s), hanging up.\n", limit_str);
05721 config->timelimit = config->play_warning = config->warning_freq = 0;
05722 config->warning_sound = NULL;
05723 return -1;
05724 } else if ( (delta = config->play_warning - config->timelimit) > 0) {
05725 int w = config->warning_freq;
05726
05727
05728
05729
05730
05731
05732
05733
05734
05735
05736
05737
05738
05739 if (w == 0) {
05740 config->play_warning = 0;
05741 } else {
05742 config->play_warning -= w * ( 1 + (delta-1)/w );
05743 if (config->play_warning < 1)
05744 config->play_warning = config->warning_freq = 0;
05745 }
05746 }
05747
05748 ast_channel_lock(chan);
05749
05750 var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLER");
05751 play_to_caller = var ? ast_true(var) : 1;
05752
05753 var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLEE");
05754 play_to_callee = var ? ast_true(var) : 0;
05755
05756 if (!play_to_caller && !play_to_callee)
05757 play_to_caller = 1;
05758
05759 var = pbx_builtin_getvar_helper(chan, "LIMIT_WARNING_FILE");
05760 config->warning_sound = !ast_strlen_zero(var) ? ast_strdup(var) : ast_strdup("timeleft");
05761
05762
05763
05764
05765
05766
05767
05768 var = pbx_builtin_getvar_helper(chan, "LIMIT_TIMEOUT_FILE");
05769 config->end_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL;
05770
05771 var = pbx_builtin_getvar_helper(chan, "LIMIT_CONNECT_FILE");
05772 config->start_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL;
05773
05774 ast_channel_unlock(chan);
05775
05776
05777 calldurationlimit->tv_sec = 0;
05778 calldurationlimit->tv_usec = 0;
05779
05780
05781 if (!config->play_warning && !config->start_sound && !config->end_sound && config->timelimit) {
05782 calldurationlimit->tv_sec = config->timelimit / 1000;
05783 calldurationlimit->tv_usec = (config->timelimit % 1000) * 1000;
05784 ast_verb(3, "Setting call duration limit to %.3lf seconds.\n",
05785 calldurationlimit->tv_sec + calldurationlimit->tv_usec / 1000000.0);
05786 config->timelimit = play_to_caller = play_to_callee =
05787 config->play_warning = config->warning_freq = 0;
05788 } else {
05789 ast_verb(4, "Limit Data for this call:\n");
05790 ast_verb(4, "timelimit = %ld ms (%.3lf s)\n", config->timelimit, config->timelimit / 1000.0);
05791 ast_verb(4, "play_warning = %ld ms (%.3lf s)\n", config->play_warning, config->play_warning / 1000.0);
05792 ast_verb(4, "play_to_caller = %s\n", play_to_caller ? "yes" : "no");
05793 ast_verb(4, "play_to_callee = %s\n", play_to_callee ? "yes" : "no");
05794 ast_verb(4, "warning_freq = %ld ms (%.3lf s)\n", config->warning_freq, config->warning_freq / 1000.0);
05795 ast_verb(4, "start_sound = %s\n", S_OR(config->start_sound, ""));
05796 ast_verb(4, "warning_sound = %s\n", config->warning_sound);
05797 ast_verb(4, "end_sound = %s\n", S_OR(config->end_sound, ""));
05798 }
05799 if (play_to_caller)
05800 ast_set_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
05801 if (play_to_callee)
05802 ast_set_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
05803 return 0;
05804 }
05805
05806
05807
05808
05809
05810
05811
05812
05813
05814
05815
05816 static int bridge_exec(struct ast_channel *chan, const char *data)
05817 {
05818 struct ast_channel *current_dest_chan, *final_dest_chan, *chans[2];
05819 char *tmp_data = NULL;
05820 struct ast_flags opts = { 0, };
05821 struct ast_bridge_config bconfig = { { 0, }, };
05822 char *opt_args[OPT_ARG_ARRAY_SIZE];
05823 struct timeval calldurationlimit = { 0, };
05824
05825 AST_DECLARE_APP_ARGS(args,
05826 AST_APP_ARG(dest_chan);
05827 AST_APP_ARG(options);
05828 );
05829
05830 if (ast_strlen_zero(data)) {
05831 ast_log(LOG_WARNING, "Bridge require at least 1 argument specifying the other end of the bridge\n");
05832 return -1;
05833 }
05834
05835 tmp_data = ast_strdupa(data);
05836 AST_STANDARD_APP_ARGS(args, tmp_data);
05837 if (!ast_strlen_zero(args.options))
05838 ast_app_parse_options(bridge_exec_options, &opts, opt_args, args.options);
05839
05840
05841 if (!strcmp(chan->name, args.dest_chan)) {
05842 ast_log(LOG_WARNING, "Unable to bridge channel %s with itself\n", chan->name);
05843 ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
05844 "Response: Failed\r\n"
05845 "Reason: Unable to bridge channel to itself\r\n"
05846 "Channel1: %s\r\n"
05847 "Channel2: %s\r\n",
05848 chan->name, args.dest_chan);
05849 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "LOOP");
05850 return 0;
05851 }
05852
05853
05854 if (!(current_dest_chan = ast_channel_get_by_name_prefix(args.dest_chan,
05855 strlen(args.dest_chan)))) {
05856 ast_log(LOG_WARNING, "Bridge failed because channel %s does not exists or we "
05857 "cannot get its lock\n", args.dest_chan);
05858 ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
05859 "Response: Failed\r\n"
05860 "Reason: Cannot grab end point\r\n"
05861 "Channel1: %s\r\n"
05862 "Channel2: %s\r\n", chan->name, args.dest_chan);
05863 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "NONEXISTENT");
05864 return 0;
05865 }
05866
05867
05868 if (current_dest_chan->_state != AST_STATE_UP) {
05869 ast_answer(current_dest_chan);
05870 }
05871
05872
05873 if (!(final_dest_chan = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
05874 NULL, NULL, current_dest_chan->linkedid, 0, "Bridge/%s", current_dest_chan->name))) {
05875 ast_log(LOG_WARNING, "Cannot create placeholder channel for chan %s\n", args.dest_chan);
05876 ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
05877 "Response: Failed\r\n"
05878 "Reason: cannot create placeholder\r\n"
05879 "Channel1: %s\r\n"
05880 "Channel2: %s\r\n", chan->name, args.dest_chan);
05881 }
05882
05883 ast_channel_unlock(current_dest_chan);
05884
05885 do_bridge_masquerade(current_dest_chan, final_dest_chan);
05886
05887 chans[0] = current_dest_chan;
05888 chans[1] = final_dest_chan;
05889
05890
05891
05892 if (ast_channel_make_compatible(chan, final_dest_chan) < 0) {
05893 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, final_dest_chan->name);
05894 ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeExec", 2, chans,
05895 "Response: Failed\r\n"
05896 "Reason: Could not make channels compatible for bridge\r\n"
05897 "Channel1: %s\r\n"
05898 "Channel2: %s\r\n", chan->name, final_dest_chan->name);
05899 ast_hangup(final_dest_chan);
05900 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "INCOMPATIBLE");
05901 current_dest_chan = ast_channel_unref(current_dest_chan);
05902 return 0;
05903 }
05904
05905
05906 ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeExec", 2, chans,
05907 "Response: Success\r\n"
05908 "Channel1: %s\r\n"
05909 "Channel2: %s\r\n", chan->name, final_dest_chan->name);
05910
05911
05912 if (ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE) && !ast_strlen_zero(xfersound)) {
05913 if (!ast_streamfile(final_dest_chan, xfersound, final_dest_chan->language)) {
05914 if (ast_waitstream(final_dest_chan, "") < 0)
05915 ast_log(LOG_WARNING, "Failed to play courtesy tone on %s\n", final_dest_chan->name);
05916 }
05917 }
05918
05919 current_dest_chan = ast_channel_unref(current_dest_chan);
05920
05921 if (ast_test_flag(&opts, OPT_DURATION_LIMIT) && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_LIMIT])) {
05922 if (ast_bridge_timelimit(chan, &bconfig, opt_args[OPT_ARG_DURATION_LIMIT], &calldurationlimit))
05923 goto done;
05924 }
05925
05926 if (ast_test_flag(&opts, OPT_CALLEE_TRANSFER))
05927 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_REDIRECT);
05928 if (ast_test_flag(&opts, OPT_CALLER_TRANSFER))
05929 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_REDIRECT);
05930 if (ast_test_flag(&opts, OPT_CALLEE_HANGUP))
05931 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
05932 if (ast_test_flag(&opts, OPT_CALLER_HANGUP))
05933 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
05934 if (ast_test_flag(&opts, OPT_CALLEE_MONITOR))
05935 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_AUTOMON);
05936 if (ast_test_flag(&opts, OPT_CALLER_MONITOR))
05937 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_AUTOMON);
05938 if (ast_test_flag(&opts, OPT_CALLEE_PARK))
05939 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_PARKCALL);
05940 if (ast_test_flag(&opts, OPT_CALLER_PARK))
05941 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_PARKCALL);
05942
05943 ast_bridge_call(chan, final_dest_chan, &bconfig);
05944
05945
05946 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "SUCCESS");
05947 if (!ast_check_hangup(final_dest_chan) && !ast_test_flag(&opts, OPT_CALLEE_KILL)) {
05948 ast_debug(1, "starting new PBX in %s,%s,%d for chan %s\n",
05949 final_dest_chan->context, final_dest_chan->exten,
05950 final_dest_chan->priority, final_dest_chan->name);
05951
05952 if (ast_pbx_start(final_dest_chan) != AST_PBX_SUCCESS) {
05953 ast_log(LOG_WARNING, "FAILED continuing PBX on dest chan %s\n", final_dest_chan->name);
05954 ast_hangup(final_dest_chan);
05955 } else
05956 ast_debug(1, "SUCCESS continuing PBX on chan %s\n", final_dest_chan->name);
05957 } else {
05958 ast_debug(1, "hangup chan %s since the other endpoint has hung up or the x flag was passed\n", final_dest_chan->name);
05959 ast_hangup(final_dest_chan);
05960 }
05961 done:
05962 if (bconfig.warning_sound) {
05963 ast_free((char *)bconfig.warning_sound);
05964 }
05965 if (bconfig.end_sound) {
05966 ast_free((char *)bconfig.end_sound);
05967 }
05968 if (bconfig.start_sound) {
05969 ast_free((char *)bconfig.start_sound);
05970 }
05971
05972 return 0;
05973 }
05974
05975 int ast_features_init(void)
05976 {
05977 int res;
05978
05979 ast_register_application2(app_bridge, bridge_exec, NULL, NULL, NULL);
05980
05981 parkinglots = ao2_container_alloc(7, parkinglot_hash_cb, parkinglot_cmp_cb);
05982
05983 if ((res = load_config()))
05984 return res;
05985 ast_cli_register_multiple(cli_features, ARRAY_LEN(cli_features));
05986 ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
05987 res = ast_register_application2(parkedcall, park_exec, NULL, NULL, NULL);
05988 if (!res)
05989 res = ast_register_application2(parkcall, park_call_exec, NULL, NULL, NULL);
05990 if (!res) {
05991 ast_manager_register_xml("ParkedCalls", 0, manager_parking_status);
05992 ast_manager_register_xml("Park", EVENT_FLAG_CALL, manager_park);
05993 ast_manager_register_xml("Bridge", EVENT_FLAG_CALL, action_bridge);
05994 }
05995
05996 res |= ast_devstate_prov_add("Park", metermaidstate);
05997 #ifdef TEST_FRAMEWORK
05998 res |= AST_TEST_REGISTER(features_test);
05999 #endif
06000
06001 return res;
06002 }