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: 38686 $")
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():"
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 ? 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, transferer->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 transfer sound!\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 transfer sound!\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 ast_moh_stop(transferee);
00846 ast_autoservice_stop(transferee);
00847 ast_indicate(transferee, AST_CONTROL_UNHOLD);
00848 res = ast_streamfile(transferer, "beeperr", transferer->language);
00849 if (ast_waitstream(transferer, "") < 0) {
00850 return -1;
00851 }
00852 }
00853 ast_moh_stop(transferee);
00854 ast_autoservice_stop(transferee);
00855 ast_indicate(transferee, AST_CONTROL_UNHOLD);
00856
00857 return FEATURE_RETURN_SUCCESS;
00858 }
00859
00860
00861
00862 #define FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0]))
00863 struct ast_call_feature builtin_features[] =
00864 {
00865 { AST_FEATURE_REDIRECT, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer, AST_FEATURE_FLAG_NEEDSDTMF },
00866 { AST_FEATURE_REDIRECT, "Attended Transfer", "atxfer", "", "", builtin_atxfer, AST_FEATURE_FLAG_NEEDSDTMF },
00867 { AST_FEATURE_AUTOMON, "One Touch Monitor", "automon", "", "", builtin_automonitor, AST_FEATURE_FLAG_NEEDSDTMF },
00868 { AST_FEATURE_DISCONNECT, "Disconnect Call", "disconnect", "*", "*", builtin_disconnect, AST_FEATURE_FLAG_NEEDSDTMF },
00869 };
00870
00871
00872 static AST_LIST_HEAD_STATIC(feature_list,ast_call_feature);
00873
00874
00875 void ast_register_feature(struct ast_call_feature *feature)
00876 {
00877 if (!feature) {
00878 ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
00879 return;
00880 }
00881
00882 AST_LIST_LOCK(&feature_list);
00883 AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry);
00884 AST_LIST_UNLOCK(&feature_list);
00885
00886 if (option_verbose >= 2)
00887 ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
00888 }
00889
00890
00891 void ast_unregister_feature(struct ast_call_feature *feature)
00892 {
00893 if (!feature) return;
00894
00895 AST_LIST_LOCK(&feature_list);
00896 AST_LIST_REMOVE(&feature_list,feature,feature_entry);
00897 AST_LIST_UNLOCK(&feature_list);
00898 free(feature);
00899 }
00900
00901 static void ast_unregister_features(void)
00902 {
00903 struct ast_call_feature *feature;
00904
00905 AST_LIST_LOCK(&feature_list);
00906 while ((feature = AST_LIST_REMOVE_HEAD(&feature_list,feature_entry)))
00907 free(feature);
00908 AST_LIST_UNLOCK(&feature_list);
00909 }
00910
00911
00912 static struct ast_call_feature *find_feature(char *name)
00913 {
00914 struct ast_call_feature *tmp;
00915
00916 AST_LIST_LOCK(&feature_list);
00917 AST_LIST_TRAVERSE(&feature_list, tmp, feature_entry) {
00918 if (!strcasecmp(tmp->sname, name))
00919 break;
00920 }
00921 AST_LIST_UNLOCK(&feature_list);
00922
00923 return tmp;
00924 }
00925
00926
00927 static int feature_exec_app(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
00928 {
00929 struct ast_app *app;
00930 struct ast_call_feature *feature;
00931 int res;
00932
00933 AST_LIST_LOCK(&feature_list);
00934 AST_LIST_TRAVERSE(&feature_list,feature,feature_entry) {
00935 if (!strcasecmp(feature->exten,code)) break;
00936 }
00937 AST_LIST_UNLOCK(&feature_list);
00938
00939 if (!feature) {
00940 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
00941 return -1;
00942 }
00943
00944 app = pbx_findapp(feature->app);
00945 if (app) {
00946 struct ast_channel *work = chan;
00947 if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLEE))
00948 work = peer;
00949 res = pbx_exec(work, app, feature->app_args, 1);
00950 if (res == AST_PBX_KEEPALIVE)
00951 return FEATURE_RETURN_PBX_KEEPALIVE;
00952 else if (res == AST_PBX_NO_HANGUP_PEER)
00953 return FEATURE_RETURN_NO_HANGUP_PEER;
00954 else if (res)
00955 return FEATURE_RETURN_SUCCESSBREAK;
00956 } else {
00957 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
00958 return -2;
00959 }
00960
00961 return FEATURE_RETURN_SUCCESS;
00962 }
00963
00964 static void unmap_features(void)
00965 {
00966 int x;
00967 for (x = 0; x < FEATURES_COUNT; x++)
00968 strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
00969 }
00970
00971 static int remap_feature(const char *name, const char *value)
00972 {
00973 int x;
00974 int res = -1;
00975 for (x = 0; x < FEATURES_COUNT; x++) {
00976 if (!strcasecmp(name, builtin_features[x].sname)) {
00977 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
00978 if (option_verbose > 1)
00979 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);
00980 res = 0;
00981 } else if (!strcmp(value, builtin_features[x].exten))
00982 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);
00983 }
00984 return res;
00985 }
00986
00987 static int ast_feature_interpret(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
00988 {
00989 int x;
00990 struct ast_flags features;
00991 int res = FEATURE_RETURN_PASSDIGITS;
00992 struct ast_call_feature *feature;
00993 char *dynamic_features=pbx_builtin_getvar_helper(chan,"DYNAMIC_FEATURES");
00994
00995 if (sense == FEATURE_SENSE_CHAN)
00996 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
00997 else
00998 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);
00999 ast_log(LOG_DEBUG, "Feature interpret: chan=%s, peer=%s, sense=%d, features=%d\n", chan->name, peer->name, sense, features.flags);
01000
01001 for (x=0; x < FEATURES_COUNT; x++) {
01002 if ((ast_test_flag(&features, builtin_features[x].feature_mask)) &&
01003 !ast_strlen_zero(builtin_features[x].exten)) {
01004
01005 if (!strcmp(builtin_features[x].exten, code)) {
01006 res = builtin_features[x].operation(chan, peer, config, code, sense);
01007 break;
01008 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
01009 if (res == FEATURE_RETURN_PASSDIGITS)
01010 res = FEATURE_RETURN_STOREDIGITS;
01011 }
01012 }
01013 }
01014
01015
01016 if (!ast_strlen_zero(dynamic_features)) {
01017 char *tmp = ast_strdupa(dynamic_features);
01018 char *tok;
01019
01020 if (!tmp)
01021 return res;
01022
01023 while ((tok = strsep(&tmp, "#")) != NULL) {
01024 feature = find_feature(tok);
01025
01026 if (feature) {
01027
01028 if (!strcmp(feature->exten, code)) {
01029 if (option_verbose > 2)
01030 ast_verbose(VERBOSE_PREFIX_3 " Feature Found: %s exten: %s\n",feature->sname, tok);
01031 if (sense == FEATURE_SENSE_CHAN)
01032 res = feature->operation(chan, peer, config, code, sense);
01033 else
01034 res = feature->operation(peer, chan, config, code, sense);
01035 break;
01036 } else if (!strncmp(feature->exten, code, strlen(code))) {
01037 res = FEATURE_RETURN_STOREDIGITS;
01038 }
01039 }
01040 }
01041 }
01042
01043 return res;
01044 }
01045
01046 static void set_config_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
01047 {
01048 int x;
01049
01050 ast_clear_flag(config, AST_FLAGS_ALL);
01051 for (x = 0; x < FEATURES_COUNT; x++) {
01052 if (ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF)) {
01053 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
01054 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01055
01056 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
01057 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01058 }
01059 }
01060
01061 if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
01062 char *dynamic_features;
01063
01064 dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
01065
01066 if (dynamic_features) {
01067 char *tmp = ast_strdupa(dynamic_features);
01068 char *tok;
01069 struct ast_call_feature *feature;
01070
01071 if (!tmp) {
01072 return;
01073 }
01074
01075
01076 while (NULL != (tok = strsep(&tmp, "#"))) {
01077 if ((feature = find_feature(tok))) {
01078 if (ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
01079 if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLER))
01080 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01081 if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLEE))
01082 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01083 }
01084 }
01085 }
01086 }
01087 }
01088 }
01089
01090
01091 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)
01092 {
01093 int state = 0;
01094 int cause = 0;
01095 int to;
01096 struct ast_channel *chan;
01097 struct ast_channel *monitor_chans[2];
01098 struct ast_channel *active_channel;
01099 struct ast_frame *f = NULL;
01100 int res = 0, ready = 0;
01101
01102 if ((chan = ast_request(type, format, data, &cause))) {
01103 ast_set_callerid(chan, cid_num, cid_name, cid_num);
01104 ast_channel_inherit_variables(caller, chan);
01105 if (!ast_call(chan, data, timeout)) {
01106 struct timeval started;
01107 int x, len = 0;
01108 char *disconnect_code = NULL, *dialed_code = NULL;
01109
01110 ast_indicate(caller, AST_CONTROL_RINGING);
01111
01112 for (x=0; x < FEATURES_COUNT; x++) {
01113 if (strcasecmp(builtin_features[x].sname, "disconnect"))
01114 continue;
01115
01116 disconnect_code = builtin_features[x].exten;
01117 len = strlen(disconnect_code) + 1;
01118 dialed_code = alloca(len);
01119 memset(dialed_code, 0, len);
01120 break;
01121 }
01122 x = 0;
01123 started = ast_tvnow();
01124 to = timeout;
01125 while (!ast_check_hangup(caller) && timeout && (chan->_state != AST_STATE_UP)) {
01126 monitor_chans[0] = caller;
01127 monitor_chans[1] = chan;
01128 active_channel = ast_waitfor_n(monitor_chans, 2, &to);
01129
01130
01131 if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
01132 state = AST_CONTROL_UNHOLD;
01133 ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n");
01134 break;
01135 }
01136
01137 if (!active_channel) {
01138 continue;
01139 }
01140
01141 if (chan && (chan == active_channel)){
01142 f = ast_read(chan);
01143 if (f == NULL) {
01144 state = AST_CONTROL_HANGUP;
01145 res = 0;
01146 break;
01147 }
01148
01149 if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) {
01150 if (f->subclass == AST_CONTROL_RINGING) {
01151 state = f->subclass;
01152 if (option_verbose > 2)
01153 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", chan->name);
01154 ast_indicate(caller, AST_CONTROL_RINGING);
01155 } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) {
01156 state = f->subclass;
01157 if (option_verbose > 2)
01158 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", chan->name);
01159 ast_indicate(caller, AST_CONTROL_BUSY);
01160 ast_frfree(f);
01161 f = NULL;
01162 break;
01163 } else if (f->subclass == AST_CONTROL_ANSWER) {
01164
01165 state = f->subclass;
01166 ast_frfree(f);
01167 f = NULL;
01168 ready=1;
01169 break;
01170 } else {
01171 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass);
01172 }
01173
01174 }
01175
01176 } else if (caller && (active_channel == caller)) {
01177 f = ast_read(caller);
01178 if (f == NULL) {
01179 if (caller->_softhangup && !chan->_softhangup) {
01180
01181 ready = 1;
01182 break;
01183 }
01184 state = AST_CONTROL_HANGUP;
01185 res = 0;
01186 break;
01187 }
01188
01189 if (f->frametype == AST_FRAME_DTMF) {
01190 dialed_code[x++] = f->subclass;
01191 dialed_code[x] = '\0';
01192 if (strlen(dialed_code) == len) {
01193 x = 0;
01194 } else if (x && strncmp(dialed_code, disconnect_code, x)) {
01195 x = 0;
01196 dialed_code[x] = '\0';
01197 }
01198 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
01199
01200 state = AST_CONTROL_UNHOLD;
01201 ast_frfree(f);
01202 f = NULL;
01203 break;
01204 }
01205 }
01206 }
01207 if (f) {
01208 ast_frfree(f);
01209 }
01210 }
01211 } else
01212 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
01213 } else {
01214 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
01215 switch(cause) {
01216 case AST_CAUSE_BUSY:
01217 state = AST_CONTROL_BUSY;
01218 break;
01219 case AST_CAUSE_CONGESTION:
01220 state = AST_CONTROL_CONGESTION;
01221 break;
01222 }
01223 }
01224
01225 ast_indicate(caller, -1);
01226 if (chan && ready) {
01227 if (chan->_state == AST_STATE_UP)
01228 state = AST_CONTROL_ANSWER;
01229 res = 0;
01230 } else if(chan) {
01231 res = -1;
01232 ast_hangup(chan);
01233 chan = NULL;
01234 } else {
01235 res = -1;
01236 }
01237
01238 if (outstate)
01239 *outstate = state;
01240
01241 if (chan && res <= 0) {
01242 if (!chan->cdr) {
01243 chan->cdr = ast_cdr_alloc();
01244 }
01245 if (chan->cdr) {
01246 char tmp[256];
01247 ast_cdr_init(chan->cdr, chan);
01248 snprintf(tmp, 256, "%s/%s", type, (char *)data);
01249 ast_cdr_setapp(chan->cdr,"Dial",tmp);
01250 ast_cdr_update(chan);
01251 ast_cdr_start(chan->cdr);
01252 ast_cdr_end(chan->cdr);
01253
01254 if (ast_cdr_disposition(chan->cdr,chan->hangupcause))
01255 ast_cdr_failed(chan->cdr);
01256 } else {
01257 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
01258 }
01259 }
01260
01261 return chan;
01262 }
01263
01264 int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast_bridge_config *config)
01265 {
01266
01267
01268 struct ast_frame *f;
01269 struct ast_channel *who;
01270 char chan_featurecode[FEATURE_MAX_LEN + 1]="";
01271 char peer_featurecode[FEATURE_MAX_LEN + 1]="";
01272 int res;
01273 int diff;
01274 int hasfeatures=0;
01275 int hadfeatures=0;
01276 struct ast_option_header *aoh;
01277 struct timeval start = { 0 , 0 };
01278 struct ast_bridge_config backup_config;
01279 char *monitor_exec;
01280
01281 memset(&backup_config, 0, sizeof(backup_config));
01282
01283 config->start_time = ast_tvnow();
01284
01285 if (chan && peer) {
01286 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
01287 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
01288 } else if (chan)
01289 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
01290
01291 if (monitor_ok) {
01292 if (!monitor_app) {
01293 if (!(monitor_app = pbx_findapp("Monitor")))
01294 monitor_ok=0;
01295 }
01296 if (monitor_app) {
01297 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR")))
01298 pbx_exec(chan, monitor_app, monitor_exec, 1);
01299 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
01300 pbx_exec(peer, monitor_app, monitor_exec, 1);
01301 }
01302 }
01303
01304 set_config_flags(chan, peer, config);
01305 config->firstpass = 1;
01306
01307
01308 if (ast_answer(chan))
01309 return -1;
01310 peer->appl = "Bridged Call";
01311 peer->data = chan->name;
01312
01313
01314 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
01315 char tmp[256];
01316 if (!ast_strlen_zero(chan->cdr->userfield)) {
01317 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield);
01318 ast_cdr_appenduserfield(chan, tmp);
01319 } else
01320 ast_cdr_setuserfield(chan, peer->cdr->userfield);
01321
01322 free(peer->cdr);
01323 peer->cdr = NULL;
01324 }
01325 for (;;) {
01326 if (config->feature_timer)
01327 start = ast_tvnow();
01328
01329 res = ast_channel_bridge(chan, peer, config, &f, &who);
01330
01331 if (config->feature_timer) {
01332
01333 diff = ast_tvdiff_ms(ast_tvnow(), start);
01334 config->feature_timer -= diff;
01335 if (hasfeatures) {
01336
01337
01338
01339 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
01340 ast_log(LOG_DEBUG, "Timed out, realtime this time!\n");
01341 config->feature_timer = 0;
01342 who = chan;
01343 if (f)
01344 ast_frfree(f);
01345 f = NULL;
01346 res = 0;
01347 } else if (config->feature_timer <= 0) {
01348
01349
01350 ast_log(LOG_DEBUG, "Timed out for feature!\n");
01351 if (!ast_strlen_zero(peer_featurecode)) {
01352 ast_dtmf_stream(chan, peer, peer_featurecode, 0);
01353 memset(peer_featurecode, 0, sizeof(peer_featurecode));
01354 }
01355 if (!ast_strlen_zero(chan_featurecode)) {
01356 ast_dtmf_stream(peer, chan, chan_featurecode, 0);
01357 memset(chan_featurecode, 0, sizeof(chan_featurecode));
01358 }
01359 if (f)
01360 ast_frfree(f);
01361 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01362 if (!hasfeatures) {
01363
01364 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01365 memset(&backup_config, 0, sizeof(backup_config));
01366 }
01367 hadfeatures = hasfeatures;
01368
01369 continue;
01370 }
01371 } else {
01372 if (config->feature_timer <=0) {
01373
01374 config->feature_timer = 0;
01375 who = chan;
01376 if (f)
01377 ast_frfree(f);
01378 f = NULL;
01379 res = 0;
01380 }
01381 }
01382 }
01383 if (res < 0) {
01384 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
01385 return -1;
01386 }
01387
01388 if (!f || ((f->frametype == AST_FRAME_CONTROL) && ((f->subclass == AST_CONTROL_HANGUP) || (f->subclass == AST_CONTROL_BUSY) ||
01389 (f->subclass == AST_CONTROL_CONGESTION)))) {
01390 res = -1;
01391 break;
01392 }
01393 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_RINGING)) {
01394 if (who == chan)
01395 ast_indicate(peer, AST_CONTROL_RINGING);
01396 else
01397 ast_indicate(chan, AST_CONTROL_RINGING);
01398 }
01399 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == -1)) {
01400 if (who == chan)
01401 ast_indicate(peer, -1);
01402 else
01403 ast_indicate(chan, -1);
01404 }
01405 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_FLASH)) {
01406 if (who == chan)
01407 ast_indicate(peer, AST_CONTROL_FLASH);
01408 else
01409 ast_indicate(chan, AST_CONTROL_FLASH);
01410 }
01411 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_OPTION)) {
01412 aoh = f->data;
01413
01414 if (aoh && (aoh->flag == AST_OPTION_FLAG_REQUEST)) {
01415 if (who == chan)
01416 ast_channel_setoption(peer, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
01417 else
01418 ast_channel_setoption(chan, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
01419 }
01420 }
01421
01422 if (f && (f->frametype == AST_FRAME_DTMF)) {
01423 char *featurecode;
01424 int sense;
01425 struct ast_channel *other;
01426
01427 hadfeatures = hasfeatures;
01428
01429 if (who == chan) {
01430 other = peer;
01431 sense = FEATURE_SENSE_CHAN;
01432 featurecode = chan_featurecode;
01433 } else {
01434 other = chan;
01435 sense = FEATURE_SENSE_PEER;
01436 featurecode = peer_featurecode;
01437 }
01438 featurecode[strlen(featurecode)] = f->subclass;
01439
01440 ast_frfree(f);
01441 f = NULL;
01442 config->feature_timer = backup_config.feature_timer;
01443 res = ast_feature_interpret(chan, peer, config, featurecode, sense);
01444 switch(res) {
01445 case FEATURE_RETURN_PASSDIGITS:
01446 ast_dtmf_stream(other, who, featurecode, 0);
01447
01448 case FEATURE_RETURN_SUCCESS:
01449 memset(featurecode, 0, sizeof(chan_featurecode));
01450 break;
01451 }
01452 if (res >= FEATURE_RETURN_PASSDIGITS) {
01453 res = 0;
01454 } else
01455 break;
01456 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01457 if (hadfeatures && !hasfeatures) {
01458
01459 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01460 memset(&backup_config, 0, sizeof(struct ast_bridge_config));
01461 } else if (hasfeatures) {
01462 if (!hadfeatures) {
01463
01464 memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
01465
01466 config->play_warning = 0;
01467 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
01468 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
01469 config->warning_freq = 0;
01470 config->warning_sound = NULL;
01471 config->end_sound = NULL;
01472 config->start_sound = NULL;
01473 config->firstpass = 0;
01474 }
01475 config->start_time = ast_tvnow();
01476 config->feature_timer = featuredigittimeout;
01477 ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer);
01478 }
01479 }
01480 if (f)
01481 ast_frfree(f);
01482 }
01483 return res;
01484 }
01485
01486 static void *do_parking_thread(void *ignore)
01487 {
01488 int ms, tms, max;
01489 struct parkeduser *pu, *pl, *pt = NULL;
01490 struct timeval tv;
01491 struct ast_frame *f;
01492 char exten[AST_MAX_EXTENSION];
01493 char *peername,*cp;
01494 char returnexten[AST_MAX_EXTENSION];
01495 struct ast_context *con;
01496 int x;
01497 fd_set rfds, efds;
01498 fd_set nrfds, nefds;
01499 FD_ZERO(&rfds);
01500 FD_ZERO(&efds);
01501
01502 for (;;) {
01503 ms = -1;
01504 max = -1;
01505 ast_mutex_lock(&parking_lock);
01506 pl = NULL;
01507 pu = parkinglot;
01508 FD_ZERO(&nrfds);
01509 FD_ZERO(&nefds);
01510 while(pu) {
01511 if (pu->notquiteyet) {
01512
01513 pl = pu;
01514 pu = pu->next;
01515 continue;
01516 }
01517 tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
01518 if (tms > pu->parkingtime) {
01519
01520 ast_moh_stop(pu->chan);
01521 ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
01522
01523 if (pu->peername[0]) {
01524 peername = ast_strdupa(pu->peername);
01525 cp = strrchr(peername, '-');
01526 if (cp)
01527 *cp = 0;
01528 con = ast_context_find(parking_con_dial);
01529 if (!con) {
01530 con = ast_context_create(NULL, parking_con_dial, registrar);
01531 if (!con) {
01532 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
01533 }
01534 }
01535 if (con) {
01536 snprintf(returnexten, sizeof(returnexten), "%s||t", peername);
01537 ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), FREE, registrar);
01538 }
01539 ast_copy_string(pu->chan->exten, peername, sizeof(pu->chan->exten));
01540 ast_copy_string(pu->chan->context, parking_con_dial, sizeof(pu->chan->context));
01541 pu->chan->priority = 1;
01542
01543 } else {
01544
01545
01546 ast_copy_string(pu->chan->exten, pu->exten, sizeof(pu->chan->exten));
01547 ast_copy_string(pu->chan->context, pu->context, sizeof(pu->chan->context));
01548 pu->chan->priority = pu->priority;
01549 }
01550
01551 manager_event(EVENT_FLAG_CALL, "ParkedCallTimeOut",
01552 "Exten: %d\r\n"
01553 "Channel: %s\r\n"
01554 "CallerID: %s\r\n"
01555 "CallerIDName: %s\r\n"
01556 ,pu->parkingnum, pu->chan->name
01557 ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
01558 ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
01559 );
01560
01561 if (option_verbose > 1)
01562 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);
01563
01564 if (ast_pbx_start(pu->chan)) {
01565 ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name);
01566 ast_hangup(pu->chan);
01567 }
01568
01569 if (pl)
01570 pl->next = pu->next;
01571 else
01572 parkinglot = pu->next;
01573 pt = pu;
01574 pu = pu->next;
01575 con = ast_context_find(parking_con);
01576 if (con) {
01577 snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
01578 if (ast_context_remove_extension2(con, exten, 1, NULL))
01579 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01580 } else
01581 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01582 free(pt);
01583 } else {
01584 for (x = 0; x < AST_MAX_FDS; x++) {
01585 if ((pu->chan->fds[x] > -1) && (FD_ISSET(pu->chan->fds[x], &rfds) || FD_ISSET(pu->chan->fds[x], &efds))) {
01586 if (FD_ISSET(pu->chan->fds[x], &efds))
01587 ast_set_flag(pu->chan, AST_FLAG_EXCEPTION);
01588 else
01589 ast_clear_flag(pu->chan, AST_FLAG_EXCEPTION);
01590 pu->chan->fdno = x;
01591
01592 f = ast_read(pu->chan);
01593 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
01594 if (f)
01595 ast_frfree(f);
01596 manager_event(EVENT_FLAG_CALL, "ParkedCallGiveUp",
01597 "Exten: %d\r\n"
01598 "Channel: %s\r\n"
01599 "CallerID: %s\r\n"
01600 "CallerIDName: %s\r\n"
01601 ,pu->parkingnum, pu->chan->name
01602 ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
01603 ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
01604 );
01605
01606
01607 if (option_verbose > 1)
01608 ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", pu->chan->name);
01609 ast_hangup(pu->chan);
01610
01611 if (pl)
01612 pl->next = pu->next;
01613 else
01614 parkinglot = pu->next;
01615 pt = pu;
01616 pu = pu->next;
01617 con = ast_context_find(parking_con);
01618 if (con) {
01619 snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
01620 if (ast_context_remove_extension2(con, exten, 1, NULL))
01621 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01622 } else
01623 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01624 free(pt);
01625 break;
01626 } else {
01627
01628 ast_frfree(f);
01629 if (pu->moh_trys < 3 && !pu->chan->generatordata) {
01630 ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source. Restarting.\n");
01631 ast_moh_start(pu->chan, NULL);
01632 pu->moh_trys++;
01633 }
01634 goto std;
01635 }
01636 }
01637 }
01638 if (x >= AST_MAX_FDS) {
01639 std: for (x=0; x<AST_MAX_FDS; x++) {
01640
01641 if (pu->chan->fds[x] > -1) {
01642 FD_SET(pu->chan->fds[x], &nrfds);
01643 FD_SET(pu->chan->fds[x], &nefds);
01644 if (pu->chan->fds[x] > max)
01645 max = pu->chan->fds[x];
01646 }
01647 }
01648
01649 if ((tms < ms) || (ms < 0))
01650 ms = tms;
01651 pl = pu;
01652 pu = pu->next;
01653 }
01654 }
01655 }
01656 ast_mutex_unlock(&parking_lock);
01657 rfds = nrfds;
01658 efds = nefds;
01659 tv = ast_samp2tv(ms, 1000);
01660
01661 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
01662 pthread_testcancel();
01663 }
01664 return NULL;
01665 }
01666
01667 static int park_call_exec(struct ast_channel *chan, void *data)
01668 {
01669
01670
01671 int res=0;
01672 struct localuser *u;
01673 LOCAL_USER_ADD(u);
01674
01675
01676 strcpy(chan->exten, "s");
01677 chan->priority = 1;
01678 if (chan->_state != AST_STATE_UP)
01679 res = ast_answer(chan);
01680 if (!res)
01681 res = ast_safe_sleep(chan, 1000);
01682 if (!res)
01683 res = ast_park_call(chan, chan, 0, NULL);
01684 LOCAL_USER_REMOVE(u);
01685 if (!res)
01686 res = AST_PBX_KEEPALIVE;
01687 return res;
01688 }
01689
01690 static int park_exec(struct ast_channel *chan, void *data)
01691 {
01692 int res=0;
01693 struct localuser *u;
01694 struct ast_channel *peer=NULL;
01695 struct parkeduser *pu, *pl=NULL;
01696 char exten[AST_MAX_EXTENSION];
01697 struct ast_context *con;
01698 int park;
01699 int dres;
01700 struct ast_bridge_config config;
01701
01702 if (!data) {
01703 ast_log(LOG_WARNING, "Park requires an argument (extension number)\n");
01704 return -1;
01705 }
01706 LOCAL_USER_ADD(u);
01707 park = atoi((char *)data);
01708 ast_mutex_lock(&parking_lock);
01709 pu = parkinglot;
01710 while(pu) {
01711 if (pu->parkingnum == park) {
01712 if (pl)
01713 pl->next = pu->next;
01714 else
01715 parkinglot = pu->next;
01716 break;
01717 }
01718 pl = pu;
01719 pu = pu->next;
01720 }
01721 ast_mutex_unlock(&parking_lock);
01722 if (pu) {
01723 peer = pu->chan;
01724 con = ast_context_find(parking_con);
01725 if (con) {
01726 snprintf(exten, sizeof(exten), "%d", pu->parkingnum);
01727 if (ast_context_remove_extension2(con, exten, 1, NULL))
01728 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01729 } else
01730 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01731
01732 manager_event(EVENT_FLAG_CALL, "UnParkedCall",
01733 "Exten: %d\r\n"
01734 "Channel: %s\r\n"
01735 "From: %s\r\n"
01736 "CallerID: %s\r\n"
01737 "CallerIDName: %s\r\n"
01738 ,pu->parkingnum, pu->chan->name, chan->name
01739 ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
01740 ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
01741 );
01742
01743 free(pu);
01744 }
01745
01746 if (chan->_state != AST_STATE_UP) {
01747 ast_answer(chan);
01748 }
01749
01750 if (peer) {
01751
01752 if (!ast_strlen_zero(courtesytone)) {
01753 if (!ast_streamfile(chan, courtesytone, chan->language)) {
01754 if (ast_waitstream(chan, "") < 0) {
01755 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
01756 ast_hangup(peer);
01757 return -1;
01758 }
01759 }
01760 }
01761
01762 ast_moh_stop(peer);
01763 ast_indicate(peer, AST_CONTROL_UNHOLD);
01764 res = ast_channel_make_compatible(chan, peer);
01765 if (res < 0) {
01766 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
01767 ast_hangup(peer);
01768 return -1;
01769 }
01770
01771
01772 if (option_verbose > 2)
01773 ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
01774
01775 memset(&config, 0, sizeof(struct ast_bridge_config));
01776 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
01777 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
01778 config.timelimit = 0;
01779 config.play_warning = 0;
01780 config.warning_freq = 0;
01781 config.warning_sound=NULL;
01782 res = ast_bridge_call(chan, peer, &config);
01783
01784
01785 if (res != AST_PBX_NO_HANGUP_PEER)
01786 ast_hangup(peer);
01787 return res;
01788 } else {
01789
01790 dres = ast_streamfile(chan, "pbx-invalidpark", chan->language);
01791 if (!dres)
01792 dres = ast_waitstream(chan, "");
01793 else {
01794 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
01795 dres = 0;
01796 }
01797 if (option_verbose > 2)
01798 ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
01799 res = -1;
01800 }
01801 LOCAL_USER_REMOVE(u);
01802 return res;
01803 }
01804
01805 static int handle_showfeatures(int fd, int argc, char *argv[])
01806 {
01807 int i;
01808 int fcount;
01809 struct ast_call_feature *feature;
01810 char format[] = "%-25s %-7s %-7s\n";
01811
01812 ast_cli(fd, format, "Builtin Feature", "Default", "Current");
01813 ast_cli(fd, format, "---------------", "-------", "-------");
01814
01815 ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext());
01816
01817 fcount = sizeof(builtin_features) / sizeof(builtin_features[0]);
01818
01819 for (i = 0; i < fcount; i++)
01820 {
01821 ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
01822 }
01823 ast_cli(fd, "\n");
01824 ast_cli(fd, format, "Dynamic Feature", "Default", "Current");
01825 ast_cli(fd, format, "---------------", "-------", "-------");
01826 if (AST_LIST_EMPTY(&feature_list)) {
01827 ast_cli(fd, "(none)\n");
01828 }
01829 else {
01830 AST_LIST_LOCK(&feature_list);
01831 AST_LIST_TRAVERSE(&feature_list, feature, feature_entry) {
01832 ast_cli(fd, format, feature->sname, "no def", feature->exten);
01833 }
01834 AST_LIST_UNLOCK(&feature_list);
01835 }
01836 ast_cli(fd, "\nCall parking\n");
01837 ast_cli(fd, "------------\n");
01838 ast_cli(fd,"%-20s: %s\n", "Parking extension", parking_ext);
01839 ast_cli(fd,"%-20s: %s\n", "Parking context", parking_con);
01840 ast_cli(fd,"%-20s: %d-%d\n", "Parked call extensions", parking_start, parking_stop);
01841 ast_cli(fd,"\n");
01842
01843 return RESULT_SUCCESS;
01844 }
01845
01846 static char showfeatures_help[] =
01847 "Usage: show features\n"
01848 " Lists currently configured features.\n";
01849
01850 static struct ast_cli_entry showfeatures =
01851 { { "show", "features", NULL }, handle_showfeatures, "Lists configured features", showfeatures_help };
01852
01853 static int handle_parkedcalls(int fd, int argc, char *argv[])
01854 {
01855 struct parkeduser *cur;
01856 int numparked = 0;
01857
01858 ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
01859 , "Context", "Extension", "Pri", "Timeout");
01860
01861 ast_mutex_lock(&parking_lock);
01862
01863 cur = parkinglot;
01864 while(cur) {
01865 ast_cli(fd, "%4d %25s (%-15s %-12s %-4d) %6lds\n"
01866 ,cur->parkingnum, cur->chan->name, cur->context, cur->exten
01867 ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
01868
01869 cur = cur->next;
01870 numparked++;
01871 }
01872 ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : "");
01873
01874 ast_mutex_unlock(&parking_lock);
01875
01876 return RESULT_SUCCESS;
01877 }
01878
01879 static char showparked_help[] =
01880 "Usage: show parkedcalls\n"
01881 " Lists currently parked calls.\n";
01882
01883 static struct ast_cli_entry showparked =
01884 { { "show", "parkedcalls", NULL }, handle_parkedcalls, "Lists parked calls", showparked_help };
01885
01886
01887 static int manager_parking_status( struct mansession *s, struct message *m )
01888 {
01889 struct parkeduser *cur;
01890 char *id = astman_get_header(m,"ActionID");
01891 char idText[256] = "";
01892
01893 if (!ast_strlen_zero(id))
01894 snprintf(idText,256,"ActionID: %s\r\n",id);
01895
01896 astman_send_ack(s, m, "Parked calls will follow");
01897
01898 ast_mutex_lock(&parking_lock);
01899
01900 cur=parkinglot;
01901 while(cur) {
01902 ast_cli(s->fd, "Event: ParkedCall\r\n"
01903 "Exten: %d\r\n"
01904 "Channel: %s\r\n"
01905 "Timeout: %ld\r\n"
01906 "CallerID: %s\r\n"
01907 "CallerIDName: %s\r\n"
01908 "%s"
01909 "\r\n"
01910 ,cur->parkingnum, cur->chan->name
01911 ,(long)cur->start.tv_sec + (long)(cur->parkingtime/1000) - (long)time(NULL)
01912 ,(cur->chan->cid.cid_num ? cur->chan->cid.cid_num : "")
01913 ,(cur->chan->cid.cid_name ? cur->chan->cid.cid_name : "")
01914 ,idText);
01915
01916 cur = cur->next;
01917 }
01918
01919 ast_cli(s->fd,
01920 "Event: ParkedCallsComplete\r\n"
01921 "%s"
01922 "\r\n",idText);
01923
01924 ast_mutex_unlock(&parking_lock);
01925
01926 return RESULT_SUCCESS;
01927 }
01928
01929
01930 int ast_pickup_call(struct ast_channel *chan)
01931 {
01932 struct ast_channel *cur = NULL;
01933 int res = -1;
01934
01935 while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
01936 if (!cur->pbx &&
01937 (cur != chan) &&
01938 (chan->pickupgroup & cur->callgroup) &&
01939 ((cur->_state == AST_STATE_RINGING) ||
01940 (cur->_state == AST_STATE_RING))) {
01941 break;
01942 }
01943 ast_mutex_unlock(&cur->lock);
01944 }
01945 if (cur) {
01946 if (option_debug)
01947 ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
01948 res = ast_answer(chan);
01949 if (res)
01950 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
01951 res = ast_queue_control(chan, AST_CONTROL_ANSWER);
01952 if (res)
01953 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
01954 res = ast_channel_masquerade(cur, chan);
01955 if (res)
01956 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);
01957 ast_mutex_unlock(&cur->lock);
01958 } else {
01959 if (option_debug)
01960 ast_log(LOG_DEBUG, "No call pickup possible...\n");
01961 }
01962 return res;
01963 }
01964
01965 static int load_config(void)
01966 {
01967 int start = 0, end = 0;
01968 struct ast_context *con = NULL;
01969 struct ast_config *cfg = NULL;
01970 struct ast_variable *var = NULL;
01971 char old_parking_ext[AST_MAX_EXTENSION];
01972 char old_parking_con[AST_MAX_EXTENSION] = "";
01973
01974 if (!ast_strlen_zero(parking_con)) {
01975 strcpy(old_parking_ext, parking_ext);
01976 strcpy(old_parking_con, parking_con);
01977 }
01978
01979
01980 strcpy(parking_con, "parkedcalls");
01981 strcpy(parking_con_dial, "park-dial");
01982 strcpy(parking_ext, "700");
01983 strcpy(pickup_ext, "*8");
01984 courtesytone[0] = '\0';
01985 strcpy(xfersound, "beep");
01986 strcpy(xferfailsound, "pbx-invalid");
01987 parking_start = 701;
01988 parking_stop = 750;
01989 parkfindnext = 0;
01990 adsipark = 0;
01991
01992 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
01993 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
01994
01995 cfg = ast_config_load("features.conf");
01996 if (!cfg) {
01997 cfg = ast_config_load("parking.conf");
01998 if (cfg)
01999 ast_log(LOG_NOTICE, "parking.conf is deprecated in favor of 'features.conf'. Please rename it.\n");
02000 }
02001 if (cfg) {
02002 var = ast_variable_browse(cfg, "general");
02003 while(var) {
02004 if (!strcasecmp(var->name, "parkext")) {
02005 ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
02006 } else if (!strcasecmp(var->name, "context")) {
02007 ast_copy_string(parking_con, var->value, sizeof(parking_con));
02008 } else if (!strcasecmp(var->name, "parkingtime")) {
02009 if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) {
02010 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
02011 parkingtime = DEFAULT_PARK_TIME;
02012 } else
02013 parkingtime = parkingtime * 1000;
02014 } else if (!strcasecmp(var->name, "parkpos")) {
02015 if (sscanf(var->value, "%d-%d", &start, &end) != 2) {
02016 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);
02017 } else {
02018 parking_start = start;
02019 parking_stop = end;
02020 }
02021 } else if (!strcasecmp(var->name, "findslot")) {
02022 parkfindnext = (!strcasecmp(var->value, "next"));
02023 } else if (!strcasecmp(var->name, "adsipark")) {
02024 adsipark = ast_true(var->value);
02025 } else if (!strcasecmp(var->name, "transferdigittimeout")) {
02026 if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
02027 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
02028 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
02029 } else
02030 transferdigittimeout = transferdigittimeout * 1000;
02031 } else if (!strcasecmp(var->name, "featuredigittimeout")) {
02032 if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
02033 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
02034 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
02035 }
02036 } else if (!strcasecmp(var->name, "courtesytone")) {
02037 ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
02038 } else if (!strcasecmp(var->name, "xfersound")) {
02039 ast_copy_string(xfersound, var->value, sizeof(xfersound));
02040 } else if (!strcasecmp(var->name, "xferfailsound")) {
02041 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
02042 } else if (!strcasecmp(var->name, "pickupexten")) {
02043 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
02044 }
02045 var = var->next;
02046 }
02047
02048 unmap_features();
02049 var = ast_variable_browse(cfg, "featuremap");
02050 while(var) {
02051 if (remap_feature(var->name, var->value))
02052 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
02053 var = var->next;
02054 }
02055
02056
02057 ast_unregister_features();
02058 var = ast_variable_browse(cfg, "applicationmap");
02059 while(var) {
02060 char *tmp_val=strdup(var->value);
02061 char *exten, *party=NULL, *app=NULL, *app_args=NULL;
02062
02063 if (!tmp_val) {
02064 ast_log(LOG_ERROR, "res_features: strdup failed");
02065 continue;
02066 }
02067
02068
02069 exten=strsep(&tmp_val,",");
02070 if (exten) party=strsep(&tmp_val,",");
02071 if (party) app=strsep(&tmp_val,",");
02072
02073 if (app) app_args=strsep(&tmp_val,",");
02074
02075 if (!(app && strlen(app)) || !(exten && strlen(exten)) || !(party && strlen(party)) || !(var->name && strlen(var->name))) {
02076 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);
02077 free(tmp_val);
02078 var = var->next;
02079 continue;
02080 }
02081
02082 {
02083 struct ast_call_feature *feature=find_feature(var->name);
02084 int mallocd=0;
02085
02086 if (!feature) {
02087 feature=malloc(sizeof(struct ast_call_feature));
02088 mallocd=1;
02089 }
02090 if (!feature) {
02091 ast_log(LOG_NOTICE, "Malloc failed at feature mapping\n");
02092 free(tmp_val);
02093 var = var->next;
02094 continue;
02095 }
02096
02097 memset(feature,0,sizeof(struct ast_call_feature));
02098 ast_copy_string(feature->sname,var->name,FEATURE_SNAME_LEN);
02099 ast_copy_string(feature->app,app,FEATURE_APP_LEN);
02100 ast_copy_string(feature->exten, exten,FEATURE_EXTEN_LEN);
02101 free(tmp_val);
02102
02103 if (app_args)
02104 ast_copy_string(feature->app_args,app_args,FEATURE_APP_ARGS_LEN);
02105
02106 ast_copy_string(feature->exten, exten,sizeof(feature->exten));
02107 feature->operation=feature_exec_app;
02108 ast_set_flag(feature,AST_FEATURE_FLAG_NEEDSDTMF);
02109
02110 if (!strcasecmp(party,"caller"))
02111 ast_set_flag(feature,AST_FEATURE_FLAG_CALLER);
02112 else if (!strcasecmp(party, "callee"))
02113 ast_set_flag(feature,AST_FEATURE_FLAG_CALLEE);
02114 else {
02115 ast_log(LOG_NOTICE, "Invalid party specification for feature '%s', must be caller, or callee\n", var->name);
02116 var = var->next;
02117 continue;
02118 }
02119
02120 ast_register_feature(feature);
02121
02122 if (option_verbose >=1) ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s' with code '%s'\n", var->name, app, exten);
02123 }
02124 var = var->next;
02125 }
02126 }
02127 ast_config_destroy(cfg);
02128
02129
02130 if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) {
02131 ast_context_remove_extension2(con, old_parking_ext, 1, registrar);
02132 ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
02133 }
02134
02135 if (!(con = ast_context_find(parking_con))) {
02136 if (!(con = ast_context_create(NULL, parking_con, registrar))) {
02137 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
02138 return -1;
02139 }
02140 }
02141 return ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, strdup(""), FREE, registrar);
02142 }
02143
02144 int reload(void) {
02145 return load_config();
02146 }
02147
02148 int load_module(void)
02149 {
02150 int res;
02151
02152 memset(parking_ext, 0, sizeof(parking_ext));
02153 memset(parking_con, 0, sizeof(parking_con));
02154
02155 if ((res = load_config()))
02156 return res;
02157 ast_cli_register(&showparked);
02158 ast_cli_register(&showfeatures);
02159 ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
02160 res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
02161 if (!res)
02162 res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
02163 if (!res) {
02164 ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" );
02165 }
02166 return res;
02167 }
02168
02169
02170 int unload_module(void)
02171 {
02172 STANDARD_HANGUP_LOCALUSERS;
02173
02174 ast_manager_unregister("ParkedCalls");
02175 ast_cli_unregister(&showfeatures);
02176 ast_cli_unregister(&showparked);
02177 ast_unregister_application(parkcall);
02178 return ast_unregister_application(parkedcall);
02179 }
02180
02181 char *description(void)
02182 {
02183 return "Call Features Resource";
02184 }
02185
02186 int usecount(void)
02187 {
02188
02189
02190 #if 0
02191 int res;
02192 STANDARD_USECOUNT(res);
02193 return res;
02194 #else
02195 return 1;
02196 #endif
02197 }
02198
02199 char *key()
02200 {
02201 return ASTERISK_GPL_KEY;
02202 }