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