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