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