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
00027
00028
00029
00030 #include "asterisk.h"
00031
00032 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 142063 $")
00033
00034 #include <pthread.h>
00035 #include <stdlib.h>
00036 #include <errno.h>
00037 #include <unistd.h>
00038 #include <string.h>
00039 #include <stdlib.h>
00040 #include <stdio.h>
00041 #include <sys/time.h>
00042 #include <sys/signal.h>
00043 #include <netinet/in.h>
00044
00045 #include "asterisk/lock.h"
00046 #include "asterisk/file.h"
00047 #include "asterisk/logger.h"
00048 #include "asterisk/channel.h"
00049 #include "asterisk/pbx.h"
00050 #include "asterisk/options.h"
00051 #include "asterisk/causes.h"
00052 #include "asterisk/module.h"
00053 #include "asterisk/translate.h"
00054 #include "asterisk/app.h"
00055 #include "asterisk/say.h"
00056 #include "asterisk/features.h"
00057 #include "asterisk/musiconhold.h"
00058 #include "asterisk/config.h"
00059 #include "asterisk/cli.h"
00060 #include "asterisk/manager.h"
00061 #include "asterisk/utils.h"
00062 #include "asterisk/adsi.h"
00063 #include "asterisk/devicestate.h"
00064 #include "asterisk/monitor.h"
00065 #include "asterisk/global_datastores.h"
00066
00067 #define DEFAULT_PARK_TIME 45000
00068 #define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000
00069 #define DEFAULT_FEATURE_DIGIT_TIMEOUT 500
00070 #define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000
00071
00072 #define AST_MAX_WATCHERS 256
00073
00074 enum {
00075 AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0),
00076 AST_FEATURE_FLAG_ONPEER = (1 << 1),
00077 AST_FEATURE_FLAG_ONSELF = (1 << 2),
00078 AST_FEATURE_FLAG_BYCALLEE = (1 << 3),
00079 AST_FEATURE_FLAG_BYCALLER = (1 << 4),
00080 AST_FEATURE_FLAG_BYBOTH = (3 << 3),
00081 };
00082
00083 static char *parkedcall = "ParkedCall";
00084
00085 static int parkaddhints = 0;
00086 static int parkingtime = DEFAULT_PARK_TIME;
00087 static char parking_con[AST_MAX_EXTENSION];
00088 static char parking_con_dial[AST_MAX_EXTENSION];
00089 static char parking_ext[AST_MAX_EXTENSION];
00090 static char pickup_ext[AST_MAX_EXTENSION];
00091 static char parkmohclass[MAX_MUSICCLASS];
00092 static int parking_start;
00093 static int parking_stop;
00094
00095 static char courtesytone[256];
00096 static int parkedplay = 0;
00097 static char xfersound[256];
00098 static char xferfailsound[256];
00099
00100 static int parking_offset;
00101 static int parkfindnext;
00102
00103 static int adsipark;
00104
00105 static int transferdigittimeout;
00106 static int featuredigittimeout;
00107
00108 static int atxfernoanswertimeout;
00109
00110 static char *registrar = "res_features";
00111
00112
00113 static char *synopsis = "Answer a parked call";
00114
00115 static char *descrip = "ParkedCall(exten):"
00116 "Used to connect to a parked call. This application is always\n"
00117 "registered internally and does not need to be explicitly added\n"
00118 "into the dialplan, although you should include the 'parkedcalls'\n"
00119 "context.\n";
00120
00121 static char *parkcall = "Park";
00122
00123 static char *synopsis2 = "Park yourself";
00124
00125 static char *descrip2 = "Park():"
00126 "Used to park yourself (typically in combination with a supervised\n"
00127 "transfer to know the parking space). This application is always\n"
00128 "registered internally and does not need to be explicitly added\n"
00129 "into the dialplan, although you should include the 'parkedcalls'\n"
00130 "context (or the context specified in features.conf).\n\n"
00131 "If you set the PARKINGEXTEN variable to an extension in your\n"
00132 "parking context, park() will park the call on that extension, unless\n"
00133 "it already exists. In that case, execution will continue at next\n"
00134 "priority.\n" ;
00135
00136 static struct ast_app *monitor_app = NULL;
00137 static int monitor_ok = 1;
00138
00139 struct parkeduser {
00140 struct ast_channel *chan;
00141 struct timeval start;
00142 int parkingnum;
00143 char parkingexten[AST_MAX_EXTENSION];
00144 char context[AST_MAX_CONTEXT];
00145 char exten[AST_MAX_EXTENSION];
00146 int priority;
00147 int parkingtime;
00148 int notquiteyet;
00149 char peername[1024];
00150 unsigned char moh_trys;
00151 struct parkeduser *next;
00152 };
00153
00154 static struct parkeduser *parkinglot;
00155
00156 AST_MUTEX_DEFINE_STATIC(parking_lock);
00157
00158 static pthread_t parking_thread;
00159
00160 char *ast_parking_ext(void)
00161 {
00162 return parking_ext;
00163 }
00164
00165 char *ast_pickup_ext(void)
00166 {
00167 return pickup_ext;
00168 }
00169
00170 struct ast_bridge_thread_obj
00171 {
00172 struct ast_bridge_config bconfig;
00173 struct ast_channel *chan;
00174 struct ast_channel *peer;
00175 };
00176
00177
00178
00179
00180 static void set_c_e_p(struct ast_channel *chan, const char *context, const char *ext, int pri)
00181 {
00182 ast_copy_string(chan->context, context, sizeof(chan->context));
00183 ast_copy_string(chan->exten, ext, sizeof(chan->exten));
00184 chan->priority = pri;
00185 }
00186
00187 static void check_goto_on_transfer(struct ast_channel *chan)
00188 {
00189 struct ast_channel *xferchan;
00190 const char *val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR");
00191 char *x, *goto_on_transfer;
00192 struct ast_frame *f;
00193
00194 if (ast_strlen_zero(val))
00195 return;
00196
00197 goto_on_transfer = ast_strdupa(val);
00198
00199 if (!(xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, chan->name)))
00200 return;
00201
00202 for (x = goto_on_transfer; x && *x; x++) {
00203 if (*x == '^')
00204 *x = '|';
00205 }
00206
00207 xferchan->readformat = chan->readformat;
00208 xferchan->writeformat = chan->writeformat;
00209 ast_channel_masquerade(xferchan, chan);
00210 ast_parseable_goto(xferchan, goto_on_transfer);
00211 xferchan->_state = AST_STATE_UP;
00212 ast_clear_flag(xferchan, AST_FLAGS_ALL);
00213 xferchan->_softhangup = 0;
00214 if ((f = ast_read(xferchan))) {
00215 ast_frfree(f);
00216 f = NULL;
00217 ast_pbx_start(xferchan);
00218 } else {
00219 ast_hangup(xferchan);
00220 }
00221 }
00222
00223 static struct ast_channel *ast_feature_request_and_dial(struct ast_channel *caller, const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name, const char *language);
00224
00225
00226 static void *ast_bridge_call_thread(void *data)
00227 {
00228 struct ast_bridge_thread_obj *tobj = data;
00229
00230 tobj->chan->appl = "Transferred Call";
00231 tobj->chan->data = tobj->peer->name;
00232 tobj->peer->appl = "Transferred Call";
00233 tobj->peer->data = tobj->chan->name;
00234
00235 ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
00236 ast_hangup(tobj->chan);
00237 ast_hangup(tobj->peer);
00238 bzero(tobj, sizeof(*tobj));
00239 free(tobj);
00240 return NULL;
00241 }
00242
00243 static void ast_bridge_call_thread_launch(void *data)
00244 {
00245 pthread_t thread;
00246 pthread_attr_t attr;
00247 struct sched_param sched;
00248
00249 pthread_attr_init(&attr);
00250 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00251 ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data);
00252 pthread_attr_destroy(&attr);
00253 memset(&sched, 0, sizeof(sched));
00254 pthread_setschedparam(thread, SCHED_RR, &sched);
00255 }
00256
00257 static int adsi_announce_park(struct ast_channel *chan, char *parkingexten)
00258 {
00259 int res;
00260 int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
00261 char tmp[256];
00262 char *message[5] = {NULL, NULL, NULL, NULL, NULL};
00263
00264 snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten);
00265 message[0] = tmp;
00266 res = ast_adsi_load_session(chan, NULL, 0, 1);
00267 if (res == -1)
00268 return res;
00269 return ast_adsi_print(chan, message, justify, 1);
00270 }
00271
00272
00273 static void notify_metermaids(char *exten, char *context)
00274 {
00275 if (option_debug > 3)
00276 ast_log(LOG_DEBUG, "Notification of state change to metermaids %s@%s\n", exten, context);
00277
00278
00279 ast_device_state_changed("park:%s@%s", exten, context);
00280 return;
00281 }
00282
00283
00284 static int metermaidstate(const char *data)
00285 {
00286 int res = AST_DEVICE_INVALID;
00287 char *context = ast_strdupa(data);
00288 char *exten;
00289
00290 exten = strsep(&context, "@");
00291 if (!context)
00292 return res;
00293
00294 if (option_debug > 3)
00295 ast_log(LOG_DEBUG, "Checking state of exten %s in context %s\n", exten, context);
00296
00297 res = ast_exists_extension(NULL, context, exten, 1, NULL);
00298
00299 if (!res)
00300 return AST_DEVICE_NOT_INUSE;
00301 else
00302 return AST_DEVICE_INUSE;
00303 }
00304
00305 static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout, char *orig_chan_name)
00306 {
00307 struct parkeduser *pu, *cur;
00308 int i, x = -1, parking_range;
00309 struct ast_context *con;
00310 const char *parkingexten;
00311
00312
00313 if (!(pu = ast_calloc(1, sizeof(*pu))))
00314 return -1;
00315
00316
00317 ast_mutex_lock(&parking_lock);
00318
00319 parkingexten = pbx_builtin_getvar_helper(chan, "PARKINGEXTEN");
00320 if (!ast_strlen_zero(parkingexten)) {
00321
00322
00323
00324
00325
00326
00327 if (sscanf(parkingexten, "%d", &x) != 1 || x < 0) {
00328 ast_log(LOG_WARNING, "PARKINGEXTEN does not indicate a valid parking slot: '%s'.\n", parkingexten);
00329 ast_mutex_unlock(&parking_lock);
00330 free(pu);
00331 return 1;
00332 }
00333 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", x);
00334
00335 if (ast_exists_extension(NULL, parking_con, pu->parkingexten, 1, NULL)) {
00336 ast_mutex_unlock(&parking_lock);
00337 free(pu);
00338 ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parking_con);
00339 return 1;
00340 }
00341 } else {
00342
00343 parking_range = parking_stop - parking_start+1;
00344 for (i = 0; i < parking_range; i++) {
00345 x = (i + parking_offset) % parking_range + parking_start;
00346 cur = parkinglot;
00347 while(cur) {
00348 if (cur->parkingnum == x)
00349 break;
00350 cur = cur->next;
00351 }
00352 if (!cur)
00353 break;
00354 }
00355
00356 if (!(i < parking_range)) {
00357 ast_log(LOG_WARNING, "No more parking spaces\n");
00358 free(pu);
00359 ast_mutex_unlock(&parking_lock);
00360 return -1;
00361 }
00362
00363 if (parkfindnext)
00364 parking_offset = x - parking_start + 1;
00365 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", x);
00366 }
00367
00368 chan->appl = "Parked Call";
00369 chan->data = NULL;
00370
00371 pu->chan = chan;
00372
00373
00374 if (chan != peer) {
00375 ast_indicate_data(pu->chan, AST_CONTROL_HOLD,
00376 S_OR(parkmohclass, NULL),
00377 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
00378 }
00379
00380 pu->start = ast_tvnow();
00381 pu->parkingnum = x;
00382 pu->parkingtime = (timeout > 0) ? timeout : parkingtime;
00383 if (extout)
00384 *extout = x;
00385
00386 if (peer) {
00387
00388
00389
00390
00391
00392 if (!strcasecmp(peer->tech->type, "Local")) {
00393 struct ast_channel *tmpchan, *base_peer;
00394 char other_side[AST_CHANNEL_NAME];
00395 char *c;
00396 ast_copy_string(other_side, peer->name, sizeof(other_side));
00397 if ((c = strrchr(other_side, ','))) {
00398 *++c = '1';
00399 }
00400 if ((tmpchan = ast_get_channel_by_name_locked(other_side))) {
00401 if ((base_peer = ast_bridged_channel(tmpchan))) {
00402 ast_copy_string(pu->peername, base_peer->name, sizeof(pu->peername));
00403 }
00404 ast_channel_unlock(tmpchan);
00405 }
00406 } else {
00407 ast_copy_string(pu->peername, peer->name, sizeof(pu->peername));
00408 }
00409 }
00410
00411
00412
00413 ast_copy_string(pu->context, S_OR(chan->macrocontext, chan->context), sizeof(pu->context));
00414 ast_copy_string(pu->exten, S_OR(chan->macroexten, chan->exten), sizeof(pu->exten));
00415 pu->priority = chan->macropriority ? chan->macropriority : chan->priority;
00416 pu->next = parkinglot;
00417 parkinglot = pu;
00418
00419
00420 if (peer == chan)
00421 pu->notquiteyet = 1;
00422 ast_mutex_unlock(&parking_lock);
00423
00424 pthread_kill(parking_thread, SIGURG);
00425 if (option_verbose > 1)
00426 ast_verbose(VERBOSE_PREFIX_2 "Parked %s on %d@%s. Will timeout back to extension [%s] %s, %d in %d seconds\n", pu->chan->name, pu->parkingnum, parking_con, pu->context, pu->exten, pu->priority, (pu->parkingtime/1000));
00427
00428 manager_event(EVENT_FLAG_CALL, "ParkedCall",
00429 "Exten: %s\r\n"
00430 "Channel: %s\r\n"
00431 "From: %s\r\n"
00432 "Timeout: %ld\r\n"
00433 "CallerID: %s\r\n"
00434 "CallerIDName: %s\r\n",
00435 pu->parkingexten, pu->chan->name, peer ? peer->name : "",
00436 (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL),
00437 S_OR(pu->chan->cid.cid_num, "<unknown>"),
00438 S_OR(pu->chan->cid.cid_name, "<unknown>")
00439 );
00440
00441 if (peer && adsipark && ast_adsi_available(peer)) {
00442 adsi_announce_park(peer, pu->parkingexten);
00443 ast_adsi_unload_session(peer);
00444 }
00445
00446 con = ast_context_find(parking_con);
00447 if (!con)
00448 con = ast_context_create(NULL, parking_con, registrar);
00449 if (!con)
00450 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
00451
00452 if (peer && (ast_strlen_zero(orig_chan_name) || !strcasecmp(peer->name, orig_chan_name))) {
00453
00454 ast_set_flag(peer, AST_FLAG_MASQ_NOSTREAM);
00455 ast_say_digits(peer, pu->parkingnum, "", peer->language);
00456 ast_clear_flag(peer, AST_FLAG_MASQ_NOSTREAM);
00457 }
00458 if (con) {
00459 if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, strdup(pu->parkingexten), ast_free, registrar))
00460 notify_metermaids(pu->parkingexten, parking_con);
00461 }
00462 if (pu->notquiteyet) {
00463
00464 ast_indicate_data(pu->chan, AST_CONTROL_HOLD,
00465 S_OR(parkmohclass, NULL),
00466 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
00467 pu->notquiteyet = 0;
00468 pthread_kill(parking_thread, SIGURG);
00469 }
00470 return 0;
00471 }
00472
00473
00474
00475
00476 int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
00477 {
00478 return park_call_full(chan, peer, timeout, extout, NULL);
00479 }
00480
00481 int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
00482 {
00483 struct ast_channel *chan;
00484 struct ast_frame *f;
00485 char *orig_chan_name = NULL;
00486 int park_status;
00487
00488
00489 if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) {
00490 ast_log(LOG_WARNING, "Unable to create parked channel\n");
00491 return -1;
00492 }
00493
00494
00495 chan->readformat = rchan->readformat;
00496 chan->writeformat = rchan->writeformat;
00497 ast_channel_masquerade(chan, rchan);
00498
00499
00500 set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority);
00501
00502
00503 f = ast_read(chan);
00504 if (f)
00505 ast_frfree(f);
00506
00507 orig_chan_name = ast_strdupa(chan->name);
00508
00509 park_status = park_call_full(chan, peer, timeout, extout, orig_chan_name);
00510 if (park_status == 1) {
00511
00512 ast_hangup(chan);
00513 return -1;
00514 }
00515
00516 return 0;
00517 }
00518
00519
00520 #define FEATURE_RETURN_HANGUP -1
00521 #define FEATURE_RETURN_SUCCESSBREAK 0
00522 #define FEATURE_RETURN_PBX_KEEPALIVE AST_PBX_KEEPALIVE
00523 #define FEATURE_RETURN_NO_HANGUP_PEER AST_PBX_NO_HANGUP_PEER
00524 #define FEATURE_RETURN_PASSDIGITS 21
00525 #define FEATURE_RETURN_STOREDIGITS 22
00526 #define FEATURE_RETURN_SUCCESS 23
00527 #define FEATURE_RETURN_KEEPTRYING 24
00528
00529 #define FEATURE_SENSE_CHAN (1 << 0)
00530 #define FEATURE_SENSE_PEER (1 << 1)
00531
00532
00533
00534
00535 static void set_peers(struct ast_channel **caller, struct ast_channel **callee,
00536 struct ast_channel *peer, struct ast_channel *chan, int sense)
00537 {
00538 if (sense == FEATURE_SENSE_PEER) {
00539 *caller = peer;
00540 *callee = chan;
00541 } else {
00542 *callee = peer;
00543 *caller = chan;
00544 }
00545 }
00546
00547
00548 static int builtin_parkcall(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00549 {
00550 struct ast_channel *parker;
00551 struct ast_channel *parkee;
00552 int res = 0;
00553 struct ast_module_user *u;
00554
00555 u = ast_module_user_add(chan);
00556
00557 set_peers(&parker, &parkee, peer, chan, sense);
00558
00559
00560 strcpy(chan->exten, "s");
00561 chan->priority = 1;
00562 if (chan->_state != AST_STATE_UP)
00563 res = ast_answer(chan);
00564 if (!res)
00565 res = ast_safe_sleep(chan, 1000);
00566 if (!res)
00567 res = ast_park_call(parkee, parker, 0, NULL);
00568
00569 ast_module_user_remove(u);
00570
00571 if (!res) {
00572 if (sense == FEATURE_SENSE_CHAN)
00573 res = AST_PBX_NO_HANGUP_PEER;
00574 else
00575 res = AST_PBX_KEEPALIVE;
00576 }
00577 return res;
00578
00579 }
00580
00581 static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00582 {
00583 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
00584 int x = 0;
00585 size_t len;
00586 struct ast_channel *caller_chan, *callee_chan;
00587
00588 if (!monitor_ok) {
00589 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00590 return -1;
00591 }
00592
00593 if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) {
00594 monitor_ok = 0;
00595 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00596 return -1;
00597 }
00598
00599 set_peers(&caller_chan, &callee_chan, peer, chan, sense);
00600
00601 if (!ast_strlen_zero(courtesytone)) {
00602 if (ast_autoservice_start(callee_chan))
00603 return -1;
00604 if (ast_stream_and_wait(caller_chan, courtesytone, caller_chan->language, "")) {
00605 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
00606 ast_autoservice_stop(callee_chan);
00607 return -1;
00608 }
00609 if (ast_autoservice_stop(callee_chan))
00610 return -1;
00611 }
00612
00613 if (callee_chan->monitor) {
00614 if (option_verbose > 3)
00615 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to stop recording call.\n", code);
00616 ast_monitor_stop(callee_chan, 1);
00617 return FEATURE_RETURN_SUCCESS;
00618 }
00619
00620 if (caller_chan && callee_chan) {
00621 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT");
00622 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
00623
00624 if (!touch_format)
00625 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
00626
00627 if (!touch_monitor)
00628 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
00629
00630 if (touch_monitor) {
00631 len = strlen(touch_monitor) + 50;
00632 args = alloca(len);
00633 touch_filename = alloca(len);
00634 snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor);
00635 snprintf(args, len, "%s|%s|m", (touch_format) ? touch_format : "wav", touch_filename);
00636 } else {
00637 caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name));
00638 callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name));
00639 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
00640 args = alloca(len);
00641 touch_filename = alloca(len);
00642 snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id);
00643 snprintf(args, len, "%s|%s|m", S_OR(touch_format, "wav"), touch_filename);
00644 }
00645
00646 for( x = 0; x < strlen(args); x++) {
00647 if (args[x] == '/')
00648 args[x] = '-';
00649 }
00650
00651 if (option_verbose > 3)
00652 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call. filename: %s\n", code, args);
00653
00654 pbx_exec(callee_chan, monitor_app, args);
00655 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
00656 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
00657
00658 return FEATURE_RETURN_SUCCESS;
00659 }
00660
00661 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");
00662 return -1;
00663 }
00664
00665 static int builtin_disconnect(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00666 {
00667 if (option_verbose > 3)
00668 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code);
00669 return FEATURE_RETURN_HANGUP;
00670 }
00671
00672 static int finishup(struct ast_channel *chan)
00673 {
00674 ast_indicate(chan, AST_CONTROL_UNHOLD);
00675
00676 return ast_autoservice_stop(chan);
00677 }
00678
00679
00680 static const char *real_ctx(struct ast_channel *transferer, struct ast_channel *transferee)
00681 {
00682 const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT");
00683 if (ast_strlen_zero(s))
00684 s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT");
00685 if (ast_strlen_zero(s))
00686 s = transferer->macrocontext;
00687 if (ast_strlen_zero(s))
00688 s = transferer->context;
00689 return s;
00690 }
00691
00692 static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00693 {
00694 struct ast_channel *transferer;
00695 struct ast_channel *transferee;
00696 const char *transferer_real_context;
00697 char xferto[256];
00698 int res;
00699
00700 set_peers(&transferer, &transferee, peer, chan, sense);
00701 transferer_real_context = real_ctx(transferer, transferee);
00702
00703 ast_autoservice_start(transferee);
00704 ast_indicate(transferee, AST_CONTROL_HOLD);
00705
00706 memset(xferto, 0, sizeof(xferto));
00707
00708
00709 res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY);
00710 if (res < 0) {
00711 finishup(transferee);
00712 return -1;
00713 }
00714 if (res > 0)
00715 xferto[0] = (char) res;
00716
00717 ast_stopstream(transferer);
00718 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
00719 if (res < 0) {
00720 finishup(transferee);
00721 return res;
00722 }
00723 if (!strcmp(xferto, ast_parking_ext())) {
00724 res = finishup(transferee);
00725 if (res)
00726 res = -1;
00727 else if (!ast_park_call(transferee, transferer, 0, NULL)) {
00728
00729
00730
00731
00732 return (transferer == peer) ? AST_PBX_KEEPALIVE : AST_PBX_NO_HANGUP_PEER;
00733 } else {
00734 ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name);
00735 }
00736
00737 } else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
00738 pbx_builtin_setvar_helper(transferer, "BLINDTRANSFER", transferee->name);
00739 pbx_builtin_setvar_helper(transferee, "BLINDTRANSFER", transferer->name);
00740 res=finishup(transferee);
00741 if (!transferer->cdr) {
00742 transferer->cdr=ast_cdr_alloc();
00743 if (transferer) {
00744 ast_cdr_init(transferer->cdr, transferer);
00745 ast_cdr_start(transferer->cdr);
00746 }
00747 }
00748 if (transferer->cdr) {
00749 ast_cdr_setdestchan(transferer->cdr, transferee->name);
00750 ast_cdr_setapp(transferer->cdr, "BLINDTRANSFER","");
00751 }
00752 if (!transferee->pbx) {
00753
00754 if (option_verbose > 2)
00755 ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n"
00756 ,transferee->name, xferto, transferer_real_context);
00757 if (ast_async_goto(transferee, transferer_real_context, xferto, 1))
00758 ast_log(LOG_WARNING, "Async goto failed :-(\n");
00759 res = -1;
00760 } else {
00761
00762 set_c_e_p(transferee, transferer_real_context, xferto, 0);
00763 }
00764 check_goto_on_transfer(transferer);
00765 return res;
00766 } else {
00767 if (option_verbose > 2)
00768 ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context);
00769 }
00770 if (ast_stream_and_wait(transferer, xferfailsound, transferer->language, AST_DIGIT_ANY) < 0 ) {
00771 finishup(transferee);
00772 return -1;
00773 }
00774 ast_stopstream(transferer);
00775 res = finishup(transferee);
00776 if (res) {
00777 if (option_verbose > 1)
00778 ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name);
00779 return res;
00780 }
00781 return FEATURE_RETURN_SUCCESS;
00782 }
00783
00784 static int check_compat(struct ast_channel *c, struct ast_channel *newchan)
00785 {
00786 if (ast_channel_make_compatible(c, newchan) < 0) {
00787 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n",
00788 c->name, newchan->name);
00789 ast_hangup(newchan);
00790 return -1;
00791 }
00792 return 0;
00793 }
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810 static int do_atxfer(struct ast_channel *chan,struct ast_channel *peer,struct ast_bridge_config *config,int sense,const char *toExt,const char *toCont)
00811 {
00812 struct ast_channel *transferer;
00813 struct ast_channel *transferee;
00814 const char *transferer_real_context;
00815 const char *transfer_context;
00816 char xferto[256] = "";
00817 int res;
00818 int outstate=0;
00819 struct ast_channel *newchan;
00820 struct ast_channel *xferchan;
00821 struct ast_bridge_thread_obj *tobj;
00822 struct ast_bridge_config bconfig;
00823 struct ast_frame *f;
00824 int l;
00825 struct ast_datastore *features_datastore;
00826 struct ast_dial_features *dialfeatures = NULL;
00827
00828 if (option_debug)
00829 ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense);
00830 set_peers(&transferer, &transferee, peer, chan, sense);
00831 transferer_real_context = real_ctx(transferer, transferee);
00832 transfer_context = S_OR(toCont, transferer_real_context);
00833
00834
00835 ast_autoservice_start(transferee);
00836 ast_indicate(transferee, AST_CONTROL_HOLD);
00837
00838 if (!ast_strlen_zero(toExt)) {
00839 ast_copy_string(xferto, toExt, sizeof(xferto));
00840 } else {
00841
00842 res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY);
00843 if (res < 0) {
00844 finishup(transferee);
00845 return res;
00846 }
00847 if (res > 0)
00848 xferto[0] = (char) res;
00849
00850
00851 res = ast_app_dtget(transferer, transfer_context, xferto, sizeof(xferto), 100, transferdigittimeout);
00852 if (res < 0) {
00853 finishup(transferee);
00854 return res;
00855 }
00856 if (res == 0) {
00857 ast_log(LOG_WARNING, "Did not read data.\n");
00858 finishup(transferee);
00859 if (ast_stream_and_wait(transferer, "beeperr", transferer->language, ""))
00860 return -1;
00861 return FEATURE_RETURN_SUCCESS;
00862 }
00863 }
00864
00865
00866 if (!ast_exists_extension(transferer, transfer_context, xferto, 1, transferer->cid.cid_num)) {
00867 ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transfer_context);
00868 finishup(transferee);
00869 if (ast_stream_and_wait(transferer, "beeperr", transferer->language, ""))
00870 return -1;
00871 return FEATURE_RETURN_SUCCESS;
00872 }
00873
00874 l = strlen(xferto);
00875 snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transfer_context);
00876 newchan = ast_feature_request_and_dial(transferer, "Local", ast_best_codec(transferer->nativeformats),
00877 xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, transferer->language);
00878
00879
00880
00881 ast_channel_lock(transferee);
00882 if ((features_datastore = ast_channel_datastore_find(transferee, &dial_features_info, NULL))) {
00883 dialfeatures = features_datastore->data;
00884 }
00885 ast_channel_unlock(transferee);
00886
00887 if (dialfeatures && !dialfeatures->is_caller) {
00888 ast_copy_flags(&(config->features_caller), &(dialfeatures->features_callee), AST_FLAGS_ALL);
00889 }
00890
00891 ast_indicate(transferer, -1);
00892 if (!newchan) {
00893 finishup(transferee);
00894
00895 if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY &&
00896 ast_stream_and_wait(transferer, xferfailsound, transferer->language, ""))
00897 return -1;
00898 return FEATURE_RETURN_SUCCESS;
00899 }
00900
00901 if (check_compat(transferer, newchan)) {
00902
00903 finishup(transferee);
00904 return -1;
00905 }
00906 memset(&bconfig,0,sizeof(struct ast_bridge_config));
00907 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
00908 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
00909 res = ast_bridge_call(transferer, newchan, &bconfig);
00910 if (newchan->_softhangup || !transferer->_softhangup) {
00911 ast_hangup(newchan);
00912 if (ast_stream_and_wait(transferer, xfersound, transferer->language, ""))
00913 ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
00914 finishup(transferee);
00915 transferer->_softhangup = 0;
00916 return FEATURE_RETURN_SUCCESS;
00917 }
00918
00919 if (check_compat(transferee, newchan)) {
00920 finishup(transferee);
00921 return -1;
00922 }
00923
00924 ast_indicate(transferee, AST_CONTROL_UNHOLD);
00925
00926 if ((ast_autoservice_stop(transferee) < 0)
00927 || (ast_waitfordigit(transferee, 100) < 0)
00928 || (ast_waitfordigit(newchan, 100) < 0)
00929 || ast_check_hangup(transferee)
00930 || ast_check_hangup(newchan)) {
00931 ast_hangup(newchan);
00932 return -1;
00933 }
00934
00935 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name);
00936 if (!xferchan) {
00937 ast_hangup(newchan);
00938 return -1;
00939 }
00940
00941 xferchan->visible_indication = transferer->visible_indication;
00942 xferchan->readformat = transferee->readformat;
00943 xferchan->writeformat = transferee->writeformat;
00944 ast_channel_masquerade(xferchan, transferee);
00945 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
00946 xferchan->_state = AST_STATE_UP;
00947 ast_clear_flag(xferchan, AST_FLAGS_ALL);
00948 xferchan->_softhangup = 0;
00949
00950 if ((f = ast_read(xferchan)))
00951 ast_frfree(f);
00952
00953 newchan->_state = AST_STATE_UP;
00954 ast_clear_flag(newchan, AST_FLAGS_ALL);
00955 newchan->_softhangup = 0;
00956
00957 tobj = ast_calloc(1, sizeof(struct ast_bridge_thread_obj));
00958 if (!tobj) {
00959 ast_hangup(xferchan);
00960 ast_hangup(newchan);
00961 return -1;
00962 }
00963
00964
00965
00966 ast_channel_lock(newchan);
00967 if ((features_datastore = ast_channel_datastore_find(newchan, &dial_features_info, NULL))) {
00968 dialfeatures = features_datastore->data;
00969 }
00970 ast_channel_unlock(newchan);
00971
00972 if (dialfeatures) {
00973 ast_copy_flags(&(config->features_callee), &(dialfeatures->features_callee), AST_FLAGS_ALL);
00974 }
00975
00976 tobj->chan = newchan;
00977 tobj->peer = xferchan;
00978 tobj->bconfig = *config;
00979
00980 if (ast_stream_and_wait(newchan, xfersound, newchan->language, ""))
00981 ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
00982 ast_bridge_call_thread_launch(tobj);
00983 return -1;
00984 }
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999
01000 static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
01001 {
01002 return do_atxfer(chan, peer, config, sense, NULL, NULL);
01003 }
01004
01005
01006 #define FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0]))
01007
01008 AST_RWLOCK_DEFINE_STATIC(features_lock);
01009
01010 static struct ast_call_feature builtin_features[] =
01011 {
01012 { AST_FEATURE_REDIRECT, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
01013 { AST_FEATURE_REDIRECT, "Attended Transfer", "atxfer", "", "", builtin_atxfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
01014 { AST_FEATURE_AUTOMON, "One Touch Monitor", "automon", "", "", builtin_automonitor, AST_FEATURE_FLAG_NEEDSDTMF, "" },
01015 { AST_FEATURE_DISCONNECT, "Disconnect Call", "disconnect", "*", "*", builtin_disconnect, AST_FEATURE_FLAG_NEEDSDTMF, "" },
01016 { AST_FEATURE_PARKCALL, "Park Call", "parkcall", "", "", builtin_parkcall, AST_FEATURE_FLAG_NEEDSDTMF, "" },
01017 };
01018
01019
01020 static AST_LIST_HEAD_STATIC(feature_list,ast_call_feature);
01021
01022
01023 void ast_register_feature(struct ast_call_feature *feature)
01024 {
01025 if (!feature) {
01026 ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
01027 return;
01028 }
01029
01030 AST_LIST_LOCK(&feature_list);
01031 AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry);
01032 AST_LIST_UNLOCK(&feature_list);
01033
01034 if (option_verbose >= 2)
01035 ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
01036 }
01037
01038
01039 void ast_unregister_feature(struct ast_call_feature *feature)
01040 {
01041 if (!feature)
01042 return;
01043
01044 AST_LIST_LOCK(&feature_list);
01045 AST_LIST_REMOVE(&feature_list,feature,feature_entry);
01046 AST_LIST_UNLOCK(&feature_list);
01047 free(feature);
01048 }
01049
01050
01051 static void ast_unregister_features(void)
01052 {
01053 struct ast_call_feature *feature;
01054
01055 AST_LIST_LOCK(&feature_list);
01056 while ((feature = AST_LIST_REMOVE_HEAD(&feature_list,feature_entry)))
01057 free(feature);
01058 AST_LIST_UNLOCK(&feature_list);
01059 }
01060
01061
01062 static struct ast_call_feature *find_dynamic_feature(const char *name)
01063 {
01064 struct ast_call_feature *tmp;
01065
01066 AST_LIST_TRAVERSE(&feature_list, tmp, feature_entry) {
01067 if (!strcasecmp(tmp->sname, name))
01068 break;
01069 }
01070
01071 return tmp;
01072 }
01073
01074
01075 static int feature_exec_app(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
01076 {
01077 struct ast_app *app;
01078 struct ast_call_feature *feature = data;
01079 struct ast_channel *work, *idle;
01080 int res;
01081
01082 if (!feature) {
01083 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
01084 return -1;
01085 }
01086
01087 if (sense == FEATURE_SENSE_CHAN) {
01088 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
01089 return FEATURE_RETURN_KEEPTRYING;
01090 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
01091 work = chan;
01092 idle = peer;
01093 } else {
01094 work = peer;
01095 idle = chan;
01096 }
01097 } else {
01098 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
01099 return FEATURE_RETURN_KEEPTRYING;
01100 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
01101 work = peer;
01102 idle = chan;
01103 } else {
01104 work = chan;
01105 idle = peer;
01106 }
01107 }
01108
01109 if (!(app = pbx_findapp(feature->app))) {
01110 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
01111 return -2;
01112 }
01113
01114 ast_autoservice_start(idle);
01115
01116 if (!ast_strlen_zero(feature->moh_class))
01117 ast_moh_start(idle, feature->moh_class, NULL);
01118
01119 res = pbx_exec(work, app, feature->app_args);
01120
01121 if (!ast_strlen_zero(feature->moh_class))
01122 ast_moh_stop(idle);
01123
01124 ast_autoservice_stop(idle);
01125
01126 if (res == AST_PBX_KEEPALIVE) {
01127
01128 if ((ast_test_flag(feature, AST_FEATURE_FLAG_ONPEER) && sense == FEATURE_SENSE_CHAN) || (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF) && sense == FEATURE_SENSE_PEER))
01129 return FEATURE_RETURN_NO_HANGUP_PEER;
01130 else
01131 return FEATURE_RETURN_PBX_KEEPALIVE;
01132 }
01133 else if (res == AST_PBX_NO_HANGUP_PEER)
01134 return FEATURE_RETURN_NO_HANGUP_PEER;
01135 else if (res)
01136 return FEATURE_RETURN_SUCCESSBREAK;
01137
01138 return FEATURE_RETURN_SUCCESS;
01139 }
01140
01141 static void unmap_features(void)
01142 {
01143 int x;
01144
01145 ast_rwlock_wrlock(&features_lock);
01146 for (x = 0; x < FEATURES_COUNT; x++)
01147 strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
01148 ast_rwlock_unlock(&features_lock);
01149 }
01150
01151 static int remap_feature(const char *name, const char *value)
01152 {
01153 int x, res = -1;
01154
01155 ast_rwlock_wrlock(&features_lock);
01156 for (x = 0; x < FEATURES_COUNT; x++) {
01157 if (strcasecmp(builtin_features[x].sname, name))
01158 continue;
01159
01160 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
01161 res = 0;
01162 break;
01163 }
01164 ast_rwlock_unlock(&features_lock);
01165
01166 return res;
01167 }
01168
01169 static int ast_feature_interpret(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
01170 {
01171 int x;
01172 struct ast_flags features;
01173 struct ast_call_feature *feature;
01174 const char *dynamic_features;
01175 char *tmp, *tok;
01176 int res = FEATURE_RETURN_PASSDIGITS;
01177 int feature_detected = 0;
01178
01179 if (sense == FEATURE_SENSE_CHAN) {
01180 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
01181 dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
01182 } else {
01183 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);
01184 dynamic_features = pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES");
01185 }
01186 if (option_debug > 2)
01187 ast_log(LOG_DEBUG, "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);
01188
01189 ast_rwlock_rdlock(&features_lock);
01190 for (x = 0; x < FEATURES_COUNT; x++) {
01191 if ((ast_test_flag(&features, builtin_features[x].feature_mask)) &&
01192 !ast_strlen_zero(builtin_features[x].exten)) {
01193
01194 if (!strcmp(builtin_features[x].exten, code)) {
01195 res = builtin_features[x].operation(chan, peer, config, code, sense, NULL);
01196 feature_detected = 1;
01197 break;
01198 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
01199 if (res == FEATURE_RETURN_PASSDIGITS)
01200 res = FEATURE_RETURN_STOREDIGITS;
01201 }
01202 }
01203 }
01204 ast_rwlock_unlock(&features_lock);
01205
01206 if (ast_strlen_zero(dynamic_features) || feature_detected)
01207 return res;
01208
01209 tmp = ast_strdupa(dynamic_features);
01210
01211 while ((tok = strsep(&tmp, "#"))) {
01212 AST_LIST_LOCK(&feature_list);
01213 if (!(feature = find_dynamic_feature(tok))) {
01214 AST_LIST_UNLOCK(&feature_list);
01215 continue;
01216 }
01217
01218
01219 if (!strcmp(feature->exten, code)) {
01220 if (option_verbose > 2)
01221 ast_verbose(VERBOSE_PREFIX_3 " Feature Found: %s exten: %s\n",feature->sname, tok);
01222 res = feature->operation(chan, peer, config, code, sense, feature);
01223 if (res != FEATURE_RETURN_KEEPTRYING) {
01224 AST_LIST_UNLOCK(&feature_list);
01225 break;
01226 }
01227 res = FEATURE_RETURN_PASSDIGITS;
01228 } else if (!strncmp(feature->exten, code, strlen(code)))
01229 res = FEATURE_RETURN_STOREDIGITS;
01230
01231 AST_LIST_UNLOCK(&feature_list);
01232 }
01233
01234 return res;
01235 }
01236
01237 static void set_config_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
01238 {
01239 int x;
01240
01241 ast_clear_flag(config, AST_FLAGS_ALL);
01242
01243 ast_rwlock_rdlock(&features_lock);
01244 for (x = 0; x < FEATURES_COUNT; x++) {
01245 if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF))
01246 continue;
01247
01248 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
01249 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01250
01251 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
01252 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01253 }
01254 ast_rwlock_unlock(&features_lock);
01255
01256 if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
01257 const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
01258
01259 if (dynamic_features) {
01260 char *tmp = ast_strdupa(dynamic_features);
01261 char *tok;
01262 struct ast_call_feature *feature;
01263
01264
01265 while ((tok = strsep(&tmp, "#"))) {
01266 AST_LIST_LOCK(&feature_list);
01267 if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
01268 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
01269 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01270 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
01271 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01272 }
01273 AST_LIST_UNLOCK(&feature_list);
01274 }
01275 }
01276 }
01277 }
01278
01279
01280 static struct ast_channel *ast_feature_request_and_dial(struct ast_channel *caller, const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name, const char *language)
01281 {
01282 int state = 0;
01283 int cause = 0;
01284 int to;
01285 struct ast_channel *chan;
01286 struct ast_channel *monitor_chans[2];
01287 struct ast_channel *active_channel;
01288 int res = 0, ready = 0;
01289
01290 if ((chan = ast_request(type, format, data, &cause))) {
01291 ast_set_callerid(chan, cid_num, cid_name, cid_num);
01292 ast_string_field_set(chan, language, language);
01293 ast_channel_inherit_variables(caller, chan);
01294 pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name);
01295
01296 if (!ast_call(chan, data, timeout)) {
01297 struct timeval started;
01298 int x, len = 0;
01299 char *disconnect_code = NULL, *dialed_code = NULL;
01300
01301 ast_indicate(caller, AST_CONTROL_RINGING);
01302
01303 ast_rwlock_rdlock(&features_lock);
01304 for (x = 0; x < FEATURES_COUNT; x++) {
01305 if (strcasecmp(builtin_features[x].sname, "disconnect"))
01306 continue;
01307
01308 disconnect_code = builtin_features[x].exten;
01309 len = strlen(disconnect_code) + 1;
01310 dialed_code = alloca(len);
01311 memset(dialed_code, 0, len);
01312 break;
01313 }
01314 ast_rwlock_unlock(&features_lock);
01315 x = 0;
01316 started = ast_tvnow();
01317 to = timeout;
01318 while (!ast_check_hangup(caller) && timeout && (chan->_state != AST_STATE_UP)) {
01319 struct ast_frame *f = NULL;
01320
01321 monitor_chans[0] = caller;
01322 monitor_chans[1] = chan;
01323 active_channel = ast_waitfor_n(monitor_chans, 2, &to);
01324
01325
01326 if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
01327 state = AST_CONTROL_UNHOLD;
01328 ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n");
01329 break;
01330 }
01331
01332 if (!active_channel)
01333 continue;
01334
01335 if (chan && (chan == active_channel)){
01336 f = ast_read(chan);
01337 if (f == NULL) {
01338 state = AST_CONTROL_HANGUP;
01339 res = 0;
01340 break;
01341 }
01342
01343 if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) {
01344 if (f->subclass == AST_CONTROL_RINGING) {
01345 state = f->subclass;
01346 if (option_verbose > 2)
01347 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", chan->name);
01348 ast_indicate(caller, AST_CONTROL_RINGING);
01349 } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) {
01350 state = f->subclass;
01351 if (option_verbose > 2)
01352 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", chan->name);
01353 ast_indicate(caller, AST_CONTROL_BUSY);
01354 ast_frfree(f);
01355 f = NULL;
01356 break;
01357 } else if (f->subclass == AST_CONTROL_ANSWER) {
01358
01359 state = f->subclass;
01360 ast_frfree(f);
01361 f = NULL;
01362 ready=1;
01363 break;
01364 } else if (f->subclass != -1) {
01365 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass);
01366 }
01367
01368 }
01369
01370 } else if (caller && (active_channel == caller)) {
01371 f = ast_read(caller);
01372 if (f == NULL) {
01373 if (caller->_softhangup && !chan->_softhangup) {
01374
01375 ready = 1;
01376 break;
01377 }
01378 state = AST_CONTROL_HANGUP;
01379 res = 0;
01380 break;
01381 }
01382
01383 if (f->frametype == AST_FRAME_DTMF) {
01384 dialed_code[x++] = f->subclass;
01385 dialed_code[x] = '\0';
01386 if (strlen(dialed_code) == len) {
01387 x = 0;
01388 } else if (x && strncmp(dialed_code, disconnect_code, x)) {
01389 x = 0;
01390 dialed_code[x] = '\0';
01391 }
01392 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
01393
01394 state = AST_CONTROL_UNHOLD;
01395 ast_frfree(f);
01396 f = NULL;
01397 break;
01398 }
01399 }
01400 }
01401 if (f)
01402 ast_frfree(f);
01403 }
01404 } else
01405 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
01406 } else {
01407 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
01408 switch(cause) {
01409 case AST_CAUSE_BUSY:
01410 state = AST_CONTROL_BUSY;
01411 break;
01412 case AST_CAUSE_CONGESTION:
01413 state = AST_CONTROL_CONGESTION;
01414 break;
01415 }
01416 }
01417
01418 ast_indicate(caller, -1);
01419 if (chan && ready) {
01420 if (chan->_state == AST_STATE_UP)
01421 state = AST_CONTROL_ANSWER;
01422 res = 0;
01423 } else if(chan) {
01424 res = -1;
01425 ast_hangup(chan);
01426 chan = NULL;
01427 } else {
01428 res = -1;
01429 }
01430
01431 if (outstate)
01432 *outstate = state;
01433
01434 return chan;
01435 }
01436
01437 static void cmd_atxfer(struct ast_channel *a, struct ast_channel *b, struct ast_bridge_config *conf, struct ast_channel *who, char *xferto)
01438 {
01439 int sense = (a == who) ? FEATURE_SENSE_CHAN : FEATURE_SENSE_PEER;
01440 char *context = strchr(xferto, '@');;
01441 if (context)
01442 *context++ = '\0';
01443 do_atxfer(a, b, conf, sense, xferto, context);
01444 }
01445
01446 int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast_bridge_config *config)
01447 {
01448
01449
01450 struct ast_frame *f;
01451 struct ast_channel *who;
01452 char chan_featurecode[FEATURE_MAX_LEN + 1]="";
01453 char peer_featurecode[FEATURE_MAX_LEN + 1]="";
01454 char orig_channame[AST_MAX_EXTENSION];
01455 char orig_peername[AST_MAX_EXTENSION];
01456
01457 int res;
01458 int diff;
01459 int hasfeatures=0;
01460 int hadfeatures=0;
01461 struct ast_option_header *aoh;
01462 struct ast_bridge_config backup_config;
01463 struct ast_cdr *bridge_cdr = NULL;
01464 struct ast_cdr *orig_peer_cdr = NULL;
01465
01466 memset(&backup_config, 0, sizeof(backup_config));
01467
01468 config->start_time = ast_tvnow();
01469
01470 if (chan && peer) {
01471 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
01472 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
01473 } else if (chan)
01474 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
01475
01476 if (monitor_ok) {
01477 const char *monitor_exec;
01478 struct ast_channel *src = NULL;
01479 if (!monitor_app) {
01480 if (!(monitor_app = pbx_findapp("Monitor")))
01481 monitor_ok=0;
01482 }
01483 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR")))
01484 src = chan;
01485 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
01486 src = peer;
01487 if (monitor_app && src) {
01488 char *tmp = ast_strdupa(monitor_exec);
01489 pbx_exec(src, monitor_app, tmp);
01490 }
01491 }
01492
01493 set_config_flags(chan, peer, config);
01494 config->firstpass = 1;
01495
01496
01497 if (ast_answer(chan))
01498 return -1;
01499
01500 ast_copy_string(orig_channame,chan->name,sizeof(orig_channame));
01501 ast_copy_string(orig_peername,peer->name,sizeof(orig_peername));
01502 orig_peer_cdr = peer->cdr;
01503
01504 if (!chan->cdr || (chan->cdr && !ast_test_flag(chan->cdr, AST_CDR_FLAG_POST_DISABLED))) {
01505
01506 if (chan->cdr) {
01507 ast_set_flag(chan->cdr, AST_CDR_FLAG_MAIN);
01508 ast_cdr_update(chan);
01509 bridge_cdr = ast_cdr_dup(chan->cdr);
01510 ast_copy_string(bridge_cdr->lastapp, chan->appl, sizeof(bridge_cdr->lastapp));
01511 ast_copy_string(bridge_cdr->lastdata, chan->data, sizeof(bridge_cdr->lastdata));
01512 } else {
01513
01514 bridge_cdr = ast_cdr_alloc();
01515 ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel));
01516 ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel));
01517 ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid));
01518 ast_copy_string(bridge_cdr->lastapp, chan->appl, sizeof(bridge_cdr->lastapp));
01519 ast_copy_string(bridge_cdr->lastdata, chan->data, sizeof(bridge_cdr->lastdata));
01520 ast_cdr_setcid(bridge_cdr, chan);
01521 bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ? AST_CDR_ANSWERED : AST_CDR_NULL;
01522 bridge_cdr->amaflags = chan->amaflags ? chan->amaflags : ast_default_amaflags;
01523 ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode));
01524
01525 ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst));
01526 ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext));
01527 if (peer->cdr) {
01528 bridge_cdr->start = peer->cdr->start;
01529 ast_copy_string(bridge_cdr->userfield, peer->cdr->userfield, sizeof(bridge_cdr->userfield));
01530 } else {
01531 ast_cdr_start(bridge_cdr);
01532 }
01533 }
01534
01535
01536
01537
01538
01539
01540 if (peer->cdr && !ast_tvzero(peer->cdr->answer)) {
01541 bridge_cdr->answer = peer->cdr->answer;
01542 chan->cdr->answer = peer->cdr->answer;
01543 } else {
01544 ast_cdr_answer(bridge_cdr);
01545 ast_cdr_answer(chan->cdr);
01546 }
01547 ast_set_flag(chan->cdr, AST_CDR_FLAG_BRIDGED);
01548 if (peer->cdr) {
01549 ast_set_flag(peer->cdr, AST_CDR_FLAG_BRIDGED);
01550 }
01551 }
01552
01553 for (;;) {
01554 struct ast_channel *other;
01555
01556 res = ast_channel_bridge(chan, peer, config, &f, &who);
01557
01558 if (config->feature_timer) {
01559
01560 diff = ast_tvdiff_ms(ast_tvnow(), config->start_time);
01561 config->feature_timer -= diff;
01562 if (hasfeatures) {
01563
01564
01565
01566 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
01567 if (option_debug)
01568 ast_log(LOG_DEBUG, "Timed out, realtime this time!\n");
01569 config->feature_timer = 0;
01570 who = chan;
01571 if (f)
01572 ast_frfree(f);
01573 f = NULL;
01574 res = 0;
01575 } else if (config->feature_timer <= 0) {
01576
01577
01578 if (option_debug)
01579 ast_log(LOG_DEBUG, "Timed out for feature!\n");
01580 if (!ast_strlen_zero(peer_featurecode)) {
01581 ast_dtmf_stream(chan, peer, peer_featurecode, 0);
01582 memset(peer_featurecode, 0, sizeof(peer_featurecode));
01583 }
01584 if (!ast_strlen_zero(chan_featurecode)) {
01585 ast_dtmf_stream(peer, chan, chan_featurecode, 0);
01586 memset(chan_featurecode, 0, sizeof(chan_featurecode));
01587 }
01588 if (f)
01589 ast_frfree(f);
01590 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01591 if (!hasfeatures) {
01592
01593 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01594 memset(&backup_config, 0, sizeof(backup_config));
01595 }
01596 hadfeatures = hasfeatures;
01597
01598 continue;
01599 } else if (!f) {
01600
01601
01602
01603 continue;
01604 }
01605 } else {
01606 if (config->feature_timer <=0) {
01607
01608 config->feature_timer = 0;
01609 who = chan;
01610 if (f)
01611 ast_frfree(f);
01612 f = NULL;
01613 res = 0;
01614 }
01615 }
01616 }
01617 if (res < 0) {
01618 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer))
01619 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
01620 goto before_you_go;
01621 }
01622
01623 if (!f || (f->frametype == AST_FRAME_CONTROL &&
01624 (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY ||
01625 f->subclass == AST_CONTROL_CONGESTION ) ) ) {
01626 res = -1;
01627 break;
01628 }
01629
01630 other = (who == chan) ? peer : chan;
01631 if (f->frametype == AST_FRAME_CONTROL) {
01632 switch (f->subclass) {
01633 case AST_CONTROL_RINGING:
01634 case AST_CONTROL_FLASH:
01635 case -1:
01636 ast_indicate(other, f->subclass);
01637 break;
01638 case AST_CONTROL_HOLD:
01639 case AST_CONTROL_UNHOLD:
01640 ast_indicate_data(other, f->subclass, f->data, f->datalen);
01641 break;
01642 case AST_CONTROL_OPTION:
01643 aoh = f->data;
01644
01645 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) {
01646 ast_channel_setoption(other, ntohs(aoh->option), aoh->data,
01647 f->datalen - sizeof(struct ast_option_header), 0);
01648 }
01649 break;
01650 case AST_CONTROL_ATXFERCMD:
01651 cmd_atxfer(chan, peer, config, who, f->data);
01652 break;
01653 }
01654 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
01655
01656 } else if (f->frametype == AST_FRAME_DTMF) {
01657 char *featurecode;
01658 int sense;
01659
01660 hadfeatures = hasfeatures;
01661
01662 if (who == chan) {
01663 sense = FEATURE_SENSE_CHAN;
01664 featurecode = chan_featurecode;
01665 } else {
01666 sense = FEATURE_SENSE_PEER;
01667 featurecode = peer_featurecode;
01668 }
01669
01670
01671
01672
01673 featurecode[strlen(featurecode)] = f->subclass;
01674
01675 ast_frfree(f);
01676 f = NULL;
01677 config->feature_timer = backup_config.feature_timer;
01678 res = ast_feature_interpret(chan, peer, config, featurecode, sense);
01679 switch(res) {
01680 case FEATURE_RETURN_PASSDIGITS:
01681 ast_dtmf_stream(other, who, featurecode, 0);
01682
01683 case FEATURE_RETURN_SUCCESS:
01684 memset(featurecode, 0, sizeof(chan_featurecode));
01685 break;
01686 }
01687 if (res >= FEATURE_RETURN_PASSDIGITS) {
01688 res = 0;
01689 } else
01690 break;
01691 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01692 if (hadfeatures && !hasfeatures) {
01693
01694 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01695 memset(&backup_config, 0, sizeof(struct ast_bridge_config));
01696 } else if (hasfeatures) {
01697 if (!hadfeatures) {
01698
01699 memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
01700
01701 config->play_warning = 0;
01702 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
01703 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
01704 config->warning_freq = 0;
01705 config->warning_sound = NULL;
01706 config->end_sound = NULL;
01707 config->start_sound = NULL;
01708 config->firstpass = 0;
01709 }
01710 config->start_time = ast_tvnow();
01711 config->feature_timer = featuredigittimeout;
01712 if (option_debug)
01713 ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer);
01714 }
01715 }
01716 if (f)
01717 ast_frfree(f);
01718
01719 }
01720 before_you_go:
01721
01722 if (!chan->cdr || (chan->cdr && !ast_test_flag(chan->cdr, AST_CDR_FLAG_POST_DISABLED))) {
01723
01724 ast_cdr_end(bridge_cdr);
01725
01726 ast_cdr_detach(bridge_cdr);
01727
01728
01729 if (chan->cdr) {
01730 ast_cdr_specialized_reset(chan->cdr,0);
01731 }
01732 if (peer->cdr) {
01733 struct ast_cdr *cur;
01734
01735 ast_channel_lock(peer);
01736 for (cur = peer->cdr; cur; cur = cur->next) {
01737 if (cur == orig_peer_cdr) {
01738 break;
01739 }
01740 }
01741
01742 if (!cur) {
01743
01744
01745 ast_channel_unlock(peer);
01746 return res;
01747 }
01748
01749
01750
01751
01752
01753
01754
01755
01756 if (ast_cdr_isset_unanswered()) {
01757 struct ast_cdr *dupd = ast_cdr_dup(orig_peer_cdr);
01758 if (dupd) {
01759 if (ast_tvzero(dupd->end) && ast_cdr_isset_unanswered())
01760 ast_cdr_end(dupd);
01761 ast_cdr_detach(dupd);
01762 }
01763 }
01764 ast_cdr_specialized_reset(orig_peer_cdr,0);
01765 ast_channel_unlock(peer);
01766 }
01767 }
01768 return res;
01769 }
01770
01771 static void post_manager_event(const char *s, char *parkingexten, struct ast_channel *chan)
01772 {
01773 manager_event(EVENT_FLAG_CALL, s,
01774 "Exten: %s\r\n"
01775 "Channel: %s\r\n"
01776 "CallerID: %s\r\n"
01777 "CallerIDName: %s\r\n\r\n",
01778 parkingexten,
01779 chan->name,
01780 S_OR(chan->cid.cid_num, "<unknown>"),
01781 S_OR(chan->cid.cid_name, "<unknown>")
01782 );
01783 }
01784
01785
01786 static void *do_parking_thread(void *ignore)
01787 {
01788 fd_set rfds, efds;
01789 FD_ZERO(&rfds);
01790 FD_ZERO(&efds);
01791
01792 for (;;) {
01793 struct parkeduser *pu, *pl, *pt = NULL;
01794 int ms = -1;
01795 int max = -1;
01796 fd_set nrfds, nefds;
01797 FD_ZERO(&nrfds);
01798 FD_ZERO(&nefds);
01799
01800 ast_mutex_lock(&parking_lock);
01801 pl = NULL;
01802 pu = parkinglot;
01803
01804 while (pu) {
01805 struct ast_channel *chan = pu->chan;
01806 int tms;
01807 int x;
01808 struct ast_context *con;
01809
01810 if (pu->notquiteyet) {
01811 pl = pu;
01812 pu = pu->next;
01813 continue;
01814 }
01815 tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
01816 if (tms > pu->parkingtime) {
01817 ast_indicate(chan, AST_CONTROL_UNHOLD);
01818
01819 if (pu->peername[0]) {
01820 char *peername = ast_strdupa(pu->peername);
01821 char *cp = strrchr(peername, '-');
01822 if (cp)
01823 *cp = 0;
01824 con = ast_context_find(parking_con_dial);
01825 if (!con) {
01826 con = ast_context_create(NULL, parking_con_dial, registrar);
01827 if (!con)
01828 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
01829 }
01830 if (con) {
01831 char returnexten[AST_MAX_EXTENSION];
01832 struct ast_datastore *features_datastore;
01833 struct ast_dial_features *dialfeatures = NULL;
01834
01835 ast_channel_lock(chan);
01836
01837 if ((features_datastore = ast_channel_datastore_find(chan, &dial_features_info, NULL)))
01838 dialfeatures = features_datastore->data;
01839
01840 ast_channel_unlock(chan);
01841
01842 if (dialfeatures)
01843 snprintf(returnexten, sizeof(returnexten), "%s|30|%s", peername, dialfeatures->options);
01844 else
01845 snprintf(returnexten, sizeof(returnexten), "%s|30|t", peername);
01846
01847 ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), ast_free, registrar);
01848 }
01849 set_c_e_p(chan, parking_con_dial, peername, 1);
01850 } else {
01851
01852
01853 set_c_e_p(chan, pu->context, pu->exten, pu->priority);
01854 }
01855
01856 post_manager_event("ParkedCallTimeOut", pu->parkingexten, chan);
01857
01858 if (option_verbose > 1)
01859 ast_verbose(VERBOSE_PREFIX_2 "Timeout for %s parked on %d. Returning to %s,%s,%d\n", chan->name, pu->parkingnum, chan->context, chan->exten, chan->priority);
01860
01861 if (ast_pbx_start(chan)) {
01862 ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", chan->name);
01863 ast_hangup(chan);
01864 }
01865
01866 if (pl)
01867 pl->next = pu->next;
01868 else
01869 parkinglot = pu->next;
01870 pt = pu;
01871 pu = pu->next;
01872 con = ast_context_find(parking_con);
01873 if (con) {
01874 if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL))
01875 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01876 else
01877 notify_metermaids(pt->parkingexten, parking_con);
01878 } else
01879 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01880 free(pt);
01881 } else {
01882 for (x = 0; x < AST_MAX_FDS; x++) {
01883 struct ast_frame *f;
01884
01885 if (chan->fds[x] == -1 || (!FD_ISSET(chan->fds[x], &rfds) && !FD_ISSET(chan->fds[x], &efds)))
01886 continue;
01887
01888 if (FD_ISSET(chan->fds[x], &efds))
01889 ast_set_flag(chan, AST_FLAG_EXCEPTION);
01890 else
01891 ast_clear_flag(chan, AST_FLAG_EXCEPTION);
01892 chan->fdno = x;
01893
01894
01895 f = ast_read(chan);
01896 if (!f || (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_HANGUP)) {
01897 if (f)
01898 ast_frfree(f);
01899 post_manager_event("ParkedCallGiveUp", pu->parkingexten, chan);
01900
01901
01902 if (option_verbose > 1)
01903 ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", chan->name);
01904 ast_hangup(chan);
01905
01906 if (pl)
01907 pl->next = pu->next;
01908 else
01909 parkinglot = pu->next;
01910 pt = pu;
01911 pu = pu->next;
01912 con = ast_context_find(parking_con);
01913 if (con) {
01914 if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL))
01915 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01916 else
01917 notify_metermaids(pt->parkingexten, parking_con);
01918 } else
01919 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01920 free(pt);
01921 break;
01922 } else {
01923
01924 ast_frfree(f);
01925 if (pu->moh_trys < 3 && !chan->generatordata) {
01926 if (option_debug)
01927 ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source. Restarting.\n");
01928 ast_indicate_data(pu->chan, AST_CONTROL_HOLD,
01929 S_OR(parkmohclass, NULL),
01930 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
01931 pu->moh_trys++;
01932 }
01933 goto std;
01934 }
01935
01936 }
01937 if (x >= AST_MAX_FDS) {
01938 std: for (x=0; x<AST_MAX_FDS; x++) {
01939 if (chan->fds[x] > -1) {
01940 FD_SET(chan->fds[x], &nrfds);
01941 FD_SET(chan->fds[x], &nefds);
01942 if (chan->fds[x] > max)
01943 max = chan->fds[x];
01944 }
01945 }
01946
01947 if (tms < ms || ms < 0)
01948 ms = tms;
01949 pl = pu;
01950 pu = pu->next;
01951 }
01952 }
01953 }
01954 ast_mutex_unlock(&parking_lock);
01955 rfds = nrfds;
01956 efds = nefds;
01957 {
01958 struct timeval tv = ast_samp2tv(ms, 1000);
01959
01960 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
01961 }
01962 pthread_testcancel();
01963 }
01964 return NULL;
01965 }
01966
01967
01968 static int park_call_exec(struct ast_channel *chan, void *data)
01969 {
01970
01971
01972
01973 char *orig_chan_name = ast_strdupa(chan->name);
01974 char orig_exten[AST_MAX_EXTENSION];
01975 int orig_priority = chan->priority;
01976
01977
01978
01979 int res = 0;
01980 struct ast_module_user *u;
01981
01982 u = ast_module_user_add(chan);
01983
01984 ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten));
01985
01986
01987
01988 strcpy(chan->exten, "s");
01989 chan->priority = 1;
01990
01991 if (chan->_state != AST_STATE_UP)
01992 res = ast_answer(chan);
01993
01994 if (!res)
01995 res = ast_safe_sleep(chan, 1000);
01996
01997 if (!res) {
01998 res = park_call_full(chan, chan, 0, NULL, orig_chan_name);
01999
02000 if (res == 1) {
02001 ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten));
02002 chan->priority = orig_priority;
02003 res = 0;
02004 } else if (!res)
02005 res = AST_PBX_KEEPALIVE;
02006 }
02007
02008 ast_module_user_remove(u);
02009
02010 return res;
02011 }
02012
02013
02014 static int park_exec(struct ast_channel *chan, void *data)
02015 {
02016 int res = 0;
02017 struct ast_module_user *u;
02018 struct ast_channel *peer=NULL;
02019 struct parkeduser *pu, *pl=NULL;
02020 struct ast_context *con;
02021
02022 int park;
02023 struct ast_bridge_config config;
02024
02025 if (!data) {
02026 ast_log(LOG_WARNING, "Parkedcall requires an argument (extension number)\n");
02027 return -1;
02028 }
02029
02030 u = ast_module_user_add(chan);
02031
02032 park = atoi((char *)data);
02033 ast_mutex_lock(&parking_lock);
02034 pu = parkinglot;
02035 while(pu) {
02036 if (pu->parkingnum == park) {
02037 if (pl)
02038 pl->next = pu->next;
02039 else
02040 parkinglot = pu->next;
02041 break;
02042 }
02043 pl = pu;
02044 pu = pu->next;
02045 }
02046 ast_mutex_unlock(&parking_lock);
02047 if (pu) {
02048 peer = pu->chan;
02049 con = ast_context_find(parking_con);
02050 if (con) {
02051 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL))
02052 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
02053 else
02054 notify_metermaids(pu->parkingexten, parking_con);
02055 } else
02056 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
02057
02058 manager_event(EVENT_FLAG_CALL, "UnParkedCall",
02059 "Exten: %s\r\n"
02060 "Channel: %s\r\n"
02061 "From: %s\r\n"
02062 "CallerID: %s\r\n"
02063 "CallerIDName: %s\r\n",
02064 pu->parkingexten, pu->chan->name, chan->name,
02065 S_OR(pu->chan->cid.cid_num, "<unknown>"),
02066 S_OR(pu->chan->cid.cid_name, "<unknown>")
02067 );
02068
02069 free(pu);
02070 }
02071
02072 if (chan->_state != AST_STATE_UP)
02073 ast_answer(chan);
02074
02075 if (peer) {
02076
02077
02078 if (!ast_strlen_zero(courtesytone)) {
02079 int error = 0;
02080 ast_indicate(peer, AST_CONTROL_UNHOLD);
02081 if (parkedplay == 0) {
02082 error = ast_stream_and_wait(chan, courtesytone, chan->language, "");
02083 } else if (parkedplay == 1) {
02084 error = ast_stream_and_wait(peer, courtesytone, chan->language, "");
02085 } else if (parkedplay == 2) {
02086 if (!ast_streamfile(chan, courtesytone, chan->language) &&
02087 !ast_streamfile(peer, courtesytone, chan->language)) {
02088
02089 res = ast_waitstream(chan, "");
02090 if (res >= 0)
02091 res = ast_waitstream(peer, "");
02092 if (res < 0)
02093 error = 1;
02094 }
02095 }
02096 if (error) {
02097 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
02098 ast_hangup(peer);
02099 ast_module_user_remove(u);
02100 return -1;
02101 }
02102 } else
02103 ast_indicate(peer, AST_CONTROL_UNHOLD);
02104
02105 res = ast_channel_make_compatible(chan, peer);
02106 if (res < 0) {
02107 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
02108 ast_hangup(peer);
02109 ast_module_user_remove(u);
02110 return -1;
02111 }
02112
02113
02114 if (option_verbose > 2)
02115 ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
02116
02117 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
02118 ast_cdr_setdestchan(chan->cdr, peer->name);
02119 memset(&config, 0, sizeof(struct ast_bridge_config));
02120 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
02121 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
02122 res = ast_bridge_call(chan, peer, &config);
02123
02124 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
02125 ast_cdr_setdestchan(chan->cdr, peer->name);
02126
02127
02128 if (res != AST_PBX_NO_HANGUP_PEER)
02129 ast_hangup(peer);
02130 ast_module_user_remove(u);
02131 return res;
02132 } else {
02133
02134 if (ast_stream_and_wait(chan, "pbx-invalidpark", chan->language, ""))
02135 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
02136 if (option_verbose > 2)
02137 ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
02138 res = -1;
02139 }
02140
02141 ast_module_user_remove(u);
02142
02143 return res;
02144 }
02145
02146 static int handle_showfeatures(int fd, int argc, char *argv[])
02147 {
02148 int i;
02149 struct ast_call_feature *feature;
02150 char format[] = "%-25s %-7s %-7s\n";
02151
02152 ast_cli(fd, format, "Builtin Feature", "Default", "Current");
02153 ast_cli(fd, format, "---------------", "-------", "-------");
02154
02155 ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext());
02156
02157 ast_rwlock_rdlock(&features_lock);
02158 for (i = 0; i < FEATURES_COUNT; i++)
02159 ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
02160 ast_rwlock_unlock(&features_lock);
02161
02162 ast_cli(fd, "\n");
02163 ast_cli(fd, format, "Dynamic Feature", "Default", "Current");
02164 ast_cli(fd, format, "---------------", "-------", "-------");
02165 if (AST_LIST_EMPTY(&feature_list))
02166 ast_cli(fd, "(none)\n");
02167 else {
02168 AST_LIST_LOCK(&feature_list);
02169 AST_LIST_TRAVERSE(&feature_list, feature, feature_entry)
02170 ast_cli(fd, format, feature->sname, "no def", feature->exten);
02171 AST_LIST_UNLOCK(&feature_list);
02172 }
02173 ast_cli(fd, "\nCall parking\n");
02174 ast_cli(fd, "------------\n");
02175 ast_cli(fd,"%-20s: %s\n", "Parking extension", parking_ext);
02176 ast_cli(fd,"%-20s: %s\n", "Parking context", parking_con);
02177 ast_cli(fd,"%-20s: %d-%d\n", "Parked call extensions", parking_start, parking_stop);
02178 ast_cli(fd,"\n");
02179
02180 return RESULT_SUCCESS;
02181 }
02182
02183 static char showfeatures_help[] =
02184 "Usage: feature list\n"
02185 " Lists currently configured features.\n";
02186
02187 static int handle_parkedcalls(int fd, int argc, char *argv[])
02188 {
02189 struct parkeduser *cur;
02190 int numparked = 0;
02191
02192 ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
02193 , "Context", "Extension", "Pri", "Timeout");
02194
02195 ast_mutex_lock(&parking_lock);
02196
02197 for (cur = parkinglot; cur; cur = cur->next) {
02198 ast_cli(fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n"
02199 ,cur->parkingexten, cur->chan->name, cur->context, cur->exten
02200 ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
02201
02202 numparked++;
02203 }
02204 ast_mutex_unlock(&parking_lock);
02205 ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : "");
02206
02207
02208 return RESULT_SUCCESS;
02209 }
02210
02211 static char showparked_help[] =
02212 "Usage: show parkedcalls\n"
02213 " Lists currently parked calls.\n";
02214
02215 static struct ast_cli_entry cli_show_features_deprecated = {
02216 { "show", "features", NULL },
02217 handle_showfeatures, NULL,
02218 NULL };
02219
02220 static struct ast_cli_entry cli_features[] = {
02221 { { "feature", "show", NULL },
02222 handle_showfeatures, "Lists configured features",
02223 showfeatures_help, NULL, &cli_show_features_deprecated },
02224
02225 { { "show", "parkedcalls", NULL },
02226 handle_parkedcalls, "Lists parked calls",
02227 showparked_help },
02228 };
02229
02230
02231 static int manager_parking_status( struct mansession *s, const struct message *m)
02232 {
02233 struct parkeduser *cur;
02234 const char *id = astman_get_header(m, "ActionID");
02235 char idText[256] = "";
02236
02237 if (!ast_strlen_zero(id))
02238 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
02239
02240 astman_send_ack(s, m, "Parked calls will follow");
02241
02242 ast_mutex_lock(&parking_lock);
02243
02244 for (cur = parkinglot; cur; cur = cur->next) {
02245 astman_append(s, "Event: ParkedCall\r\n"
02246 "Exten: %d\r\n"
02247 "Channel: %s\r\n"
02248 "From: %s\r\n"
02249 "Timeout: %ld\r\n"
02250 "CallerID: %s\r\n"
02251 "CallerIDName: %s\r\n"
02252 "%s"
02253 "\r\n",
02254 cur->parkingnum, cur->chan->name, cur->peername,
02255 (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
02256 S_OR(cur->chan->cid.cid_num, ""),
02257 S_OR(cur->chan->cid.cid_name, ""),
02258 idText);
02259 }
02260
02261 astman_append(s,
02262 "Event: ParkedCallsComplete\r\n"
02263 "%s"
02264 "\r\n",idText);
02265
02266 ast_mutex_unlock(&parking_lock);
02267
02268 return RESULT_SUCCESS;
02269 }
02270
02271 static char mandescr_park[] =
02272 "Description: Park a channel.\n"
02273 "Variables: (Names marked with * are required)\n"
02274 " *Channel: Channel name to park\n"
02275 " *Channel2: Channel to announce park info to (and return to if timeout)\n"
02276 " Timeout: Number of milliseconds to wait before callback.\n";
02277
02278 static int manager_park(struct mansession *s, const struct message *m)
02279 {
02280 const char *channel = astman_get_header(m, "Channel");
02281 const char *channel2 = astman_get_header(m, "Channel2");
02282 const char *timeout = astman_get_header(m, "Timeout");
02283 char buf[BUFSIZ];
02284 int to = 0;
02285 int res = 0;
02286 int parkExt = 0;
02287 struct ast_channel *ch1, *ch2;
02288
02289 if (ast_strlen_zero(channel)) {
02290 astman_send_error(s, m, "Channel not specified");
02291 return 0;
02292 }
02293
02294 if (ast_strlen_zero(channel2)) {
02295 astman_send_error(s, m, "Channel2 not specified");
02296 return 0;
02297 }
02298
02299 ch1 = ast_get_channel_by_name_locked(channel);
02300 if (!ch1) {
02301 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
02302 astman_send_error(s, m, buf);
02303 return 0;
02304 }
02305
02306 ch2 = ast_get_channel_by_name_locked(channel2);
02307 if (!ch2) {
02308 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
02309 astman_send_error(s, m, buf);
02310 ast_channel_unlock(ch1);
02311 return 0;
02312 }
02313
02314 if (!ast_strlen_zero(timeout)) {
02315 sscanf(timeout, "%d", &to);
02316 }
02317
02318 res = ast_masq_park_call(ch1, ch2, to, &parkExt);
02319 if (!res) {
02320 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
02321 astman_send_ack(s, m, "Park successful");
02322 } else {
02323 astman_send_error(s, m, "Park failure");
02324 }
02325
02326 ast_channel_unlock(ch1);
02327 ast_channel_unlock(ch2);
02328
02329 return 0;
02330 }
02331
02332
02333 int ast_pickup_call(struct ast_channel *chan)
02334 {
02335 struct ast_channel *cur = NULL;
02336 int res = -1;
02337
02338 while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
02339 if (!cur->pbx &&
02340 (cur != chan) &&
02341 (chan->pickupgroup & cur->callgroup) &&
02342 ((cur->_state == AST_STATE_RINGING) ||
02343 (cur->_state == AST_STATE_RING))) {
02344 break;
02345 }
02346 ast_channel_unlock(cur);
02347 }
02348 if (cur) {
02349 if (option_debug)
02350 ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
02351 res = ast_answer(chan);
02352 if (res)
02353 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
02354 res = ast_queue_control(chan, AST_CONTROL_ANSWER);
02355 if (res)
02356 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
02357 res = ast_channel_masquerade(cur, chan);
02358 if (res)
02359 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);
02360 ast_channel_unlock(cur);
02361 } else {
02362 if (option_debug)
02363 ast_log(LOG_DEBUG, "No call pickup possible...\n");
02364 }
02365 return res;
02366 }
02367
02368
02369 static void park_add_hints(char *context, int start, int stop)
02370 {
02371 int numext;
02372 char device[AST_MAX_EXTENSION];
02373 char exten[10];
02374
02375 for (numext = start; numext <= stop; numext++) {
02376 snprintf(exten, sizeof(exten), "%d", numext);
02377 snprintf(device, sizeof(device), "park:%s@%s", exten, context);
02378 ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
02379 }
02380 }
02381
02382
02383 static int load_config(void)
02384 {
02385 int start = 0, end = 0;
02386 int res;
02387 struct ast_context *con = NULL;
02388 struct ast_config *cfg = NULL;
02389 struct ast_variable *var = NULL;
02390 char old_parking_ext[AST_MAX_EXTENSION];
02391 char old_parking_con[AST_MAX_EXTENSION] = "";
02392
02393 if (!ast_strlen_zero(parking_con)) {
02394 strcpy(old_parking_ext, parking_ext);
02395 strcpy(old_parking_con, parking_con);
02396 }
02397
02398
02399 strcpy(parking_con, "parkedcalls");
02400 strcpy(parking_con_dial, "park-dial");
02401 strcpy(parking_ext, "700");
02402 strcpy(pickup_ext, "*8");
02403 strcpy(parkmohclass, "default");
02404 courtesytone[0] = '\0';
02405 strcpy(xfersound, "beep");
02406 strcpy(xferfailsound, "pbx-invalid");
02407 parking_start = 701;
02408 parking_stop = 750;
02409 parkfindnext = 0;
02410 adsipark = 0;
02411 parkaddhints = 0;
02412
02413 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
02414 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
02415 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
02416
02417 cfg = ast_config_load("features.conf");
02418 if (!cfg) {
02419 ast_log(LOG_WARNING,"Could not load features.conf\n");
02420 return AST_MODULE_LOAD_DECLINE;
02421 }
02422 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
02423 if (!strcasecmp(var->name, "parkext")) {
02424 ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
02425 } else if (!strcasecmp(var->name, "context")) {
02426 ast_copy_string(parking_con, var->value, sizeof(parking_con));
02427 } else if (!strcasecmp(var->name, "parkingtime")) {
02428 if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) {
02429 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
02430 parkingtime = DEFAULT_PARK_TIME;
02431 } else
02432 parkingtime = parkingtime * 1000;
02433 } else if (!strcasecmp(var->name, "parkpos")) {
02434 if (sscanf(var->value, "%d-%d", &start, &end) != 2) {
02435 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);
02436 } else {
02437 parking_start = start;
02438 parking_stop = end;
02439 }
02440 } else if (!strcasecmp(var->name, "findslot")) {
02441 parkfindnext = (!strcasecmp(var->value, "next"));
02442 } else if (!strcasecmp(var->name, "parkinghints")) {
02443 parkaddhints = ast_true(var->value);
02444 } else if (!strcasecmp(var->name, "adsipark")) {
02445 adsipark = ast_true(var->value);
02446 } else if (!strcasecmp(var->name, "transferdigittimeout")) {
02447 if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
02448 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
02449 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
02450 } else
02451 transferdigittimeout = transferdigittimeout * 1000;
02452 } else if (!strcasecmp(var->name, "featuredigittimeout")) {
02453 if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
02454 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
02455 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
02456 }
02457 } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) {
02458 if ((sscanf(var->value, "%d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) {
02459 ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value);
02460 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
02461 } else
02462 atxfernoanswertimeout = atxfernoanswertimeout * 1000;
02463 } else if (!strcasecmp(var->name, "courtesytone")) {
02464 ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
02465 } else if (!strcasecmp(var->name, "parkedplay")) {
02466 if (!strcasecmp(var->value, "both"))
02467 parkedplay = 2;
02468 else if (!strcasecmp(var->value, "parked"))
02469 parkedplay = 1;
02470 else
02471 parkedplay = 0;
02472 } else if (!strcasecmp(var->name, "xfersound")) {
02473 ast_copy_string(xfersound, var->value, sizeof(xfersound));
02474 } else if (!strcasecmp(var->name, "xferfailsound")) {
02475 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
02476 } else if (!strcasecmp(var->name, "pickupexten")) {
02477 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
02478 } else if (!strcasecmp(var->name, "parkedmusicclass")) {
02479 ast_copy_string(parkmohclass, var->value, sizeof(parkmohclass));
02480 }
02481 }
02482
02483 unmap_features();
02484 for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) {
02485 if (remap_feature(var->name, var->value))
02486 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
02487 }
02488
02489
02490 ast_unregister_features();
02491 for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) {
02492 char *tmp_val = ast_strdupa(var->value);
02493 char *exten, *activateon, *activatedby, *app, *app_args, *moh_class;
02494 struct ast_call_feature *feature;
02495
02496
02497
02498
02499
02500 exten = strsep(&tmp_val,",");
02501 activatedby = strsep(&tmp_val,",");
02502 app = strsep(&tmp_val,",");
02503 app_args = strsep(&tmp_val,",");
02504 moh_class = strsep(&tmp_val,",");
02505
02506 activateon = strsep(&activatedby, "/");
02507
02508
02509 if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) {
02510 ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",
02511 app, exten, activateon, var->name);
02512 continue;
02513 }
02514
02515 AST_LIST_LOCK(&feature_list);
02516 if ((feature = find_dynamic_feature(var->name))) {
02517 AST_LIST_UNLOCK(&feature_list);
02518 ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name);
02519 continue;
02520 }
02521 AST_LIST_UNLOCK(&feature_list);
02522
02523 if (!(feature = ast_calloc(1, sizeof(*feature))))
02524 continue;
02525
02526 ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN);
02527 ast_copy_string(feature->app, app, FEATURE_APP_LEN);
02528 ast_copy_string(feature->exten, exten, FEATURE_EXTEN_LEN);
02529
02530 if (app_args)
02531 ast_copy_string(feature->app_args, app_args, FEATURE_APP_ARGS_LEN);
02532
02533 if (moh_class)
02534 ast_copy_string(feature->moh_class, moh_class, FEATURE_MOH_LEN);
02535
02536 ast_copy_string(feature->exten, exten, sizeof(feature->exten));
02537 feature->operation = feature_exec_app;
02538 ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF);
02539
02540
02541 if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller"))
02542 ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF);
02543 else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee"))
02544 ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER);
02545 else {
02546 ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s',"
02547 " must be 'self', or 'peer'\n", var->name);
02548 continue;
02549 }
02550
02551 if (ast_strlen_zero(activatedby))
02552 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
02553 else if (!strcasecmp(activatedby, "caller"))
02554 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER);
02555 else if (!strcasecmp(activatedby, "callee"))
02556 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE);
02557 else if (!strcasecmp(activatedby, "both"))
02558 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
02559 else {
02560 ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s',"
02561 " must be 'caller', or 'callee', or 'both'\n", var->name);
02562 continue;
02563 }
02564
02565 ast_register_feature(feature);
02566
02567 if (option_verbose >= 1)
02568 ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, app, app_args, exten);
02569 }
02570 ast_config_destroy(cfg);
02571
02572
02573 if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) {
02574 if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar))
02575 notify_metermaids(old_parking_ext, old_parking_con);
02576 if (option_debug)
02577 ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
02578 }
02579
02580 if (!(con = ast_context_find(parking_con)) && !(con = ast_context_create(NULL, parking_con, registrar))) {
02581 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
02582 return -1;
02583 }
02584 res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar);
02585 if (parkaddhints)
02586 park_add_hints(parking_con, parking_start, parking_stop);
02587 if (!res)
02588 notify_metermaids(ast_parking_ext(), parking_con);
02589 return res;
02590
02591 }
02592
02593 static int reload(void)
02594 {
02595 return load_config();
02596 }
02597
02598 static int load_module(void)
02599 {
02600 int res;
02601
02602 memset(parking_ext, 0, sizeof(parking_ext));
02603 memset(parking_con, 0, sizeof(parking_con));
02604
02605 if ((res = load_config()))
02606 return res;
02607 ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
02608 ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
02609 res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
02610 if (!res)
02611 res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
02612 if (!res) {
02613 ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" );
02614 ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park,
02615 "Park a channel", mandescr_park);
02616 }
02617
02618 res |= ast_devstate_prov_add("Park", metermaidstate);
02619
02620 return res;
02621 }
02622
02623
02624 static int unload_module(void)
02625 {
02626 ast_module_user_hangup_all();
02627
02628 ast_manager_unregister("ParkedCalls");
02629 ast_manager_unregister("Park");
02630 ast_cli_unregister_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
02631 ast_unregister_application(parkcall);
02632 ast_devstate_prov_del("Park");
02633 return ast_unregister_application(parkedcall);
02634 }
02635
02636 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Call Features Resource",
02637 .load = load_module,
02638 .unload = unload_module,
02639 .reload = reload,
02640 );