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 #include <pthread.h>
00026 #include <stdlib.h>
00027 #include <errno.h>
00028 #include <unistd.h>
00029 #include <string.h>
00030 #include <stdlib.h>
00031 #include <stdio.h>
00032 #include <sys/time.h>
00033 #include <sys/signal.h>
00034 #include <netinet/in.h>
00035
00036 #include "asterisk.h"
00037
00038 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 8134 $")
00039
00040 #include "asterisk/lock.h"
00041 #include "asterisk/file.h"
00042 #include "asterisk/logger.h"
00043 #include "asterisk/channel.h"
00044 #include "asterisk/pbx.h"
00045 #include "asterisk/options.h"
00046 #include "asterisk/causes.h"
00047 #include "asterisk/module.h"
00048 #include "asterisk/translate.h"
00049 #include "asterisk/app.h"
00050 #include "asterisk/say.h"
00051 #include "asterisk/features.h"
00052 #include "asterisk/musiconhold.h"
00053 #include "asterisk/config.h"
00054 #include "asterisk/cli.h"
00055 #include "asterisk/manager.h"
00056 #include "asterisk/utils.h"
00057 #include "asterisk/adsi.h"
00058 #include "asterisk/monitor.h"
00059
00060 #ifdef __AST_DEBUG_MALLOC
00061 static void FREE(void *ptr)
00062 {
00063 free(ptr);
00064 }
00065 #else
00066 #define FREE free
00067 #endif
00068
00069 #define DEFAULT_PARK_TIME 45000
00070 #define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000
00071 #define DEFAULT_FEATURE_DIGIT_TIMEOUT 500
00072
00073 #define AST_MAX_WATCHERS 256
00074
00075 static char *parkedcall = "ParkedCall";
00076
00077
00078 static int parkingtime = DEFAULT_PARK_TIME;
00079
00080
00081 static char parking_con[AST_MAX_EXTENSION];
00082
00083
00084 static char parking_con_dial[AST_MAX_EXTENSION];
00085
00086
00087 static char parking_ext[AST_MAX_EXTENSION];
00088
00089 static char pickup_ext[AST_MAX_EXTENSION];
00090
00091
00092 static char courtesytone[256];
00093 static char xfersound[256];
00094 static char xferfailsound[256];
00095
00096
00097 static int parking_start;
00098
00099
00100 static int parking_stop;
00101
00102 static int parking_offset;
00103
00104 static int parkfindnext;
00105
00106 static int adsipark;
00107
00108 static int transferdigittimeout;
00109 static int featuredigittimeout;
00110
00111
00112
00113
00114 static char *registrar = "res_features";
00115
00116 static char *synopsis = "Answer a parked call";
00117
00118 static char *descrip = "ParkedCall(exten):"
00119 "Used to connect to a parked call. This application is always\n"
00120 "registered internally and does not need to be explicitly added\n"
00121 "into the dialplan, although you should include the 'parkedcalls'\n"
00122 "context.\n";
00123
00124 static char *parkcall = "Park";
00125
00126 static char *synopsis2 = "Park yourself";
00127
00128 static char *descrip2 = "Park(exten):"
00129 "Used to park yourself (typically in combination with a supervised\n"
00130 "transfer to know the parking space). This application is always\n"
00131 "registered internally and does not need to be explicitly added\n"
00132 "into the dialplan, although you should include the 'parkedcalls'\n"
00133 "context.\n";
00134
00135 static struct ast_app *monitor_app=NULL;
00136 static int monitor_ok=1;
00137
00138 struct parkeduser {
00139 struct ast_channel *chan;
00140 struct timeval start;
00141 int parkingnum;
00142
00143 char context[AST_MAX_CONTEXT];
00144 char exten[AST_MAX_EXTENSION];
00145 int priority;
00146 int parkingtime;
00147 int notquiteyet;
00148 char peername[1024];
00149 unsigned char moh_trys;
00150 struct parkeduser *next;
00151 };
00152
00153 static struct parkeduser *parkinglot;
00154
00155 AST_MUTEX_DEFINE_STATIC(parking_lock);
00156
00157 static pthread_t parking_thread;
00158
00159 STANDARD_LOCAL_USER;
00160
00161 LOCAL_USER_DECL;
00162
00163 char *ast_parking_ext(void)
00164 {
00165 return parking_ext;
00166 }
00167
00168 char *ast_pickup_ext(void)
00169 {
00170 return pickup_ext;
00171 }
00172
00173 struct ast_bridge_thread_obj
00174 {
00175 struct ast_bridge_config bconfig;
00176 struct ast_channel *chan;
00177 struct ast_channel *peer;
00178 };
00179
00180 static void check_goto_on_transfer(struct ast_channel *chan)
00181 {
00182 struct ast_channel *xferchan;
00183 char *goto_on_transfer;
00184
00185 goto_on_transfer = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR");
00186
00187 if (!ast_strlen_zero(goto_on_transfer) && (xferchan = ast_channel_alloc(0))) {
00188 char *x;
00189 struct ast_frame *f;
00190
00191 for (x = goto_on_transfer; x && *x; x++)
00192 if (*x == '^')
00193 *x = '|';
00194
00195 strcpy(xferchan->name, chan->name);
00196
00197 xferchan->readformat = chan->readformat;
00198 xferchan->writeformat = chan->writeformat;
00199 ast_channel_masquerade(xferchan, chan);
00200 ast_parseable_goto(xferchan, goto_on_transfer);
00201 xferchan->_state = AST_STATE_UP;
00202 ast_clear_flag(xferchan, AST_FLAGS_ALL);
00203 xferchan->_softhangup = 0;
00204 if ((f = ast_read(xferchan))) {
00205 ast_frfree(f);
00206 f = NULL;
00207 ast_pbx_start(xferchan);
00208 } else {
00209 ast_hangup(xferchan);
00210 }
00211 }
00212 }
00213
00214 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);
00215
00216
00217 static void *ast_bridge_call_thread(void *data)
00218 {
00219 struct ast_bridge_thread_obj *tobj = data;
00220
00221 tobj->chan->appl = "Transferred Call";
00222 tobj->chan->data = tobj->peer->name;
00223 tobj->peer->appl = "Transferred Call";
00224 tobj->peer->data = tobj->chan->name;
00225 if (tobj->chan->cdr) {
00226 ast_cdr_reset(tobj->chan->cdr, NULL);
00227 ast_cdr_setdestchan(tobj->chan->cdr, tobj->peer->name);
00228 }
00229 if (tobj->peer->cdr) {
00230 ast_cdr_reset(tobj->peer->cdr, NULL);
00231 ast_cdr_setdestchan(tobj->peer->cdr, tobj->chan->name);
00232 }
00233
00234 ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
00235 ast_hangup(tobj->chan);
00236 ast_hangup(tobj->peer);
00237 tobj->chan = tobj->peer = NULL;
00238 free(tobj);
00239 tobj=NULL;
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
00258
00259 static int adsi_announce_park(struct ast_channel *chan, int parkingnum)
00260 {
00261 int res;
00262 int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
00263 char tmp[256];
00264 char *message[5] = {NULL, NULL, NULL, NULL, NULL};
00265
00266 snprintf(tmp, sizeof(tmp), "Parked on %d", parkingnum);
00267 message[0] = tmp;
00268 res = adsi_load_session(chan, NULL, 0, 1);
00269 if (res == -1) {
00270 return res;
00271 }
00272 return adsi_print(chan, message, justify, 1);
00273 }
00274
00275
00276
00277
00278 int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
00279 {
00280 struct parkeduser *pu, *cur;
00281 int i,x,parking_range;
00282 char exten[AST_MAX_EXTENSION];
00283 struct ast_context *con;
00284
00285 pu = malloc(sizeof(struct parkeduser));
00286 if (!pu) {
00287 ast_log(LOG_WARNING, "Out of memory\n");
00288 return -1;
00289 }
00290 memset(pu, 0, sizeof(struct parkeduser));
00291 ast_mutex_lock(&parking_lock);
00292 parking_range = parking_stop - parking_start+1;
00293 for (i = 0; i < parking_range; i++) {
00294 x = (i + parking_offset) % parking_range + parking_start;
00295 cur = parkinglot;
00296 while(cur) {
00297 if (cur->parkingnum == x)
00298 break;
00299 cur = cur->next;
00300 }
00301 if (!cur)
00302 break;
00303 }
00304
00305 if (!(i < parking_range)) {
00306 ast_log(LOG_WARNING, "No more parking spaces\n");
00307 free(pu);
00308 ast_mutex_unlock(&parking_lock);
00309 return -1;
00310 }
00311 if (parkfindnext)
00312 parking_offset = x - parking_start + 1;
00313 chan->appl = "Parked Call";
00314 chan->data = NULL;
00315
00316 pu->chan = chan;
00317
00318 if (chan != peer) {
00319 ast_indicate(pu->chan, AST_CONTROL_HOLD);
00320 ast_moh_start(pu->chan, NULL);
00321 }
00322 pu->start = ast_tvnow();
00323 pu->parkingnum = x;
00324 if (timeout > 0)
00325 pu->parkingtime = timeout;
00326 else
00327 pu->parkingtime = parkingtime;
00328 if (extout)
00329 *extout = x;
00330 if (peer)
00331 ast_copy_string(pu->peername, peer->name, sizeof(pu->peername));
00332
00333
00334
00335 if (!ast_strlen_zero(chan->macrocontext))
00336 ast_copy_string(pu->context, chan->macrocontext, sizeof(pu->context));
00337 else
00338 ast_copy_string(pu->context, chan->context, sizeof(pu->context));
00339 if (!ast_strlen_zero(chan->macroexten))
00340 ast_copy_string(pu->exten, chan->macroexten, sizeof(pu->exten));
00341 else
00342 ast_copy_string(pu->exten, chan->exten, sizeof(pu->exten));
00343 if (chan->macropriority)
00344 pu->priority = chan->macropriority;
00345 else
00346 pu->priority = chan->priority;
00347 pu->next = parkinglot;
00348 parkinglot = pu;
00349
00350 if (peer == chan)
00351 pu->notquiteyet = 1;
00352 ast_mutex_unlock(&parking_lock);
00353
00354 pthread_kill(parking_thread, SIGURG);
00355 if (option_verbose > 1)
00356 ast_verbose(VERBOSE_PREFIX_2 "Parked %s on %d. Will timeout back to extension [%s] %s, %d in %d seconds\n", pu->chan->name, pu->parkingnum, pu->context, pu->exten, pu->priority, (pu->parkingtime/1000));
00357
00358 manager_event(EVENT_FLAG_CALL, "ParkedCall",
00359 "Exten: %d\r\n"
00360 "Channel: %s\r\n"
00361 "From: %s\r\n"
00362 "Timeout: %ld\r\n"
00363 "CallerID: %s\r\n"
00364 "CallerIDName: %s\r\n"
00365 ,pu->parkingnum, pu->chan->name, peer->name
00366 ,(long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL)
00367 ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
00368 ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
00369 );
00370
00371 if (peer) {
00372 if (adsipark && adsi_available(peer)) {
00373 adsi_announce_park(peer, pu->parkingnum);
00374 }
00375 if (adsipark && adsi_available(peer)) {
00376 adsi_unload_session(peer);
00377 }
00378 }
00379 con = ast_context_find(parking_con);
00380 if (!con) {
00381 con = ast_context_create(NULL, parking_con, registrar);
00382 if (!con) {
00383 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
00384 }
00385 }
00386 if (con) {
00387 snprintf(exten, sizeof(exten), "%d", x);
00388 ast_add_extension2(con, 1, exten, 1, NULL, NULL, parkedcall, strdup(exten), FREE, registrar);
00389 }
00390 if (peer)
00391 ast_say_digits(peer, pu->parkingnum, "", peer->language);
00392 if (pu->notquiteyet) {
00393
00394 ast_moh_start(pu->chan, NULL);
00395 pu->notquiteyet = 0;
00396 pthread_kill(parking_thread, SIGURG);
00397 }
00398 return 0;
00399 }
00400
00401 int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
00402 {
00403 struct ast_channel *chan;
00404 struct ast_frame *f;
00405
00406
00407 chan = ast_channel_alloc(0);
00408 if (chan) {
00409
00410 snprintf(chan->name, sizeof (chan->name), "Parked/%s",rchan->name);
00411
00412
00413 chan->readformat = rchan->readformat;
00414 chan->writeformat = rchan->writeformat;
00415 ast_channel_masquerade(chan, rchan);
00416
00417
00418 ast_copy_string(chan->context, rchan->context, sizeof(chan->context));
00419 ast_copy_string(chan->exten, rchan->exten, sizeof(chan->exten));
00420 chan->priority = rchan->priority;
00421
00422
00423 f = ast_read(chan);
00424 if (f)
00425 ast_frfree(f);
00426 ast_park_call(chan, peer, timeout, extout);
00427 } else {
00428 ast_log(LOG_WARNING, "Unable to create parked channel\n");
00429 return -1;
00430 }
00431 return 0;
00432 }
00433
00434
00435 #define FEATURE_RETURN_HANGUP -1
00436 #define FEATURE_RETURN_SUCCESSBREAK 0
00437 #define FEATURE_RETURN_PBX_KEEPALIVE AST_PBX_KEEPALIVE
00438 #define FEATURE_RETURN_NO_HANGUP_PEER AST_PBX_NO_HANGUP_PEER
00439 #define FEATURE_RETURN_PASSDIGITS 21
00440 #define FEATURE_RETURN_STOREDIGITS 22
00441 #define FEATURE_RETURN_SUCCESS 23
00442
00443 #define FEATURE_SENSE_CHAN (1 << 0)
00444 #define FEATURE_SENSE_PEER (1 << 1)
00445
00446
00447 static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
00448 {
00449 char *touch_monitor = NULL, *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_format = NULL;
00450 int x = 0;
00451 size_t len;
00452 struct ast_channel *caller_chan = NULL, *callee_chan = NULL;
00453
00454
00455 if(sense == 2) {
00456 caller_chan = peer;
00457 callee_chan = chan;
00458 } else {
00459 callee_chan = peer;
00460 caller_chan = chan;
00461 }
00462
00463 if (!monitor_ok) {
00464 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00465 return -1;
00466 }
00467
00468 if (!monitor_app) {
00469 if (!(monitor_app = pbx_findapp("Monitor"))) {
00470 monitor_ok=0;
00471 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00472 return -1;
00473 }
00474 }
00475 if (!ast_strlen_zero(courtesytone)) {
00476 if (ast_autoservice_start(callee_chan))
00477 return -1;
00478 if (!ast_streamfile(caller_chan, courtesytone, caller_chan->language)) {
00479 if (ast_waitstream(caller_chan, "") < 0) {
00480 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
00481 ast_autoservice_stop(callee_chan);
00482 return -1;
00483 }
00484 }
00485 if (ast_autoservice_stop(callee_chan))
00486 return -1;
00487 }
00488
00489 if (callee_chan->monitor) {
00490 if (option_verbose > 3)
00491 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to stop recording call.\n", code);
00492 ast_monitor_stop(callee_chan, 1);
00493 return FEATURE_RETURN_SUCCESS;
00494 }
00495
00496 if (caller_chan && callee_chan) {
00497 touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT");
00498 if (!touch_format)
00499 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
00500
00501 touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
00502 if (!touch_monitor)
00503 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
00504
00505 if (touch_monitor) {
00506 len = strlen(touch_monitor) + 50;
00507 args = alloca(len);
00508 snprintf(args, len, "%s|auto-%ld-%s|m", (touch_format) ? touch_format : "wav", time(NULL), touch_monitor);
00509 } else {
00510 caller_chan_id = ast_strdupa(caller_chan->cid.cid_num ? caller_chan->cid.cid_num : caller_chan->name);
00511 callee_chan_id = ast_strdupa(callee_chan->cid.cid_num ? callee_chan->cid.cid_num : callee_chan->name);
00512 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
00513 args = alloca(len);
00514 snprintf(args, len, "%s|auto-%ld-%s-%s|m", (touch_format) ? touch_format : "wav", time(NULL), caller_chan_id, callee_chan_id);
00515 }
00516
00517 for( x = 0; x < strlen(args); x++)
00518 if (args[x] == '/')
00519 args[x] = '-';
00520
00521 if (option_verbose > 3)
00522 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call. filename: %s\n", code, args);
00523
00524 pbx_exec(callee_chan, monitor_app, args, 1);
00525
00526 return FEATURE_RETURN_SUCCESS;
00527 }
00528
00529 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");
00530 return -1;
00531 }
00532
00533 static int builtin_disconnect(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
00534 {
00535 if (option_verbose > 3)
00536 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code);
00537 return FEATURE_RETURN_HANGUP;
00538 }
00539
00540 static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
00541 {
00542 struct ast_channel *transferer;
00543 struct ast_channel *transferee;
00544 char *transferer_real_context;
00545 char newext[256];
00546 int res;
00547
00548 if (sense == FEATURE_SENSE_PEER) {
00549 transferer = peer;
00550 transferee = chan;
00551 } else {
00552 transferer = chan;
00553 transferee = peer;
00554 }
00555 if (!(transferer_real_context = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT")) &&
00556 !(transferer_real_context = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"))) {
00557
00558 if (!ast_strlen_zero(transferer->macrocontext))
00559 transferer_real_context = transferer->macrocontext;
00560 else
00561 transferer_real_context = transferer->context;
00562 }
00563
00564
00565 ast_indicate(transferee, AST_CONTROL_HOLD);
00566 ast_autoservice_start(transferee);
00567 ast_moh_start(transferee, NULL);
00568
00569 memset(newext, 0, sizeof(newext));
00570
00571
00572 if ((res=ast_streamfile(transferer, "pbx-transfer", transferer->language))) {
00573 ast_moh_stop(transferee);
00574 ast_autoservice_stop(transferee);
00575 ast_indicate(transferee, AST_CONTROL_UNHOLD);
00576 return res;
00577 }
00578 if ((res=ast_waitstream(transferer, AST_DIGIT_ANY)) < 0) {
00579 ast_moh_stop(transferee);
00580 ast_autoservice_stop(transferee);
00581 ast_indicate(transferee, AST_CONTROL_UNHOLD);
00582 return res;
00583 } else if (res > 0) {
00584
00585 newext[0] = (char) res;
00586 }
00587
00588 ast_stopstream(transferer);
00589 res = ast_app_dtget(transferer, transferer_real_context, newext, sizeof(newext), 100, transferdigittimeout);
00590 if (res < 0) {
00591 ast_moh_stop(transferee);
00592 ast_autoservice_stop(transferee);
00593 ast_indicate(transferee, AST_CONTROL_UNHOLD);
00594 return res;
00595 }
00596 if (!strcmp(newext, ast_parking_ext())) {
00597 ast_moh_stop(transferee);
00598
00599 res = ast_autoservice_stop(transferee);
00600 ast_indicate(transferee, AST_CONTROL_UNHOLD);
00601 if (res)
00602 res = -1;
00603 else if (!ast_park_call(transferee, transferer, 0, NULL)) {
00604
00605
00606
00607
00608 if (transferer == peer)
00609 res = AST_PBX_KEEPALIVE;
00610 else
00611 res = AST_PBX_NO_HANGUP_PEER;
00612 return res;
00613 } else {
00614 ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name);
00615 }
00616
00617 } else if (ast_exists_extension(transferee, transferer_real_context, newext, 1, transferer->cid.cid_num)) {
00618 pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", chan->name);
00619 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", peer->name);
00620 ast_moh_stop(transferee);
00621 res=ast_autoservice_stop(transferee);
00622 ast_indicate(transferee, AST_CONTROL_UNHOLD);
00623 if (!transferee->pbx) {
00624
00625 if (option_verbose > 2)
00626 ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n"
00627 ,transferee->name, newext, transferer_real_context);
00628 if (ast_async_goto(transferee, transferer_real_context, newext, 1))
00629 ast_log(LOG_WARNING, "Async goto failed :-(\n");
00630 res = -1;
00631 } else {
00632
00633 ast_copy_string(transferee->exten, newext, sizeof(transferee->exten));
00634 ast_copy_string(transferee->context, transferer_real_context, sizeof(transferee->context));
00635 transferee->priority = 0;
00636 }
00637 check_goto_on_transfer(transferer);
00638 return res;
00639 } else {
00640 if (option_verbose > 2)
00641 ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", newext, transferer_real_context);
00642 }
00643 if (!ast_strlen_zero(xferfailsound))
00644 res = ast_streamfile(transferer, xferfailsound, transferee->language);
00645 else
00646 res = 0;
00647 if (res) {
00648 ast_moh_stop(transferee);
00649 ast_autoservice_stop(transferee);
00650 ast_indicate(transferee, AST_CONTROL_UNHOLD);
00651 return res;
00652 }
00653 res = ast_waitstream(transferer, AST_DIGIT_ANY);
00654 ast_stopstream(transferer);
00655 ast_moh_stop(transferee);
00656 res = ast_autoservice_stop(transferee);
00657 ast_indicate(transferee, AST_CONTROL_UNHOLD);
00658 if (res) {
00659 if (option_verbose > 1)
00660 ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name);
00661 return res;
00662 }
00663 return FEATURE_RETURN_SUCCESS;
00664 }
00665
00666 static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
00667 {
00668 struct ast_channel *transferer;
00669 struct ast_channel *transferee;
00670 struct ast_channel *newchan, *xferchan=NULL;
00671 int outstate=0;
00672 struct ast_bridge_config bconfig;
00673 char *transferer_real_context;
00674 char xferto[256],dialstr[265];
00675 char *cid_num;
00676 char *cid_name;
00677 int res;
00678 struct ast_frame *f = NULL;
00679 struct ast_bridge_thread_obj *tobj;
00680
00681 ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) XXX\n", chan->name, peer->name, sense);
00682 if (sense == FEATURE_SENSE_PEER) {
00683 transferer = peer;
00684 transferee = chan;
00685 } else {
00686 transferer = chan;
00687 transferee = peer;
00688 }
00689 if (!(transferer_real_context=pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT")) &&
00690 !(transferer_real_context=pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"))) {
00691
00692 if (!ast_strlen_zero(transferer->macrocontext))
00693 transferer_real_context = transferer->macrocontext;
00694 else
00695 transferer_real_context = transferer->context;
00696 }
00697
00698
00699 ast_indicate(transferee, AST_CONTROL_HOLD);
00700 ast_autoservice_start(transferee);
00701 ast_moh_start(transferee, NULL);
00702 memset(xferto, 0, sizeof(xferto));
00703
00704 if ((res = ast_streamfile(transferer, "pbx-transfer", transferer->language))) {
00705 ast_moh_stop(transferee);
00706 ast_autoservice_stop(transferee);
00707 ast_indicate(transferee, AST_CONTROL_UNHOLD);
00708 return res;
00709 }
00710 if ((res=ast_waitstream(transferer, AST_DIGIT_ANY)) < 0) {
00711 ast_moh_stop(transferee);
00712 ast_autoservice_stop(transferee);
00713 ast_indicate(transferee, AST_CONTROL_UNHOLD);
00714 return res;
00715 } else if(res > 0) {
00716
00717 xferto[0] = (char) res;
00718 }
00719 if ((ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout))) {
00720 cid_num = transferer->cid.cid_num;
00721 cid_name = transferer->cid.cid_name;
00722 if (ast_exists_extension(transferer, transferer_real_context,xferto, 1, cid_num)) {
00723 snprintf(dialstr, sizeof(dialstr), "%s@%s/n", xferto, transferer_real_context);
00724 newchan = ast_feature_request_and_dial(transferer, "Local", ast_best_codec(transferer->nativeformats), dialstr, 15000, &outstate, cid_num, cid_name);
00725 ast_indicate(transferer, -1);
00726 if (newchan) {
00727 res = ast_channel_make_compatible(transferer, newchan);
00728 if (res < 0) {
00729 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", transferer->name, newchan->name);
00730 ast_hangup(newchan);
00731 return -1;
00732 }
00733 memset(&bconfig,0,sizeof(struct ast_bridge_config));
00734 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
00735 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
00736 res = ast_bridge_call(transferer,newchan,&bconfig);
00737 if (newchan->_softhangup || newchan->_state != AST_STATE_UP || !transferer->_softhangup) {
00738 ast_hangup(newchan);
00739 if (f) {
00740 ast_frfree(f);
00741 f = NULL;
00742 }
00743 if (!ast_strlen_zero(xfersound) && !ast_streamfile(transferer, xfersound, transferer->language)) {
00744 if (ast_waitstream(transferer, "") < 0) {
00745 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
00746 }
00747 }
00748 ast_moh_stop(transferee);
00749 ast_autoservice_stop(transferee);
00750 ast_indicate(transferee, AST_CONTROL_UNHOLD);
00751 transferer->_softhangup = 0;
00752 return FEATURE_RETURN_SUCCESS;
00753 }
00754
00755 res = ast_channel_make_compatible(transferee, newchan);
00756 if (res < 0) {
00757 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", transferee->name, newchan->name);
00758 ast_hangup(newchan);
00759 return -1;
00760 }
00761
00762
00763 ast_moh_stop(transferee);
00764
00765 if ((ast_autoservice_stop(transferee) < 0)
00766 || (ast_waitfordigit(transferee, 100) < 0)
00767 || (ast_waitfordigit(newchan, 100) < 0)
00768 || ast_check_hangup(transferee)
00769 || ast_check_hangup(newchan)) {
00770 ast_hangup(newchan);
00771 res = -1;
00772 return -1;
00773 }
00774
00775 if ((xferchan = ast_channel_alloc(0))) {
00776 snprintf(xferchan->name, sizeof (xferchan->name), "Transfered/%s",transferee->name);
00777
00778 xferchan->readformat = transferee->readformat;
00779 xferchan->writeformat = transferee->writeformat;
00780 ast_channel_masquerade(xferchan, transferee);
00781 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
00782 xferchan->_state = AST_STATE_UP;
00783 ast_clear_flag(xferchan, AST_FLAGS_ALL);
00784 xferchan->_softhangup = 0;
00785
00786 if ((f = ast_read(xferchan))) {
00787 ast_frfree(f);
00788 f = NULL;
00789 }
00790
00791 } else {
00792 ast_hangup(newchan);
00793 return -1;
00794 }
00795
00796 newchan->_state = AST_STATE_UP;
00797 ast_clear_flag(newchan, AST_FLAGS_ALL);
00798 newchan->_softhangup = 0;
00799
00800 tobj = malloc(sizeof(struct ast_bridge_thread_obj));
00801 if (tobj) {
00802 memset(tobj,0,sizeof(struct ast_bridge_thread_obj));
00803 tobj->chan = xferchan;
00804 tobj->peer = newchan;
00805 tobj->bconfig = *config;
00806
00807 if (!ast_strlen_zero(xfersound) && !ast_streamfile(newchan, xfersound, newchan->language)) {
00808 if (ast_waitstream(newchan, "") < 0) {
00809 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
00810 }
00811 }
00812 ast_bridge_call_thread_launch(tobj);
00813 } else {
00814 ast_log(LOG_WARNING, "Out of memory!\n");
00815 ast_hangup(xferchan);
00816 ast_hangup(newchan);
00817 }
00818 return -1;
00819
00820 } else {
00821 ast_moh_stop(transferee);
00822 ast_autoservice_stop(transferee);
00823 ast_indicate(transferee, AST_CONTROL_UNHOLD);
00824
00825 if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY && !ast_strlen_zero(xferfailsound)) {
00826 res = ast_streamfile(transferer, xferfailsound, transferer->language);
00827 if (!res && (ast_waitstream(transferer, "") < 0)) {
00828 return -1;
00829 }
00830 }
00831 return FEATURE_RETURN_SUCCESS;
00832 }
00833 } else {
00834 ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context);
00835 ast_moh_stop(transferee);
00836 ast_autoservice_stop(transferee);
00837 ast_indicate(transferee, AST_CONTROL_UNHOLD);
00838 res = ast_streamfile(transferer, "beeperr", transferer->language);
00839 if (!res && (ast_waitstream(transferer, "") < 0)) {
00840 return -1;
00841 }
00842 }
00843 } else {
00844 ast_log(LOG_WARNING, "Did not read data.\n");
00845 res = ast_streamfile(transferer, "beeperr", transferer->language);
00846 if (ast_waitstream(transferer, "") < 0) {
00847 return -1;
00848 }
00849 }
00850 ast_moh_stop(transferee);
00851 ast_autoservice_stop(transferee);
00852 ast_indicate(transferee, AST_CONTROL_UNHOLD);
00853
00854 return FEATURE_RETURN_SUCCESS;
00855 }
00856
00857
00858
00859 #define FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0]))
00860 struct ast_call_feature builtin_features[] =
00861 {
00862 { AST_FEATURE_REDIRECT, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer, AST_FEATURE_FLAG_NEEDSDTMF },
00863 { AST_FEATURE_REDIRECT, "Attended Transfer", "atxfer", "", "", builtin_atxfer, AST_FEATURE_FLAG_NEEDSDTMF },
00864 { AST_FEATURE_AUTOMON, "One Touch Monitor", "automon", "", "", builtin_automonitor, AST_FEATURE_FLAG_NEEDSDTMF },
00865 { AST_FEATURE_DISCONNECT, "Disconnect Call", "disconnect", "*", "*", builtin_disconnect, AST_FEATURE_FLAG_NEEDSDTMF },
00866 };
00867
00868
00869 static AST_LIST_HEAD(feature_list,ast_call_feature) feature_list;
00870
00871
00872 void ast_register_feature(struct ast_call_feature *feature)
00873 {
00874 if (!feature) {
00875 ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
00876 return;
00877 }
00878
00879 AST_LIST_LOCK(&feature_list);
00880 AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry);
00881 AST_LIST_UNLOCK(&feature_list);
00882
00883 if (option_verbose >= 2)
00884 ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
00885 }
00886
00887
00888 void ast_unregister_feature(struct ast_call_feature *feature)
00889 {
00890 if (!feature) return;
00891
00892 AST_LIST_LOCK(&feature_list);
00893 AST_LIST_REMOVE(&feature_list,feature,feature_entry);
00894 AST_LIST_UNLOCK(&feature_list);
00895 free(feature);
00896 }
00897
00898 static void ast_unregister_features(void)
00899 {
00900 struct ast_call_feature *feature;
00901
00902 AST_LIST_LOCK(&feature_list);
00903 while ((feature = AST_LIST_REMOVE_HEAD(&feature_list,feature_entry)))
00904 free(feature);
00905 AST_LIST_UNLOCK(&feature_list);
00906 }
00907
00908
00909 static struct ast_call_feature *find_feature(char *name)
00910 {
00911 struct ast_call_feature *tmp;
00912
00913 AST_LIST_LOCK(&feature_list);
00914 AST_LIST_TRAVERSE(&feature_list, tmp, feature_entry) {
00915 if (!strcasecmp(tmp->sname, name))
00916 break;
00917 }
00918 AST_LIST_UNLOCK(&feature_list);
00919
00920 return tmp;
00921 }
00922
00923
00924 static int feature_exec_app(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
00925 {
00926 struct ast_app *app;
00927 struct ast_call_feature *feature;
00928 int res;
00929
00930 AST_LIST_LOCK(&feature_list);
00931 AST_LIST_TRAVERSE(&feature_list,feature,feature_entry) {
00932 if (!strcasecmp(feature->exten,code)) break;
00933 }
00934 AST_LIST_UNLOCK(&feature_list);
00935
00936 if (!feature) {
00937 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
00938 return -1;
00939 }
00940
00941 app = pbx_findapp(feature->app);
00942 if (app) {
00943 struct ast_channel *work = chan;
00944 if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLEE))
00945 work = peer;
00946 res = pbx_exec(work, app, feature->app_args, 1);
00947 if (res < 0)
00948 return res;
00949 } else {
00950 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
00951 return -2;
00952 }
00953
00954 return FEATURE_RETURN_SUCCESS;
00955 }
00956
00957 static void unmap_features(void)
00958 {
00959 int x;
00960 for (x = 0; x < FEATURES_COUNT; x++)
00961 strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
00962 }
00963
00964 static int remap_feature(const char *name, const char *value)
00965 {
00966 int x;
00967 int res = -1;
00968 for (x = 0; x < FEATURES_COUNT; x++) {
00969 if (!strcasecmp(name, builtin_features[x].sname)) {
00970 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
00971 if (option_verbose > 1)
00972 ast_verbose(VERBOSE_PREFIX_2 "Remapping feature %s (%s) to sequence '%s'\n", builtin_features[x].fname, builtin_features[x].sname, builtin_features[x].exten);
00973 res = 0;
00974 } else if (!strcmp(value, builtin_features[x].exten))
00975 ast_log(LOG_WARNING, "Sequence '%s' already mapped to function %s (%s) while assigning to %s\n", value, builtin_features[x].fname, builtin_features[x].sname, name);
00976 }
00977 return res;
00978 }
00979
00980 static int ast_feature_interpret(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
00981 {
00982 int x;
00983 struct ast_flags features;
00984 int res = FEATURE_RETURN_PASSDIGITS;
00985 struct ast_call_feature *feature;
00986 char *dynamic_features=pbx_builtin_getvar_helper(chan,"DYNAMIC_FEATURES");
00987
00988 if (sense == FEATURE_SENSE_CHAN)
00989 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
00990 else
00991 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);
00992 ast_log(LOG_DEBUG, "Feature interpret: chan=%s, peer=%s, sense=%d, features=%d\n", chan->name, peer->name, sense, features.flags);
00993
00994 for (x=0; x < FEATURES_COUNT; x++) {
00995 if ((ast_test_flag(&features, builtin_features[x].feature_mask)) &&
00996 !ast_strlen_zero(builtin_features[x].exten)) {
00997
00998 if (!strcmp(builtin_features[x].exten, code)) {
00999 res = builtin_features[x].operation(chan, peer, config, code, sense);
01000 break;
01001 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
01002 if (res == FEATURE_RETURN_PASSDIGITS)
01003 res = FEATURE_RETURN_STOREDIGITS;
01004 }
01005 }
01006 }
01007
01008
01009 if (!ast_strlen_zero(dynamic_features)) {
01010 char *tmp = ast_strdupa(dynamic_features);
01011 char *tok;
01012
01013 if (!tmp)
01014 return res;
01015
01016 while ((tok = strsep(&tmp, "#")) != NULL) {
01017 feature = find_feature(tok);
01018
01019 if (feature) {
01020
01021 if (!strcmp(feature->exten, code)) {
01022 if (option_verbose > 2)
01023 ast_verbose(VERBOSE_PREFIX_3 " Feature Found: %s exten: %s\n",feature->sname, tok);
01024 res = feature->operation(chan, peer, config, code, sense);
01025 break;
01026 } else if (!strncmp(feature->exten, code, strlen(code))) {
01027 res = FEATURE_RETURN_STOREDIGITS;
01028 }
01029 }
01030 }
01031 }
01032
01033 return res;
01034 }
01035
01036 static void set_config_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
01037 {
01038 int x;
01039
01040 ast_clear_flag(config, AST_FLAGS_ALL);
01041 for (x = 0; x < FEATURES_COUNT; x++) {
01042 if (ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF)) {
01043 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
01044 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01045
01046 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
01047 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01048 }
01049 }
01050
01051 if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
01052 char *dynamic_features;
01053
01054 dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
01055
01056 if (dynamic_features) {
01057 char *tmp = ast_strdupa(dynamic_features);
01058 char *tok;
01059 struct ast_call_feature *feature;
01060
01061 if (!tmp) {
01062 return;
01063 }
01064
01065
01066 while (NULL != (tok = strsep(&tmp, "#"))) {
01067 if ((feature = find_feature(tok))) {
01068 if (ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
01069 if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLER))
01070 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01071 if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLEE))
01072 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01073 }
01074 }
01075 }
01076 }
01077 }
01078 }
01079
01080
01081 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)
01082 {
01083 int state = 0;
01084 int cause = 0;
01085 int to;
01086 struct ast_channel *chan;
01087 struct ast_channel *monitor_chans[2];
01088 struct ast_channel *active_channel;
01089 struct ast_frame *f = NULL;
01090 int res = 0, ready = 0;
01091
01092 if ((chan = ast_request(type, format, data, &cause))) {
01093 ast_set_callerid(chan, cid_num, cid_name, cid_num);
01094 ast_channel_inherit_variables(caller, chan);
01095 if (!ast_call(chan, data, timeout)) {
01096 struct timeval started;
01097 int x, len = 0;
01098 char *disconnect_code = NULL, *dialed_code = NULL;
01099
01100 ast_indicate(caller, AST_CONTROL_RINGING);
01101
01102 for (x=0; x < FEATURES_COUNT; x++) {
01103 if (strcasecmp(builtin_features[x].sname, "disconnect"))
01104 continue;
01105
01106 disconnect_code = builtin_features[x].exten;
01107 len = strlen(disconnect_code) + 1;
01108 dialed_code = alloca(len);
01109 memset(dialed_code, 0, len);
01110 break;
01111 }
01112 x = 0;
01113 started = ast_tvnow();
01114 to = timeout;
01115 while (!ast_check_hangup(caller) && timeout && (chan->_state != AST_STATE_UP)) {
01116 monitor_chans[0] = caller;
01117 monitor_chans[1] = chan;
01118 active_channel = ast_waitfor_n(monitor_chans, 2, &to);
01119
01120
01121 if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
01122 state = AST_CONTROL_UNHOLD;
01123 ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n");
01124 break;
01125 }
01126
01127 if (!active_channel) {
01128 continue;
01129 }
01130
01131 if (chan && (chan == active_channel)){
01132 f = ast_read(chan);
01133 if (f == NULL) {
01134 state = AST_CONTROL_HANGUP;
01135 res = 0;
01136 break;
01137 }
01138
01139 if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) {
01140 if (f->subclass == AST_CONTROL_RINGING) {
01141 state = f->subclass;
01142 if (option_verbose > 2)
01143 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", chan->name);
01144 ast_indicate(caller, AST_CONTROL_RINGING);
01145 } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) {
01146 state = f->subclass;
01147 ast_frfree(f);
01148 f = NULL;
01149 break;
01150 } else if (f->subclass == AST_CONTROL_ANSWER) {
01151
01152 state = f->subclass;
01153 ast_frfree(f);
01154 f = NULL;
01155 ready=1;
01156 break;
01157 } else {
01158 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass);
01159 }
01160
01161 }
01162
01163 } else if (caller && (active_channel == caller)) {
01164 f = ast_read(caller);
01165 if (f == NULL) {
01166 if (caller->_softhangup && !chan->_softhangup) {
01167
01168 ready = 1;
01169 break;
01170 }
01171 state = AST_CONTROL_HANGUP;
01172 res = 0;
01173 break;
01174 }
01175
01176 if (f->frametype == AST_FRAME_DTMF) {
01177 dialed_code[x++] = f->subclass;
01178 dialed_code[x] = '\0';
01179 if (strlen(dialed_code) == len) {
01180 x = 0;
01181 } else if (x && strncmp(dialed_code, disconnect_code, x)) {
01182 x = 0;
01183 dialed_code[x] = '\0';
01184 }
01185 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
01186
01187 state = AST_CONTROL_UNHOLD;
01188 ast_frfree(f);
01189 f = NULL;
01190 break;
01191 }
01192 }
01193 }
01194 if (f) {
01195 ast_frfree(f);
01196 }
01197 }
01198 } else
01199 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
01200 } else {
01201 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
01202 switch(cause) {
01203 case AST_CAUSE_BUSY:
01204 state = AST_CONTROL_BUSY;
01205 break;
01206 case AST_CAUSE_CONGESTION:
01207 state = AST_CONTROL_CONGESTION;
01208 break;
01209 }
01210 }
01211
01212 ast_indicate(caller, -1);
01213 if (chan && ready) {
01214 if (chan->_state == AST_STATE_UP)
01215 state = AST_CONTROL_ANSWER;
01216 res = 0;
01217 } else if(chan) {
01218 res = -1;
01219 ast_hangup(chan);
01220 chan = NULL;
01221 } else {
01222 res = -1;
01223 }
01224
01225 if (outstate)
01226 *outstate = state;
01227
01228 if (chan && res <= 0) {
01229 if (!chan->cdr) {
01230 chan->cdr = ast_cdr_alloc();
01231 }
01232 if (chan->cdr) {
01233 char tmp[256];
01234 ast_cdr_init(chan->cdr, chan);
01235 snprintf(tmp, 256, "%s/%s", type, (char *)data);
01236 ast_cdr_setapp(chan->cdr,"Dial",tmp);
01237 ast_cdr_update(chan);
01238 ast_cdr_start(chan->cdr);
01239 ast_cdr_end(chan->cdr);
01240
01241 if (ast_cdr_disposition(chan->cdr,chan->hangupcause))
01242 ast_cdr_failed(chan->cdr);
01243 } else {
01244 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
01245 }
01246 }
01247
01248 return chan;
01249 }
01250
01251 int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast_bridge_config *config)
01252 {
01253
01254
01255 struct ast_frame *f;
01256 struct ast_channel *who;
01257 char chan_featurecode[FEATURE_MAX_LEN + 1]="";
01258 char peer_featurecode[FEATURE_MAX_LEN + 1]="";
01259 int res;
01260 int diff;
01261 int hasfeatures=0;
01262 int hadfeatures=0;
01263 struct ast_option_header *aoh;
01264 struct timeval start = { 0 , 0 };
01265 struct ast_bridge_config backup_config;
01266 char *monitor_exec;
01267
01268 memset(&backup_config, 0, sizeof(backup_config));
01269
01270 config->start_time = ast_tvnow();
01271
01272 if (chan && peer) {
01273 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
01274 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
01275 } else if (chan)
01276 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
01277
01278 if (monitor_ok) {
01279 if (!monitor_app) {
01280 if (!(monitor_app = pbx_findapp("Monitor")))
01281 monitor_ok=0;
01282 }
01283 if (monitor_app) {
01284 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR")))
01285 pbx_exec(chan, monitor_app, monitor_exec, 1);
01286 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
01287 pbx_exec(peer, monitor_app, monitor_exec, 1);
01288 }
01289 }
01290
01291 set_config_flags(chan, peer, config);
01292 config->firstpass = 1;
01293
01294
01295 if (ast_answer(chan))
01296 return -1;
01297 peer->appl = "Bridged Call";
01298 peer->data = chan->name;
01299
01300
01301 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
01302 char tmp[256];
01303 if (!ast_strlen_zero(chan->cdr->userfield)) {
01304 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield);
01305 ast_cdr_appenduserfield(chan, tmp);
01306 } else
01307 ast_cdr_setuserfield(chan, peer->cdr->userfield);
01308
01309 free(peer->cdr);
01310 peer->cdr = NULL;
01311 }
01312 for (;;) {
01313 if (config->feature_timer)
01314 start = ast_tvnow();
01315
01316 res = ast_channel_bridge(chan, peer, config, &f, &who);
01317
01318 if (config->feature_timer) {
01319
01320 diff = ast_tvdiff_ms(ast_tvnow(), start);
01321 config->feature_timer -= diff;
01322 if (hasfeatures) {
01323
01324
01325
01326 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
01327 ast_log(LOG_DEBUG, "Timed out, realtime this time!\n");
01328 config->feature_timer = 0;
01329 who = chan;
01330 if (f)
01331 ast_frfree(f);
01332 f = NULL;
01333 res = 0;
01334 } else if (config->feature_timer <= 0) {
01335
01336
01337 ast_log(LOG_DEBUG, "Timed out for feature!\n");
01338 if (!ast_strlen_zero(peer_featurecode)) {
01339 ast_dtmf_stream(chan, peer, peer_featurecode, 0);
01340 memset(peer_featurecode, 0, sizeof(peer_featurecode));
01341 }
01342 if (!ast_strlen_zero(chan_featurecode)) {
01343 ast_dtmf_stream(peer, chan, chan_featurecode, 0);
01344 memset(chan_featurecode, 0, sizeof(chan_featurecode));
01345 }
01346 if (f)
01347 ast_frfree(f);
01348 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01349 if (!hasfeatures) {
01350
01351 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01352 memset(&backup_config, 0, sizeof(backup_config));
01353 }
01354 hadfeatures = hasfeatures;
01355
01356 continue;
01357 }
01358 } else {
01359 if (config->feature_timer <=0) {
01360
01361 config->feature_timer = 0;
01362 who = chan;
01363 if (f)
01364 ast_frfree(f);
01365 f = NULL;
01366 res = 0;
01367 }
01368 }
01369 }
01370 if (res < 0) {
01371 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
01372 return -1;
01373 }
01374
01375 if (!f || ((f->frametype == AST_FRAME_CONTROL) && ((f->subclass == AST_CONTROL_HANGUP) || (f->subclass == AST_CONTROL_BUSY) ||
01376 (f->subclass == AST_CONTROL_CONGESTION)))) {
01377 res = -1;
01378 break;
01379 }
01380 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_RINGING)) {
01381 if (who == chan)
01382 ast_indicate(peer, AST_CONTROL_RINGING);
01383 else
01384 ast_indicate(chan, AST_CONTROL_RINGING);
01385 }
01386 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == -1)) {
01387 if (who == chan)
01388 ast_indicate(peer, -1);
01389 else
01390 ast_indicate(chan, -1);
01391 }
01392 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_FLASH)) {
01393 if (who == chan)
01394 ast_indicate(peer, AST_CONTROL_FLASH);
01395 else
01396 ast_indicate(chan, AST_CONTROL_FLASH);
01397 }
01398 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_OPTION)) {
01399 aoh = f->data;
01400
01401 if (aoh && (aoh->flag == AST_OPTION_FLAG_REQUEST)) {
01402 if (who == chan)
01403 ast_channel_setoption(peer, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
01404 else
01405 ast_channel_setoption(chan, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
01406 }
01407 }
01408
01409 if (f && (f->frametype == AST_FRAME_DTMF)) {
01410 char *featurecode;
01411 int sense;
01412 struct ast_channel *other;
01413
01414 hadfeatures = hasfeatures;
01415
01416 if (who == chan) {
01417 other = peer;
01418 sense = FEATURE_SENSE_CHAN;
01419 featurecode = chan_featurecode;
01420 } else {
01421 other = chan;
01422 sense = FEATURE_SENSE_PEER;
01423 featurecode = peer_featurecode;
01424 }
01425 featurecode[strlen(featurecode)] = f->subclass;
01426 config->feature_timer = backup_config.feature_timer;
01427 res = ast_feature_interpret(chan, peer, config, featurecode, sense);
01428 switch(res) {
01429 case FEATURE_RETURN_PASSDIGITS:
01430 ast_dtmf_stream(other, who, featurecode, 0);
01431
01432 case FEATURE_RETURN_SUCCESS:
01433 memset(featurecode, 0, sizeof(chan_featurecode));
01434 break;
01435 }
01436 if (res >= FEATURE_RETURN_PASSDIGITS) {
01437 res = 0;
01438 } else {
01439 ast_frfree(f);
01440 break;
01441 }
01442 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01443 if (hadfeatures && !hasfeatures) {
01444
01445 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01446 memset(&backup_config, 0, sizeof(struct ast_bridge_config));
01447 } else if (hasfeatures) {
01448 if (!hadfeatures) {
01449
01450 memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
01451
01452 config->play_warning = 0;
01453 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
01454 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
01455 config->warning_freq = 0;
01456 config->warning_sound = NULL;
01457 config->end_sound = NULL;
01458 config->start_sound = NULL;
01459 config->firstpass = 0;
01460 }
01461 config->feature_timer = featuredigittimeout;
01462 ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer);
01463 }
01464 }
01465 if (f)
01466 ast_frfree(f);
01467 }
01468 return res;
01469 }
01470
01471 static void *do_parking_thread(void *ignore)
01472 {
01473 int ms, tms, max;
01474 struct parkeduser *pu, *pl, *pt = NULL;
01475 struct timeval tv;
01476 struct ast_frame *f;
01477 char exten[AST_MAX_EXTENSION];
01478 char *peername,*cp;
01479 char returnexten[AST_MAX_EXTENSION];
01480 struct ast_context *con;
01481 int x;
01482 fd_set rfds, efds;
01483 fd_set nrfds, nefds;
01484 FD_ZERO(&rfds);
01485 FD_ZERO(&efds);
01486
01487 for (;;) {
01488 ms = -1;
01489 max = -1;
01490 ast_mutex_lock(&parking_lock);
01491 pl = NULL;
01492 pu = parkinglot;
01493 FD_ZERO(&nrfds);
01494 FD_ZERO(&nefds);
01495 while(pu) {
01496 if (pu->notquiteyet) {
01497
01498 pl = pu;
01499 pu = pu->next;
01500 continue;
01501 }
01502 tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
01503 if (tms > pu->parkingtime) {
01504
01505 ast_moh_stop(pu->chan);
01506 ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
01507
01508 if (pu->peername[0]) {
01509 peername = ast_strdupa(pu->peername);
01510 cp = strrchr(peername, '-');
01511 if (cp)
01512 *cp = 0;
01513 con = ast_context_find(parking_con_dial);
01514 if (!con) {
01515 con = ast_context_create(NULL, parking_con_dial, registrar);
01516 if (!con) {
01517 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
01518 }
01519 }
01520 if (con) {
01521 snprintf(returnexten, sizeof(returnexten), "%s||t", peername);
01522 ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), FREE, registrar);
01523 }
01524 ast_copy_string(pu->chan->exten, peername, sizeof(pu->chan->exten));
01525 ast_copy_string(pu->chan->context, parking_con_dial, sizeof(pu->chan->context));
01526 pu->chan->priority = 1;
01527
01528 } else {
01529
01530
01531 ast_copy_string(pu->chan->exten, pu->exten, sizeof(pu->chan->exten));
01532 ast_copy_string(pu->chan->context, pu->context, sizeof(pu->chan->context));
01533 pu->chan->priority = pu->priority;
01534 }
01535
01536 manager_event(EVENT_FLAG_CALL, "ParkedCallTimeOut",
01537 "Exten: %d\r\n"
01538 "Channel: %s\r\n"
01539 "CallerID: %s\r\n"
01540 "CallerIDName: %s\r\n"
01541 ,pu->parkingnum, pu->chan->name
01542 ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
01543 ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
01544 );
01545
01546 if (option_verbose > 1)
01547 ast_verbose(VERBOSE_PREFIX_2 "Timeout for %s parked on %d. Returning to %s,%s,%d\n", pu->chan->name, pu->parkingnum, pu->chan->context, pu->chan->exten, pu->chan->priority);
01548
01549 if (ast_pbx_start(pu->chan)) {
01550 ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name);
01551 ast_hangup(pu->chan);
01552 }
01553
01554 if (pl)
01555 pl->next = pu->next;
01556 else
01557 parkinglot = pu->next;
01558 pt = pu;
01559 pu = pu->next;
01560 con = ast_context_find(parking_con);
01561 if (con) {
01562 snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
01563 if (ast_context_remove_extension2(con, exten, 1, NULL))
01564 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01565 } else
01566 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01567 free(pt);
01568 } else {
01569 for (x = 0; x < AST_MAX_FDS; x++) {
01570 if ((pu->chan->fds[x] > -1) && (FD_ISSET(pu->chan->fds[x], &rfds) || FD_ISSET(pu->chan->fds[x], &efds))) {
01571 if (FD_ISSET(pu->chan->fds[x], &efds))
01572 ast_set_flag(pu->chan, AST_FLAG_EXCEPTION);
01573 else
01574 ast_clear_flag(pu->chan, AST_FLAG_EXCEPTION);
01575 pu->chan->fdno = x;
01576
01577 f = ast_read(pu->chan);
01578 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
01579 if (f)
01580 ast_frfree(f);
01581 manager_event(EVENT_FLAG_CALL, "ParkedCallGiveUp",
01582 "Exten: %d\r\n"
01583 "Channel: %s\r\n"
01584 "CallerID: %s\r\n"
01585 "CallerIDName: %s\r\n"
01586 ,pu->parkingnum, pu->chan->name
01587 ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
01588 ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
01589 );
01590
01591
01592 if (option_verbose > 1)
01593 ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", pu->chan->name);
01594 ast_hangup(pu->chan);
01595
01596 if (pl)
01597 pl->next = pu->next;
01598 else
01599 parkinglot = pu->next;
01600 pt = pu;
01601 pu = pu->next;
01602 con = ast_context_find(parking_con);
01603 if (con) {
01604 snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
01605 if (ast_context_remove_extension2(con, exten, 1, NULL))
01606 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01607 } else
01608 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01609 free(pt);
01610 break;
01611 } else {
01612
01613 ast_frfree(f);
01614 if (pu->moh_trys < 3 && !pu->chan->generatordata) {
01615 ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source. Restarting.\n");
01616 ast_moh_start(pu->chan, NULL);
01617 pu->moh_trys++;
01618 }
01619 goto std;
01620 }
01621 }
01622 }
01623 if (x >= AST_MAX_FDS) {
01624 std: for (x=0; x<AST_MAX_FDS; x++) {
01625
01626 if (pu->chan->fds[x] > -1) {
01627 FD_SET(pu->chan->fds[x], &nrfds);
01628 FD_SET(pu->chan->fds[x], &nefds);
01629 if (pu->chan->fds[x] > max)
01630 max = pu->chan->fds[x];
01631 }
01632 }
01633
01634 if ((tms < ms) || (ms < 0))
01635 ms = tms;
01636 pl = pu;
01637 pu = pu->next;
01638 }
01639 }
01640 }
01641 ast_mutex_unlock(&parking_lock);
01642 rfds = nrfds;
01643 efds = nefds;
01644 tv = ast_samp2tv(ms, 1000);
01645
01646 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
01647 pthread_testcancel();
01648 }
01649 return NULL;
01650 }
01651
01652 static int park_call_exec(struct ast_channel *chan, void *data)
01653 {
01654
01655
01656 int res=0;
01657 struct localuser *u;
01658 LOCAL_USER_ADD(u);
01659
01660
01661 strcpy(chan->exten, "s");
01662 chan->priority = 1;
01663 if (chan->_state != AST_STATE_UP)
01664 res = ast_answer(chan);
01665 if (!res)
01666 res = ast_safe_sleep(chan, 1000);
01667 if (!res)
01668 res = ast_park_call(chan, chan, 0, NULL);
01669 LOCAL_USER_REMOVE(u);
01670 if (!res)
01671 res = AST_PBX_KEEPALIVE;
01672 return res;
01673 }
01674
01675 static int park_exec(struct ast_channel *chan, void *data)
01676 {
01677 int res=0;
01678 struct localuser *u;
01679 struct ast_channel *peer=NULL;
01680 struct parkeduser *pu, *pl=NULL;
01681 char exten[AST_MAX_EXTENSION];
01682 struct ast_context *con;
01683 int park;
01684 int dres;
01685 struct ast_bridge_config config;
01686
01687 if (!data) {
01688 ast_log(LOG_WARNING, "Park requires an argument (extension number)\n");
01689 return -1;
01690 }
01691 LOCAL_USER_ADD(u);
01692 park = atoi((char *)data);
01693 ast_mutex_lock(&parking_lock);
01694 pu = parkinglot;
01695 while(pu) {
01696 if (pu->parkingnum == park) {
01697 if (pl)
01698 pl->next = pu->next;
01699 else
01700 parkinglot = pu->next;
01701 break;
01702 }
01703 pl = pu;
01704 pu = pu->next;
01705 }
01706 ast_mutex_unlock(&parking_lock);
01707 if (pu) {
01708 peer = pu->chan;
01709 con = ast_context_find(parking_con);
01710 if (con) {
01711 snprintf(exten, sizeof(exten), "%d", pu->parkingnum);
01712 if (ast_context_remove_extension2(con, exten, 1, NULL))
01713 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01714 } else
01715 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01716
01717 manager_event(EVENT_FLAG_CALL, "UnParkedCall",
01718 "Exten: %d\r\n"
01719 "Channel: %s\r\n"
01720 "From: %s\r\n"
01721 "CallerID: %s\r\n"
01722 "CallerIDName: %s\r\n"
01723 ,pu->parkingnum, pu->chan->name, chan->name
01724 ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
01725 ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
01726 );
01727
01728 free(pu);
01729 }
01730
01731 if (chan->_state != AST_STATE_UP) {
01732 ast_answer(chan);
01733 }
01734
01735 if (peer) {
01736
01737 if (!ast_strlen_zero(courtesytone)) {
01738 if (!ast_streamfile(chan, courtesytone, chan->language)) {
01739 if (ast_waitstream(chan, "") < 0) {
01740 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
01741 ast_hangup(peer);
01742 return -1;
01743 }
01744 }
01745 }
01746
01747 ast_moh_stop(peer);
01748 ast_indicate(peer, AST_CONTROL_UNHOLD);
01749 res = ast_channel_make_compatible(chan, peer);
01750 if (res < 0) {
01751 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
01752 ast_hangup(peer);
01753 return -1;
01754 }
01755
01756
01757 if (option_verbose > 2)
01758 ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
01759
01760 memset(&config, 0, sizeof(struct ast_bridge_config));
01761 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
01762 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
01763 config.timelimit = 0;
01764 config.play_warning = 0;
01765 config.warning_freq = 0;
01766 config.warning_sound=NULL;
01767 res = ast_bridge_call(chan, peer, &config);
01768
01769
01770 if (res != AST_PBX_NO_HANGUP_PEER)
01771 ast_hangup(peer);
01772 return res;
01773 } else {
01774
01775 dres = ast_streamfile(chan, "pbx-invalidpark", chan->language);
01776 if (!dres)
01777 dres = ast_waitstream(chan, "");
01778 else {
01779 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
01780 dres = 0;
01781 }
01782 if (option_verbose > 2)
01783 ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
01784 res = -1;
01785 }
01786 LOCAL_USER_REMOVE(u);
01787 return res;
01788 }
01789
01790 static int handle_showfeatures(int fd, int argc, char *argv[])
01791 {
01792 int i;
01793 int fcount;
01794 struct ast_call_feature *feature;
01795 char format[] = "%-25s %-7s %-7s\n";
01796
01797 ast_cli(fd, format, "Builtin Feature", "Default", "Current");
01798 ast_cli(fd, format, "---------------", "-------", "-------");
01799
01800 ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext());
01801
01802 fcount = sizeof(builtin_features) / sizeof(builtin_features[0]);
01803
01804 for (i = 0; i < fcount; i++)
01805 {
01806 ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
01807 }
01808 ast_cli(fd, "\n");
01809 ast_cli(fd, format, "Dynamic Feature", "Default", "Current");
01810 ast_cli(fd, format, "---------------", "-------", "-------");
01811 if (AST_LIST_EMPTY(&feature_list)) {
01812 ast_cli(fd, "(none)\n");
01813 }
01814 else {
01815 AST_LIST_LOCK(&feature_list);
01816 AST_LIST_TRAVERSE(&feature_list, feature, feature_entry) {
01817 ast_cli(fd, format, feature->sname, "no def", feature->exten);
01818 }
01819 AST_LIST_UNLOCK(&feature_list);
01820 }
01821 ast_cli(fd, "\nCall parking\n");
01822 ast_cli(fd, "------------\n");
01823 ast_cli(fd,"%-20s: %s\n", "Parking extension", parking_ext);
01824 ast_cli(fd,"%-20s: %s\n", "Parking context", parking_con);
01825 ast_cli(fd,"%-20s: %d-%d\n", "Parked call extensions", parking_start, parking_stop);
01826 ast_cli(fd,"\n");
01827
01828 return RESULT_SUCCESS;
01829 }
01830
01831 static char showfeatures_help[] =
01832 "Usage: show features\n"
01833 " Lists currently configured features.\n";
01834
01835 static struct ast_cli_entry showfeatures =
01836 { { "show", "features", NULL }, handle_showfeatures, "Lists configured features", showfeatures_help };
01837
01838 static int handle_parkedcalls(int fd, int argc, char *argv[])
01839 {
01840 struct parkeduser *cur;
01841 int numparked = 0;
01842
01843 ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
01844 , "Context", "Extension", "Pri", "Timeout");
01845
01846 ast_mutex_lock(&parking_lock);
01847
01848 cur = parkinglot;
01849 while(cur) {
01850 ast_cli(fd, "%4d %25s (%-15s %-12s %-4d) %6lds\n"
01851 ,cur->parkingnum, cur->chan->name, cur->context, cur->exten
01852 ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
01853
01854 cur = cur->next;
01855 numparked++;
01856 }
01857 ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : "");
01858
01859 ast_mutex_unlock(&parking_lock);
01860
01861 return RESULT_SUCCESS;
01862 }
01863
01864 static char showparked_help[] =
01865 "Usage: show parkedcalls\n"
01866 " Lists currently parked calls.\n";
01867
01868 static struct ast_cli_entry showparked =
01869 { { "show", "parkedcalls", NULL }, handle_parkedcalls, "Lists parked calls", showparked_help };
01870
01871
01872 static int manager_parking_status( struct mansession *s, struct message *m )
01873 {
01874 struct parkeduser *cur;
01875 char *id = astman_get_header(m,"ActionID");
01876 char idText[256] = "";
01877
01878 if (!ast_strlen_zero(id))
01879 snprintf(idText,256,"ActionID: %s\r\n",id);
01880
01881 astman_send_ack(s, m, "Parked calls will follow");
01882
01883 ast_mutex_lock(&parking_lock);
01884
01885 cur=parkinglot;
01886 while(cur) {
01887 ast_cli(s->fd, "Event: ParkedCall\r\n"
01888 "Exten: %d\r\n"
01889 "Channel: %s\r\n"
01890 "Timeout: %ld\r\n"
01891 "CallerID: %s\r\n"
01892 "CallerIDName: %s\r\n"
01893 "%s"
01894 "\r\n"
01895 ,cur->parkingnum, cur->chan->name
01896 ,(long)cur->start.tv_sec + (long)(cur->parkingtime/1000) - (long)time(NULL)
01897 ,(cur->chan->cid.cid_num ? cur->chan->cid.cid_num : "")
01898 ,(cur->chan->cid.cid_name ? cur->chan->cid.cid_name : "")
01899 ,idText);
01900
01901 cur = cur->next;
01902 }
01903
01904 ast_cli(s->fd,
01905 "Event: ParkedCallsComplete\r\n"
01906 "%s"
01907 "\r\n",idText);
01908
01909 ast_mutex_unlock(&parking_lock);
01910
01911 return RESULT_SUCCESS;
01912 }
01913
01914
01915 int ast_pickup_call(struct ast_channel *chan)
01916 {
01917 struct ast_channel *cur = NULL;
01918 int res = -1;
01919
01920 while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
01921 if (!cur->pbx &&
01922 (cur != chan) &&
01923 (chan->pickupgroup & cur->callgroup) &&
01924 ((cur->_state == AST_STATE_RINGING) ||
01925 (cur->_state == AST_STATE_RING))) {
01926 break;
01927 }
01928 ast_mutex_unlock(&cur->lock);
01929 }
01930 if (cur) {
01931 if (option_debug)
01932 ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
01933 res = ast_answer(chan);
01934 if (res)
01935 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
01936 res = ast_queue_control(chan, AST_CONTROL_ANSWER);
01937 if (res)
01938 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
01939 res = ast_channel_masquerade(cur, chan);
01940 if (res)
01941 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);
01942 ast_mutex_unlock(&cur->lock);
01943 } else {
01944 if (option_debug)
01945 ast_log(LOG_DEBUG, "No call pickup possible...\n");
01946 }
01947 return res;
01948 }
01949
01950 static int load_config(void)
01951 {
01952 int start = 0, end = 0;
01953 struct ast_context *con = NULL;
01954 struct ast_config *cfg = NULL;
01955 struct ast_variable *var = NULL;
01956 char old_parking_ext[AST_MAX_EXTENSION];
01957 char old_parking_con[AST_MAX_EXTENSION] = "";
01958
01959 if (!ast_strlen_zero(parking_con)) {
01960 strcpy(old_parking_ext, parking_ext);
01961 strcpy(old_parking_con, parking_con);
01962 }
01963
01964
01965 strcpy(parking_con, "parkedcalls");
01966 strcpy(parking_con_dial, "park-dial");
01967 strcpy(parking_ext, "700");
01968 strcpy(pickup_ext, "*8");
01969 courtesytone[0] = '\0';
01970 strcpy(xfersound, "beep");
01971 strcpy(xferfailsound, "pbx-invalid");
01972 parking_start = 701;
01973 parking_stop = 750;
01974 parkfindnext = 0;
01975
01976 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
01977 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
01978
01979 cfg = ast_config_load("features.conf");
01980 if (!cfg) {
01981 cfg = ast_config_load("parking.conf");
01982 if (cfg)
01983 ast_log(LOG_NOTICE, "parking.conf is deprecated in favor of 'features.conf'. Please rename it.\n");
01984 }
01985 if (cfg) {
01986 var = ast_variable_browse(cfg, "general");
01987 while(var) {
01988 if (!strcasecmp(var->name, "parkext")) {
01989 ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
01990 } else if (!strcasecmp(var->name, "context")) {
01991 ast_copy_string(parking_con, var->value, sizeof(parking_con));
01992 } else if (!strcasecmp(var->name, "parkingtime")) {
01993 if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) {
01994 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
01995 parkingtime = DEFAULT_PARK_TIME;
01996 } else
01997 parkingtime = parkingtime * 1000;
01998 } else if (!strcasecmp(var->name, "parkpos")) {
01999 if (sscanf(var->value, "%d-%d", &start, &end) != 2) {
02000 ast_log(LOG_WARNING, "Format for parking positions is a-b, where a and b are numbers at line %d of parking.conf\n", var->lineno);
02001 } else {
02002 parking_start = start;
02003 parking_stop = end;
02004 }
02005 } else if (!strcasecmp(var->name, "findslot")) {
02006 parkfindnext = (!strcasecmp(var->value, "next"));
02007 } else if (!strcasecmp(var->name, "adsipark")) {
02008 adsipark = ast_true(var->value);
02009 } else if (!strcasecmp(var->name, "transferdigittimeout")) {
02010 if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
02011 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
02012 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
02013 } else
02014 transferdigittimeout = transferdigittimeout * 1000;
02015 } else if (!strcasecmp(var->name, "featuredigittimeout")) {
02016 if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
02017 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
02018 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
02019 }
02020 } else if (!strcasecmp(var->name, "courtesytone")) {
02021 ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
02022 } else if (!strcasecmp(var->name, "xfersound")) {
02023 ast_copy_string(xfersound, var->value, sizeof(xfersound));
02024 } else if (!strcasecmp(var->name, "xferfailsound")) {
02025 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
02026 } else if (!strcasecmp(var->name, "pickupexten")) {
02027 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
02028 }
02029 var = var->next;
02030 }
02031
02032 unmap_features();
02033 var = ast_variable_browse(cfg, "featuremap");
02034 while(var) {
02035 if (remap_feature(var->name, var->value))
02036 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
02037 var = var->next;
02038 }
02039
02040
02041 ast_unregister_features();
02042 var = ast_variable_browse(cfg, "applicationmap");
02043 while(var) {
02044 char *tmp_val=strdup(var->value);
02045 char *exten, *party=NULL, *app=NULL, *app_args=NULL;
02046
02047 if (!tmp_val) {
02048 ast_log(LOG_ERROR, "res_features: strdup failed");
02049 continue;
02050 }
02051
02052
02053 exten=strsep(&tmp_val,",");
02054 if (exten) party=strsep(&tmp_val,",");
02055 if (party) app=strsep(&tmp_val,",");
02056
02057 if (app) app_args=strsep(&tmp_val,",");
02058
02059 if (!(app && strlen(app)) || !(exten && strlen(exten)) || !(party && strlen(party)) || !(var->name && strlen(var->name))) {
02060 ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",app,exten,party,var->name);
02061 free(tmp_val);
02062 var = var->next;
02063 continue;
02064 }
02065
02066 {
02067 struct ast_call_feature *feature=find_feature(var->name);
02068 int mallocd=0;
02069
02070 if (!feature) {
02071 feature=malloc(sizeof(struct ast_call_feature));
02072 mallocd=1;
02073 }
02074 if (!feature) {
02075 ast_log(LOG_NOTICE, "Malloc failed at feature mapping\n");
02076 free(tmp_val);
02077 var = var->next;
02078 continue;
02079 }
02080
02081 memset(feature,0,sizeof(struct ast_call_feature));
02082 ast_copy_string(feature->sname,var->name,FEATURE_SNAME_LEN);
02083 ast_copy_string(feature->app,app,FEATURE_APP_LEN);
02084 ast_copy_string(feature->exten, exten,FEATURE_EXTEN_LEN);
02085 free(tmp_val);
02086
02087 if (app_args)
02088 ast_copy_string(feature->app_args,app_args,FEATURE_APP_ARGS_LEN);
02089
02090 ast_copy_string(feature->exten, exten,sizeof(feature->exten));
02091 feature->operation=feature_exec_app;
02092 ast_set_flag(feature,AST_FEATURE_FLAG_NEEDSDTMF);
02093
02094 if (!strcasecmp(party,"caller"))
02095 ast_set_flag(feature,AST_FEATURE_FLAG_CALLER);
02096 else if (!strcasecmp(party, "callee"))
02097 ast_set_flag(feature,AST_FEATURE_FLAG_CALLEE);
02098 else {
02099 ast_log(LOG_NOTICE, "Invalid party specification for feature '%s', must be caller, or callee\n", var->name);
02100 var = var->next;
02101 continue;
02102 }
02103
02104 ast_register_feature(feature);
02105
02106 if (option_verbose >=1) ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s' with code '%s'\n", var->name, app, exten);
02107 }
02108 var = var->next;
02109 }
02110 }
02111 ast_config_destroy(cfg);
02112
02113
02114 if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) {
02115 ast_context_remove_extension2(con, old_parking_ext, 1, registrar);
02116 ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
02117 }
02118
02119 if (!(con = ast_context_find(parking_con))) {
02120 if (!(con = ast_context_create(NULL, parking_con, registrar))) {
02121 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
02122 return -1;
02123 }
02124 }
02125 return ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, strdup(""), FREE, registrar);
02126 }
02127
02128 int reload(void) {
02129 return load_config();
02130 }
02131
02132 int load_module(void)
02133 {
02134 int res;
02135
02136 AST_LIST_HEAD_INIT(&feature_list);
02137 memset(parking_ext, 0, sizeof(parking_ext));
02138 memset(parking_con, 0, sizeof(parking_con));
02139
02140 if ((res = load_config()))
02141 return res;
02142 ast_cli_register(&showparked);
02143 ast_cli_register(&showfeatures);
02144 ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
02145 res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
02146 if (!res)
02147 res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
02148 if (!res) {
02149 ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" );
02150 }
02151 return res;
02152 }
02153
02154
02155 int unload_module(void)
02156 {
02157 STANDARD_HANGUP_LOCALUSERS;
02158
02159 ast_manager_unregister("ParkedCalls");
02160 ast_cli_unregister(&showfeatures);
02161 ast_cli_unregister(&showparked);
02162 ast_unregister_application(parkcall);
02163 return ast_unregister_application(parkedcall);
02164 }
02165
02166 char *description(void)
02167 {
02168 return "Call Features Resource";
02169 }
02170
02171 int usecount(void)
02172 {
02173
02174
02175 #if 0
02176 int res;
02177 STANDARD_USECOUNT(res);
02178 return res;
02179 #else
02180 return 1;
02181 #endif
02182 }
02183
02184 char *key()
02185 {
02186 return ASTERISK_GPL_KEY;
02187 }