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