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