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