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