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: 187600 $")
00029
00030 #include "asterisk/_private.h"
00031
00032 #include <pthread.h>
00033 #include <sys/time.h>
00034 #include <sys/signal.h>
00035 #include <netinet/in.h>
00036
00037 #include "asterisk/lock.h"
00038 #include "asterisk/file.h"
00039 #include "asterisk/channel.h"
00040 #include "asterisk/pbx.h"
00041 #include "asterisk/causes.h"
00042 #include "asterisk/module.h"
00043 #include "asterisk/translate.h"
00044 #include "asterisk/app.h"
00045 #include "asterisk/say.h"
00046 #include "asterisk/features.h"
00047 #include "asterisk/musiconhold.h"
00048 #include "asterisk/config.h"
00049 #include "asterisk/cli.h"
00050 #include "asterisk/manager.h"
00051 #include "asterisk/utils.h"
00052 #include "asterisk/adsi.h"
00053 #include "asterisk/devicestate.h"
00054 #include "asterisk/monitor.h"
00055 #include "asterisk/audiohook.h"
00056 #include "asterisk/global_datastores.h"
00057 #include "asterisk/astobj2.h"
00058
00059 #define DEFAULT_PARK_TIME 45000
00060 #define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000
00061 #define DEFAULT_FEATURE_DIGIT_TIMEOUT 1000
00062 #define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000
00063 #define DEFAULT_PARKINGLOT "default"
00064 #define DEFAULT_ATXFER_DROP_CALL 0
00065 #define DEFAULT_ATXFER_LOOP_DELAY 10000
00066 #define DEFAULT_ATXFER_CALLBACK_RETRIES 2
00067
00068 #define AST_MAX_WATCHERS 256
00069 #define MAX_DIAL_FEATURE_OPTIONS 30
00070
00071 struct feature_group_exten {
00072 AST_LIST_ENTRY(feature_group_exten) entry;
00073 AST_DECLARE_STRING_FIELDS(
00074 AST_STRING_FIELD(exten);
00075 );
00076 struct ast_call_feature *feature;
00077 };
00078
00079 struct feature_group {
00080 AST_LIST_ENTRY(feature_group) entry;
00081 AST_DECLARE_STRING_FIELDS(
00082 AST_STRING_FIELD(gname);
00083 );
00084 AST_LIST_HEAD_NOLOCK(, feature_group_exten) features;
00085 };
00086
00087 static AST_RWLIST_HEAD_STATIC(feature_groups, feature_group);
00088
00089 static char *parkedcall = "ParkedCall";
00090
00091 static char pickup_ext[AST_MAX_EXTENSION];
00092
00093
00094
00095
00096 struct parkeduser {
00097 struct ast_channel *chan;
00098 struct timeval start;
00099 int parkingnum;
00100 char parkingexten[AST_MAX_EXTENSION];
00101 char context[AST_MAX_CONTEXT];
00102 char exten[AST_MAX_EXTENSION];
00103 int priority;
00104 int parkingtime;
00105 int notquiteyet;
00106 char peername[1024];
00107 unsigned char moh_trys;
00108 struct ast_parkinglot *parkinglot;
00109 AST_LIST_ENTRY(parkeduser) list;
00110 };
00111
00112
00113 struct ast_parkinglot {
00114 char name[AST_MAX_CONTEXT];
00115 char parking_con[AST_MAX_EXTENSION];
00116 char parking_con_dial[AST_MAX_EXTENSION];
00117 int parking_start;
00118 int parking_stop;
00119 int parking_offset;
00120 int parkfindnext;
00121 int parkingtime;
00122 char mohclass[MAX_MUSICCLASS];
00123 int parkaddhints;
00124 int parkedcalltransfers;
00125 int parkedcallreparking;
00126 int parkedcallhangup;
00127 int parkedcallrecording;
00128 AST_LIST_HEAD(parkinglot_parklist, parkeduser) parkings;
00129 };
00130
00131
00132 static struct ao2_container *parkinglots;
00133
00134 struct ast_parkinglot *default_parkinglot;
00135 char parking_ext[AST_MAX_EXTENSION];
00136
00137 static char courtesytone[256];
00138 static int parkedplay = 0;
00139 static char xfersound[256];
00140 static char xferfailsound[256];
00141
00142 static int adsipark;
00143
00144 static int transferdigittimeout;
00145 static int featuredigittimeout;
00146 static int comebacktoorigin = 1;
00147
00148 static int atxfernoanswertimeout;
00149 static unsigned int atxferdropcall;
00150 static unsigned int atxferloopdelay;
00151 static unsigned int atxfercallbackretries;
00152
00153 static char *registrar = "features";
00154
00155
00156 static char *synopsis = "Answer a parked call";
00157
00158 static char *descrip = "ParkedCall(exten): "
00159 "Used to connect to a parked call. This application is always\n"
00160 "registered internally and does not need to be explicitly added\n"
00161 "into the dialplan, although you should include the 'parkedcalls'\n"
00162 "context. If no extension is provided, then the first available\n"
00163 "parked call will be acquired.\n";
00164
00165 static char *parkcall = PARK_APP_NAME;
00166
00167 static char *synopsis2 = "Park yourself";
00168
00169 static char *descrip2 =
00170 " Park([timeout,[return_context,[return_exten,[return_priority,[options]]]]]):"
00171 "Used to park yourself (typically in combination with a supervised\n"
00172 "transfer to know the parking space). This application is always\n"
00173 "registered internally and does not need to be explicitly added\n"
00174 "into the dialplan, although you should include the 'parkedcalls'\n"
00175 "context (or the context specified in features.conf).\n\n"
00176 "If you set the PARKINGEXTEN variable to an extension in your\n"
00177 "parking context, Park() will park the call on that extension, unless\n"
00178 "it already exists. In that case, execution will continue at next\n"
00179 "priority.\n"
00180 " This application can accept arguments as well.\n"
00181 " timeout - A custom parking timeout for this parked call.\n"
00182 " return_context - The context to return the call to after it times out.\n"
00183 " return_exten - The extension to return the call to after it times out.\n"
00184 " return_priority - The priority to return the call to after it times out.\n"
00185 " options - A list of options for this parked call. Valid options are:\n"
00186 " 'r' - Send ringing instead of MOH to the parked call.\n"
00187 " 'R' - Randomize the selection of a parking space.\n"
00188 " 's' - Silence announcement of the parking space number.\n"
00189 "";
00190
00191 static struct ast_app *monitor_app = NULL;
00192 static int monitor_ok = 1;
00193
00194 static struct ast_app *mixmonitor_app = NULL;
00195 static int mixmonitor_ok = 1;
00196
00197 static struct ast_app *stopmixmonitor_app = NULL;
00198 static int stopmixmonitor_ok = 1;
00199
00200 static pthread_t parking_thread;
00201 struct ast_dial_features {
00202 struct ast_flags features_caller;
00203 struct ast_flags features_callee;
00204 int is_caller;
00205 };
00206
00207 static void *dial_features_duplicate(void *data)
00208 {
00209 struct ast_dial_features *df = data, *df_copy;
00210
00211 if (!(df_copy = ast_calloc(1, sizeof(*df)))) {
00212 return NULL;
00213 }
00214
00215 memcpy(df_copy, df, sizeof(*df));
00216
00217 return df_copy;
00218 }
00219
00220 static void dial_features_destroy(void *data)
00221 {
00222 struct ast_dial_features *df = data;
00223 if (df) {
00224 ast_free(df);
00225 }
00226 }
00227
00228 const struct ast_datastore_info dial_features_info = {
00229 .type = "dial-features",
00230 .destroy = dial_features_destroy,
00231 .duplicate = dial_features_duplicate,
00232 };
00233
00234
00235 static struct ast_parkinglot *parkinglot_addref(struct ast_parkinglot *parkinglot);
00236 static void parkinglot_unref(struct ast_parkinglot *parkinglot);
00237 static void parkinglot_destroy(void *obj);
00238 int manage_parkinglot(struct ast_parkinglot *curlot, fd_set *rfds, fd_set *efds, fd_set *nrfds, fd_set *nefds, int *fs, int *max);
00239 struct ast_parkinglot *find_parkinglot(const char *name);
00240
00241
00242 const char *ast_parking_ext(void)
00243 {
00244 return parking_ext;
00245 }
00246
00247 const char *ast_pickup_ext(void)
00248 {
00249 return pickup_ext;
00250 }
00251
00252 struct ast_bridge_thread_obj
00253 {
00254 struct ast_bridge_config bconfig;
00255 struct ast_channel *chan;
00256 struct ast_channel *peer;
00257 unsigned int return_to_pbx:1;
00258 };
00259
00260 static int parkinglot_hash_cb(const void *obj, const int flags)
00261 {
00262 const struct ast_parkinglot *parkinglot = obj;
00263
00264 return ast_str_case_hash(parkinglot->name);
00265 }
00266
00267 static int parkinglot_cmp_cb(void *obj, void *arg, int flags)
00268 {
00269 struct ast_parkinglot *parkinglot = obj, *parkinglot2 = arg;
00270
00271 return !strcasecmp(parkinglot->name, parkinglot2->name) ? CMP_MATCH | CMP_STOP : 0;
00272 }
00273
00274
00275
00276
00277
00278 static void set_c_e_p(struct ast_channel *chan, const char *context, const char *ext, int pri)
00279 {
00280 ast_copy_string(chan->context, context, sizeof(chan->context));
00281 ast_copy_string(chan->exten, ext, sizeof(chan->exten));
00282 chan->priority = pri;
00283 }
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293 static void check_goto_on_transfer(struct ast_channel *chan)
00294 {
00295 struct ast_channel *xferchan;
00296 const char *val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR");
00297 char *x, *goto_on_transfer;
00298 struct ast_frame *f;
00299
00300 if (ast_strlen_zero(val))
00301 return;
00302
00303 goto_on_transfer = ast_strdupa(val);
00304
00305 if (!(xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "%s", chan->name)))
00306 return;
00307
00308 for (x = goto_on_transfer; x && *x; x++) {
00309 if (*x == '^')
00310 *x = '|';
00311 }
00312
00313 xferchan->readformat = chan->readformat;
00314 xferchan->writeformat = chan->writeformat;
00315 ast_channel_masquerade(xferchan, chan);
00316 ast_parseable_goto(xferchan, goto_on_transfer);
00317 xferchan->_state = AST_STATE_UP;
00318 ast_clear_flag(xferchan, AST_FLAGS_ALL);
00319 xferchan->_softhangup = 0;
00320 if ((f = ast_read(xferchan))) {
00321 ast_frfree(f);
00322 f = NULL;
00323 ast_pbx_start(xferchan);
00324 } else {
00325 ast_hangup(xferchan);
00326 }
00327 }
00328
00329 static struct ast_channel *ast_feature_request_and_dial(struct ast_channel *caller, struct ast_channel *transferee, const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name, int igncallerstate, const char *language);
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339 static void *ast_bridge_call_thread(void *data)
00340 {
00341 struct ast_bridge_thread_obj *tobj = data;
00342 int res;
00343
00344 tobj->chan->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge";
00345 tobj->chan->data = tobj->peer->name;
00346 tobj->peer->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge";
00347 tobj->peer->data = tobj->chan->name;
00348
00349 ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
00350
00351 if (tobj->return_to_pbx) {
00352 if (!ast_check_hangup(tobj->peer)) {
00353 ast_log(LOG_VERBOSE, "putting peer %s into PBX again\n", tobj->peer->name);
00354 res = ast_pbx_start(tobj->peer);
00355 if (res != AST_PBX_SUCCESS)
00356 ast_log(LOG_WARNING, "FAILED continuing PBX on peer %s\n", tobj->peer->name);
00357 } else
00358 ast_hangup(tobj->peer);
00359 if (!ast_check_hangup(tobj->chan)) {
00360 ast_log(LOG_VERBOSE, "putting chan %s into PBX again\n", tobj->chan->name);
00361 res = ast_pbx_start(tobj->chan);
00362 if (res != AST_PBX_SUCCESS)
00363 ast_log(LOG_WARNING, "FAILED continuing PBX on chan %s\n", tobj->chan->name);
00364 } else
00365 ast_hangup(tobj->chan);
00366 } else {
00367 ast_hangup(tobj->chan);
00368 ast_hangup(tobj->peer);
00369 }
00370
00371 ast_free(tobj);
00372
00373 return NULL;
00374 }
00375
00376
00377
00378
00379
00380
00381
00382 static void ast_bridge_call_thread_launch(void *data)
00383 {
00384 pthread_t thread;
00385 pthread_attr_t attr;
00386 struct sched_param sched;
00387
00388 pthread_attr_init(&attr);
00389 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00390 ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data);
00391 pthread_attr_destroy(&attr);
00392 memset(&sched, 0, sizeof(sched));
00393 pthread_setschedparam(thread, SCHED_RR, &sched);
00394 }
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404 static int adsi_announce_park(struct ast_channel *chan, char *parkingexten)
00405 {
00406 int res;
00407 int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
00408 char tmp[256];
00409 char *message[5] = {NULL, NULL, NULL, NULL, NULL};
00410
00411 snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten);
00412 message[0] = tmp;
00413 res = ast_adsi_load_session(chan, NULL, 0, 1);
00414 if (res == -1)
00415 return res;
00416 return ast_adsi_print(chan, message, justify, 1);
00417 }
00418
00419
00420 static const char *findparkinglotname(struct ast_channel *chan)
00421 {
00422 const char *temp, *parkinglot = NULL;
00423
00424
00425 if (!ast_strlen_zero(chan->parkinglot))
00426 parkinglot = chan->parkinglot;
00427
00428
00429
00430 if ((temp = pbx_builtin_getvar_helper(chan, "PARKINGLOT")))
00431 return temp;
00432
00433 return parkinglot;
00434 }
00435
00436
00437 static void notify_metermaids(const char *exten, char *context, enum ast_device_state state)
00438 {
00439 ast_debug(4, "Notification of state change to metermaids %s@%s\n to state '%s'",
00440 exten, context, devstate2str(state));
00441
00442 ast_devstate_changed(state, "park:%s@%s", exten, context);
00443 }
00444
00445
00446 static enum ast_device_state metermaidstate(const char *data)
00447 {
00448 char *context;
00449 char *exten;
00450
00451 context = ast_strdupa(data);
00452
00453 exten = strsep(&context, "@");
00454 if (!context)
00455 return AST_DEVICE_INVALID;
00456
00457 ast_debug(4, "Checking state of exten %s in context %s\n", exten, context);
00458
00459 if (!ast_exists_extension(NULL, context, exten, 1, NULL))
00460 return AST_DEVICE_NOT_INUSE;
00461
00462 return AST_DEVICE_INUSE;
00463 }
00464
00465
00466 enum ast_park_call_options {
00467
00468 AST_PARK_OPT_RINGING = (1 << 0),
00469
00470
00471 AST_PARK_OPT_RANDOMIZE = (1 << 1),
00472
00473 AST_PARK_OPT_SILENCE = (1 << 2),
00474 };
00475
00476 struct ast_park_call_args {
00477
00478
00479
00480 int timeout;
00481
00482
00483 int *extout;
00484 const char *orig_chan_name;
00485 const char *return_con;
00486 const char *return_ext;
00487 int return_pri;
00488 uint32_t flags;
00489
00490 struct parkeduser *pu;
00491 };
00492
00493 static struct parkeduser *park_space_reserve(struct ast_channel *chan,
00494 struct ast_channel *peer, struct ast_park_call_args *args)
00495 {
00496 struct parkeduser *pu;
00497 int i, parking_space = -1, parking_range;
00498 const char *parkinglotname = NULL;
00499 const char *parkingexten;
00500 struct ast_parkinglot *parkinglot = NULL;
00501
00502 if (peer)
00503 parkinglotname = findparkinglotname(peer);
00504
00505 if (parkinglotname) {
00506 if (option_debug)
00507 ast_log(LOG_DEBUG, "Found chanvar Parkinglot: %s\n", parkinglotname);
00508 parkinglot = find_parkinglot(parkinglotname);
00509 }
00510 if (!parkinglot)
00511 parkinglot = default_parkinglot;
00512
00513 parkinglot_addref(parkinglot);
00514 if (option_debug)
00515 ast_log(LOG_DEBUG, "Parkinglot: %s\n", parkinglot->name);
00516
00517
00518 if (!(pu = ast_calloc(1, sizeof(*pu)))) {
00519 parkinglot_unref(parkinglot);
00520 return NULL;
00521 }
00522
00523
00524 AST_LIST_LOCK(&parkinglot->parkings);
00525
00526 parkingexten = pbx_builtin_getvar_helper(chan, "PARKINGEXTEN");
00527 if (!ast_strlen_zero(parkingexten)) {
00528
00529
00530
00531
00532
00533
00534 if (sscanf(parkingexten, "%d", &parking_space) != 1 || parking_space < 0) {
00535 AST_LIST_UNLOCK(&parkinglot->parkings);
00536 parkinglot_unref(parkinglot);
00537 free(pu);
00538 ast_log(LOG_WARNING, "PARKINGEXTEN does not indicate a valid parking slot: '%s'.\n", parkingexten);
00539 return NULL;
00540 }
00541 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space);
00542
00543 if (ast_exists_extension(NULL, parkinglot->parking_con, pu->parkingexten, 1, NULL)) {
00544 AST_LIST_UNLOCK(&parkinglot->parkings);
00545 parkinglot_unref(parkinglot);
00546 ast_free(pu);
00547 ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parkinglot->parking_con);
00548 return NULL;
00549 }
00550 } else {
00551 int start;
00552 struct parkeduser *cur = NULL;
00553
00554
00555 parking_range = parkinglot->parking_stop - parkinglot->parking_start + 1;
00556
00557 if (ast_test_flag(args, AST_PARK_OPT_RANDOMIZE)) {
00558 start = ast_random() % (parkinglot->parking_stop - parkinglot->parking_start + 1);
00559 } else {
00560 start = parkinglot->parking_start;
00561 }
00562
00563 for (i = start; 1; i++) {
00564 if (i == parkinglot->parking_stop + 1) {
00565 i = parkinglot->parking_start - 1;
00566 continue;
00567 }
00568
00569 AST_LIST_TRAVERSE(&parkinglot->parkings, cur, list) {
00570 if (cur->parkingnum == i) {
00571 break;
00572 }
00573 }
00574
00575 if (!cur || i == start - 1) {
00576 parking_space = i;
00577 break;
00578 }
00579 }
00580
00581 if (i == start - 1 && cur) {
00582 ast_log(LOG_WARNING, "No more parking spaces\n");
00583 ast_free(pu);
00584 AST_LIST_UNLOCK(&parkinglot->parkings);
00585 parkinglot_unref(parkinglot);
00586 return NULL;
00587 }
00588
00589 if (parkinglot->parkfindnext)
00590 parkinglot->parking_offset = parking_space - parkinglot->parking_start + 1;
00591 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space);
00592 }
00593
00594 pu->notquiteyet = 1;
00595 pu->parkingnum = parking_space;
00596 pu->parkinglot = parkinglot;
00597 AST_LIST_INSERT_TAIL(&parkinglot->parkings, pu, list);
00598 parkinglot_unref(parkinglot);
00599
00600 return pu;
00601 }
00602
00603
00604 static int ast_park_call_full(struct ast_channel *chan, struct ast_channel *peer, struct ast_park_call_args *args)
00605 {
00606 struct ast_context *con;
00607 int parkingnum_copy;
00608 struct parkeduser *pu = args->pu;
00609 const char *event_from;
00610
00611 if (pu == NULL)
00612 pu = park_space_reserve(chan, peer, args);
00613 if (pu == NULL)
00614 return 1;
00615
00616 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", pu->parkingnum);
00617
00618 chan->appl = "Parked Call";
00619 chan->data = NULL;
00620
00621 pu->chan = chan;
00622
00623
00624 if (chan != peer) {
00625 if (ast_test_flag(args, AST_PARK_OPT_RINGING)) {
00626 ast_indicate(pu->chan, AST_CONTROL_RINGING);
00627 } else {
00628 ast_indicate_data(pu->chan, AST_CONTROL_HOLD,
00629 S_OR(pu->parkinglot->mohclass, NULL),
00630 !ast_strlen_zero(pu->parkinglot->mohclass) ? strlen(pu->parkinglot->mohclass) + 1 : 0);
00631 }
00632 }
00633
00634 pu->start = ast_tvnow();
00635 pu->parkingtime = (args->timeout > 0) ? args->timeout : pu->parkinglot->parkingtime;
00636 parkingnum_copy = pu->parkingnum;
00637 if (args->extout)
00638 *(args->extout) = pu->parkingnum;
00639
00640 if (peer) {
00641
00642
00643
00644
00645
00646 if (!strcasecmp(peer->tech->type, "Local")) {
00647 struct ast_channel *tmpchan, *base_peer;
00648 char other_side[AST_CHANNEL_NAME];
00649 char *c;
00650 ast_copy_string(other_side, S_OR(args->orig_chan_name, peer->name), sizeof(other_side));
00651 if ((c = strrchr(other_side, ';'))) {
00652 *++c = '1';
00653 }
00654 if ((tmpchan = ast_get_channel_by_name_locked(other_side))) {
00655 if ((base_peer = ast_bridged_channel(tmpchan))) {
00656 ast_copy_string(pu->peername, base_peer->name, sizeof(pu->peername));
00657 }
00658 ast_channel_unlock(tmpchan);
00659 }
00660 } else {
00661 ast_copy_string(pu->peername, S_OR(args->orig_chan_name, peer->name), sizeof(pu->peername));
00662 }
00663 }
00664
00665
00666
00667 ast_copy_string(pu->context,
00668 S_OR(args->return_con, S_OR(chan->macrocontext, chan->context)),
00669 sizeof(pu->context));
00670 ast_copy_string(pu->exten,
00671 S_OR(args->return_ext, S_OR(chan->macroexten, chan->exten)),
00672 sizeof(pu->exten));
00673 pu->priority = pu->priority ? pu->priority :
00674 (chan->macropriority ? chan->macropriority : chan->priority);
00675
00676
00677
00678 if (peer != chan)
00679 pu->notquiteyet = 0;
00680
00681
00682 pthread_kill(parking_thread, SIGURG);
00683 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));
00684
00685 if (peer) {
00686 event_from = peer->name;
00687 } else {
00688 event_from = pbx_builtin_getvar_helper(chan, "BLINDTRANSFER");
00689 }
00690
00691 manager_event(EVENT_FLAG_CALL, "ParkedCall",
00692 "Exten: %s\r\n"
00693 "Channel: %s\r\n"
00694 "Parkinglot: %s\r\n"
00695 "From: %s\r\n"
00696 "Timeout: %ld\r\n"
00697 "CallerIDNum: %s\r\n"
00698 "CallerIDName: %s\r\n"
00699 "Uniqueid: %s\r\n",
00700 pu->parkingexten, pu->chan->name, pu->parkinglot->name, event_from ? event_from : "",
00701 (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL),
00702 S_OR(pu->chan->cid.cid_num, "<unknown>"),
00703 S_OR(pu->chan->cid.cid_name, "<unknown>"),
00704 pu->chan->uniqueid
00705 );
00706
00707 if (peer && adsipark && ast_adsi_available(peer)) {
00708 adsi_announce_park(peer, pu->parkingexten);
00709 ast_adsi_unload_session(peer);
00710 }
00711
00712 con = ast_context_find_or_create(NULL, NULL, pu->parkinglot->parking_con, registrar);
00713 if (!con)
00714 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", pu->parkinglot->parking_con);
00715 if (con) {
00716 if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, ast_strdup(pu->parkingexten), ast_free_ptr, registrar))
00717 notify_metermaids(pu->parkingexten, pu->parkinglot->parking_con, AST_DEVICE_INUSE);
00718 }
00719
00720 AST_LIST_UNLOCK(&pu->parkinglot->parkings);
00721
00722
00723 if (peer && !ast_test_flag(args, AST_PARK_OPT_SILENCE) && (ast_strlen_zero(args->orig_chan_name) || !strcasecmp(peer->name, args->orig_chan_name))) {
00724
00725 ast_set_flag(peer, AST_FLAG_MASQ_NOSTREAM);
00726
00727 ast_say_digits(peer, pu->parkingnum, "", peer->language);
00728 ast_clear_flag(peer, AST_FLAG_MASQ_NOSTREAM);
00729 }
00730 if (peer == chan) {
00731
00732 ast_indicate_data(pu->chan, AST_CONTROL_HOLD,
00733 S_OR(pu->parkinglot->mohclass, NULL),
00734 !ast_strlen_zero(pu->parkinglot->mohclass) ? strlen(pu->parkinglot->mohclass) + 1 : 0);
00735 pu->notquiteyet = 0;
00736 pthread_kill(parking_thread, SIGURG);
00737 }
00738 return 0;
00739 }
00740
00741
00742 int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
00743 {
00744 struct ast_park_call_args args = {
00745 .timeout = timeout,
00746 .extout = extout,
00747 };
00748
00749 return ast_park_call_full(chan, peer, &args);
00750 }
00751
00752 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)
00753 {
00754 struct ast_channel *chan;
00755 struct ast_frame *f;
00756 int park_status;
00757 struct ast_park_call_args park_args = {0,};
00758
00759 if (!args) {
00760 args = &park_args;
00761 args->timeout = timeout;
00762 args->extout = extout;
00763 }
00764
00765 if ((args->pu = park_space_reserve(rchan, peer, args)) == NULL) {
00766 if (peer)
00767 ast_stream_and_wait(peer, "beeperr", "");
00768 return AST_FEATURE_RETURN_PARKFAILED;
00769 }
00770
00771
00772 if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) {
00773 ast_log(LOG_WARNING, "Unable to create parked channel\n");
00774 return -1;
00775 }
00776
00777
00778 chan->readformat = rchan->readformat;
00779 chan->writeformat = rchan->writeformat;
00780 ast_channel_masquerade(chan, rchan);
00781
00782
00783 set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority);
00784
00785
00786 if ((f = ast_read(chan)))
00787 ast_frfree(f);
00788
00789 if (peer == rchan) {
00790 peer = chan;
00791 }
00792
00793 if (!play_announcement && args == &park_args) {
00794 args->orig_chan_name = ast_strdupa(chan->name);
00795 }
00796
00797 park_status = ast_park_call_full(chan, peer, args);
00798 if (park_status == 1) {
00799
00800 ast_hangup(chan);
00801 return -1;
00802 }
00803
00804 return 0;
00805 }
00806
00807
00808 int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
00809 {
00810 return masq_park_call(rchan, peer, timeout, extout, 0, NULL);
00811 }
00812
00813 static int masq_park_call_announce_args(struct ast_channel *rchan, struct ast_channel *peer, struct ast_park_call_args *args)
00814 {
00815 return masq_park_call(rchan, peer, 0, NULL, 1, args);
00816 }
00817
00818 static int masq_park_call_announce(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
00819 {
00820 return masq_park_call(rchan, peer, timeout, extout, 1, NULL);
00821 }
00822
00823
00824
00825
00826
00827
00828
00829 static void set_peers(struct ast_channel **caller, struct ast_channel **callee,
00830 struct ast_channel *peer, struct ast_channel *chan, int sense)
00831 {
00832 if (sense == FEATURE_SENSE_PEER) {
00833 *caller = peer;
00834 *callee = chan;
00835 } else {
00836 *callee = peer;
00837 *caller = chan;
00838 }
00839 }
00840
00841
00842
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853 static int builtin_parkcall(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00854 {
00855 struct ast_channel *parker;
00856 struct ast_channel *parkee;
00857 int res = 0;
00858
00859 set_peers(&parker, &parkee, peer, chan, sense);
00860
00861
00862
00863
00864
00865
00866
00867
00868 if (chan->_state != AST_STATE_UP)
00869 res = ast_answer(chan);
00870 if (!res)
00871 res = ast_safe_sleep(chan, 1000);
00872
00873 if (!res) {
00874 res = masq_park_call_announce(parkee, parker, 0, NULL);
00875
00876 }
00877
00878 return res;
00879 }
00880
00881
00882
00883
00884 static int play_message_in_bridged_call(struct ast_channel *caller_chan, struct ast_channel *callee_chan, const char *audiofile)
00885 {
00886
00887 if (ast_autoservice_start(callee_chan))
00888 return -1;
00889 if (ast_stream_and_wait(caller_chan, audiofile, "")) {
00890 ast_log(LOG_WARNING, "Failed to play automon message!\n");
00891 ast_autoservice_stop(callee_chan);
00892 return -1;
00893 }
00894 if (ast_autoservice_stop(callee_chan))
00895 return -1;
00896
00897 if (ast_autoservice_start(caller_chan))
00898 return -1;
00899 if (ast_stream_and_wait(callee_chan, audiofile, "")) {
00900 ast_log(LOG_WARNING, "Failed to play automon message !\n");
00901 ast_autoservice_stop(caller_chan);
00902 return -1;
00903 }
00904 if (ast_autoservice_stop(caller_chan))
00905 return -1;
00906 return(0);
00907 }
00908
00909
00910
00911
00912
00913
00914
00915
00916
00917
00918
00919
00920
00921
00922
00923 static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00924 {
00925 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
00926 int x = 0;
00927 size_t len;
00928 struct ast_channel *caller_chan, *callee_chan;
00929 const char *automon_message_start = NULL;
00930 const char *automon_message_stop = NULL;
00931
00932 if (!monitor_ok) {
00933 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00934 return -1;
00935 }
00936
00937 if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) {
00938 monitor_ok = 0;
00939 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00940 return -1;
00941 }
00942
00943 set_peers(&caller_chan, &callee_chan, peer, chan, sense);
00944 if (caller_chan) {
00945 automon_message_start = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_START");
00946 automon_message_stop = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_STOP");
00947 }
00948
00949 if (!ast_strlen_zero(courtesytone)) {
00950 if(play_message_in_bridged_call(caller_chan, callee_chan, courtesytone) == -1) {
00951 return -1;
00952 }
00953 }
00954
00955 if (callee_chan->monitor) {
00956 ast_verb(4, "User hit '%s' to stop recording call.\n", code);
00957 if (!ast_strlen_zero(automon_message_stop)) {
00958 play_message_in_bridged_call(caller_chan, callee_chan, automon_message_stop);
00959 }
00960 callee_chan->monitor->stop(callee_chan, 1);
00961 return AST_FEATURE_RETURN_SUCCESS;
00962 }
00963
00964 if (caller_chan && callee_chan) {
00965 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT");
00966 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
00967 const char *touch_monitor_prefix = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_PREFIX");
00968
00969 if (!touch_format)
00970 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
00971
00972 if (!touch_monitor)
00973 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
00974
00975 if (!touch_monitor_prefix)
00976 touch_monitor_prefix = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_PREFIX");
00977
00978 if (touch_monitor) {
00979 len = strlen(touch_monitor) + 50;
00980 args = alloca(len);
00981 touch_filename = alloca(len);
00982 snprintf(touch_filename, len, "%s-%ld-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), touch_monitor);
00983 snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename);
00984 } else {
00985 caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name));
00986 callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name));
00987 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
00988 args = alloca(len);
00989 touch_filename = alloca(len);
00990 snprintf(touch_filename, len, "%s-%ld-%s-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), caller_chan_id, callee_chan_id);
00991 snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename);
00992 }
00993
00994 for(x = 0; x < strlen(args); x++) {
00995 if (args[x] == '/')
00996 args[x] = '-';
00997 }
00998
00999 ast_verb(4, "User hit '%s' to record call. filename: %s\n", code, args);
01000
01001 pbx_exec(callee_chan, monitor_app, args);
01002 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
01003 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
01004
01005 if (!ast_strlen_zero(automon_message_start)) {
01006 play_message_in_bridged_call(caller_chan, callee_chan, automon_message_start);
01007 }
01008
01009 return AST_FEATURE_RETURN_SUCCESS;
01010 }
01011
01012 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");
01013 return -1;
01014 }
01015
01016 static int builtin_automixmonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
01017 {
01018 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
01019 int x = 0;
01020 size_t len;
01021 struct ast_channel *caller_chan, *callee_chan;
01022 const char *mixmonitor_spy_type = "MixMonitor";
01023 int count = 0;
01024
01025 if (!mixmonitor_ok) {
01026 ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n");
01027 return -1;
01028 }
01029
01030 if (!(mixmonitor_app = pbx_findapp("MixMonitor"))) {
01031 mixmonitor_ok = 0;
01032 ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n");
01033 return -1;
01034 }
01035
01036 set_peers(&caller_chan, &callee_chan, peer, chan, sense);
01037
01038 if (!ast_strlen_zero(courtesytone)) {
01039 if (ast_autoservice_start(callee_chan))
01040 return -1;
01041 if (ast_stream_and_wait(caller_chan, courtesytone, "")) {
01042 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
01043 ast_autoservice_stop(callee_chan);
01044 return -1;
01045 }
01046 if (ast_autoservice_stop(callee_chan))
01047 return -1;
01048 }
01049
01050 ast_channel_lock(callee_chan);
01051 count = ast_channel_audiohook_count_by_source(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY);
01052 ast_channel_unlock(callee_chan);
01053
01054
01055 if (count > 0) {
01056
01057 ast_verb(3, "User hit '%s' to stop recording call.\n", code);
01058
01059
01060 ast_channel_lock(callee_chan);
01061 count = ast_channel_audiohook_count_by_source_running(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY);
01062 ast_channel_unlock(callee_chan);
01063 if (count > 0) {
01064 if (!stopmixmonitor_ok) {
01065 ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n");
01066 return -1;
01067 }
01068 if (!(stopmixmonitor_app = pbx_findapp("StopMixMonitor"))) {
01069 stopmixmonitor_ok = 0;
01070 ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n");
01071 return -1;
01072 } else {
01073 pbx_exec(callee_chan, stopmixmonitor_app, "");
01074 return AST_FEATURE_RETURN_SUCCESS;
01075 }
01076 }
01077
01078 ast_log(LOG_WARNING,"Stopped MixMonitors are attached to the channel.\n");
01079 }
01080
01081 if (caller_chan && callee_chan) {
01082 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR_FORMAT");
01083 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR");
01084
01085 if (!touch_format)
01086 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR_FORMAT");
01087
01088 if (!touch_monitor)
01089 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR");
01090
01091 if (touch_monitor) {
01092 len = strlen(touch_monitor) + 50;
01093 args = alloca(len);
01094 touch_filename = alloca(len);
01095 snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor);
01096 snprintf(args, len, "%s.%s,b", touch_filename, (touch_format) ? touch_format : "wav");
01097 } else {
01098 caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name));
01099 callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name));
01100 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
01101 args = alloca(len);
01102 touch_filename = alloca(len);
01103 snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id);
01104 snprintf(args, len, "%s.%s,b", touch_filename, S_OR(touch_format, "wav"));
01105 }
01106
01107 for( x = 0; x < strlen(args); x++) {
01108 if (args[x] == '/')
01109 args[x] = '-';
01110 }
01111
01112 ast_verb(3, "User hit '%s' to record call. filename: %s\n", code, touch_filename);
01113
01114 pbx_exec(callee_chan, mixmonitor_app, args);
01115 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename);
01116 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename);
01117 return AST_FEATURE_RETURN_SUCCESS;
01118
01119 }
01120
01121 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");
01122 return -1;
01123
01124 }
01125
01126 static int builtin_disconnect(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
01127 {
01128 ast_verb(4, "User hit '%s' to disconnect call.\n", code);
01129 return AST_FEATURE_RETURN_HANGUP;
01130 }
01131
01132 static int finishup(struct ast_channel *chan)
01133 {
01134 ast_indicate(chan, AST_CONTROL_UNHOLD);
01135
01136 return ast_autoservice_stop(chan);
01137 }
01138
01139
01140
01141
01142
01143
01144
01145
01146
01147 static const char *real_ctx(struct ast_channel *transferer, struct ast_channel *transferee)
01148 {
01149 const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT");
01150 if (ast_strlen_zero(s)) {
01151 s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT");
01152 }
01153 if (ast_strlen_zero(s)) {
01154 s = transferer->macrocontext;
01155 }
01156 if (ast_strlen_zero(s)) {
01157 s = transferer->context;
01158 }
01159 return s;
01160 }
01161
01162
01163
01164
01165
01166
01167
01168
01169
01170
01171
01172
01173
01174
01175
01176 static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
01177 {
01178 struct ast_channel *transferer;
01179 struct ast_channel *transferee;
01180 const char *transferer_real_context;
01181 char xferto[256];
01182 int res, parkstatus = 0;
01183
01184 set_peers(&transferer, &transferee, peer, chan, sense);
01185 transferer_real_context = real_ctx(transferer, transferee);
01186
01187 ast_autoservice_start(transferee);
01188 ast_indicate(transferee, AST_CONTROL_HOLD);
01189
01190 memset(xferto, 0, sizeof(xferto));
01191
01192
01193 res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY);
01194 if (res < 0) {
01195 finishup(transferee);
01196 return -1;
01197 }
01198 if (res > 0)
01199 xferto[0] = (char) res;
01200
01201 ast_stopstream(transferer);
01202 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
01203 if (res < 0) {
01204 finishup(transferee);
01205 return res;
01206 }
01207 if (!strcmp(xferto, ast_parking_ext())) {
01208 res = finishup(transferee);
01209 if (res)
01210 res = -1;
01211 else if (!(parkstatus = masq_park_call_announce(transferee, transferer, 0, NULL))) {
01212
01213
01214
01215
01216 return 0;
01217 } else {
01218 ast_log(LOG_WARNING, "Unable to park call %s, parkstatus = %d\n", transferee->name, parkstatus);
01219 }
01220
01221 } else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
01222 pbx_builtin_setvar_helper(transferer, "BLINDTRANSFER", transferee->name);
01223 pbx_builtin_setvar_helper(transferee, "BLINDTRANSFER", transferer->name);
01224 res=finishup(transferee);
01225 if (!transferer->cdr) {
01226 transferer->cdr=ast_cdr_alloc();
01227 if (transferer->cdr) {
01228 ast_cdr_init(transferer->cdr, transferer);
01229 ast_cdr_start(transferer->cdr);
01230 }
01231 }
01232 if (transferer->cdr) {
01233 struct ast_cdr *swap = transferer->cdr;
01234 ast_log(LOG_DEBUG,"transferer=%s; transferee=%s; lastapp=%s; lastdata=%s; chan=%s; dstchan=%s\n",
01235 transferer->name, transferee->name, transferer->cdr->lastapp, transferer->cdr->lastdata,
01236 transferer->cdr->channel, transferer->cdr->dstchannel);
01237 ast_log(LOG_DEBUG,"TRANSFEREE; lastapp=%s; lastdata=%s, chan=%s; dstchan=%s\n",
01238 transferee->cdr->lastapp, transferee->cdr->lastdata, transferee->cdr->channel, transferee->cdr->dstchannel);
01239 ast_log(LOG_DEBUG,"transferer_real_context=%s; xferto=%s\n", transferer_real_context, xferto);
01240
01241 transferer->cdr = transferee->cdr;
01242 transferee->cdr = swap;
01243 }
01244 if (!transferee->pbx) {
01245
01246 ast_verb(3, "Transferring %s to '%s' (context %s) priority 1\n"
01247 ,transferee->name, xferto, transferer_real_context);
01248 if (ast_async_goto(transferee, transferer_real_context, xferto, 1))
01249 ast_log(LOG_WARNING, "Async goto failed :-(\n");
01250 } else {
01251
01252 ast_set_flag(transferee, AST_FLAG_BRIDGE_HANGUP_DONT);
01253 ast_log(LOG_DEBUG,"ABOUT TO AST_ASYNC_GOTO, have a pbx... set HANGUP_DONT on chan=%s\n", transferee->name);
01254 set_c_e_p(transferee, transferer_real_context, xferto, 0);
01255 }
01256 check_goto_on_transfer(transferer);
01257 return res;
01258 } else {
01259 ast_verb(3, "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context);
01260 }
01261 if (parkstatus != AST_FEATURE_RETURN_PARKFAILED && ast_stream_and_wait(transferer, xferfailsound, AST_DIGIT_ANY) < 0) {
01262 finishup(transferee);
01263 return -1;
01264 }
01265 ast_stopstream(transferer);
01266 res = finishup(transferee);
01267 if (res) {
01268 ast_verb(2, "Hungup during autoservice stop on '%s'\n", transferee->name);
01269 return res;
01270 }
01271 return AST_FEATURE_RETURN_SUCCESS;
01272 }
01273
01274
01275
01276
01277
01278
01279
01280
01281 static int check_compat(struct ast_channel *c, struct ast_channel *newchan)
01282 {
01283 if (ast_channel_make_compatible(c, newchan) < 0) {
01284 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n",
01285 c->name, newchan->name);
01286 ast_hangup(newchan);
01287 return -1;
01288 }
01289 return 0;
01290 }
01291
01292
01293
01294
01295
01296
01297
01298
01299
01300
01301
01302
01303
01304
01305
01306
01307 static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
01308 {
01309 struct ast_channel *transferer;
01310 struct ast_channel *transferee;
01311 const char *transferer_real_context;
01312 char xferto[256] = "";
01313 int res;
01314 int outstate=0;
01315 struct ast_channel *newchan;
01316 struct ast_channel *xferchan;
01317 struct ast_bridge_thread_obj *tobj;
01318 struct ast_bridge_config bconfig;
01319 struct ast_frame *f;
01320 int l;
01321 struct ast_datastore *features_datastore;
01322 struct ast_dial_features *dialfeatures = NULL;
01323
01324 ast_debug(1, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense);
01325 set_peers(&transferer, &transferee, peer, chan, sense);
01326 transferer_real_context = real_ctx(transferer, transferee);
01327
01328 ast_autoservice_start(transferee);
01329 ast_indicate(transferee, AST_CONTROL_HOLD);
01330
01331
01332 res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY);
01333 if (res < 0) {
01334 finishup(transferee);
01335 return res;
01336 }
01337 if (res > 0)
01338 xferto[0] = (char) res;
01339
01340
01341 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
01342 if (res < 0) {
01343 finishup(transferee);
01344 return res;
01345 }
01346 if (res == 0) {
01347 ast_log(LOG_WARNING, "Did not read data.\n");
01348 finishup(transferee);
01349 if (ast_stream_and_wait(transferer, "beeperr", ""))
01350 return -1;
01351 return AST_FEATURE_RETURN_SUCCESS;
01352 }
01353
01354
01355 if (!ast_exists_extension(transferer, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
01356 ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context);
01357 finishup(transferee);
01358 if (ast_stream_and_wait(transferer, "beeperr", ""))
01359 return -1;
01360 return AST_FEATURE_RETURN_SUCCESS;
01361 }
01362
01363
01364
01365 if (!strcmp(xferto, ast_parking_ext())) {
01366 finishup(transferee);
01367 return builtin_parkcall(chan, peer, config, code, sense, data);
01368 }
01369
01370 l = strlen(xferto);
01371 snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context);
01372
01373
01374
01375 if (transferee) {
01376 const char *chan1_attended_sound = pbx_builtin_getvar_helper(transferer, "ATTENDED_TRANSFER_COMPLETE_SOUND");
01377 const char *chan2_attended_sound = pbx_builtin_getvar_helper(transferee, "ATTENDED_TRANSFER_COMPLETE_SOUND");
01378
01379 if (!ast_strlen_zero(chan1_attended_sound)) {
01380 pbx_builtin_setvar_helper(transferer, "BRIDGE_PLAY_SOUND", chan1_attended_sound);
01381 }
01382 if (!ast_strlen_zero(chan2_attended_sound)) {
01383 pbx_builtin_setvar_helper(transferee, "BRIDGE_PLAY_SOUND", chan2_attended_sound);
01384 }
01385 }
01386
01387 newchan = ast_feature_request_and_dial(transferer, transferee, "Local", ast_best_codec(transferer->nativeformats),
01388 xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, 1, transferer->language);
01389
01390 if (!ast_check_hangup(transferer)) {
01391
01392 ast_indicate(transferer, -1);
01393 if (!newchan) {
01394 finishup(transferee);
01395
01396 if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY &&
01397 ast_stream_and_wait(transferer, xferfailsound, ""))
01398 return -1;
01399 if (ast_stream_and_wait(transferer, xfersound, ""))
01400 ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
01401 return AST_FEATURE_RETURN_SUCCESS;
01402 }
01403
01404 if (check_compat(transferer, newchan)) {
01405
01406 finishup(transferee);
01407 return -1;
01408 }
01409 memset(&bconfig,0,sizeof(struct ast_bridge_config));
01410 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
01411 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
01412 res = ast_bridge_call(transferer, newchan, &bconfig);
01413 if (ast_check_hangup(newchan) || !ast_check_hangup(transferer)) {
01414 ast_hangup(newchan);
01415 if (ast_stream_and_wait(transferer, xfersound, ""))
01416 ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
01417 finishup(transferee);
01418 transferer->_softhangup = 0;
01419 return AST_FEATURE_RETURN_SUCCESS;
01420 }
01421 if (check_compat(transferee, newchan)) {
01422 finishup(transferee);
01423 return -1;
01424 }
01425 ast_indicate(transferee, AST_CONTROL_UNHOLD);
01426
01427 if ((ast_autoservice_stop(transferee) < 0)
01428 || (ast_waitfordigit(transferee, 100) < 0)
01429 || (ast_waitfordigit(newchan, 100) < 0)
01430 || ast_check_hangup(transferee)
01431 || ast_check_hangup(newchan)) {
01432 ast_hangup(newchan);
01433 return -1;
01434 }
01435 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name);
01436 if (!xferchan) {
01437 ast_hangup(newchan);
01438 return -1;
01439 }
01440
01441 xferchan->visible_indication = transferer->visible_indication;
01442 xferchan->readformat = transferee->readformat;
01443 xferchan->writeformat = transferee->writeformat;
01444 ast_channel_masquerade(xferchan, transferee);
01445 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
01446 xferchan->_state = AST_STATE_UP;
01447 ast_clear_flag(xferchan, AST_FLAGS_ALL);
01448 xferchan->_softhangup = 0;
01449 if ((f = ast_read(xferchan)))
01450 ast_frfree(f);
01451 newchan->_state = AST_STATE_UP;
01452 ast_clear_flag(newchan, AST_FLAGS_ALL);
01453 newchan->_softhangup = 0;
01454 if (!(tobj = ast_calloc(1, sizeof(*tobj)))) {
01455 ast_hangup(xferchan);
01456 ast_hangup(newchan);
01457 return -1;
01458 }
01459
01460 ast_channel_lock(newchan);
01461 if ((features_datastore = ast_channel_datastore_find(newchan, &dial_features_info, NULL))) {
01462 dialfeatures = features_datastore->data;
01463 }
01464 ast_channel_unlock(newchan);
01465
01466 if (dialfeatures) {
01467
01468
01469 ast_copy_flags(&(config->features_callee), &(dialfeatures->features_caller), AST_FLAGS_ALL);
01470 dialfeatures = NULL;
01471 }
01472
01473 ast_channel_lock(xferchan);
01474 if ((features_datastore = ast_channel_datastore_find(xferchan, &dial_features_info, NULL))) {
01475 dialfeatures = features_datastore->data;
01476 }
01477 ast_channel_unlock(xferchan);
01478
01479 if (dialfeatures) {
01480 ast_copy_flags(&(config->features_caller), &(dialfeatures->features_caller), AST_FLAGS_ALL);
01481 }
01482
01483 tobj->chan = newchan;
01484 tobj->peer = xferchan;
01485 tobj->bconfig = *config;
01486
01487 if (tobj->bconfig.end_bridge_callback_data_fixup) {
01488 tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan);
01489 }
01490
01491 if (ast_stream_and_wait(newchan, xfersound, ""))
01492 ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
01493 ast_bridge_call_thread_launch(tobj);
01494 return -1;
01495 } else if (!ast_check_hangup(transferee)) {
01496
01497 if (ast_autoservice_stop(transferee) < 0) {
01498 ast_hangup(newchan);
01499 return -1;
01500 }
01501
01502 if (!newchan) {
01503 unsigned int tries = 0;
01504 char *transferer_tech, *transferer_name = ast_strdupa(transferer->name);
01505
01506 transferer_tech = strsep(&transferer_name, "/");
01507 transferer_name = strsep(&transferer_name, "-");
01508
01509 if (ast_strlen_zero(transferer_name) || ast_strlen_zero(transferer_tech)) {
01510 ast_log(LOG_WARNING, "Transferer has invalid channel name: '%s'\n", transferer->name);
01511 if (ast_stream_and_wait(transferee, "beeperr", ""))
01512 return -1;
01513 return AST_FEATURE_RETURN_SUCCESS;
01514 }
01515
01516 ast_log(LOG_NOTICE, "We're trying to call %s/%s\n", transferer_tech, transferer_name);
01517 newchan = ast_feature_request_and_dial(transferee, NULL, transferer_tech, ast_best_codec(transferee->nativeformats),
01518 transferer_name, atxfernoanswertimeout, &outstate, transferee->cid.cid_num, transferee->cid.cid_name, 0, transferer->language);
01519 while (!newchan && !atxferdropcall && tries < atxfercallbackretries) {
01520
01521 ast_autoservice_start(transferee);
01522 ast_indicate(transferee, AST_CONTROL_HOLD);
01523
01524 newchan = ast_feature_request_and_dial(transferer, transferee, "Local", ast_best_codec(transferer->nativeformats),
01525 xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, 1, transferer->language);
01526 if (ast_autoservice_stop(transferee) < 0) {
01527 if (newchan)
01528 ast_hangup(newchan);
01529 return -1;
01530 }
01531 if (!newchan) {
01532
01533 ast_debug(1, "Sleeping for %d ms before callback.\n", atxferloopdelay);
01534 ast_safe_sleep(transferee, atxferloopdelay);
01535 ast_debug(1, "Trying to callback...\n");
01536 newchan = ast_feature_request_and_dial(transferee, NULL, transferer_tech, ast_best_codec(transferee->nativeformats),
01537 transferer_name, atxfernoanswertimeout, &outstate, transferee->cid.cid_num, transferee->cid.cid_name, 0, transferer->language);
01538 }
01539 tries++;
01540 }
01541 }
01542 if (!newchan)
01543 return -1;
01544
01545
01546 if (check_compat(transferee, newchan)) {
01547 finishup(transferee);
01548 return -1;
01549 }
01550 ast_indicate(transferee, AST_CONTROL_UNHOLD);
01551
01552 if ((ast_waitfordigit(transferee, 100) < 0)
01553 || (ast_waitfordigit(newchan, 100) < 0)
01554 || ast_check_hangup(transferee)
01555 || ast_check_hangup(newchan)) {
01556 ast_hangup(newchan);
01557 return -1;
01558 }
01559
01560 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name);
01561 if (!xferchan) {
01562 ast_hangup(newchan);
01563 return -1;
01564 }
01565
01566 xferchan->visible_indication = transferer->visible_indication;
01567 xferchan->readformat = transferee->readformat;
01568 xferchan->writeformat = transferee->writeformat;
01569 ast_channel_masquerade(xferchan, transferee);
01570 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
01571 xferchan->_state = AST_STATE_UP;
01572 ast_clear_flag(xferchan, AST_FLAGS_ALL);
01573 xferchan->_softhangup = 0;
01574 if ((f = ast_read(xferchan)))
01575 ast_frfree(f);
01576 newchan->_state = AST_STATE_UP;
01577 ast_clear_flag(newchan, AST_FLAGS_ALL);
01578 newchan->_softhangup = 0;
01579 if (!(tobj = ast_calloc(1, sizeof(*tobj)))) {
01580 ast_hangup(xferchan);
01581 ast_hangup(newchan);
01582 return -1;
01583 }
01584 tobj->chan = newchan;
01585 tobj->peer = xferchan;
01586 tobj->bconfig = *config;
01587
01588 if (tobj->bconfig.end_bridge_callback_data_fixup) {
01589 tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan);
01590 }
01591
01592 if (ast_stream_and_wait(newchan, xfersound, ""))
01593 ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
01594 ast_bridge_call_thread_launch(tobj);
01595 return -1;
01596 } else {
01597
01598 finishup(transferee);
01599 return -1;
01600 }
01601 }
01602
01603
01604 #define FEATURES_COUNT ARRAY_LEN(builtin_features)
01605
01606 AST_RWLOCK_DEFINE_STATIC(features_lock);
01607
01608 static struct ast_call_feature builtin_features[] =
01609 {
01610 { AST_FEATURE_REDIRECT, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
01611 { AST_FEATURE_REDIRECT, "Attended Transfer", "atxfer", "", "", builtin_atxfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
01612 { AST_FEATURE_AUTOMON, "One Touch Monitor", "automon", "", "", builtin_automonitor, AST_FEATURE_FLAG_NEEDSDTMF, "" },
01613 { AST_FEATURE_DISCONNECT, "Disconnect Call", "disconnect", "*", "*", builtin_disconnect, AST_FEATURE_FLAG_NEEDSDTMF, "" },
01614 { AST_FEATURE_PARKCALL, "Park Call", "parkcall", "", "", builtin_parkcall, AST_FEATURE_FLAG_NEEDSDTMF, "" },
01615 { AST_FEATURE_AUTOMIXMON, "One Touch MixMonitor", "automixmon", "", "", builtin_automixmonitor, AST_FEATURE_FLAG_NEEDSDTMF, "" },
01616 };
01617
01618
01619 static AST_RWLIST_HEAD_STATIC(feature_list, ast_call_feature);
01620
01621
01622 void ast_register_feature(struct ast_call_feature *feature)
01623 {
01624 if (!feature) {
01625 ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
01626 return;
01627 }
01628
01629 AST_RWLIST_WRLOCK(&feature_list);
01630 AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry);
01631 AST_RWLIST_UNLOCK(&feature_list);
01632
01633 ast_verb(2, "Registered Feature '%s'\n",feature->sname);
01634 }
01635
01636
01637
01638
01639
01640
01641
01642
01643 static struct feature_group* register_group(const char *fgname)
01644 {
01645 struct feature_group *fg;
01646
01647 if (!fgname) {
01648 ast_log(LOG_NOTICE, "You didn't pass a new group name!\n");
01649 return NULL;
01650 }
01651
01652 if (!(fg = ast_calloc(1, sizeof(*fg))))
01653 return NULL;
01654
01655 if (ast_string_field_init(fg, 128)) {
01656 ast_free(fg);
01657 return NULL;
01658 }
01659
01660 ast_string_field_set(fg, gname, fgname);
01661
01662 AST_LIST_INSERT_HEAD(&feature_groups, fg, entry);
01663
01664 ast_verb(2, "Registered group '%s'\n", fg->gname);
01665
01666 return fg;
01667 }
01668
01669
01670
01671
01672
01673
01674
01675
01676
01677
01678 static void register_group_feature(struct feature_group *fg, const char *exten, struct ast_call_feature *feature)
01679 {
01680 struct feature_group_exten *fge;
01681
01682 if (!fg) {
01683 ast_log(LOG_NOTICE, "You didn't pass a group!\n");
01684 return;
01685 }
01686
01687 if (!feature) {
01688 ast_log(LOG_NOTICE, "You didn't pass a feature!\n");
01689 return;
01690 }
01691
01692 if (!(fge = ast_calloc(1, sizeof(*fge))))
01693 return;
01694
01695 if (ast_string_field_init(fge, 128)) {
01696 ast_free(fge);
01697 return;
01698 }
01699
01700 ast_string_field_set(fge, exten, S_OR(exten, feature->exten));
01701
01702 fge->feature = feature;
01703
01704 AST_LIST_INSERT_HEAD(&fg->features, fge, entry);
01705
01706 ast_verb(2, "Registered feature '%s' for group '%s' at exten '%s'\n",
01707 feature->sname, fg->gname, exten);
01708 }
01709
01710 void ast_unregister_feature(struct ast_call_feature *feature)
01711 {
01712 if (!feature) {
01713 return;
01714 }
01715
01716 AST_RWLIST_WRLOCK(&feature_list);
01717 AST_RWLIST_REMOVE(&feature_list, feature, feature_entry);
01718 AST_RWLIST_UNLOCK(&feature_list);
01719
01720 ast_free(feature);
01721 }
01722
01723
01724 static void ast_unregister_features(void)
01725 {
01726 struct ast_call_feature *feature;
01727
01728 AST_RWLIST_WRLOCK(&feature_list);
01729 while ((feature = AST_RWLIST_REMOVE_HEAD(&feature_list, feature_entry))) {
01730 ast_free(feature);
01731 }
01732 AST_RWLIST_UNLOCK(&feature_list);
01733 }
01734
01735
01736 static struct ast_call_feature *find_dynamic_feature(const char *name)
01737 {
01738 struct ast_call_feature *tmp;
01739
01740 AST_RWLIST_TRAVERSE(&feature_list, tmp, feature_entry) {
01741 if (!strcasecmp(tmp->sname, name)) {
01742 break;
01743 }
01744 }
01745
01746 return tmp;
01747 }
01748
01749
01750 static void ast_unregister_groups(void)
01751 {
01752 struct feature_group *fg;
01753 struct feature_group_exten *fge;
01754
01755 AST_RWLIST_WRLOCK(&feature_groups);
01756 while ((fg = AST_LIST_REMOVE_HEAD(&feature_groups, entry))) {
01757 while ((fge = AST_LIST_REMOVE_HEAD(&fg->features, entry))) {
01758 ast_string_field_free_memory(fge);
01759 ast_free(fge);
01760 }
01761
01762 ast_string_field_free_memory(fg);
01763 ast_free(fg);
01764 }
01765 AST_RWLIST_UNLOCK(&feature_groups);
01766 }
01767
01768
01769
01770
01771
01772
01773
01774 static struct feature_group *find_group(const char *name) {
01775 struct feature_group *fg = NULL;
01776
01777 AST_LIST_TRAVERSE(&feature_groups, fg, entry) {
01778 if (!strcasecmp(fg->gname, name))
01779 break;
01780 }
01781
01782 return fg;
01783 }
01784
01785 void ast_rdlock_call_features(void)
01786 {
01787 ast_rwlock_rdlock(&features_lock);
01788 }
01789
01790 void ast_unlock_call_features(void)
01791 {
01792 ast_rwlock_unlock(&features_lock);
01793 }
01794
01795 struct ast_call_feature *ast_find_call_feature(const char *name)
01796 {
01797 int x;
01798 for (x = 0; x < FEATURES_COUNT; x++) {
01799 if (!strcasecmp(name, builtin_features[x].sname))
01800 return &builtin_features[x];
01801 }
01802 return NULL;
01803 }
01804
01805
01806
01807
01808
01809
01810
01811
01812
01813
01814 static int feature_exec_app(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
01815 {
01816 struct ast_app *app;
01817 struct ast_call_feature *feature = data;
01818 struct ast_channel *work, *idle;
01819 int res;
01820
01821 if (!feature) {
01822 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
01823 return -1;
01824 }
01825
01826 if (sense == FEATURE_SENSE_CHAN) {
01827 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
01828 return AST_FEATURE_RETURN_KEEPTRYING;
01829 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
01830 work = chan;
01831 idle = peer;
01832 } else {
01833 work = peer;
01834 idle = chan;
01835 }
01836 } else {
01837 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
01838 return AST_FEATURE_RETURN_KEEPTRYING;
01839 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
01840 work = peer;
01841 idle = chan;
01842 } else {
01843 work = chan;
01844 idle = peer;
01845 }
01846 }
01847
01848 if (!(app = pbx_findapp(feature->app))) {
01849 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
01850 return -2;
01851 }
01852
01853 ast_autoservice_start(idle);
01854
01855 if (!ast_strlen_zero(feature->moh_class))
01856 ast_moh_start(idle, feature->moh_class, NULL);
01857
01858 res = pbx_exec(work, app, feature->app_args);
01859
01860 if (!ast_strlen_zero(feature->moh_class))
01861 ast_moh_stop(idle);
01862
01863 ast_autoservice_stop(idle);
01864
01865 if (res) {
01866 return AST_FEATURE_RETURN_SUCCESSBREAK;
01867 }
01868 return AST_FEATURE_RETURN_SUCCESS;
01869 }
01870
01871 static void unmap_features(void)
01872 {
01873 int x;
01874
01875 ast_rwlock_wrlock(&features_lock);
01876 for (x = 0; x < FEATURES_COUNT; x++)
01877 strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
01878 ast_rwlock_unlock(&features_lock);
01879 }
01880
01881 static int remap_feature(const char *name, const char *value)
01882 {
01883 int x, res = -1;
01884
01885 ast_rwlock_wrlock(&features_lock);
01886 for (x = 0; x < FEATURES_COUNT; x++) {
01887 if (strcasecmp(builtin_features[x].sname, name))
01888 continue;
01889
01890 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
01891 res = 0;
01892 break;
01893 }
01894 ast_rwlock_unlock(&features_lock);
01895
01896 return res;
01897 }
01898
01899
01900
01901
01902
01903
01904
01905
01906
01907
01908
01909 static int feature_interpret_helper(struct ast_channel *chan, struct ast_channel *peer,
01910 struct ast_bridge_config *config, char *code, int sense, char *dynamic_features_buf,
01911 struct ast_flags *features, int operation, struct ast_call_feature *feature)
01912 {
01913 int x;
01914 struct feature_group *fg = NULL;
01915 struct feature_group_exten *fge;
01916 struct ast_call_feature *tmpfeature;
01917 char *tmp, *tok;
01918 int res = AST_FEATURE_RETURN_PASSDIGITS;
01919 int feature_detected = 0;
01920
01921 if (!(peer && chan && config) && operation) {
01922 return -1;
01923 }
01924
01925 ast_rwlock_rdlock(&features_lock);
01926 for (x = 0; x < FEATURES_COUNT; x++) {
01927 if ((ast_test_flag(features, builtin_features[x].feature_mask)) &&
01928 !ast_strlen_zero(builtin_features[x].exten)) {
01929
01930 if (!strcmp(builtin_features[x].exten, code)) {
01931 ast_debug(3, "Feature detected: fname=%s sname=%s exten=%s\n", builtin_features[x].fname, builtin_features[x].sname, builtin_features[x].exten);
01932 if (operation) {
01933 res = builtin_features[x].operation(chan, peer, config, code, sense, NULL);
01934 }
01935 memcpy(feature, &builtin_features[x], sizeof(feature));
01936 feature_detected = 1;
01937 break;
01938 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
01939 if (res == AST_FEATURE_RETURN_PASSDIGITS)
01940 res = AST_FEATURE_RETURN_STOREDIGITS;
01941 }
01942 }
01943 }
01944 ast_rwlock_unlock(&features_lock);
01945
01946 if (ast_strlen_zero(dynamic_features_buf) || feature_detected) {
01947 return res;
01948 }
01949
01950 tmp = dynamic_features_buf;
01951
01952 while ((tok = strsep(&tmp, "#"))) {
01953 AST_RWLIST_RDLOCK(&feature_groups);
01954
01955 fg = find_group(tok);
01956
01957 if (fg) {
01958 AST_LIST_TRAVERSE(&fg->features, fge, entry) {
01959 if (strcasecmp(fge->exten, code))
01960 continue;
01961 if (operation) {
01962 res = fge->feature->operation(chan, peer, config, code, sense, fge->feature);
01963 }
01964 memcpy(feature, fge->feature, sizeof(feature));
01965 if (res != AST_FEATURE_RETURN_KEEPTRYING) {
01966 AST_RWLIST_UNLOCK(&feature_groups);
01967 break;
01968 }
01969 res = AST_FEATURE_RETURN_PASSDIGITS;
01970 }
01971 if (fge)
01972 break;
01973 }
01974
01975 AST_RWLIST_UNLOCK(&feature_groups);
01976
01977 AST_RWLIST_RDLOCK(&feature_list);
01978
01979 if (!(tmpfeature = find_dynamic_feature(tok))) {
01980 AST_RWLIST_UNLOCK(&feature_list);
01981 continue;
01982 }
01983
01984
01985 if (!strcmp(tmpfeature->exten, code)) {
01986 ast_verb(3, " Feature Found: %s exten: %s\n",tmpfeature->sname, tok);
01987 if (operation) {
01988 res = tmpfeature->operation(chan, peer, config, code, sense, tmpfeature);
01989 }
01990 memcpy(feature, tmpfeature, sizeof(feature));
01991 if (res != AST_FEATURE_RETURN_KEEPTRYING) {
01992 AST_RWLIST_UNLOCK(&feature_list);
01993 break;
01994 }
01995 res = AST_FEATURE_RETURN_PASSDIGITS;
01996 } else if (!strncmp(tmpfeature->exten, code, strlen(code)))
01997 res = AST_FEATURE_RETURN_STOREDIGITS;
01998
01999 AST_RWLIST_UNLOCK(&feature_list);
02000 }
02001
02002 return res;
02003 }
02004
02005
02006
02007
02008
02009
02010
02011
02012
02013 static int ast_feature_interpret(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) {
02014
02015 char dynamic_features_buf[128];
02016 const char *peer_dynamic_features, *chan_dynamic_features;
02017 struct ast_flags features;
02018 struct ast_call_feature feature;
02019 if (sense == FEATURE_SENSE_CHAN) {
02020 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
02021 }
02022 else {
02023 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);
02024 }
02025
02026 ast_channel_lock(peer);
02027 peer_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES"),""));
02028 ast_channel_unlock(peer);
02029
02030 ast_channel_lock(chan);
02031 chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),""));
02032 ast_channel_unlock(chan);
02033
02034 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,""));
02035
02036 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);
02037
02038 return feature_interpret_helper(chan, peer, config, code, sense, dynamic_features_buf, &features, 1, &feature);
02039 }
02040
02041
02042 int ast_feature_detect(struct ast_channel *chan, struct ast_flags *features, char *code, struct ast_call_feature *feature) {
02043
02044 return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, 0, feature);
02045 }
02046
02047 static void set_config_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
02048 {
02049 int x;
02050
02051 ast_clear_flag(config, AST_FLAGS_ALL);
02052
02053 ast_rwlock_rdlock(&features_lock);
02054 for (x = 0; x < FEATURES_COUNT; x++) {
02055 if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF))
02056 continue;
02057
02058 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
02059 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
02060
02061 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
02062 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
02063 }
02064 ast_rwlock_unlock(&features_lock);
02065
02066 if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
02067 const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
02068
02069 if (dynamic_features) {
02070 char *tmp = ast_strdupa(dynamic_features);
02071 char *tok;
02072 struct ast_call_feature *feature;
02073
02074
02075 while ((tok = strsep(&tmp, "#"))) {
02076 AST_RWLIST_RDLOCK(&feature_list);
02077 if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
02078 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
02079 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
02080 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
02081 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
02082 }
02083 AST_RWLIST_UNLOCK(&feature_list);
02084 }
02085 }
02086 }
02087 }
02088
02089
02090
02091
02092
02093
02094
02095
02096
02097
02098
02099
02100 static struct ast_channel *ast_feature_request_and_dial(struct ast_channel *caller, struct ast_channel *transferee, const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name, int igncallerstate, const char *language)
02101 {
02102 int state = 0;
02103 int cause = 0;
02104 int to;
02105 struct ast_channel *chan;
02106 struct ast_channel *monitor_chans[2];
02107 struct ast_channel *active_channel;
02108 int res = 0, ready = 0;
02109
02110 if ((chan = ast_request(type, format, data, &cause))) {
02111 ast_set_callerid(chan, cid_num, cid_name, cid_num);
02112 ast_string_field_set(chan, language, language);
02113 ast_channel_inherit_variables(caller, chan);
02114 pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name);
02115
02116 if (!ast_call(chan, data, timeout)) {
02117 struct timeval started;
02118 int x, len = 0;
02119 char *disconnect_code = NULL, *dialed_code = NULL;
02120
02121 ast_indicate(caller, AST_CONTROL_RINGING);
02122
02123 ast_rwlock_rdlock(&features_lock);
02124 for (x = 0; x < FEATURES_COUNT; x++) {
02125 if (strcasecmp(builtin_features[x].sname, "disconnect"))
02126 continue;
02127
02128 disconnect_code = builtin_features[x].exten;
02129 len = strlen(disconnect_code) + 1;
02130 dialed_code = alloca(len);
02131 memset(dialed_code, 0, len);
02132 break;
02133 }
02134 ast_rwlock_unlock(&features_lock);
02135 x = 0;
02136 started = ast_tvnow();
02137 to = timeout;
02138
02139 ast_poll_channel_add(caller, chan);
02140
02141 while (!((transferee && ast_check_hangup(transferee)) && (!igncallerstate && ast_check_hangup(caller))) && timeout && (chan->_state != AST_STATE_UP)) {
02142 struct ast_frame *f = NULL;
02143
02144 monitor_chans[0] = caller;
02145 monitor_chans[1] = chan;
02146 active_channel = ast_waitfor_n(monitor_chans, 2, &to);
02147
02148
02149 if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
02150 state = AST_CONTROL_UNHOLD;
02151 ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n");
02152 break;
02153 }
02154
02155 if (!active_channel)
02156 continue;
02157
02158 if (chan && (chan == active_channel)){
02159 f = ast_read(chan);
02160 if (f == NULL) {
02161 state = AST_CONTROL_HANGUP;
02162 res = 0;
02163 break;
02164 }
02165
02166 if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) {
02167 if (f->subclass == AST_CONTROL_RINGING) {
02168 state = f->subclass;
02169 ast_verb(3, "%s is ringing\n", chan->name);
02170 ast_indicate(caller, AST_CONTROL_RINGING);
02171 } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) {
02172 state = f->subclass;
02173 ast_verb(3, "%s is busy\n", chan->name);
02174 ast_indicate(caller, AST_CONTROL_BUSY);
02175 ast_frfree(f);
02176 f = NULL;
02177 break;
02178 } else if (f->subclass == AST_CONTROL_ANSWER) {
02179
02180 state = f->subclass;
02181 ast_frfree(f);
02182 f = NULL;
02183 ready=1;
02184 break;
02185 } else if (f->subclass != -1) {
02186 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass);
02187 }
02188
02189 }
02190
02191 } else if (caller && (active_channel == caller)) {
02192 f = ast_read(caller);
02193 if (f == NULL) {
02194 if (!igncallerstate) {
02195 if (ast_check_hangup(caller) && !ast_check_hangup(chan)) {
02196
02197 ready = 1;
02198 break;
02199 }
02200 state = AST_CONTROL_HANGUP;
02201 res = 0;
02202 break;
02203 }
02204 } else {
02205
02206 if (f->frametype == AST_FRAME_DTMF) {
02207 dialed_code[x++] = f->subclass;
02208 dialed_code[x] = '\0';
02209 if (strlen(dialed_code) == len) {
02210 x = 0;
02211 } else if (x && strncmp(dialed_code, disconnect_code, x)) {
02212 x = 0;
02213 dialed_code[x] = '\0';
02214 }
02215 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
02216
02217 state = AST_CONTROL_UNHOLD;
02218 ast_frfree(f);
02219 f = NULL;
02220 break;
02221 }
02222 }
02223 }
02224 }
02225 if (f)
02226 ast_frfree(f);
02227 }
02228
02229 ast_poll_channel_del(caller, chan);
02230
02231 } else
02232 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
02233 } else {
02234 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
02235 switch(cause) {
02236 case AST_CAUSE_BUSY:
02237 state = AST_CONTROL_BUSY;
02238 break;
02239 case AST_CAUSE_CONGESTION:
02240 state = AST_CONTROL_CONGESTION;
02241 break;
02242 }
02243 }
02244
02245 ast_indicate(caller, -1);
02246 if (chan && ready) {
02247 if (chan->_state == AST_STATE_UP)
02248 state = AST_CONTROL_ANSWER;
02249 res = 0;
02250 } else if(chan) {
02251 res = -1;
02252 ast_hangup(chan);
02253 chan = NULL;
02254 } else {
02255 res = -1;
02256 }
02257
02258 if (outstate)
02259 *outstate = state;
02260
02261 return chan;
02262 }
02263
02264
02265
02266
02267 static struct ast_cdr *pick_unlocked_cdr(struct ast_cdr *cdr)
02268 {
02269 struct ast_cdr *cdr_orig = cdr;
02270 while (cdr) {
02271 if (!ast_test_flag(cdr,AST_CDR_FLAG_LOCKED))
02272 return cdr;
02273 cdr = cdr->next;
02274 }
02275 return cdr_orig;
02276 }
02277
02278 static void set_bridge_features_on_config(struct ast_bridge_config *config, const char *features)
02279 {
02280 const char *feature;
02281
02282 if (ast_strlen_zero(features)) {
02283 return;
02284 }
02285
02286 for (feature = features; *feature; feature++) {
02287 switch (*feature) {
02288 case 'T' :
02289 case 't' :
02290 ast_set_flag(&(config->features_caller), AST_FEATURE_REDIRECT);
02291 break;
02292 case 'K' :
02293 case 'k' :
02294 ast_set_flag(&(config->features_caller), AST_FEATURE_PARKCALL);
02295 break;
02296 case 'H' :
02297 case 'h' :
02298 ast_set_flag(&(config->features_caller), AST_FEATURE_DISCONNECT);
02299 break;
02300 case 'W' :
02301 case 'w' :
02302 ast_set_flag(&(config->features_caller), AST_FEATURE_AUTOMON);
02303 break;
02304 default :
02305 ast_log(LOG_WARNING, "Skipping unknown feature code '%c'\n", *feature);
02306 }
02307 }
02308 }
02309
02310 static void add_features_datastores(struct ast_channel *caller, struct ast_channel *callee, struct ast_bridge_config *config)
02311 {
02312 struct ast_datastore *ds_callee_features = NULL, *ds_caller_features = NULL;
02313 struct ast_dial_features *callee_features = NULL, *caller_features = NULL;
02314
02315 ast_channel_lock(caller);
02316 ds_caller_features = ast_channel_datastore_find(caller, &dial_features_info, NULL);
02317 ast_channel_unlock(caller);
02318 if (!ds_caller_features) {
02319 if (!(ds_caller_features = ast_datastore_alloc(&dial_features_info, NULL))) {
02320 ast_log(LOG_WARNING, "Unable to create channel datastore for caller features. Aborting!\n");
02321 return;
02322 }
02323 if (!(caller_features = ast_calloc(1, sizeof(*caller_features)))) {
02324 ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n");
02325 ast_datastore_free(ds_caller_features);
02326 return;
02327 }
02328 ds_caller_features->inheritance = DATASTORE_INHERIT_FOREVER;
02329 caller_features->is_caller = 1;
02330 ast_copy_flags(&(caller_features->features_callee), &(config->features_callee), AST_FLAGS_ALL);
02331 ast_copy_flags(&(caller_features->features_caller), &(config->features_caller), AST_FLAGS_ALL);
02332 ds_caller_features->data = caller_features;
02333 ast_channel_lock(caller);
02334 ast_channel_datastore_add(caller, ds_caller_features);
02335 ast_channel_unlock(caller);
02336 } else {
02337
02338
02339 return;
02340 }
02341
02342 ast_channel_lock(callee);
02343 ds_callee_features = ast_channel_datastore_find(callee, &dial_features_info, NULL);
02344 ast_channel_unlock(callee);
02345 if (!ds_callee_features) {
02346 if (!(ds_callee_features = ast_datastore_alloc(&dial_features_info, NULL))) {
02347 ast_log(LOG_WARNING, "Unable to create channel datastore for callee features. Aborting!\n");
02348 return;
02349 }
02350 if (!(callee_features = ast_calloc(1, sizeof(*callee_features)))) {
02351 ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n");
02352 ast_datastore_free(ds_callee_features);
02353 return;
02354 }
02355 ds_callee_features->inheritance = DATASTORE_INHERIT_FOREVER;
02356 callee_features->is_caller = 0;
02357 ast_copy_flags(&(callee_features->features_callee), &(config->features_caller), AST_FLAGS_ALL);
02358 ast_copy_flags(&(callee_features->features_caller), &(config->features_callee), AST_FLAGS_ALL);
02359 ds_callee_features->data = callee_features;
02360 ast_channel_lock(callee);
02361 ast_channel_datastore_add(callee, ds_callee_features);
02362 ast_channel_unlock(callee);
02363 }
02364
02365 return;
02366 }
02367
02368
02369
02370
02371
02372
02373
02374
02375
02376
02377 int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast_bridge_config *config)
02378 {
02379
02380
02381 struct ast_frame *f;
02382 struct ast_channel *who;
02383 char chan_featurecode[FEATURE_MAX_LEN + 1]="";
02384 char peer_featurecode[FEATURE_MAX_LEN + 1]="";
02385 char orig_channame[AST_MAX_EXTENSION];
02386 char orig_peername[AST_MAX_EXTENSION];
02387 int res;
02388 int diff;
02389 int hasfeatures=0;
02390 int hadfeatures=0;
02391 int autoloopflag;
02392 struct ast_option_header *aoh;
02393 struct ast_bridge_config backup_config;
02394 struct ast_cdr *bridge_cdr = NULL;
02395 struct ast_cdr *orig_peer_cdr = NULL;
02396 struct ast_cdr *chan_cdr = pick_unlocked_cdr(chan->cdr);
02397 struct ast_cdr *peer_cdr = pick_unlocked_cdr(peer->cdr);
02398 struct ast_cdr *new_chan_cdr = NULL;
02399 struct ast_cdr *new_peer_cdr = NULL;
02400
02401 memset(&backup_config, 0, sizeof(backup_config));
02402
02403 config->start_time = ast_tvnow();
02404
02405 if (chan && peer) {
02406 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
02407 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
02408 } else if (chan) {
02409 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
02410 }
02411
02412 set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES"));
02413 add_features_datastores(chan, peer, config);
02414
02415
02416
02417
02418 if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) {
02419 ast_indicate(peer, AST_CONTROL_RINGING);
02420 }
02421
02422 if (monitor_ok) {
02423 const char *monitor_exec;
02424 struct ast_channel *src = NULL;
02425 if (!monitor_app) {
02426 if (!(monitor_app = pbx_findapp("Monitor")))
02427 monitor_ok=0;
02428 }
02429 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR")))
02430 src = chan;
02431 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
02432 src = peer;
02433 if (monitor_app && src) {
02434 char *tmp = ast_strdupa(monitor_exec);
02435 pbx_exec(src, monitor_app, tmp);
02436 }
02437 }
02438
02439 set_config_flags(chan, peer, config);
02440 config->firstpass = 1;
02441
02442
02443 if (chan->_state != AST_STATE_UP) {
02444 if (ast_raw_answer(chan, 1)) {
02445 return -1;
02446 }
02447 }
02448
02449 ast_copy_string(orig_channame,chan->name,sizeof(orig_channame));
02450 ast_copy_string(orig_peername,peer->name,sizeof(orig_peername));
02451 orig_peer_cdr = peer_cdr;
02452
02453 if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) {
02454
02455 if (chan_cdr) {
02456 ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN);
02457 ast_cdr_update(chan);
02458 bridge_cdr = ast_cdr_dup(chan_cdr);
02459 ast_copy_string(bridge_cdr->lastapp, chan->appl, sizeof(bridge_cdr->lastapp));
02460 ast_copy_string(bridge_cdr->lastdata, chan->data, sizeof(bridge_cdr->lastdata));
02461 } else {
02462
02463 bridge_cdr = ast_cdr_alloc();
02464 ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel));
02465 ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel));
02466 ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid));
02467 ast_copy_string(bridge_cdr->lastapp, chan->appl, sizeof(bridge_cdr->lastapp));
02468 ast_copy_string(bridge_cdr->lastdata, chan->data, sizeof(bridge_cdr->lastdata));
02469 ast_cdr_setcid(bridge_cdr, chan);
02470 bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ? AST_CDR_ANSWERED : AST_CDR_NULL;
02471 bridge_cdr->amaflags = chan->amaflags ? chan->amaflags : ast_default_amaflags;
02472 ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode));
02473
02474 ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst));
02475 ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext));
02476 if (peer_cdr) {
02477 bridge_cdr->start = peer_cdr->start;
02478 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield));
02479 } else {
02480 ast_cdr_start(bridge_cdr);
02481 }
02482 }
02483 ast_debug(4,"bridge answer set, chan answer set\n");
02484
02485
02486
02487
02488
02489
02490 if (peer_cdr && !ast_tvzero(peer_cdr->answer)) {
02491 bridge_cdr->answer = peer_cdr->answer;
02492 chan_cdr->answer = peer_cdr->answer;
02493 bridge_cdr->disposition = peer_cdr->disposition;
02494 chan_cdr->disposition = peer_cdr->disposition;
02495 } else {
02496 ast_cdr_answer(bridge_cdr);
02497 ast_cdr_answer(chan_cdr);
02498 }
02499 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) {
02500 ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED);
02501 if (peer_cdr) {
02502 ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED);
02503 }
02504 }
02505 }
02506 for (;;) {
02507 struct ast_channel *other;
02508
02509 res = ast_channel_bridge(chan, peer, config, &f, &who);
02510
02511
02512
02513
02514
02515
02516
02517
02518 if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) {
02519
02520 diff = ast_tvdiff_ms(ast_tvnow(), config->start_time);
02521 if (res == AST_BRIDGE_RETRY) {
02522
02523
02524
02525 config->feature_timer = -1;
02526 } else {
02527 config->feature_timer -= diff;
02528 }
02529
02530 if (hasfeatures) {
02531
02532
02533
02534 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
02535 ast_debug(1, "Timed out, realtime this time!\n");
02536 config->feature_timer = 0;
02537 who = chan;
02538 if (f)
02539 ast_frfree(f);
02540 f = NULL;
02541 res = 0;
02542 } else if (config->feature_timer <= 0) {
02543
02544
02545 ast_debug(1, "Timed out for feature!\n");
02546 if (!ast_strlen_zero(peer_featurecode)) {
02547 ast_dtmf_stream(chan, peer, peer_featurecode, 0, 0);
02548 memset(peer_featurecode, 0, sizeof(peer_featurecode));
02549 }
02550 if (!ast_strlen_zero(chan_featurecode)) {
02551 ast_dtmf_stream(peer, chan, chan_featurecode, 0, 0);
02552 memset(chan_featurecode, 0, sizeof(chan_featurecode));
02553 }
02554 if (f)
02555 ast_frfree(f);
02556 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
02557 if (!hasfeatures) {
02558
02559 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
02560 memset(&backup_config, 0, sizeof(backup_config));
02561 }
02562 hadfeatures = hasfeatures;
02563
02564 continue;
02565 } else if (!f) {
02566
02567
02568
02569 continue;
02570 }
02571 } else {
02572 if (config->feature_timer <=0) {
02573
02574 config->feature_timer = 0;
02575 who = chan;
02576 if (f)
02577 ast_frfree(f);
02578 f = NULL;
02579 res = 0;
02580 }
02581 }
02582 }
02583 if (res < 0) {
02584 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer))
02585 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
02586 goto before_you_go;
02587 }
02588
02589 if (!f || (f->frametype == AST_FRAME_CONTROL &&
02590 (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY ||
02591 f->subclass == AST_CONTROL_CONGESTION))) {
02592 res = -1;
02593 break;
02594 }
02595
02596 other = (who == chan) ? peer : chan;
02597 if (f->frametype == AST_FRAME_CONTROL) {
02598 switch (f->subclass) {
02599 case AST_CONTROL_RINGING:
02600 case AST_CONTROL_FLASH:
02601 case -1:
02602 ast_indicate(other, f->subclass);
02603 break;
02604 case AST_CONTROL_HOLD:
02605 case AST_CONTROL_UNHOLD:
02606 ast_indicate_data(other, f->subclass, f->data.ptr, f->datalen);
02607 break;
02608 case AST_CONTROL_OPTION:
02609 aoh = f->data.ptr;
02610
02611 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) {
02612 ast_channel_setoption(other, ntohs(aoh->option), aoh->data,
02613 f->datalen - sizeof(struct ast_option_header), 0);
02614 }
02615 break;
02616 }
02617 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
02618
02619 } else if (f->frametype == AST_FRAME_DTMF) {
02620 char *featurecode;
02621 int sense;
02622
02623 hadfeatures = hasfeatures;
02624
02625 if (who == chan) {
02626 sense = FEATURE_SENSE_CHAN;
02627 featurecode = chan_featurecode;
02628 } else {
02629 sense = FEATURE_SENSE_PEER;
02630 featurecode = peer_featurecode;
02631 }
02632
02633
02634
02635
02636 featurecode[strlen(featurecode)] = f->subclass;
02637
02638 ast_frfree(f);
02639 f = NULL;
02640 config->feature_timer = backup_config.feature_timer;
02641 res = ast_feature_interpret(chan, peer, config, featurecode, sense);
02642 switch(res) {
02643 case AST_FEATURE_RETURN_PASSDIGITS:
02644 ast_dtmf_stream(other, who, featurecode, 0, 0);
02645
02646 case AST_FEATURE_RETURN_SUCCESS:
02647 memset(featurecode, 0, sizeof(chan_featurecode));
02648 break;
02649 }
02650 if (res >= AST_FEATURE_RETURN_PASSDIGITS) {
02651 res = 0;
02652 } else
02653 break;
02654 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
02655 if (hadfeatures && !hasfeatures) {
02656
02657 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
02658 memset(&backup_config, 0, sizeof(struct ast_bridge_config));
02659 } else if (hasfeatures) {
02660 if (!hadfeatures) {
02661
02662 memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
02663
02664 config->play_warning = 0;
02665 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
02666 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
02667 config->warning_freq = 0;
02668 config->warning_sound = NULL;
02669 config->end_sound = NULL;
02670 config->start_sound = NULL;
02671 config->firstpass = 0;
02672 }
02673 config->start_time = ast_tvnow();
02674 config->feature_timer = featuredigittimeout;
02675 ast_debug(1, "Set time limit to %ld\n", config->feature_timer);
02676 }
02677 }
02678 if (f)
02679 ast_frfree(f);
02680
02681 }
02682 before_you_go:
02683
02684 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) {
02685 ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT);
02686 if (bridge_cdr) {
02687 ast_cdr_discard(bridge_cdr);
02688
02689 }
02690 return res;
02691 }
02692
02693 if (config->end_bridge_callback) {
02694 config->end_bridge_callback(config->end_bridge_callback_data);
02695 }
02696
02697
02698
02699
02700
02701 if (!ast_test_flag(&(config->features_caller),AST_FEATURE_NO_H_EXTEN) &&
02702 ast_exists_extension(chan, chan->context, "h", 1, chan->cid.cid_num)) {
02703 struct ast_cdr *swapper = NULL;
02704 char savelastapp[AST_MAX_EXTENSION];
02705 char savelastdata[AST_MAX_EXTENSION];
02706 char save_exten[AST_MAX_EXTENSION];
02707 int save_prio;
02708 int found = 0;
02709 int spawn_error = 0;
02710
02711 autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP);
02712 ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP);
02713 if (bridge_cdr && ast_opt_end_cdr_before_h_exten) {
02714 ast_cdr_end(bridge_cdr);
02715 }
02716
02717
02718 ast_channel_lock(chan);
02719 if (bridge_cdr) {
02720 swapper = chan->cdr;
02721 ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp));
02722 ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata));
02723 chan->cdr = bridge_cdr;
02724 }
02725 ast_copy_string(save_exten, chan->exten, sizeof(save_exten));
02726 save_prio = chan->priority;
02727 ast_copy_string(chan->exten, "h", sizeof(chan->exten));
02728 chan->priority = 1;
02729 ast_channel_unlock(chan);
02730 while ((spawn_error = ast_spawn_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num, &found, 1)) == 0) {
02731 chan->priority++;
02732 }
02733 if (found && spawn_error) {
02734
02735 ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name);
02736 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name);
02737 }
02738
02739 ast_channel_lock(chan);
02740 ast_copy_string(chan->exten, save_exten, sizeof(chan->exten));
02741 chan->priority = save_prio;
02742 if (bridge_cdr) {
02743 if (chan->cdr == bridge_cdr) {
02744 chan->cdr = swapper;
02745 } else {
02746 bridge_cdr = NULL;
02747 }
02748 }
02749 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN);
02750 ast_channel_unlock(chan);
02751
02752 if (bridge_cdr) {
02753 ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp));
02754 ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata));
02755 }
02756 ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP);
02757 }
02758
02759
02760 new_chan_cdr = pick_unlocked_cdr(chan->cdr);
02761 if (bridge_cdr && new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED))
02762 ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED);
02763
02764
02765 if (bridge_cdr) {
02766 ast_cdr_end(bridge_cdr);
02767 ast_cdr_detach(bridge_cdr);
02768 }
02769
02770
02771
02772
02773
02774
02775
02776
02777
02778
02779
02780
02781
02782
02783
02784
02785
02786
02787
02788
02789
02790
02791
02792
02793
02794 if (new_chan_cdr) {
02795 struct ast_channel *chan_ptr = NULL;
02796
02797 if (strcasecmp(orig_channame, chan->name) != 0) {
02798
02799 chan_ptr = ast_get_channel_by_name_locked(orig_channame);
02800 if (chan_ptr) {
02801 if (!ast_bridged_channel(chan_ptr)) {
02802 struct ast_cdr *cur;
02803 for (cur = chan_ptr->cdr; cur; cur = cur->next) {
02804 if (cur == chan_cdr) {
02805 break;
02806 }
02807 }
02808 if (cur)
02809 ast_cdr_specialized_reset(chan_cdr,0);
02810 }
02811 ast_channel_unlock(chan_ptr);
02812 }
02813
02814 ast_cdr_specialized_reset(new_chan_cdr,0);
02815 } else {
02816 ast_cdr_specialized_reset(chan_cdr,0);
02817 }
02818 }
02819
02820 {
02821 struct ast_channel *chan_ptr = NULL;
02822 new_peer_cdr = pick_unlocked_cdr(peer->cdr);
02823 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))
02824 ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED);
02825 if (strcasecmp(orig_peername, peer->name) != 0) {
02826
02827 chan_ptr = ast_get_channel_by_name_locked(orig_peername);
02828 if (chan_ptr) {
02829 if (!ast_bridged_channel(chan_ptr)) {
02830 struct ast_cdr *cur;
02831 for (cur = chan_ptr->cdr; cur; cur = cur->next) {
02832 if (cur == peer_cdr) {
02833 break;
02834 }
02835 }
02836 if (cur)
02837 ast_cdr_specialized_reset(peer_cdr,0);
02838 }
02839 ast_channel_unlock(chan_ptr);
02840 }
02841
02842 ast_cdr_specialized_reset(new_peer_cdr,0);
02843 } else {
02844 ast_cdr_specialized_reset(peer_cdr,0);
02845 }
02846 }
02847
02848 return res;
02849 }
02850
02851
02852 static void post_manager_event(const char *s, struct parkeduser *pu)
02853 {
02854 manager_event(EVENT_FLAG_CALL, s,
02855 "Exten: %s\r\n"
02856 "Channel: %s\r\n"
02857 "Parkinglot: %s\r\n"
02858 "CallerIDNum: %s\r\n"
02859 "CallerIDName: %s\r\n"
02860 "UniqueID: %s\r\n\r\n",
02861 pu->parkingexten,
02862 pu->chan->name,
02863 pu->parkinglot->name,
02864 S_OR(pu->chan->cid.cid_num, "<unknown>"),
02865 S_OR(pu->chan->cid.cid_name, "<unknown>"),
02866 pu->chan->uniqueid
02867 );
02868 }
02869
02870 static char *callback_dialoptions(struct ast_flags *features_callee, struct ast_flags *features_caller, char *options, size_t len)
02871 {
02872 int i = 0;
02873 enum {
02874 OPT_CALLEE_REDIRECT = 't',
02875 OPT_CALLER_REDIRECT = 'T',
02876 OPT_CALLEE_AUTOMON = 'w',
02877 OPT_CALLER_AUTOMON = 'W',
02878 OPT_CALLEE_DISCONNECT = 'h',
02879 OPT_CALLER_DISCONNECT = 'H',
02880 OPT_CALLEE_PARKCALL = 'k',
02881 OPT_CALLER_PARKCALL = 'K',
02882 };
02883
02884 memset(options, 0, len);
02885 if (ast_test_flag(features_caller, AST_FEATURE_REDIRECT) && i < len) {
02886 options[i++] = OPT_CALLER_REDIRECT;
02887 }
02888 if (ast_test_flag(features_caller, AST_FEATURE_AUTOMON) && i < len) {
02889 options[i++] = OPT_CALLER_AUTOMON;
02890 }
02891 if (ast_test_flag(features_caller, AST_FEATURE_DISCONNECT) && i < len) {
02892 options[i++] = OPT_CALLER_DISCONNECT;
02893 }
02894 if (ast_test_flag(features_caller, AST_FEATURE_PARKCALL) && i < len) {
02895 options[i++] = OPT_CALLER_PARKCALL;
02896 }
02897
02898 if (ast_test_flag(features_callee, AST_FEATURE_REDIRECT) && i < len) {
02899 options[i++] = OPT_CALLEE_REDIRECT;
02900 }
02901 if (ast_test_flag(features_callee, AST_FEATURE_AUTOMON) && i < len) {
02902 options[i++] = OPT_CALLEE_AUTOMON;
02903 }
02904 if (ast_test_flag(features_callee, AST_FEATURE_DISCONNECT) && i < len) {
02905 options[i++] = OPT_CALLEE_DISCONNECT;
02906 }
02907 if (ast_test_flag(features_callee, AST_FEATURE_PARKCALL) && i < len) {
02908 options[i++] = OPT_CALLEE_PARKCALL;
02909 }
02910
02911 return options;
02912 }
02913
02914
02915 int manage_parkinglot(struct ast_parkinglot *curlot, fd_set *rfds, fd_set *efds, fd_set *nrfds, fd_set *nefds, int *ms, int *max)
02916 {
02917
02918 struct parkeduser *pu;
02919 int res = 0;
02920 char parkingslot[AST_MAX_EXTENSION];
02921
02922
02923 AST_LIST_LOCK(&curlot->parkings);
02924 AST_LIST_TRAVERSE_SAFE_BEGIN(&curlot->parkings, pu, list) {
02925 struct ast_channel *chan = pu->chan;
02926 int tms;
02927 int x;
02928 struct ast_context *con;
02929
02930 if (pu->notquiteyet) {
02931 continue;
02932 }
02933 tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
02934 if (tms > pu->parkingtime) {
02935
02936 ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
02937
02938 if (pu->peername[0]) {
02939 char *peername = ast_strdupa(pu->peername);
02940 char *cp = strrchr(peername, '-');
02941 char peername_flat[AST_MAX_EXTENSION];
02942 int i;
02943
02944 if (cp)
02945 *cp = 0;
02946 ast_copy_string(peername_flat,peername,sizeof(peername_flat));
02947 for(i=0; peername_flat[i] && i < AST_MAX_EXTENSION; i++) {
02948 if (peername_flat[i] == '/')
02949 peername_flat[i]= '0';
02950 }
02951 con = ast_context_find_or_create(NULL, NULL, pu->parkinglot->parking_con_dial, registrar);
02952 if (!con) {
02953 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", pu->parkinglot->parking_con_dial);
02954 }
02955 if (con) {
02956 char returnexten[AST_MAX_EXTENSION];
02957 struct ast_datastore *features_datastore;
02958 struct ast_dial_features *dialfeatures = NULL;
02959
02960 ast_channel_lock(chan);
02961
02962 if ((features_datastore = ast_channel_datastore_find(chan, &dial_features_info, NULL)))
02963 dialfeatures = features_datastore->data;
02964
02965 ast_channel_unlock(chan);
02966
02967 if (!strncmp(peername, "Parked/", 7)) {
02968 peername += 7;
02969 }
02970
02971 if (dialfeatures) {
02972 char buf[MAX_DIAL_FEATURE_OPTIONS] = {0,};
02973 snprintf(returnexten, sizeof(returnexten), "%s|30|%s", peername, callback_dialoptions(&(dialfeatures->features_callee), &(dialfeatures->features_caller), buf, sizeof(buf)));
02974 } else {
02975 ast_log(LOG_WARNING, "Dialfeatures not found on %s, using default!\n", chan->name);
02976 snprintf(returnexten, sizeof(returnexten), "%s|30|t", peername);
02977 }
02978
02979 ast_add_extension2(con, 1, peername_flat, 1, NULL, NULL, "Dial", ast_strdup(returnexten), ast_free_ptr, registrar);
02980 }
02981 if (comebacktoorigin) {
02982 set_c_e_p(chan, pu->parkinglot->parking_con_dial, peername_flat, 1);
02983 } else {
02984 ast_log(LOG_WARNING, "now going to parkedcallstimeout,s,1 | ps is %d\n",pu->parkingnum);
02985 snprintf(parkingslot, sizeof(parkingslot), "%d", pu->parkingnum);
02986 pbx_builtin_setvar_helper(chan, "PARKINGSLOT", parkingslot);
02987 set_c_e_p(chan, "parkedcallstimeout", peername_flat, 1);
02988 }
02989 } else {
02990
02991
02992 set_c_e_p(chan, pu->context, pu->exten, pu->priority);
02993 }
02994 post_manager_event("ParkedCallTimeOut", pu);
02995
02996 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);
02997
02998 if (ast_pbx_start(chan)) {
02999 ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name);
03000 ast_hangup(chan);
03001 }
03002
03003 con = ast_context_find(pu->parkinglot->parking_con);
03004 if (con) {
03005 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0))
03006 ast_log(LOG_WARNING, "Whoa, failed to remove the parking extension!\n");
03007 else
03008 notify_metermaids(pu->parkingexten, curlot->parking_con, AST_DEVICE_NOT_INUSE);
03009 } else
03010 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
03011 AST_LIST_REMOVE_CURRENT(list);
03012 free(pu);
03013 } else {
03014 for (x = 0; x < AST_MAX_FDS; x++) {
03015 struct ast_frame *f;
03016
03017 if ((chan->fds[x] == -1) || (!FD_ISSET(chan->fds[x], rfds) && !FD_ISSET(pu->chan->fds[x], efds)))
03018 continue;
03019
03020 if (FD_ISSET(chan->fds[x], efds))
03021 ast_set_flag(chan, AST_FLAG_EXCEPTION);
03022 else
03023 ast_clear_flag(chan, AST_FLAG_EXCEPTION);
03024 chan->fdno = x;
03025
03026
03027 f = ast_read(pu->chan);
03028
03029 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
03030 if (f)
03031 ast_frfree(f);
03032 post_manager_event("ParkedCallGiveUp", pu);
03033
03034
03035 ast_verb(2, "%s got tired of being parked\n", chan->name);
03036 ast_hangup(chan);
03037
03038 con = ast_context_find(curlot->parking_con);
03039 if (con) {
03040 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0))
03041 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
03042 else
03043 notify_metermaids(pu->parkingexten, curlot->parking_con, AST_DEVICE_NOT_INUSE);
03044 } else
03045 ast_log(LOG_WARNING, "Whoa, no parking context for parking lot %s?\n", curlot->name);
03046 AST_LIST_REMOVE_CURRENT(list);
03047 free(pu);
03048 break;
03049 } else {
03050
03051 ast_frfree(f);
03052 if (pu->moh_trys < 3 && !chan->generatordata) {
03053 ast_debug(1, "MOH on parked call stopped by outside source. Restarting on channel %s.\n", chan->name);
03054 ast_indicate_data(chan, AST_CONTROL_HOLD,
03055 S_OR(curlot->mohclass, NULL),
03056 (!ast_strlen_zero(curlot->mohclass) ? strlen(curlot->mohclass) + 1 : 0));
03057 pu->moh_trys++;
03058 }
03059 goto std;
03060 }
03061 }
03062 if (x >= AST_MAX_FDS) {
03063 std: for (x=0; x<AST_MAX_FDS; x++) {
03064 if (chan->fds[x] > -1) {
03065 FD_SET(chan->fds[x], nrfds);
03066 FD_SET(chan->fds[x], nefds);
03067 if (chan->fds[x] > *max)
03068 *max = chan->fds[x];
03069 }
03070 }
03071
03072 if (tms < *ms || *ms < 0)
03073 *ms = tms;
03074 }
03075 }
03076 }
03077 AST_LIST_TRAVERSE_SAFE_END;
03078 AST_LIST_UNLOCK(&curlot->parkings);
03079 return res;
03080 }
03081
03082
03083
03084
03085
03086
03087
03088
03089
03090 static void *do_parking_thread(void *ignore)
03091 {
03092 fd_set rfds, efds;
03093 fd_set nrfds, nefds;
03094 FD_ZERO(&rfds);
03095 FD_ZERO(&efds);
03096
03097 for (;;) {
03098 int res = 0;
03099 int ms = -1;
03100 int max = -1;
03101 struct ao2_iterator iter;
03102 struct ast_parkinglot *curlot;
03103 FD_ZERO(&nrfds);
03104 FD_ZERO(&nefds);
03105 iter = ao2_iterator_init(parkinglots, 0);
03106
03107 while ((curlot = ao2_iterator_next(&iter))) {
03108 res = manage_parkinglot(curlot, &rfds, &efds, &nrfds, &nefds, &ms, &max);
03109 ao2_ref(curlot, -1);
03110 }
03111
03112 rfds = nrfds;
03113 efds = nefds;
03114 {
03115 struct timeval wait = ast_samp2tv(ms, 1000);
03116
03117 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &wait : NULL);
03118 }
03119 pthread_testcancel();
03120 }
03121 return NULL;
03122 }
03123
03124
03125 struct ast_parkinglot *find_parkinglot(const char *name)
03126 {
03127 struct ast_parkinglot *parkinglot = NULL;
03128 struct ast_parkinglot tmp_parkinglot;
03129
03130 if (ast_strlen_zero(name))
03131 return NULL;
03132
03133 ast_copy_string(tmp_parkinglot.name, name, sizeof(tmp_parkinglot.name));
03134
03135 parkinglot = ao2_find(parkinglots, &tmp_parkinglot, OBJ_POINTER);
03136
03137 if (parkinglot && option_debug)
03138 ast_log(LOG_DEBUG, "Found Parkinglot: %s\n", parkinglot->name);
03139
03140 return parkinglot;
03141 }
03142
03143 AST_APP_OPTIONS(park_call_options, BEGIN_OPTIONS
03144 AST_APP_OPTION('r', AST_PARK_OPT_RINGING),
03145 AST_APP_OPTION('R', AST_PARK_OPT_RANDOMIZE),
03146 AST_APP_OPTION('s', AST_PARK_OPT_SILENCE),
03147 END_OPTIONS );
03148
03149
03150 static int park_call_exec(struct ast_channel *chan, void *data)
03151 {
03152
03153
03154
03155 char *orig_chan_name = ast_strdupa(chan->name);
03156 char orig_exten[AST_MAX_EXTENSION];
03157 int orig_priority = chan->priority;
03158
03159
03160
03161 int res = 0;
03162
03163 char *parse = NULL;
03164 AST_DECLARE_APP_ARGS(app_args,
03165 AST_APP_ARG(timeout);
03166 AST_APP_ARG(return_con);
03167 AST_APP_ARG(return_ext);
03168 AST_APP_ARG(return_pri);
03169 AST_APP_ARG(options);
03170 );
03171
03172 parse = ast_strdupa(data);
03173 AST_STANDARD_APP_ARGS(app_args, parse);
03174
03175 ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten));
03176
03177
03178
03179 strcpy(chan->exten, "s");
03180 chan->priority = 1;
03181
03182
03183 if (chan->_state != AST_STATE_UP)
03184 res = ast_answer(chan);
03185
03186
03187 if (!res)
03188 res = ast_safe_sleep(chan, 1000);
03189
03190
03191 if (!res) {
03192 struct ast_park_call_args args = {
03193 .orig_chan_name = orig_chan_name,
03194 };
03195 struct ast_flags flags = { 0 };
03196
03197 if (parse) {
03198 if (!ast_strlen_zero(app_args.timeout)) {
03199 if (sscanf(app_args.timeout, "%d", &args.timeout) != 1) {
03200 ast_log(LOG_WARNING, "Invalid timeout '%s' provided\n", app_args.timeout);
03201 args.timeout = 0;
03202 }
03203 }
03204 if (!ast_strlen_zero(app_args.return_con)) {
03205 args.return_con = app_args.return_con;
03206 }
03207 if (!ast_strlen_zero(app_args.return_ext)) {
03208 args.return_ext = app_args.return_ext;
03209 }
03210 if (!ast_strlen_zero(app_args.return_pri)) {
03211 if (sscanf(app_args.return_pri, "%d", &args.return_pri) != 1) {
03212 ast_log(LOG_WARNING, "Invalid priority '%s' specified\n", app_args.return_pri);
03213 args.return_pri = 0;
03214 }
03215 }
03216 }
03217
03218 ast_app_parse_options(park_call_options, &flags, NULL, app_args.options);
03219 args.flags = flags.flags;
03220
03221 res = masq_park_call_announce_args(chan, chan, &args);
03222
03223 if (res == 1) {
03224 ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten));
03225 chan->priority = orig_priority;
03226 res = 0;
03227 } else if (!res) {
03228 res = 1;
03229 }
03230 }
03231
03232 return res;
03233 }
03234
03235
03236 static int park_exec_full(struct ast_channel *chan, void *data, struct ast_parkinglot *parkinglot)
03237 {
03238 int res = 0;
03239 struct ast_channel *peer=NULL;
03240 struct parkeduser *pu;
03241 struct ast_context *con;
03242 int park = 0;
03243 struct ast_bridge_config config;
03244
03245 if (data)
03246 park = atoi((char *)data);
03247
03248 parkinglot = find_parkinglot(findparkinglotname(chan));
03249 if (!parkinglot)
03250 parkinglot = default_parkinglot;
03251
03252 AST_LIST_LOCK(&parkinglot->parkings);
03253 AST_LIST_TRAVERSE_SAFE_BEGIN(&parkinglot->parkings, pu, list) {
03254 if (!data || pu->parkingnum == park) {
03255 if (pu->chan->pbx) {
03256 AST_LIST_UNLOCK(&parkinglot->parkings);
03257 return -1;
03258 }
03259 AST_LIST_REMOVE_CURRENT(list);
03260 break;
03261 }
03262 }
03263 AST_LIST_TRAVERSE_SAFE_END;
03264 AST_LIST_UNLOCK(&parkinglot->parkings);
03265
03266 if (pu) {
03267 peer = pu->chan;
03268 con = ast_context_find(parkinglot->parking_con);
03269 if (con) {
03270 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0))
03271 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
03272 else
03273 notify_metermaids(pu->parkingexten, parkinglot->parking_con, AST_DEVICE_NOT_INUSE);
03274 } else
03275 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
03276
03277 manager_event(EVENT_FLAG_CALL, "UnParkedCall",
03278 "Exten: %s\r\n"
03279 "Channel: %s\r\n"
03280 "From: %s\r\n"
03281 "CallerIDNum: %s\r\n"
03282 "CallerIDName: %s\r\n",
03283 pu->parkingexten, pu->chan->name, chan->name,
03284 S_OR(pu->chan->cid.cid_num, "<unknown>"),
03285 S_OR(pu->chan->cid.cid_name, "<unknown>")
03286 );
03287
03288 ast_free(pu);
03289 }
03290
03291 if (chan->_state != AST_STATE_UP)
03292 ast_answer(chan);
03293
03294
03295
03296
03297
03298 if (peer) {
03299 struct ast_datastore *features_datastore;
03300 struct ast_dial_features *dialfeatures = NULL;
03301
03302
03303
03304 if (!ast_strlen_zero(courtesytone)) {
03305 int error = 0;
03306 ast_indicate(peer, AST_CONTROL_UNHOLD);
03307 if (parkedplay == 0) {
03308 error = ast_stream_and_wait(chan, courtesytone, "");
03309 } else if (parkedplay == 1) {
03310 error = ast_stream_and_wait(peer, courtesytone, "");
03311 } else if (parkedplay == 2) {
03312 if (!ast_streamfile(chan, courtesytone, chan->language) &&
03313 !ast_streamfile(peer, courtesytone, chan->language)) {
03314
03315 res = ast_waitstream(chan, "");
03316 if (res >= 0)
03317 res = ast_waitstream(peer, "");
03318 if (res < 0)
03319 error = 1;
03320 }
03321 }
03322 if (error) {
03323 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
03324 ast_hangup(peer);
03325 return -1;
03326 }
03327 } else
03328 ast_indicate(peer, AST_CONTROL_UNHOLD);
03329
03330 res = ast_channel_make_compatible(chan, peer);
03331 if (res < 0) {
03332 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
03333 ast_hangup(peer);
03334 return -1;
03335 }
03336
03337
03338 ast_verb(3, "Channel %s connected to parked call %d\n", chan->name, park);
03339
03340 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
03341 ast_cdr_setdestchan(chan->cdr, peer->name);
03342 memset(&config, 0, sizeof(struct ast_bridge_config));
03343
03344
03345 ast_channel_lock(peer);
03346 if ((features_datastore = ast_channel_datastore_find(peer, &dial_features_info, NULL))) {
03347 dialfeatures = features_datastore->data;
03348 }
03349 ast_channel_unlock(peer);
03350
03351 if (dialfeatures) {
03352 ast_copy_flags(&(config.features_callee), dialfeatures->is_caller ? &(dialfeatures->features_caller) : &(dialfeatures->features_callee), AST_FLAGS_ALL);
03353 }
03354
03355 if ((parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
03356 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
03357 }
03358 if ((parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
03359 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
03360 }
03361 if ((parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
03362 ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL);
03363 }
03364 if ((parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
03365 ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL);
03366 }
03367 if ((parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
03368 ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT);
03369 }
03370 if ((parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
03371 ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT);
03372 }
03373 if ((parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
03374 ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
03375 }
03376 if ((parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
03377 ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
03378 }
03379
03380 res = ast_bridge_call(chan, peer, &config);
03381
03382 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
03383 ast_cdr_setdestchan(chan->cdr, peer->name);
03384
03385
03386 ast_hangup(peer);
03387 return res;
03388 } else {
03389
03390 if (ast_stream_and_wait(chan, "pbx-invalidpark", ""))
03391 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
03392 ast_verb(3, "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
03393 res = -1;
03394 }
03395
03396 return res;
03397 }
03398
03399 static int park_exec(struct ast_channel *chan, void *data)
03400 {
03401 return park_exec_full(chan, data, default_parkinglot);
03402 }
03403
03404
03405
03406 static void parkinglot_unref(struct ast_parkinglot *parkinglot)
03407 {
03408 int refcount = ao2_ref(parkinglot, -1);
03409 if (option_debug > 2)
03410 ast_log(LOG_DEBUG, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount - 1);
03411 }
03412
03413 static struct ast_parkinglot *parkinglot_addref(struct ast_parkinglot *parkinglot)
03414 {
03415 int refcount = ao2_ref(parkinglot, +1);
03416 if (option_debug > 2)
03417 ast_log(LOG_DEBUG, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount + 1);
03418 return parkinglot;
03419 }
03420
03421
03422 static struct ast_parkinglot *create_parkinglot(char *name)
03423 {
03424 struct ast_parkinglot *newlot = (struct ast_parkinglot *) NULL;
03425
03426 if (!name)
03427 return NULL;
03428
03429 newlot = ao2_alloc(sizeof(*newlot), parkinglot_destroy);
03430 if (!newlot)
03431 return NULL;
03432
03433 ast_copy_string(newlot->name, name, sizeof(newlot->name));
03434
03435 return newlot;
03436 }
03437
03438
03439 static void parkinglot_destroy(void *obj)
03440 {
03441 struct ast_parkinglot *ruin = obj;
03442 struct ast_context *con;
03443 con = ast_context_find(ruin->parking_con);
03444 if (con)
03445 ast_context_destroy(con, registrar);
03446 ao2_unlink(parkinglots, ruin);
03447 }
03448
03449
03450 static struct ast_parkinglot *build_parkinglot(char *name, struct ast_variable *var)
03451 {
03452 struct ast_parkinglot *parkinglot;
03453 struct ast_context *con = NULL;
03454
03455 struct ast_variable *confvar = var;
03456 int error = 0;
03457 int start = 0, end = 0;
03458 int oldparkinglot = 0;
03459
03460 parkinglot = find_parkinglot(name);
03461 if (parkinglot)
03462 oldparkinglot = 1;
03463 else
03464 parkinglot = create_parkinglot(name);
03465
03466 if (!parkinglot)
03467 return NULL;
03468
03469 ao2_lock(parkinglot);
03470
03471 if (option_debug)
03472 ast_log(LOG_DEBUG, "Building parking lot %s\n", name);
03473
03474
03475 while(confvar) {
03476 if (!strcasecmp(confvar->name, "context")) {
03477 ast_copy_string(parkinglot->parking_con, confvar->value, sizeof(parkinglot->parking_con));
03478 } else if (!strcasecmp(confvar->name, "parkingtime")) {
03479 if ((sscanf(confvar->value, "%d", &parkinglot->parkingtime) != 1) || (parkinglot->parkingtime < 1)) {
03480 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", confvar->value);
03481 parkinglot->parkingtime = DEFAULT_PARK_TIME;
03482 } else
03483 parkinglot->parkingtime = parkinglot->parkingtime * 1000;
03484 } else if (!strcasecmp(confvar->name, "parkpos")) {
03485 if (sscanf(confvar->value, "%d-%d", &start, &end) != 2) {
03486 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);
03487 error = 1;
03488 } else {
03489 parkinglot->parking_start = start;
03490 parkinglot->parking_stop = end;
03491 }
03492 } else if (!strcasecmp(confvar->name, "findslot")) {
03493 parkinglot->parkfindnext = (!strcasecmp(confvar->value, "next"));
03494 }
03495 confvar = confvar->next;
03496 }
03497
03498 if (parkinglot->parkingtime == 0) {
03499 parkinglot->parkingtime = DEFAULT_PARK_TIME;
03500 }
03501
03502 if (!var) {
03503 ast_copy_string(parkinglot->parking_con, "parkedcalls", sizeof(parkinglot->parking_con));
03504 ast_copy_string(parkinglot->parking_con_dial, "park-dial", sizeof(parkinglot->parking_con_dial));
03505 ast_copy_string(parkinglot->mohclass, "default", sizeof(parkinglot->mohclass));
03506 }
03507
03508
03509 if (ast_strlen_zero(parkinglot->parking_con)) {
03510 ast_log(LOG_WARNING, "Parking lot %s lacks context\n", name);
03511 error = 1;
03512 }
03513
03514
03515 if (!error && !(con = ast_context_find_or_create(NULL, NULL, parkinglot->parking_con, registrar))) {
03516 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parkinglot->parking_con);
03517 error = 1;
03518 }
03519
03520
03521 if (!oldparkinglot) {
03522 if (!ast_strlen_zero(ast_parking_ext())) {
03523 if (ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, strdup(""), ast_free_ptr, registrar) == -1)
03524 error = 1;
03525 }
03526 }
03527
03528 ao2_unlock(parkinglot);
03529
03530 if (error) {
03531 ast_log(LOG_WARNING, "Parking %s not open for business. Configuration error.\n", name);
03532 parkinglot_destroy(parkinglot);
03533 return NULL;
03534 }
03535 if (option_debug)
03536 ast_log(LOG_DEBUG, "Parking %s now open for business. (start exten %d end %d)\n", name, start, end);
03537
03538
03539
03540 if (!oldparkinglot) {
03541 ao2_link(parkinglots, parkinglot);
03542 }
03543 parkinglot_unref(parkinglot);
03544
03545 return parkinglot;
03546 }
03547
03548
03549
03550
03551
03552
03553
03554
03555 static void park_add_hints(char *context, int start, int stop)
03556 {
03557 int numext;
03558 char device[AST_MAX_EXTENSION];
03559 char exten[10];
03560
03561 for (numext = start; numext <= stop; numext++) {
03562 snprintf(exten, sizeof(exten), "%d", numext);
03563 snprintf(device, sizeof(device), "park:%s@%s", exten, context);
03564 ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
03565 }
03566 }
03567
03568 static int load_config(void)
03569 {
03570 int start = 0, end = 0;
03571 int res;
03572 int i;
03573 struct ast_context *con = NULL;
03574 struct ast_config *cfg = NULL;
03575 struct ast_variable *var = NULL;
03576 struct feature_group *fg = NULL;
03577 struct ast_flags config_flags = { 0 };
03578 char old_parking_ext[AST_MAX_EXTENSION];
03579 char old_parking_con[AST_MAX_EXTENSION] = "";
03580 char *ctg;
03581 static const char *categories[] = {
03582
03583
03584
03585 "general",
03586 "featuremap",
03587 "applicationmap"
03588 };
03589
03590 if (default_parkinglot) {
03591 strcpy(old_parking_con, default_parkinglot->parking_con);
03592 strcpy(old_parking_ext, parking_ext);
03593 } else {
03594 default_parkinglot = build_parkinglot(DEFAULT_PARKINGLOT, NULL);
03595 if (default_parkinglot) {
03596 ao2_lock(default_parkinglot);
03597 default_parkinglot->parking_start = 701;
03598 default_parkinglot->parking_stop = 750;
03599 default_parkinglot->parking_offset = 0;
03600 default_parkinglot->parkfindnext = 0;
03601 default_parkinglot->parkingtime = DEFAULT_PARK_TIME;
03602 ao2_unlock(default_parkinglot);
03603 }
03604 }
03605 if (default_parkinglot) {
03606 if (option_debug)
03607 ast_log(LOG_DEBUG, "Configuration of default parkinglot done.\n");
03608 } else {
03609 ast_log(LOG_ERROR, "Configuration of default parkinglot failed.\n");
03610 return -1;
03611 }
03612
03613
03614
03615 strcpy(parking_ext, "700");
03616 strcpy(pickup_ext, "*8");
03617 courtesytone[0] = '\0';
03618 strcpy(xfersound, "beep");
03619 strcpy(xferfailsound, "pbx-invalid");
03620 adsipark = 0;
03621 comebacktoorigin = 1;
03622
03623 default_parkinglot->parkaddhints = 0;
03624 default_parkinglot->parkedcalltransfers = 0;
03625 default_parkinglot->parkedcallreparking = 0;
03626 default_parkinglot->parkedcallrecording = 0;
03627 default_parkinglot->parkedcallhangup = 0;
03628
03629 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
03630 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
03631 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
03632 atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY;
03633 atxferdropcall = DEFAULT_ATXFER_DROP_CALL;
03634 atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES;
03635
03636 cfg = ast_config_load2("features.conf", "features", config_flags);
03637 if (!cfg) {
03638 ast_log(LOG_WARNING,"Could not load features.conf\n");
03639 return 0;
03640 }
03641 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
03642 if (!strcasecmp(var->name, "parkext")) {
03643 ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
03644 } else if (!strcasecmp(var->name, "context")) {
03645 ast_copy_string(default_parkinglot->parking_con, var->value, sizeof(default_parkinglot->parking_con));
03646 } else if (!strcasecmp(var->name, "parkingtime")) {
03647 if ((sscanf(var->value, "%d", &default_parkinglot->parkingtime) != 1) || (default_parkinglot->parkingtime < 1)) {
03648 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
03649 default_parkinglot->parkingtime = DEFAULT_PARK_TIME;
03650 } else
03651 default_parkinglot->parkingtime = default_parkinglot->parkingtime * 1000;
03652 } else if (!strcasecmp(var->name, "parkpos")) {
03653 if (sscanf(var->value, "%d-%d", &start, &end) != 2) {
03654 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);
03655 } else if (default_parkinglot) {
03656 default_parkinglot->parking_start = start;
03657 default_parkinglot->parking_stop = end;
03658 } else {
03659 ast_log(LOG_WARNING, "No default parking lot!\n");
03660 }
03661 } else if (!strcasecmp(var->name, "findslot")) {
03662 default_parkinglot->parkfindnext = (!strcasecmp(var->value, "next"));
03663 } else if (!strcasecmp(var->name, "parkinghints")) {
03664 default_parkinglot->parkaddhints = ast_true(var->value);
03665 } else if (!strcasecmp(var->name, "parkedcalltransfers")) {
03666 if (!strcasecmp(var->value, "both"))
03667 default_parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH;
03668 else if (!strcasecmp(var->value, "caller"))
03669 default_parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYCALLER;
03670 else if (!strcasecmp(var->value, "callee"))
03671 default_parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYCALLEE;
03672 } else if (!strcasecmp(var->name, "parkedcallreparking")) {
03673 if (!strcasecmp(var->value, "both"))
03674 default_parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYBOTH;
03675 else if (!strcasecmp(var->value, "caller"))
03676 default_parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYCALLER;
03677 else if (!strcasecmp(var->value, "callee"))
03678 default_parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYCALLEE;
03679 } else if (!strcasecmp(var->name, "parkedcallhangup")) {
03680 if (!strcasecmp(var->value, "both"))
03681 default_parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYBOTH;
03682 else if (!strcasecmp(var->value, "caller"))
03683 default_parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYCALLER;
03684 else if (!strcasecmp(var->value, "callee"))
03685 default_parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYCALLEE;
03686 } else if (!strcasecmp(var->name, "parkedcallrecording")) {
03687 if (!strcasecmp(var->value, "both"))
03688 default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYBOTH;
03689 else if (!strcasecmp(var->value, "caller"))
03690 default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYCALLER;
03691 else if (!strcasecmp(var->value, "callee"))
03692 default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYCALLEE;
03693 } else if (!strcasecmp(var->name, "adsipark")) {
03694 adsipark = ast_true(var->value);
03695 } else if (!strcasecmp(var->name, "transferdigittimeout")) {
03696 if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
03697 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
03698 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
03699 } else
03700 transferdigittimeout = transferdigittimeout * 1000;
03701 } else if (!strcasecmp(var->name, "featuredigittimeout")) {
03702 if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
03703 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
03704 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
03705 }
03706 } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) {
03707 if ((sscanf(var->value, "%d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) {
03708 ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value);
03709 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
03710 } else
03711 atxfernoanswertimeout = atxfernoanswertimeout * 1000;
03712 } else if (!strcasecmp(var->name, "atxferloopdelay")) {
03713 if ((sscanf(var->value, "%u", &atxferloopdelay) != 1)) {
03714 ast_log(LOG_WARNING, "%s is not a valid atxferloopdelay\n", var->value);
03715 atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY;
03716 } else
03717 atxferloopdelay *= 1000;
03718 } else if (!strcasecmp(var->name, "atxferdropcall")) {
03719 atxferdropcall = ast_true(var->value);
03720 } else if (!strcasecmp(var->name, "atxfercallbackretries")) {
03721 if ((sscanf(var->value, "%u", &atxferloopdelay) != 1)) {
03722 ast_log(LOG_WARNING, "%s is not a valid atxfercallbackretries\n", var->value);
03723 atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES;
03724 }
03725 } else if (!strcasecmp(var->name, "courtesytone")) {
03726 ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
03727 } else if (!strcasecmp(var->name, "parkedplay")) {
03728 if (!strcasecmp(var->value, "both"))
03729 parkedplay = 2;
03730 else if (!strcasecmp(var->value, "parked"))
03731 parkedplay = 1;
03732 else
03733 parkedplay = 0;
03734 } else if (!strcasecmp(var->name, "xfersound")) {
03735 ast_copy_string(xfersound, var->value, sizeof(xfersound));
03736 } else if (!strcasecmp(var->name, "xferfailsound")) {
03737 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
03738 } else if (!strcasecmp(var->name, "pickupexten")) {
03739 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
03740 } else if (!strcasecmp(var->name, "comebacktoorigin")) {
03741 comebacktoorigin = ast_true(var->value);
03742 } else if (!strcasecmp(var->name, "parkedmusicclass")) {
03743 ast_copy_string(default_parkinglot->mohclass, var->value, sizeof(default_parkinglot->mohclass));
03744 }
03745 }
03746
03747 unmap_features();
03748 for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) {
03749 if (remap_feature(var->name, var->value))
03750 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
03751 }
03752
03753
03754 ast_unregister_features();
03755 for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) {
03756 char *tmp_val = ast_strdupa(var->value);
03757 char *exten, *activateon, *activatedby, *app, *app_args, *moh_class;
03758 struct ast_call_feature *feature;
03759
03760
03761
03762
03763
03764 exten = strsep(&tmp_val,",");
03765 activatedby = strsep(&tmp_val,",");
03766 app = strsep(&tmp_val,",");
03767 app_args = strsep(&tmp_val,",");
03768 moh_class = strsep(&tmp_val,",");
03769
03770 activateon = strsep(&activatedby, "/");
03771
03772
03773 if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) {
03774 ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",
03775 app, exten, activateon, var->name);
03776 continue;
03777 }
03778
03779 AST_RWLIST_RDLOCK(&feature_list);
03780 if ((feature = find_dynamic_feature(var->name))) {
03781 AST_RWLIST_UNLOCK(&feature_list);
03782 ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name);
03783 continue;
03784 }
03785 AST_RWLIST_UNLOCK(&feature_list);
03786
03787 if (!(feature = ast_calloc(1, sizeof(*feature))))
03788 continue;
03789
03790 ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN);
03791 ast_copy_string(feature->app, app, FEATURE_APP_LEN);
03792 ast_copy_string(feature->exten, exten, FEATURE_EXTEN_LEN);
03793
03794 if (app_args)
03795 ast_copy_string(feature->app_args, app_args, FEATURE_APP_ARGS_LEN);
03796
03797 if (moh_class)
03798 ast_copy_string(feature->moh_class, moh_class, FEATURE_MOH_LEN);
03799
03800 ast_copy_string(feature->exten, exten, sizeof(feature->exten));
03801 feature->operation = feature_exec_app;
03802 ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF);
03803
03804
03805 if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller"))
03806 ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF);
03807 else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee"))
03808 ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER);
03809 else {
03810 ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s',"
03811 " must be 'self', or 'peer'\n", var->name);
03812 continue;
03813 }
03814
03815 if (ast_strlen_zero(activatedby))
03816 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
03817 else if (!strcasecmp(activatedby, "caller"))
03818 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER);
03819 else if (!strcasecmp(activatedby, "callee"))
03820 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE);
03821 else if (!strcasecmp(activatedby, "both"))
03822 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
03823 else {
03824 ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s',"
03825 " must be 'caller', or 'callee', or 'both'\n", var->name);
03826 continue;
03827 }
03828
03829 ast_register_feature(feature);
03830
03831 ast_verb(2, "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, app, app_args, exten);
03832 }
03833
03834 ast_unregister_groups();
03835 AST_RWLIST_WRLOCK(&feature_groups);
03836
03837 ctg = NULL;
03838 while ((ctg = ast_category_browse(cfg, ctg))) {
03839
03840 if (!strncasecmp(ctg, "parkinglot_", strlen("parkinglot_"))) {
03841 ast_debug(2, "Found configuration section %s, assume parking context\n", ctg);
03842 if(!build_parkinglot(ctg, ast_variable_browse(cfg, ctg)))
03843 ast_log(LOG_ERROR, "Could not build parking lot %s. Configuration error.\n", ctg);
03844 else
03845 ast_debug(1, "Configured parking context %s\n", ctg);
03846 continue;
03847 }
03848
03849 for (i = 0; i < ARRAY_LEN(categories); i++) {
03850 if (!strcasecmp(categories[i], ctg))
03851 break;
03852 }
03853
03854 if (i < ARRAY_LEN(categories))
03855 continue;
03856
03857 if (!(fg = register_group(ctg)))
03858 continue;
03859
03860 for (var = ast_variable_browse(cfg, ctg); var; var = var->next) {
03861 struct ast_call_feature *feature;
03862
03863 AST_RWLIST_RDLOCK(&feature_list);
03864 if (!(feature = find_dynamic_feature(var->name)) &&
03865 !(feature = ast_find_call_feature(var->name))) {
03866 AST_RWLIST_UNLOCK(&feature_list);
03867 ast_log(LOG_WARNING, "Feature '%s' was not found.\n", var->name);
03868 continue;
03869 }
03870 AST_RWLIST_UNLOCK(&feature_list);
03871
03872 register_group_feature(fg, var->value, feature);
03873 }
03874 }
03875
03876 AST_RWLIST_UNLOCK(&feature_groups);
03877
03878 ast_config_destroy(cfg);
03879
03880
03881 if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) {
03882 if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar, 0))
03883 notify_metermaids(old_parking_ext, old_parking_con, AST_DEVICE_NOT_INUSE);
03884 ast_debug(1, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
03885 }
03886
03887 if (!(con = ast_context_find_or_create(NULL, NULL, default_parkinglot->parking_con, registrar))) {
03888 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", default_parkinglot->parking_con);
03889 return -1;
03890 }
03891 res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar);
03892 if (default_parkinglot->parkaddhints)
03893 park_add_hints(default_parkinglot->parking_con, default_parkinglot->parking_start, default_parkinglot->parking_stop);
03894 if (!res)
03895 notify_metermaids(ast_parking_ext(), default_parkinglot->parking_con, AST_DEVICE_INUSE);
03896 return res;
03897
03898 }
03899
03900
03901
03902
03903
03904
03905
03906
03907
03908
03909 static char *handle_feature_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
03910 {
03911 int i;
03912 struct ast_call_feature *feature;
03913 struct ao2_iterator iter;
03914 struct ast_parkinglot *curlot;
03915 #define HFS_FORMAT "%-25s %-7s %-7s\n"
03916
03917 switch (cmd) {
03918
03919 case CLI_INIT:
03920 e->command = "features show";
03921 e->usage =
03922 "Usage: features show\n"
03923 " Lists configured features\n";
03924 return NULL;
03925 case CLI_GENERATE:
03926 return NULL;
03927 }
03928
03929 ast_cli(a->fd, HFS_FORMAT, "Builtin Feature", "Default", "Current");
03930 ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
03931
03932 ast_cli(a->fd, HFS_FORMAT, "Pickup", "*8", ast_pickup_ext());
03933
03934 ast_rwlock_rdlock(&features_lock);
03935 for (i = 0; i < FEATURES_COUNT; i++)
03936 ast_cli(a->fd, HFS_FORMAT, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
03937 ast_rwlock_unlock(&features_lock);
03938
03939 ast_cli(a->fd, "\n");
03940 ast_cli(a->fd, HFS_FORMAT, "Dynamic Feature", "Default", "Current");
03941 ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
03942 if (AST_RWLIST_EMPTY(&feature_list)) {
03943 ast_cli(a->fd, "(none)\n");
03944 } else {
03945 AST_RWLIST_RDLOCK(&feature_list);
03946 AST_RWLIST_TRAVERSE(&feature_list, feature, feature_entry) {
03947 ast_cli(a->fd, HFS_FORMAT, feature->sname, "no def", feature->exten);
03948 }
03949 AST_RWLIST_UNLOCK(&feature_list);
03950 }
03951
03952
03953 iter = ao2_iterator_init(parkinglots, 0);
03954
03955 while ((curlot = ao2_iterator_next(&iter))) {
03956 ast_cli(a->fd, "\nCall parking (Parking lot: %s)\n", curlot->name);
03957 ast_cli(a->fd, "------------\n");
03958 ast_cli(a->fd,"%-22s: %s\n", "Parking extension", parking_ext);
03959 ast_cli(a->fd,"%-22s: %s\n", "Parking context", curlot->parking_con);
03960 ast_cli(a->fd,"%-22s: %d-%d\n", "Parked call extensions", curlot->parking_start, curlot->parking_stop);
03961 ast_cli(a->fd,"\n");
03962 ao2_ref(curlot, -1);
03963 }
03964
03965
03966 return CLI_SUCCESS;
03967 }
03968
03969 int ast_features_reload(void)
03970 {
03971 int res;
03972
03973
03974
03975
03976
03977 res = load_config();
03978
03979
03980 return res;
03981 }
03982
03983 static char *handle_features_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
03984 {
03985 switch (cmd) {
03986 case CLI_INIT:
03987 e->command = "features reload";
03988 e->usage =
03989 "Usage: features reload\n"
03990 " Reloads configured call features from features.conf\n";
03991 return NULL;
03992 case CLI_GENERATE:
03993 return NULL;
03994 }
03995 ast_features_reload();
03996
03997 return CLI_SUCCESS;
03998 }
03999
04000 static char mandescr_bridge[] =
04001 "Description: Bridge together two channels already in the PBX\n"
04002 "Variables: ( Headers marked with * are required )\n"
04003 " *Channel1: Channel to Bridge to Channel2\n"
04004 " *Channel2: Channel to Bridge to Channel1\n"
04005 " Tone: (Yes|No) Play courtesy tone to Channel 2\n"
04006 "\n";
04007
04008
04009
04010
04011
04012
04013
04014
04015
04016 static void do_bridge_masquerade(struct ast_channel *chan, struct ast_channel *tmpchan)
04017 {
04018 ast_moh_stop(chan);
04019 ast_channel_lock(chan);
04020 ast_setstate(tmpchan, chan->_state);
04021 tmpchan->readformat = chan->readformat;
04022 tmpchan->writeformat = chan->writeformat;
04023 ast_channel_masquerade(tmpchan, chan);
04024 ast_channel_lock(tmpchan);
04025 ast_do_masquerade(tmpchan);
04026
04027 ast_explicit_goto(tmpchan, chan->context, chan->exten, chan->priority + 1);
04028 ast_channel_unlock(tmpchan);
04029 ast_channel_unlock(chan);
04030 }
04031
04032
04033
04034
04035
04036
04037
04038
04039
04040
04041
04042
04043
04044
04045
04046 static int action_bridge(struct mansession *s, const struct message *m)
04047 {
04048 const char *channela = astman_get_header(m, "Channel1");
04049 const char *channelb = astman_get_header(m, "Channel2");
04050 const char *playtone = astman_get_header(m, "Tone");
04051 struct ast_channel *chana = NULL, *chanb = NULL;
04052 struct ast_channel *tmpchana = NULL, *tmpchanb = NULL;
04053 struct ast_bridge_thread_obj *tobj = NULL;
04054
04055
04056 if (ast_strlen_zero(channela) || ast_strlen_zero(channelb)) {
04057 astman_send_error(s, m, "Missing channel parameter in request");
04058 return 0;
04059 }
04060
04061
04062
04063
04064
04065
04066 chana = ast_get_channel_by_name_prefix_locked(channela, strlen(channela));
04067
04068
04069 if (!chana) {
04070 char buf[256];
04071 snprintf(buf, sizeof(buf), "Channel1 does not exists: %s", channela);
04072 astman_send_error(s, m, buf);
04073 return 0;
04074 }
04075
04076
04077 if (chana->_state != AST_STATE_UP)
04078 ast_answer(chana);
04079
04080
04081 if (!(tmpchana = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
04082 NULL, NULL, 0, "Bridge/%s", chana->name))) {
04083 astman_send_error(s, m, "Unable to create temporary channel!");
04084 ast_channel_unlock(chana);
04085 return 1;
04086 }
04087
04088 do_bridge_masquerade(chana, tmpchana);
04089 ast_channel_unlock(chana);
04090 chana = NULL;
04091
04092
04093 chanb = ast_get_channel_by_name_prefix_locked(channelb, strlen(channelb));
04094
04095 if (!chanb) {
04096 char buf[256];
04097 snprintf(buf, sizeof(buf), "Channel2 does not exists: %s", channelb);
04098 ast_hangup(tmpchana);
04099 astman_send_error(s, m, buf);
04100 return 0;
04101 }
04102
04103
04104 if (chanb->_state != AST_STATE_UP)
04105 ast_answer(chanb);
04106
04107
04108 if (!(tmpchanb = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
04109 NULL, NULL, 0, "Bridge/%s", chanb->name))) {
04110 astman_send_error(s, m, "Unable to create temporary channels!");
04111 ast_hangup(tmpchana);
04112 ast_channel_unlock(chanb);
04113 return 1;
04114 }
04115 do_bridge_masquerade(chanb, tmpchanb);
04116 ast_channel_unlock(chanb);
04117 chanb = NULL;
04118
04119
04120 if (ast_channel_make_compatible(tmpchana, tmpchanb)) {
04121 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for manager bridge\n", tmpchana->name, tmpchanb->name);
04122 astman_send_error(s, m, "Could not make channels compatible for manager bridge");
04123 ast_hangup(tmpchana);
04124 ast_hangup(tmpchanb);
04125 return 1;
04126 }
04127
04128
04129 if (!(tobj = ast_calloc(1, sizeof(*tobj)))) {
04130 ast_log(LOG_WARNING, "Unable to spawn a new bridge thread on %s and %s: %s\n", tmpchana->name, tmpchanb->name, strerror(errno));
04131 astman_send_error(s, m, "Unable to spawn a new bridge thread");
04132 ast_hangup(tmpchana);
04133 ast_hangup(tmpchanb);
04134 return 1;
04135 }
04136
04137 tobj->chan = tmpchana;
04138 tobj->peer = tmpchanb;
04139 tobj->return_to_pbx = 1;
04140
04141 if (ast_true(playtone)) {
04142 if (!ast_strlen_zero(xfersound) && !ast_streamfile(tmpchanb, xfersound, tmpchanb->language)) {
04143 if (ast_waitstream(tmpchanb, "") < 0)
04144 ast_log(LOG_WARNING, "Failed to play a courtesy tone on chan %s\n", tmpchanb->name);
04145 }
04146 }
04147
04148 ast_bridge_call_thread_launch(tobj);
04149
04150 astman_send_ack(s, m, "Launched bridge thread with success");
04151
04152 return 0;
04153 }
04154
04155
04156
04157
04158
04159
04160
04161
04162
04163
04164
04165
04166 static char *handle_parkedcalls(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04167 {
04168 struct parkeduser *cur;
04169 int numparked = 0;
04170 struct ao2_iterator iter;
04171 struct ast_parkinglot *curlot;
04172
04173 switch (cmd) {
04174 case CLI_INIT:
04175 e->command = "parkedcalls show";
04176 e->usage =
04177 "Usage: parkedcalls show\n"
04178 " List currently parked calls\n";
04179 return NULL;
04180 case CLI_GENERATE:
04181 return NULL;
04182 }
04183
04184 if (a->argc > e->args)
04185 return CLI_SHOWUSAGE;
04186
04187 ast_cli(a->fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
04188 , "Context", "Extension", "Pri", "Timeout");
04189
04190 iter = ao2_iterator_init(parkinglots, 0);
04191 while ((curlot = ao2_iterator_next(&iter))) {
04192 int lotparked = 0;
04193 ast_cli(a->fd, "*** Parking lot: %s\n", curlot->name);
04194
04195 AST_LIST_LOCK(&curlot->parkings);
04196 AST_LIST_TRAVERSE(&curlot->parkings, cur, list) {
04197 ast_cli(a->fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n"
04198 ,cur->parkingexten, cur->chan->name, cur->context, cur->exten
04199 ,cur->priority,
04200 (long)(cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL)) );
04201 numparked++;
04202 numparked += lotparked;
04203 }
04204 AST_LIST_UNLOCK(&curlot->parkings);
04205 if (lotparked)
04206 ast_cli(a->fd, " %d parked call%s in parking lot %s\n", lotparked, ESS(lotparked), curlot->name);
04207
04208 ao2_ref(curlot, -1);
04209 }
04210
04211 ast_cli(a->fd, "---\n%d parked call%s in total.\n", numparked, ESS(numparked));
04212
04213 return CLI_SUCCESS;
04214 }
04215
04216 static struct ast_cli_entry cli_features[] = {
04217 AST_CLI_DEFINE(handle_feature_show, "Lists configured features"),
04218 AST_CLI_DEFINE(handle_features_reload, "Reloads configured features"),
04219 AST_CLI_DEFINE(handle_parkedcalls, "List currently parked calls"),
04220 };
04221
04222
04223
04224
04225
04226
04227
04228
04229
04230 static int manager_parking_status(struct mansession *s, const struct message *m)
04231 {
04232 struct parkeduser *cur;
04233 const char *id = astman_get_header(m, "ActionID");
04234 char idText[256] = "";
04235 struct ao2_iterator iter;
04236 struct ast_parkinglot *curlot;
04237
04238 if (!ast_strlen_zero(id))
04239 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
04240
04241 astman_send_ack(s, m, "Parked calls will follow");
04242
04243 iter = ao2_iterator_init(parkinglots, 0);
04244 while ((curlot = ao2_iterator_next(&iter))) {
04245
04246 AST_LIST_LOCK(&curlot->parkings);
04247 AST_LIST_TRAVERSE(&curlot->parkings, cur, list) {
04248 astman_append(s, "Event: ParkedCall\r\n"
04249 "Exten: %d\r\n"
04250 "Channel: %s\r\n"
04251 "From: %s\r\n"
04252 "Timeout: %ld\r\n"
04253 "CallerIDNum: %s\r\n"
04254 "CallerIDName: %s\r\n"
04255 "%s"
04256 "\r\n",
04257 cur->parkingnum, cur->chan->name, cur->peername,
04258 (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
04259 S_OR(cur->chan->cid.cid_num, ""),
04260 S_OR(cur->chan->cid.cid_name, ""),
04261 idText);
04262 }
04263 AST_LIST_UNLOCK(&curlot->parkings);
04264 ao2_ref(curlot, -1);
04265 }
04266
04267 astman_append(s,
04268 "Event: ParkedCallsComplete\r\n"
04269 "%s"
04270 "\r\n",idText);
04271
04272
04273 return RESULT_SUCCESS;
04274 }
04275
04276 static char mandescr_park[] =
04277 "Description: Park a channel.\n"
04278 "Variables: (Names marked with * are required)\n"
04279 " *Channel: Channel name to park\n"
04280 " *Channel2: Channel to announce park info to (and return to if timeout)\n"
04281 " Timeout: Number of milliseconds to wait before callback.\n";
04282
04283
04284
04285
04286
04287
04288
04289
04290
04291 static int manager_park(struct mansession *s, const struct message *m)
04292 {
04293 const char *channel = astman_get_header(m, "Channel");
04294 const char *channel2 = astman_get_header(m, "Channel2");
04295 const char *timeout = astman_get_header(m, "Timeout");
04296 char buf[BUFSIZ];
04297 int to = 0;
04298 int res = 0;
04299 int parkExt = 0;
04300 struct ast_channel *ch1, *ch2;
04301
04302 if (ast_strlen_zero(channel)) {
04303 astman_send_error(s, m, "Channel not specified");
04304 return 0;
04305 }
04306
04307 if (ast_strlen_zero(channel2)) {
04308 astman_send_error(s, m, "Channel2 not specified");
04309 return 0;
04310 }
04311
04312 ch1 = ast_get_channel_by_name_locked(channel);
04313 if (!ch1) {
04314 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
04315 astman_send_error(s, m, buf);
04316 return 0;
04317 }
04318
04319 ch2 = ast_get_channel_by_name_locked(channel2);
04320 if (!ch2) {
04321 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
04322 astman_send_error(s, m, buf);
04323 ast_channel_unlock(ch1);
04324 return 0;
04325 }
04326
04327 if (!ast_strlen_zero(timeout)) {
04328 sscanf(timeout, "%d", &to);
04329 }
04330
04331 res = ast_masq_park_call(ch1, ch2, to, &parkExt);
04332 if (!res) {
04333 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
04334 astman_send_ack(s, m, "Park successful");
04335 } else {
04336 astman_send_error(s, m, "Park failure");
04337 }
04338
04339 ast_channel_unlock(ch1);
04340 ast_channel_unlock(ch2);
04341
04342 return 0;
04343 }
04344
04345
04346
04347
04348
04349
04350
04351
04352
04353 int ast_pickup_call(struct ast_channel *chan)
04354 {
04355 struct ast_channel *cur = NULL;
04356 int res = -1;
04357
04358 while ((cur = ast_channel_walk_locked(cur)) != NULL) {
04359 if (!cur->pbx &&
04360 (cur != chan) &&
04361 (chan->pickupgroup & cur->callgroup) &&
04362 ((cur->_state == AST_STATE_RINGING) ||
04363 (cur->_state == AST_STATE_RING))) {
04364 break;
04365 }
04366 ast_channel_unlock(cur);
04367 }
04368 if (cur) {
04369 ast_debug(1, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
04370 res = ast_answer(chan);
04371 if (res)
04372 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
04373 res = ast_queue_control(chan, AST_CONTROL_ANSWER);
04374 if (res)
04375 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
04376 res = ast_channel_masquerade(cur, chan);
04377 if (res)
04378 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);
04379 ast_channel_unlock(cur);
04380 } else {
04381 ast_debug(1, "No call pickup possible...\n");
04382 }
04383 return res;
04384 }
04385
04386 static char *app_bridge = "Bridge";
04387 static char *bridge_synopsis = "Bridge two channels";
04388 static char *bridge_descrip =
04389 "Usage: Bridge(channel[,options])\n"
04390 " Allows the ability to bridge two channels via the dialplan.\n"
04391 "The current channel is bridged to the specified 'channel'.\n"
04392 " Options:\n"
04393 " p - Play a courtesy tone to 'channel'.\n"
04394 "This application sets the following channel variable upon completion:\n"
04395 " BRIDGERESULT The result of the bridge attempt as a text string, one of\n"
04396 " SUCCESS | FAILURE | LOOP | NONEXISTENT | INCOMPATIBLE\n";
04397
04398 enum {
04399 BRIDGE_OPT_PLAYTONE = (1 << 0),
04400 };
04401
04402 AST_APP_OPTIONS(bridge_exec_options, BEGIN_OPTIONS
04403 AST_APP_OPTION('p', BRIDGE_OPT_PLAYTONE)
04404 END_OPTIONS );
04405
04406
04407
04408
04409
04410
04411
04412
04413
04414
04415 static int bridge_exec(struct ast_channel *chan, void *data)
04416 {
04417 struct ast_channel *current_dest_chan, *final_dest_chan;
04418 char *tmp_data = NULL;
04419 struct ast_flags opts = { 0, };
04420 struct ast_bridge_config bconfig = { { 0, }, };
04421
04422 AST_DECLARE_APP_ARGS(args,
04423 AST_APP_ARG(dest_chan);
04424 AST_APP_ARG(options);
04425 );
04426
04427 if (ast_strlen_zero(data)) {
04428 ast_log(LOG_WARNING, "Bridge require at least 1 argument specifying the other end of the bridge\n");
04429 return -1;
04430 }
04431
04432 tmp_data = ast_strdupa(data);
04433 AST_STANDARD_APP_ARGS(args, tmp_data);
04434 if (!ast_strlen_zero(args.options))
04435 ast_app_parse_options(bridge_exec_options, &opts, NULL, args.options);
04436
04437
04438 if (!strncmp(chan->name, args.dest_chan,
04439 strlen(chan->name) < strlen(args.dest_chan) ?
04440 strlen(chan->name) : strlen(args.dest_chan))) {
04441 ast_log(LOG_WARNING, "Unable to bridge channel %s with itself\n", chan->name);
04442 manager_event(EVENT_FLAG_CALL, "BridgeExec",
04443 "Response: Failed\r\n"
04444 "Reason: Unable to bridge channel to itself\r\n"
04445 "Channel1: %s\r\n"
04446 "Channel2: %s\r\n",
04447 chan->name, args.dest_chan);
04448 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "LOOP");
04449 return 0;
04450 }
04451
04452
04453 if (!(current_dest_chan = ast_get_channel_by_name_prefix_locked(args.dest_chan,
04454 strlen(args.dest_chan)))) {
04455 ast_log(LOG_WARNING, "Bridge failed because channel %s does not exists or we "
04456 "cannot get its lock\n", args.dest_chan);
04457 manager_event(EVENT_FLAG_CALL, "BridgeExec",
04458 "Response: Failed\r\n"
04459 "Reason: Cannot grab end point\r\n"
04460 "Channel1: %s\r\n"
04461 "Channel2: %s\r\n", chan->name, args.dest_chan);
04462 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "NONEXISTENT");
04463 return 0;
04464 }
04465
04466
04467 if (current_dest_chan->_state != AST_STATE_UP)
04468 ast_answer(current_dest_chan);
04469
04470
04471 if (!(final_dest_chan = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
04472 NULL, NULL, 0, "Bridge/%s", current_dest_chan->name))) {
04473 ast_log(LOG_WARNING, "Cannot create placeholder channel for chan %s\n", args.dest_chan);
04474 manager_event(EVENT_FLAG_CALL, "BridgeExec",
04475 "Response: Failed\r\n"
04476 "Reason: cannot create placeholder\r\n"
04477 "Channel1: %s\r\n"
04478 "Channel2: %s\r\n", chan->name, args.dest_chan);
04479 }
04480 do_bridge_masquerade(current_dest_chan, final_dest_chan);
04481
04482 ast_channel_unlock(current_dest_chan);
04483
04484
04485
04486 if (ast_channel_make_compatible(chan, final_dest_chan) < 0) {
04487 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, final_dest_chan->name);
04488 manager_event(EVENT_FLAG_CALL, "BridgeExec",
04489 "Response: Failed\r\n"
04490 "Reason: Could not make channels compatible for bridge\r\n"
04491 "Channel1: %s\r\n"
04492 "Channel2: %s\r\n", chan->name, final_dest_chan->name);
04493 ast_hangup(final_dest_chan);
04494 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "INCOMPATIBLE");
04495 return 0;
04496 }
04497
04498
04499 manager_event(EVENT_FLAG_CALL, "BridgeExec",
04500 "Response: Success\r\n"
04501 "Channel1: %s\r\n"
04502 "Channel2: %s\r\n", chan->name, final_dest_chan->name);
04503
04504
04505 if (ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE) && !ast_strlen_zero(xfersound)) {
04506 if (!ast_streamfile(final_dest_chan, xfersound, final_dest_chan->language)) {
04507 if (ast_waitstream(final_dest_chan, "") < 0)
04508 ast_log(LOG_WARNING, "Failed to play courtesy tone on %s\n", final_dest_chan->name);
04509 }
04510 }
04511
04512
04513 ast_bridge_call(chan, final_dest_chan, &bconfig);
04514
04515
04516 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "SUCCESS");
04517 if (!ast_check_hangup(final_dest_chan)) {
04518 ast_debug(1, "starting new PBX in %s,%s,%d for chan %s\n",
04519 final_dest_chan->context, final_dest_chan->exten,
04520 final_dest_chan->priority, final_dest_chan->name);
04521
04522 if (ast_pbx_start(final_dest_chan) != AST_PBX_SUCCESS) {
04523 ast_log(LOG_WARNING, "FAILED continuing PBX on dest chan %s\n", final_dest_chan->name);
04524 ast_hangup(final_dest_chan);
04525 } else
04526 ast_debug(1, "SUCCESS continuing PBX on chan %s\n", final_dest_chan->name);
04527 } else {
04528 ast_debug(1, "hangup chan %s since the other endpoint has hung up\n", final_dest_chan->name);
04529 ast_hangup(final_dest_chan);
04530 }
04531
04532 return 0;
04533 }
04534
04535 int ast_features_init(void)
04536 {
04537 int res;
04538
04539 ast_register_application2(app_bridge, bridge_exec, bridge_synopsis, bridge_descrip, NULL);
04540
04541 parkinglots = ao2_container_alloc(7, parkinglot_hash_cb, parkinglot_cmp_cb);
04542
04543 if ((res = load_config()))
04544 return res;
04545 ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
04546 ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
04547 res = ast_register_application2(parkedcall, park_exec, synopsis, descrip, NULL);
04548 if (!res)
04549 res = ast_register_application2(parkcall, park_call_exec, synopsis2, descrip2, NULL);
04550 if (!res) {
04551 ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls");
04552 ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park, "Park a channel", mandescr_park);
04553 ast_manager_register2("Bridge", EVENT_FLAG_CALL, action_bridge, "Bridge two channels already in the PBX", mandescr_bridge);
04554 }
04555
04556 res |= ast_devstate_prov_add("Park", metermaidstate);
04557
04558 return res;
04559 }