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