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: 94793 $")
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 #include "asterisk/indications.h"
00066
00067 #define DEFAULT_PARK_TIME 45000
00068 #define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000
00069 #define DEFAULT_FEATURE_DIGIT_TIMEOUT 500
00070 #define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000
00071
00072 #define AST_MAX_WATCHERS 256
00073
00074 enum {
00075 AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0),
00076 AST_FEATURE_FLAG_ONPEER = (1 << 1),
00077 AST_FEATURE_FLAG_ONSELF = (1 << 2),
00078 AST_FEATURE_FLAG_BYCALLEE = (1 << 3),
00079 AST_FEATURE_FLAG_BYCALLER = (1 << 4),
00080 AST_FEATURE_FLAG_BYBOTH = (3 << 3),
00081 };
00082
00083 static char *parkedcall = "ParkedCall";
00084 static char *holdedcall = "HoldedCall";
00085
00086 static int parkaddhints = 0;
00087 static int parkingtime = DEFAULT_PARK_TIME;
00088 static char parking_con[AST_MAX_EXTENSION];
00089 static char parking_con_dial[AST_MAX_EXTENSION];
00090 static char parking_ext[AST_MAX_EXTENSION];
00091 static char pickup_ext[AST_MAX_EXTENSION];
00092 static char parkmohclass[MAX_MUSICCLASS];
00093 static int parking_start;
00094 static int parking_stop;
00095
00096 static char courtesytone[256];
00097 static int parkedplay = 0;
00098 static char xfersound[256];
00099 static char xferfailsound[256];
00100
00101 static int parking_offset;
00102 static int parkfindnext;
00103
00104 static int adsipark;
00105
00106 static int transferdigittimeout;
00107 static int featuredigittimeout;
00108
00109 static int atxfernoanswertimeout;
00110
00111 static char *registrar = "res_features";
00112
00113
00114 static char *synopsis = "Answer a parked call";
00115
00116 static char *descrip = "ParkedCall(exten):"
00117 "Used to connect to a parked call. This application is always\n"
00118 "registered internally and does not need to be explicitly added\n"
00119 "into the dialplan, although you should include the 'parkedcalls'\n"
00120 "context.\n";
00121
00122 static char *parkcall = "Park";
00123
00124 static char *synopsis2 = "Park yourself";
00125
00126 static char *descrip2 = "Park():"
00127 "Used to park yourself (typically in combination with a supervised\n"
00128 "transfer to know the parking space). This application is always\n"
00129 "registered internally and does not need to be explicitly added\n"
00130 "into the dialplan, although you should include the 'parkedcalls'\n"
00131 "context (or the context specified in features.conf).\n\n"
00132 "If you set the PARKINGEXTEN variable to an extension in your\n"
00133 "parking context, park() will park the call on that extension, unless\n"
00134 "it already exists. In that case, execution will continue at next\n"
00135 "priority.\n" ;
00136
00137 static char *autoanswerlogin = "AutoanswerLogin";
00138
00139 static char *synopsis3 = "Log in for autoanswer";
00140
00141 static char *descrip3 = "AutoanswerLogin([context]|exten):"
00142 "Used to login to the autoanswer application for an extension.\n";
00143
00144 static char *autoanswer = "Autoanswer";
00145
00146 static char *synopsis4 = "Autoanswer a call";
00147
00148 static char *descrip4 = "Autoanswer([context]|exten):"
00149 "Used to autoanswer a call for an extension.\n";
00150
00151 static struct ast_app *monitor_app = NULL;
00152 static int monitor_ok = 1;
00153
00154 struct parkeduser {
00155 struct ast_channel *chan;
00156 struct timeval start;
00157 int parkingnum;
00158 char parkingexten[AST_MAX_EXTENSION];
00159 char context[AST_MAX_CONTEXT];
00160 char exten[AST_MAX_EXTENSION];
00161 int priority;
00162 int parkingtime;
00163 int notquiteyet;
00164 char peername[1024];
00165 unsigned char moh_trys;
00166 struct parkeduser *next;
00167 };
00168
00169 struct holdeduser {
00170 struct ast_channel *chan;
00171 struct timeval start;
00172 int parkingnum;
00173 int cref;
00174 int tei;
00175
00176 char context[AST_MAX_EXTENSION];
00177 char exten[AST_MAX_EXTENSION];
00178 int priority;
00179 int parkingtime;
00180 char uniqueid[AST_MAX_UNIQUEID];
00181 char uniqueidpeer[AST_MAX_UNIQUEID];
00182 struct holdeduser *next;
00183 };
00184
00185
00186 struct aauser {
00187 struct ast_channel *chan;
00188 struct timeval start;
00189
00190 char exten[AST_MAX_EXTENSION];
00191 char context[AST_MAX_EXTENSION];
00192 int priority;
00193 int notquiteyet;
00194 struct aauser *next;
00195 };
00196
00197
00198 static struct aauser *aalot;
00199 AST_MUTEX_DEFINE_STATIC(autoanswer_lock);
00200 static pthread_t autoanswer_thread;
00201
00202 static struct parkeduser *parkinglot;
00203
00204 static struct holdeduser *holdlist;
00205
00206 AST_MUTEX_DEFINE_STATIC(parking_lock);
00207
00208 AST_MUTEX_DEFINE_STATIC(holding_lock);
00209
00210 static pthread_t parking_thread;
00211
00212 static pthread_t holding_thread;
00213
00214 char *ast_parking_ext(void)
00215 {
00216 return parking_ext;
00217 }
00218
00219 char *ast_pickup_ext(void)
00220 {
00221 return pickup_ext;
00222 }
00223
00224 struct ast_bridge_thread_obj
00225 {
00226 struct ast_bridge_config bconfig;
00227 struct ast_channel *chan;
00228 struct ast_channel *peer;
00229 };
00230
00231
00232
00233
00234 static void set_c_e_p(struct ast_channel *chan, const char *context, const char *ext, int pri)
00235 {
00236 ast_copy_string(chan->context, context, sizeof(chan->context));
00237 ast_copy_string(chan->exten, ext, sizeof(chan->exten));
00238 chan->priority = pri;
00239 }
00240
00241 static void check_goto_on_transfer(struct ast_channel *chan)
00242 {
00243 struct ast_channel *xferchan;
00244 const char *val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR");
00245 char *x, *goto_on_transfer;
00246 struct ast_frame *f;
00247
00248 if (ast_strlen_zero(val))
00249 return;
00250
00251 goto_on_transfer = ast_strdupa(val);
00252
00253 if (!(xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, chan->name)))
00254 return;
00255
00256 for (x = goto_on_transfer; x && *x; x++) {
00257 if (*x == '^')
00258 *x = '|';
00259 }
00260
00261 xferchan->readformat = chan->readformat;
00262 xferchan->writeformat = chan->writeformat;
00263 ast_channel_masquerade(xferchan, chan);
00264 ast_parseable_goto(xferchan, goto_on_transfer);
00265 xferchan->_state = AST_STATE_UP;
00266 ast_clear_flag(xferchan, AST_FLAGS_ALL);
00267 xferchan->_softhangup = 0;
00268 if ((f = ast_read(xferchan))) {
00269 ast_frfree(f);
00270 f = NULL;
00271 ast_pbx_start(xferchan);
00272 } else {
00273 ast_hangup(xferchan);
00274 }
00275 }
00276
00277 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);
00278
00279
00280 static void *ast_bridge_call_thread(void *data)
00281 {
00282 struct ast_bridge_thread_obj *tobj = data;
00283
00284 tobj->chan->appl = "Transferred Call";
00285 tobj->chan->data = tobj->peer->name;
00286 tobj->peer->appl = "Transferred Call";
00287 tobj->peer->data = tobj->chan->name;
00288 if (tobj->chan->cdr) {
00289 ast_cdr_reset(tobj->chan->cdr, NULL);
00290 ast_cdr_setdestchan(tobj->chan->cdr, tobj->peer->name);
00291 }
00292 if (tobj->peer->cdr) {
00293 ast_cdr_reset(tobj->peer->cdr, NULL);
00294 ast_cdr_setdestchan(tobj->peer->cdr, tobj->chan->name);
00295 }
00296
00297 ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
00298 ast_hangup(tobj->chan);
00299 ast_hangup(tobj->peer);
00300 bzero(tobj, sizeof(*tobj));
00301 free(tobj);
00302 return NULL;
00303 }
00304
00305 static void ast_bridge_call_thread_launch(void *data)
00306 {
00307 pthread_t thread;
00308 pthread_attr_t attr;
00309 struct sched_param sched;
00310
00311 pthread_attr_init(&attr);
00312 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00313 ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data);
00314 pthread_attr_destroy(&attr);
00315 memset(&sched, 0, sizeof(sched));
00316 pthread_setschedparam(thread, SCHED_RR, &sched);
00317 }
00318
00319 static int adsi_announce_park(struct ast_channel *chan, char *parkingexten)
00320 {
00321 int res;
00322 int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
00323 char tmp[256];
00324 char *message[5] = {NULL, NULL, NULL, NULL, NULL};
00325
00326 snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten);
00327 message[0] = tmp;
00328 res = ast_adsi_load_session(chan, NULL, 0, 1);
00329 if (res == -1)
00330 return res;
00331 return ast_adsi_print(chan, message, justify, 1);
00332 }
00333
00334
00335 static void notify_metermaids(char *exten, char *context)
00336 {
00337 if (option_debug > 3)
00338 ast_log(LOG_DEBUG, "Notification of state change to metermaids %s@%s\n", exten, context);
00339
00340
00341 ast_device_state_changed("park:%s@%s", exten, context);
00342 return;
00343 }
00344
00345
00346 static int metermaidstate(const char *data)
00347 {
00348 int res = AST_DEVICE_INVALID;
00349 char *context = ast_strdupa(data);
00350 char *exten;
00351
00352 exten = strsep(&context, "@");
00353 if (!context)
00354 return res;
00355
00356 if (option_debug > 3)
00357 ast_log(LOG_DEBUG, "Checking state of exten %s in context %s\n", exten, context);
00358
00359 res = ast_exists_extension(NULL, context, exten, 1, NULL);
00360
00361 if (!res)
00362 return AST_DEVICE_NOT_INUSE;
00363 else
00364 return AST_DEVICE_INUSE;
00365 }
00366
00367 static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout, char *orig_chan_name)
00368 {
00369 struct parkeduser *pu, *cur;
00370 int i, x = -1, parking_range;
00371 struct ast_context *con;
00372 const char *parkingexten;
00373
00374
00375 if (!(pu = ast_calloc(1, sizeof(*pu))))
00376 return -1;
00377
00378
00379 ast_mutex_lock(&parking_lock);
00380
00381 parkingexten = pbx_builtin_getvar_helper(chan, "PARKINGEXTEN");
00382 if (!ast_strlen_zero(parkingexten)) {
00383 if (ast_exists_extension(NULL, parking_con, parkingexten, 1, NULL)) {
00384 ast_mutex_unlock(&parking_lock);
00385 free(pu);
00386 ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parking_con);
00387 return 0;
00388 }
00389 ast_copy_string(pu->parkingexten, parkingexten, sizeof(pu->parkingexten));
00390 x = atoi(parkingexten);
00391 } else {
00392
00393 parking_range = parking_stop - parking_start+1;
00394 for (i = 0; i < parking_range; i++) {
00395 x = (i + parking_offset) % parking_range + parking_start;
00396 cur = parkinglot;
00397 while(cur) {
00398 if (cur->parkingnum == x)
00399 break;
00400 cur = cur->next;
00401 }
00402 if (!cur)
00403 break;
00404 }
00405
00406 if (!(i < parking_range)) {
00407 ast_log(LOG_WARNING, "No more parking spaces\n");
00408 free(pu);
00409 ast_mutex_unlock(&parking_lock);
00410 return -1;
00411 }
00412
00413 if (parkfindnext)
00414 parking_offset = x - parking_start + 1;
00415 }
00416
00417 chan->appl = "Parked Call";
00418 chan->data = NULL;
00419
00420 pu->chan = chan;
00421
00422
00423 if (chan != peer) {
00424 ast_indicate_data(pu->chan, AST_CONTROL_HOLD,
00425 S_OR(parkmohclass, NULL),
00426 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
00427 }
00428
00429 pu->start = ast_tvnow();
00430 pu->parkingnum = x;
00431 pu->parkingtime = (timeout > 0) ? timeout : parkingtime;
00432 if (extout)
00433 *extout = x;
00434
00435 if (peer)
00436 ast_copy_string(pu->peername, peer->name, sizeof(pu->peername));
00437
00438
00439
00440 ast_copy_string(pu->context, S_OR(chan->macrocontext, chan->context), sizeof(pu->context));
00441 ast_copy_string(pu->exten, S_OR(chan->macroexten, chan->exten), sizeof(pu->exten));
00442 pu->priority = chan->macropriority ? chan->macropriority : chan->priority;
00443 pu->next = parkinglot;
00444 parkinglot = pu;
00445
00446
00447 if (peer == chan)
00448 pu->notquiteyet = 1;
00449 ast_mutex_unlock(&parking_lock);
00450
00451 pthread_kill(parking_thread, SIGURG);
00452 if (option_verbose > 1)
00453 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));
00454
00455 if (pu->parkingnum != -1)
00456 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", x);
00457 manager_event(EVENT_FLAG_CALL, "ParkedCall",
00458 "Exten: %s\r\n"
00459 "Channel: %s\r\n"
00460 "From: %s\r\n"
00461 "Timeout: %ld\r\n"
00462 "CallerID: %s\r\n"
00463 "CallerIDName: %s\r\n"
00464 "Uniqueid: %s\r\n",
00465 pu->parkingexten, pu->chan->name, peer ? peer->name : "",
00466 (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL),
00467 S_OR(pu->chan->cid.cid_num, "<unknown>"),
00468 S_OR(pu->chan->cid.cid_name, "<unknown>"),
00469 pu->chan->uniqueid
00470 );
00471
00472 if (peer && adsipark && ast_adsi_available(peer)) {
00473 adsi_announce_park(peer, pu->parkingexten);
00474 ast_adsi_unload_session(peer);
00475 }
00476
00477 con = ast_context_find(parking_con);
00478 if (!con)
00479 con = ast_context_create(NULL, parking_con, registrar);
00480 if (!con)
00481 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
00482
00483 if (peer && ((pu->parkingnum != -1 && ast_strlen_zero(orig_chan_name)) || !strcasecmp(peer->name, orig_chan_name))) {
00484
00485 ast_set_flag(peer, AST_FLAG_MASQ_NOSTREAM);
00486 ast_say_digits(peer, pu->parkingnum, "", peer->language);
00487 ast_clear_flag(peer, AST_FLAG_MASQ_NOSTREAM);
00488 }
00489 if (con) {
00490 if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, strdup(pu->parkingexten), ast_free, registrar))
00491 notify_metermaids(pu->parkingexten, parking_con);
00492 }
00493 if (pu->notquiteyet) {
00494
00495 ast_indicate_data(pu->chan, AST_CONTROL_HOLD,
00496 S_OR(parkmohclass, NULL),
00497 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
00498 pu->notquiteyet = 0;
00499 pthread_kill(parking_thread, SIGURG);
00500 }
00501 return 0;
00502 }
00503
00504
00505
00506
00507 int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
00508 {
00509 return park_call_full(chan, peer, timeout, extout, NULL);
00510 }
00511
00512 int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
00513 {
00514 struct ast_channel *chan;
00515 struct ast_frame *f;
00516
00517
00518 if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) {
00519 ast_log(LOG_WARNING, "Unable to create parked channel\n");
00520 return -1;
00521 }
00522
00523
00524 chan->readformat = rchan->readformat;
00525 chan->writeformat = rchan->writeformat;
00526 ast_channel_masquerade(chan, rchan);
00527
00528
00529 set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority);
00530
00531
00532 f = ast_read(chan);
00533 if (f)
00534 ast_frfree(f);
00535
00536 ast_park_call(chan, peer, timeout, extout);
00537 return 0;
00538 }
00539
00540
00541 #define FEATURE_RETURN_HANGUP -1
00542 #define FEATURE_RETURN_SUCCESSBREAK 0
00543 #define FEATURE_RETURN_PBX_KEEPALIVE AST_PBX_KEEPALIVE
00544 #define FEATURE_RETURN_NO_HANGUP_PEER AST_PBX_NO_HANGUP_PEER
00545 #define FEATURE_RETURN_PASSDIGITS 21
00546 #define FEATURE_RETURN_STOREDIGITS 22
00547 #define FEATURE_RETURN_SUCCESS 23
00548 #define FEATURE_RETURN_KEEPTRYING 24
00549
00550 #define FEATURE_SENSE_CHAN (1 << 0)
00551 #define FEATURE_SENSE_PEER (1 << 1)
00552
00553
00554
00555
00556 static void set_peers(struct ast_channel **caller, struct ast_channel **callee,
00557 struct ast_channel *peer, struct ast_channel *chan, int sense)
00558 {
00559 if (sense == FEATURE_SENSE_PEER) {
00560 *caller = peer;
00561 *callee = chan;
00562 } else {
00563 *callee = peer;
00564 *caller = chan;
00565 }
00566 }
00567
00568
00569 static int builtin_parkcall(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00570 {
00571 struct ast_channel *parker;
00572 struct ast_channel *parkee;
00573 int res = 0;
00574 struct ast_module_user *u;
00575
00576 u = ast_module_user_add(chan);
00577
00578 set_peers(&parker, &parkee, peer, chan, sense);
00579
00580
00581 strcpy(chan->exten, "s");
00582 chan->priority = 1;
00583 if (chan->_state != AST_STATE_UP)
00584 res = ast_answer(chan);
00585 if (!res)
00586 res = ast_safe_sleep(chan, 1000);
00587 if (!res)
00588 res = ast_park_call(parkee, parker, 0, NULL);
00589
00590 ast_module_user_remove(u);
00591
00592 if (!res) {
00593 if (sense == FEATURE_SENSE_CHAN)
00594 res = AST_PBX_NO_HANGUP_PEER;
00595 else
00596 res = AST_PBX_KEEPALIVE;
00597 }
00598 return res;
00599
00600 }
00601
00602 static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00603 {
00604 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
00605 int x = 0;
00606 size_t len;
00607 struct ast_channel *caller_chan, *callee_chan;
00608
00609 if (!monitor_ok) {
00610 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00611 return -1;
00612 }
00613
00614 if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) {
00615 monitor_ok = 0;
00616 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00617 return -1;
00618 }
00619
00620 set_peers(&caller_chan, &callee_chan, peer, chan, sense);
00621
00622 if (!ast_strlen_zero(courtesytone)) {
00623 if (ast_autoservice_start(callee_chan))
00624 return -1;
00625 if (ast_stream_and_wait(caller_chan, courtesytone, caller_chan->language, "")) {
00626 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
00627 ast_autoservice_stop(callee_chan);
00628 return -1;
00629 }
00630 if (ast_autoservice_stop(callee_chan))
00631 return -1;
00632 }
00633
00634 if (callee_chan->monitor) {
00635 if (option_verbose > 3)
00636 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to stop recording call.\n", code);
00637 ast_monitor_stop(callee_chan, 1);
00638 return FEATURE_RETURN_SUCCESS;
00639 }
00640
00641 if (caller_chan && callee_chan) {
00642 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT");
00643 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
00644
00645 if (!touch_format)
00646 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
00647
00648 if (!touch_monitor)
00649 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
00650
00651 if (touch_monitor) {
00652 len = strlen(touch_monitor) + 50;
00653 args = alloca(len);
00654 touch_filename = alloca(len);
00655 snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor);
00656 snprintf(args, len, "%s|%s|m", (touch_format) ? touch_format : "wav", touch_filename);
00657 } else {
00658 caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name));
00659 callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name));
00660 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
00661 args = alloca(len);
00662 touch_filename = alloca(len);
00663 snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id);
00664 snprintf(args, len, "%s|%s|m", S_OR(touch_format, "wav"), touch_filename);
00665 }
00666
00667 for( x = 0; x < strlen(args); x++) {
00668 if (args[x] == '/')
00669 args[x] = '-';
00670 }
00671
00672 if (option_verbose > 3)
00673 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call. filename: %s\n", code, args);
00674
00675 pbx_exec(callee_chan, monitor_app, args);
00676 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
00677 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
00678
00679 return FEATURE_RETURN_SUCCESS;
00680 }
00681
00682 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");
00683 return -1;
00684 }
00685
00686 static int builtin_disconnect(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00687 {
00688 if (option_verbose > 3)
00689 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code);
00690 return FEATURE_RETURN_HANGUP;
00691 }
00692
00693 static int finishup(struct ast_channel *chan)
00694 {
00695 ast_indicate(chan, AST_CONTROL_UNHOLD);
00696
00697 return ast_autoservice_stop(chan);
00698 }
00699
00700
00701 static const char *real_ctx(struct ast_channel *transferer, struct ast_channel *transferee)
00702 {
00703 const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT");
00704 if (ast_strlen_zero(s))
00705 s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT");
00706 if (ast_strlen_zero(s))
00707 s = transferer->macrocontext;
00708 if (ast_strlen_zero(s))
00709 s = transferer->context;
00710 return s;
00711 }
00712
00713 static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00714 {
00715 struct ast_channel *transferer;
00716 struct ast_channel *transferee;
00717 const char *transferer_real_context;
00718 char xferto[256];
00719 int res;
00720
00721 set_peers(&transferer, &transferee, peer, chan, sense);
00722 transferer_real_context = real_ctx(transferer, transferee);
00723
00724 ast_autoservice_start(transferee);
00725 ast_indicate(transferee, AST_CONTROL_HOLD);
00726
00727 memset(xferto, 0, sizeof(xferto));
00728
00729
00730 res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY);
00731 if (res < 0) {
00732 finishup(transferee);
00733 return -1;
00734 }
00735 if (res > 0)
00736 xferto[0] = (char) res;
00737
00738 ast_stopstream(transferer);
00739 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
00740 if (res < 0) {
00741 finishup(transferee);
00742 return res;
00743 }
00744 if (!strcmp(xferto, ast_parking_ext())) {
00745 res = finishup(transferee);
00746 if (res)
00747 res = -1;
00748 else if (!ast_park_call(transferee, transferer, 0, NULL)) {
00749
00750
00751
00752
00753 return (transferer == peer) ? AST_PBX_KEEPALIVE : AST_PBX_NO_HANGUP_PEER;
00754 } else {
00755 ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name);
00756 }
00757
00758 } else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
00759 pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", transferee->name);
00760 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", peer->name);
00761 res=finishup(transferee);
00762 if (!transferer->cdr) {
00763 transferer->cdr=ast_cdr_alloc();
00764 if (transferer) {
00765 ast_cdr_init(transferer->cdr, transferer);
00766 ast_cdr_start(transferer->cdr);
00767 }
00768 }
00769 if (transferer->cdr) {
00770 ast_cdr_setdestchan(transferer->cdr, transferee->name);
00771 ast_cdr_setapp(transferer->cdr, "BLINDTRANSFER","");
00772 }
00773 if (!transferee->pbx) {
00774
00775 if (option_verbose > 2)
00776 ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n"
00777 ,transferee->name, xferto, transferer_real_context);
00778 if (ast_async_goto(transferee, transferer_real_context, xferto, 1))
00779 ast_log(LOG_WARNING, "Async goto failed :-(\n");
00780 res = -1;
00781 } else {
00782
00783 set_c_e_p(transferee, transferer_real_context, xferto, 0);
00784 }
00785 check_goto_on_transfer(transferer);
00786 return res;
00787 } else {
00788 if (option_verbose > 2)
00789 ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context);
00790 }
00791 if (ast_stream_and_wait(transferer, xferfailsound, transferer->language, AST_DIGIT_ANY) < 0 ) {
00792 finishup(transferee);
00793 return -1;
00794 }
00795 ast_stopstream(transferer);
00796 res = finishup(transferee);
00797 if (res) {
00798 if (option_verbose > 1)
00799 ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name);
00800 return res;
00801 }
00802 return FEATURE_RETURN_SUCCESS;
00803 }
00804
00805 static int check_compat(struct ast_channel *c, struct ast_channel *newchan)
00806 {
00807 if (ast_channel_make_compatible(c, newchan) < 0) {
00808 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n",
00809 c->name, newchan->name);
00810 ast_hangup(newchan);
00811 return -1;
00812 }
00813 return 0;
00814 }
00815
00816 static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00817 {
00818 struct ast_channel *transferer;
00819 struct ast_channel *transferee;
00820 const char *transferer_real_context;
00821 char xferto[256] = "";
00822 int res;
00823 int outstate=0;
00824 struct ast_channel *newchan;
00825 struct ast_channel *xferchan;
00826 struct ast_bridge_thread_obj *tobj;
00827 struct ast_bridge_config bconfig;
00828 struct ast_frame *f;
00829 int l;
00830
00831 if (option_debug)
00832 ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense);
00833 set_peers(&transferer, &transferee, peer, chan, sense);
00834 transferer_real_context = real_ctx(transferer, transferee);
00835
00836 ast_autoservice_start(transferee);
00837 ast_indicate(transferee, AST_CONTROL_HOLD);
00838
00839
00840 res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY);
00841 if (res < 0) {
00842 finishup(transferee);
00843 return res;
00844 }
00845 if (res > 0)
00846 xferto[0] = (char) res;
00847
00848
00849 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
00850 if (res < 0) {
00851 finishup(transferee);
00852 return res;
00853 }
00854 if (res == 0) {
00855 ast_log(LOG_WARNING, "Did not read data.\n");
00856 finishup(transferee);
00857 if (ast_stream_and_wait(transferer, "beeperr", transferer->language, ""))
00858 return -1;
00859 return FEATURE_RETURN_SUCCESS;
00860 }
00861
00862
00863 if (!ast_exists_extension(transferer, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
00864 ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context);
00865 finishup(transferee);
00866 if (ast_stream_and_wait(transferer, "beeperr", transferer->language, ""))
00867 return -1;
00868 return FEATURE_RETURN_SUCCESS;
00869 }
00870
00871 l = strlen(xferto);
00872 snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context);
00873 newchan = ast_feature_request_and_dial(transferer, "Local", ast_best_codec(transferer->nativeformats),
00874 xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name);
00875 ast_indicate(transferer, -1);
00876 if (!newchan) {
00877 finishup(transferee);
00878
00879 if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY &&
00880 ast_stream_and_wait(transferer, xferfailsound, transferer->language, ""))
00881 return -1;
00882 return FEATURE_RETURN_SUCCESS;
00883 }
00884
00885 if (check_compat(transferer, newchan)) {
00886
00887 finishup(transferee);
00888 return -1;
00889 }
00890 memset(&bconfig,0,sizeof(struct ast_bridge_config));
00891 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
00892 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
00893 res = ast_bridge_call(transferer, newchan, &bconfig);
00894 if (newchan->_softhangup || !transferer->_softhangup) {
00895 ast_hangup(newchan);
00896 if (ast_stream_and_wait(transferer, xfersound, transferer->language, ""))
00897 ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
00898 finishup(transferee);
00899 transferer->_softhangup = 0;
00900 return FEATURE_RETURN_SUCCESS;
00901 }
00902
00903 if (check_compat(transferee, newchan)) {
00904 finishup(transferee);
00905 return -1;
00906 }
00907
00908 ast_indicate(transferee, AST_CONTROL_UNHOLD);
00909
00910 if ((ast_autoservice_stop(transferee) < 0)
00911 || (ast_waitfordigit(transferee, 100) < 0)
00912 || (ast_waitfordigit(newchan, 100) < 0)
00913 || ast_check_hangup(transferee)
00914 || ast_check_hangup(newchan)) {
00915 ast_hangup(newchan);
00916 return -1;
00917 }
00918
00919 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name);
00920 if (!xferchan) {
00921 ast_hangup(newchan);
00922 return -1;
00923 }
00924
00925 xferchan->readformat = transferee->readformat;
00926 xferchan->writeformat = transferee->writeformat;
00927 ast_channel_masquerade(xferchan, transferee);
00928 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
00929 xferchan->_state = AST_STATE_UP;
00930 ast_clear_flag(xferchan, AST_FLAGS_ALL);
00931 xferchan->_softhangup = 0;
00932
00933 if ((f = ast_read(xferchan)))
00934 ast_frfree(f);
00935
00936 newchan->_state = AST_STATE_UP;
00937 ast_clear_flag(newchan, AST_FLAGS_ALL);
00938 newchan->_softhangup = 0;
00939
00940 tobj = ast_calloc(1, sizeof(struct ast_bridge_thread_obj));
00941 if (!tobj) {
00942 ast_hangup(xferchan);
00943 ast_hangup(newchan);
00944 return -1;
00945 }
00946 tobj->chan = xferchan;
00947 tobj->peer = newchan;
00948 tobj->bconfig = *config;
00949
00950 if (ast_stream_and_wait(newchan, xfersound, newchan->language, ""))
00951 ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
00952 ast_bridge_call_thread_launch(tobj);
00953 return -1;
00954 }
00955
00956
00957
00958 #define FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0]))
00959
00960 AST_RWLOCK_DEFINE_STATIC(features_lock);
00961
00962 static struct ast_call_feature builtin_features[] =
00963 {
00964 { AST_FEATURE_REDIRECT, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
00965 { AST_FEATURE_REDIRECT, "Attended Transfer", "atxfer", "", "", builtin_atxfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
00966 { AST_FEATURE_AUTOMON, "One Touch Monitor", "automon", "", "", builtin_automonitor, AST_FEATURE_FLAG_NEEDSDTMF, "" },
00967 { AST_FEATURE_DISCONNECT, "Disconnect Call", "disconnect", "*", "*", builtin_disconnect, AST_FEATURE_FLAG_NEEDSDTMF, "" },
00968 { AST_FEATURE_PARKCALL, "Park Call", "parkcall", "", "", builtin_parkcall, AST_FEATURE_FLAG_NEEDSDTMF, "" },
00969 };
00970
00971
00972 static AST_LIST_HEAD_STATIC(feature_list,ast_call_feature);
00973
00974
00975 void ast_register_feature(struct ast_call_feature *feature)
00976 {
00977 if (!feature) {
00978 ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
00979 return;
00980 }
00981
00982 AST_LIST_LOCK(&feature_list);
00983 AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry);
00984 AST_LIST_UNLOCK(&feature_list);
00985
00986 if (option_verbose >= 2)
00987 ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
00988 }
00989
00990
00991 void ast_unregister_feature(struct ast_call_feature *feature)
00992 {
00993 if (!feature)
00994 return;
00995
00996 AST_LIST_LOCK(&feature_list);
00997 AST_LIST_REMOVE(&feature_list,feature,feature_entry);
00998 AST_LIST_UNLOCK(&feature_list);
00999 free(feature);
01000 }
01001
01002
01003 static void ast_unregister_features(void)
01004 {
01005 struct ast_call_feature *feature;
01006
01007 AST_LIST_LOCK(&feature_list);
01008 while ((feature = AST_LIST_REMOVE_HEAD(&feature_list,feature_entry)))
01009 free(feature);
01010 AST_LIST_UNLOCK(&feature_list);
01011 }
01012
01013
01014 static struct ast_call_feature *find_dynamic_feature(const char *name)
01015 {
01016 struct ast_call_feature *tmp;
01017
01018 AST_LIST_TRAVERSE(&feature_list, tmp, feature_entry) {
01019 if (!strcasecmp(tmp->sname, name))
01020 break;
01021 }
01022
01023 return tmp;
01024 }
01025
01026
01027 static int feature_exec_app(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
01028 {
01029 struct ast_app *app;
01030 struct ast_call_feature *feature = data;
01031 struct ast_channel *work, *idle;
01032 int res;
01033
01034 if (!feature) {
01035 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
01036 return -1;
01037 }
01038
01039 if (sense == FEATURE_SENSE_CHAN) {
01040 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
01041 return FEATURE_RETURN_KEEPTRYING;
01042 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
01043 work = chan;
01044 idle = peer;
01045 } else {
01046 work = peer;
01047 idle = chan;
01048 }
01049 } else {
01050 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
01051 return FEATURE_RETURN_KEEPTRYING;
01052 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
01053 work = peer;
01054 idle = chan;
01055 } else {
01056 work = chan;
01057 idle = peer;
01058 }
01059 }
01060
01061 if (!(app = pbx_findapp(feature->app))) {
01062 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
01063 return -2;
01064 }
01065
01066 ast_autoservice_start(idle);
01067
01068 if (!ast_strlen_zero(feature->moh_class))
01069 ast_moh_start(idle, feature->moh_class, NULL);
01070
01071 res = pbx_exec(work, app, feature->app_args);
01072
01073 if (!ast_strlen_zero(feature->moh_class))
01074 ast_moh_stop(idle);
01075
01076 ast_autoservice_stop(idle);
01077
01078 if (res == AST_PBX_KEEPALIVE)
01079 return FEATURE_RETURN_PBX_KEEPALIVE;
01080 else if (res == AST_PBX_NO_HANGUP_PEER)
01081 return FEATURE_RETURN_NO_HANGUP_PEER;
01082 else if (res)
01083 return FEATURE_RETURN_SUCCESSBREAK;
01084
01085 return FEATURE_RETURN_SUCCESS;
01086 }
01087
01088 static void unmap_features(void)
01089 {
01090 int x;
01091
01092 ast_rwlock_wrlock(&features_lock);
01093 for (x = 0; x < FEATURES_COUNT; x++)
01094 strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
01095 ast_rwlock_unlock(&features_lock);
01096 }
01097
01098 static int remap_feature(const char *name, const char *value)
01099 {
01100 int x, res = -1;
01101
01102 ast_rwlock_wrlock(&features_lock);
01103 for (x = 0; x < FEATURES_COUNT; x++) {
01104 if (strcasecmp(builtin_features[x].sname, name))
01105 continue;
01106
01107 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
01108 res = 0;
01109 break;
01110 }
01111 ast_rwlock_unlock(&features_lock);
01112
01113 return res;
01114 }
01115
01116 static int ast_feature_interpret(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
01117 {
01118 int x;
01119 struct ast_flags features;
01120 int res = FEATURE_RETURN_PASSDIGITS;
01121 struct ast_call_feature *feature;
01122 const char *dynamic_features;
01123 char *tmp, *tok;
01124
01125 if (sense == FEATURE_SENSE_CHAN) {
01126 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
01127 dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
01128 } else {
01129 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);
01130 dynamic_features = pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES");
01131 }
01132 if (option_debug > 2)
01133 ast_log(LOG_DEBUG, "Feature interpret: chan=%s, peer=%s, sense=%d, features=%d dynamic=%s\n", chan->name, peer->name, sense, features.flags, dynamic_features);
01134
01135 ast_rwlock_rdlock(&features_lock);
01136 for (x = 0; x < FEATURES_COUNT; x++) {
01137 if ((ast_test_flag(&features, builtin_features[x].feature_mask)) &&
01138 !ast_strlen_zero(builtin_features[x].exten)) {
01139
01140 if (!strcmp(builtin_features[x].exten, code)) {
01141 res = builtin_features[x].operation(chan, peer, config, code, sense, NULL);
01142 break;
01143 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
01144 if (res == FEATURE_RETURN_PASSDIGITS)
01145 res = FEATURE_RETURN_STOREDIGITS;
01146 }
01147 }
01148 }
01149 ast_rwlock_unlock(&features_lock);
01150
01151 if (ast_strlen_zero(dynamic_features))
01152 return res;
01153
01154 tmp = ast_strdupa(dynamic_features);
01155
01156 while ((tok = strsep(&tmp, "#"))) {
01157 AST_LIST_LOCK(&feature_list);
01158 if (!(feature = find_dynamic_feature(tok))) {
01159 AST_LIST_UNLOCK(&feature_list);
01160 continue;
01161 }
01162
01163
01164 if (!strcmp(feature->exten, code)) {
01165 if (option_verbose > 2)
01166 ast_verbose(VERBOSE_PREFIX_3 " Feature Found: %s exten: %s\n",feature->sname, tok);
01167 res = feature->operation(chan, peer, config, code, sense, feature);
01168 if (res != FEATURE_RETURN_KEEPTRYING) {
01169 AST_LIST_UNLOCK(&feature_list);
01170 break;
01171 }
01172 res = FEATURE_RETURN_PASSDIGITS;
01173 } else if (!strncmp(feature->exten, code, strlen(code)))
01174 res = FEATURE_RETURN_STOREDIGITS;
01175
01176 AST_LIST_UNLOCK(&feature_list);
01177 }
01178
01179 return res;
01180 }
01181
01182 static void set_config_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
01183 {
01184 int x;
01185
01186 ast_clear_flag(config, AST_FLAGS_ALL);
01187
01188 ast_rwlock_rdlock(&features_lock);
01189 for (x = 0; x < FEATURES_COUNT; x++) {
01190 if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF))
01191 continue;
01192
01193 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
01194 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01195
01196 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
01197 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01198 }
01199 ast_rwlock_unlock(&features_lock);
01200
01201 if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
01202 const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
01203
01204 if (dynamic_features) {
01205 char *tmp = ast_strdupa(dynamic_features);
01206 char *tok;
01207 struct ast_call_feature *feature;
01208
01209
01210 while ((tok = strsep(&tmp, "#"))) {
01211 AST_LIST_LOCK(&feature_list);
01212 if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
01213 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
01214 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01215 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
01216 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01217 }
01218 AST_LIST_UNLOCK(&feature_list);
01219 }
01220 }
01221 }
01222 }
01223
01224
01225 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)
01226 {
01227 int state = 0;
01228 int cause = 0;
01229 int to;
01230 struct ast_channel *chan;
01231 struct ast_channel *monitor_chans[2];
01232 struct ast_channel *active_channel;
01233 int res = 0, ready = 0;
01234
01235 if ((chan = ast_request(type, format, data, &cause))) {
01236 ast_set_callerid(chan, cid_num, cid_name, cid_num);
01237 ast_channel_inherit_variables(caller, chan);
01238 pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name);
01239 if (!chan->cdr) {
01240 chan->cdr=ast_cdr_alloc();
01241 if (chan->cdr) {
01242 ast_cdr_init(chan->cdr, chan);
01243 ast_cdr_start(chan->cdr);
01244 }
01245 }
01246
01247 if (!ast_call(chan, data, timeout)) {
01248 struct timeval started;
01249 int x, len = 0;
01250 char *disconnect_code = NULL, *dialed_code = NULL;
01251
01252 ast_indicate(caller, AST_CONTROL_RINGING);
01253
01254 ast_rwlock_rdlock(&features_lock);
01255 for (x = 0; x < FEATURES_COUNT; x++) {
01256 if (strcasecmp(builtin_features[x].sname, "disconnect"))
01257 continue;
01258
01259 disconnect_code = builtin_features[x].exten;
01260 len = strlen(disconnect_code) + 1;
01261 dialed_code = alloca(len);
01262 memset(dialed_code, 0, len);
01263 break;
01264 }
01265 ast_rwlock_unlock(&features_lock);
01266 x = 0;
01267 started = ast_tvnow();
01268 to = timeout;
01269 while (!ast_check_hangup(caller) && timeout && (chan->_state != AST_STATE_UP)) {
01270 struct ast_frame *f = NULL;
01271
01272 monitor_chans[0] = caller;
01273 monitor_chans[1] = chan;
01274 active_channel = ast_waitfor_n(monitor_chans, 2, &to);
01275
01276
01277 if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
01278 state = AST_CONTROL_UNHOLD;
01279 ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n");
01280 break;
01281 }
01282
01283 if (!active_channel)
01284 continue;
01285
01286 if (chan && (chan == active_channel)){
01287 f = ast_read(chan);
01288 if (f == NULL) {
01289 state = AST_CONTROL_HANGUP;
01290 res = 0;
01291 break;
01292 }
01293
01294 if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) {
01295 if (f->subclass == AST_CONTROL_RINGING) {
01296 state = f->subclass;
01297 if (option_verbose > 2)
01298 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", chan->name);
01299 ast_indicate(caller, AST_CONTROL_RINGING);
01300 } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) {
01301 state = f->subclass;
01302 if (option_verbose > 2)
01303 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", chan->name);
01304 ast_indicate(caller, AST_CONTROL_BUSY);
01305 ast_frfree(f);
01306 f = NULL;
01307 break;
01308 } else if (f->subclass == AST_CONTROL_ANSWER) {
01309
01310 state = f->subclass;
01311 ast_frfree(f);
01312 f = NULL;
01313 ready=1;
01314 break;
01315 } else if (f->subclass != -1) {
01316 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass);
01317 }
01318
01319 }
01320
01321 } else if (caller && (active_channel == caller)) {
01322 f = ast_read(caller);
01323 if (f == NULL) {
01324 if (caller->_softhangup && !chan->_softhangup) {
01325
01326 ready = 1;
01327 break;
01328 }
01329 state = AST_CONTROL_HANGUP;
01330 res = 0;
01331 break;
01332 }
01333
01334 if (f->frametype == AST_FRAME_DTMF) {
01335 dialed_code[x++] = f->subclass;
01336 dialed_code[x] = '\0';
01337 if (strlen(dialed_code) == len) {
01338 x = 0;
01339 } else if (x && strncmp(dialed_code, disconnect_code, x)) {
01340 x = 0;
01341 dialed_code[x] = '\0';
01342 }
01343 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
01344
01345 state = AST_CONTROL_UNHOLD;
01346 ast_frfree(f);
01347 f = NULL;
01348 break;
01349 }
01350 }
01351 }
01352 if (f)
01353 ast_frfree(f);
01354 }
01355 } else
01356 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
01357 } else {
01358 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
01359 switch(cause) {
01360 case AST_CAUSE_BUSY:
01361 state = AST_CONTROL_BUSY;
01362 break;
01363 case AST_CAUSE_CONGESTION:
01364 state = AST_CONTROL_CONGESTION;
01365 break;
01366 }
01367 }
01368
01369 ast_indicate(caller, -1);
01370 if (chan && ready) {
01371 if (chan->_state == AST_STATE_UP)
01372 state = AST_CONTROL_ANSWER;
01373 res = 0;
01374 } else if(chan) {
01375 res = -1;
01376 ast_hangup(chan);
01377 chan = NULL;
01378 } else {
01379 res = -1;
01380 }
01381
01382 if (outstate)
01383 *outstate = state;
01384
01385 if (chan && res <= 0) {
01386 if (chan->cdr || (chan->cdr = ast_cdr_alloc())) {
01387 char tmp[256];
01388 ast_cdr_init(chan->cdr, chan);
01389 snprintf(tmp, 256, "%s/%s", type, (char *)data);
01390 ast_cdr_setapp(chan->cdr,"Dial",tmp);
01391 ast_cdr_update(chan);
01392 ast_cdr_start(chan->cdr);
01393 ast_cdr_end(chan->cdr);
01394
01395 if (ast_cdr_disposition(chan->cdr,chan->hangupcause))
01396 ast_cdr_failed(chan->cdr);
01397 } else {
01398 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
01399 }
01400 }
01401
01402 return chan;
01403 }
01404
01405 int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast_bridge_config *config)
01406 {
01407
01408
01409 struct ast_frame *f;
01410 struct ast_channel *who;
01411 char chan_featurecode[FEATURE_MAX_LEN + 1]="";
01412 char peer_featurecode[FEATURE_MAX_LEN + 1]="";
01413 int res;
01414 int diff;
01415 int hasfeatures=0;
01416 int hadfeatures=0;
01417 struct ast_option_header *aoh;
01418 struct ast_bridge_config backup_config;
01419 struct ast_cdr *bridge_cdr;
01420
01421 memset(&backup_config, 0, sizeof(backup_config));
01422
01423 config->start_time = ast_tvnow();
01424
01425 if (chan && peer) {
01426 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
01427 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
01428 } else if (chan)
01429 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
01430
01431 if (monitor_ok) {
01432 const char *monitor_exec;
01433 struct ast_channel *src = NULL;
01434 if (!monitor_app) {
01435 if (!(monitor_app = pbx_findapp("Monitor")))
01436 monitor_ok=0;
01437 }
01438 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR")))
01439 src = chan;
01440 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
01441 src = peer;
01442 if (monitor_app && src) {
01443 char *tmp = ast_strdupa(monitor_exec);
01444 pbx_exec(src, monitor_app, tmp);
01445 }
01446 }
01447
01448 set_config_flags(chan, peer, config);
01449 config->firstpass = 1;
01450
01451
01452 if (ast_answer(chan))
01453 return -1;
01454 peer->appl = "Bridged Call";
01455 peer->data = chan->name;
01456
01457
01458 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
01459 char tmp[256];
01460 if (!ast_strlen_zero(chan->cdr->userfield)) {
01461 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield);
01462 ast_cdr_appenduserfield(chan, tmp);
01463 } else
01464 ast_cdr_setuserfield(chan, peer->cdr->userfield);
01465
01466 free(peer->cdr);
01467 peer->cdr = NULL;
01468 }
01469
01470 for (;;) {
01471 struct ast_channel *other;
01472
01473 res = ast_channel_bridge(chan, peer, config, &f, &who);
01474
01475 if (config->feature_timer) {
01476
01477 diff = ast_tvdiff_ms(ast_tvnow(), config->start_time);
01478 config->feature_timer -= diff;
01479 if (hasfeatures) {
01480
01481
01482
01483 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
01484 if (option_debug)
01485 ast_log(LOG_DEBUG, "Timed out, realtime this time!\n");
01486 config->feature_timer = 0;
01487 who = chan;
01488 if (f)
01489 ast_frfree(f);
01490 f = NULL;
01491 res = 0;
01492 } else if (config->feature_timer <= 0) {
01493
01494
01495 if (option_debug)
01496 ast_log(LOG_DEBUG, "Timed out for feature!\n");
01497 if (!ast_strlen_zero(peer_featurecode)) {
01498 ast_dtmf_stream(chan, peer, peer_featurecode, 0);
01499 memset(peer_featurecode, 0, sizeof(peer_featurecode));
01500 }
01501 if (!ast_strlen_zero(chan_featurecode)) {
01502 ast_dtmf_stream(peer, chan, chan_featurecode, 0);
01503 memset(chan_featurecode, 0, sizeof(chan_featurecode));
01504 }
01505 if (f)
01506 ast_frfree(f);
01507 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01508 if (!hasfeatures) {
01509
01510 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01511 memset(&backup_config, 0, sizeof(backup_config));
01512 }
01513 hadfeatures = hasfeatures;
01514
01515 continue;
01516 } else if (!f) {
01517
01518
01519
01520 continue;
01521 }
01522 } else {
01523 if (config->feature_timer <=0) {
01524
01525 config->feature_timer = 0;
01526 who = chan;
01527 if (f)
01528 ast_frfree(f);
01529 f = NULL;
01530 res = 0;
01531 }
01532 }
01533 }
01534 if (res < 0) {
01535 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer))
01536 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
01537 return -1;
01538 }
01539
01540 if (!f || (f->frametype == AST_FRAME_CONTROL &&
01541 (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY ||
01542 f->subclass == AST_CONTROL_CONGESTION ) ) ) {
01543 res = -1;
01544 break;
01545 }
01546
01547 other = (who == chan) ? peer : chan;
01548 if (f->frametype == AST_FRAME_CONTROL) {
01549 switch (f->subclass) {
01550 case AST_CONTROL_RINGING:
01551 case AST_CONTROL_FLASH:
01552 case -1:
01553 ast_indicate(other, f->subclass);
01554 break;
01555 case AST_CONTROL_HOLD:
01556 case AST_CONTROL_UNHOLD:
01557 ast_indicate_data(other, f->subclass, f->data, f->datalen);
01558 break;
01559 case AST_CONTROL_OPTION:
01560 aoh = f->data;
01561
01562 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) {
01563 ast_channel_setoption(other, ntohs(aoh->option), aoh->data,
01564 f->datalen - sizeof(struct ast_option_header), 0);
01565 }
01566 break;
01567 }
01568 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
01569
01570 } else if (f->frametype == AST_FRAME_DTMF) {
01571 char *featurecode;
01572 int sense;
01573
01574 hadfeatures = hasfeatures;
01575
01576 if (who == chan) {
01577 sense = FEATURE_SENSE_CHAN;
01578 featurecode = chan_featurecode;
01579 } else {
01580 sense = FEATURE_SENSE_PEER;
01581 featurecode = peer_featurecode;
01582 }
01583
01584
01585
01586
01587 featurecode[strlen(featurecode)] = f->subclass;
01588
01589 ast_frfree(f);
01590 f = NULL;
01591 config->feature_timer = backup_config.feature_timer;
01592 res = ast_feature_interpret(chan, peer, config, featurecode, sense);
01593 switch(res) {
01594 case FEATURE_RETURN_PASSDIGITS:
01595 ast_dtmf_stream(other, who, featurecode, 0);
01596
01597 case FEATURE_RETURN_SUCCESS:
01598 memset(featurecode, 0, sizeof(chan_featurecode));
01599 break;
01600 }
01601 if (res >= FEATURE_RETURN_PASSDIGITS) {
01602 res = 0;
01603 } else
01604 break;
01605 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01606 if (hadfeatures && !hasfeatures) {
01607
01608 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01609 memset(&backup_config, 0, sizeof(struct ast_bridge_config));
01610 } else if (hasfeatures) {
01611 if (!hadfeatures) {
01612
01613 memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
01614
01615 config->play_warning = 0;
01616 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
01617 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
01618 config->warning_freq = 0;
01619 config->warning_sound = NULL;
01620 config->end_sound = NULL;
01621 config->start_sound = NULL;
01622 config->firstpass = 0;
01623 }
01624 config->start_time = ast_tvnow();
01625 config->feature_timer = featuredigittimeout;
01626 if (option_debug)
01627 ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer);
01628 }
01629 }
01630 if (f)
01631 ast_frfree(f);
01632
01633 }
01634
01635
01636 bridge_cdr = ast_cdr_alloc();
01637 if (bridge_cdr) {
01638 if (chan->cdr && peer->cdr) {
01639 ast_cdr_init(bridge_cdr,chan);
01640 ast_cdr_start(bridge_cdr);
01641
01642
01643 ast_cdr_merge(bridge_cdr, chan->cdr);
01644 if (!ast_test_flag(chan->cdr, AST_CDR_FLAG_LOCKED))
01645 ast_cdr_discard(chan->cdr);
01646
01647
01648 ast_cdr_merge(bridge_cdr, peer->cdr);
01649 if (!ast_test_flag(peer->cdr, AST_CDR_FLAG_LOCKED))
01650 ast_cdr_discard(peer->cdr);
01651
01652 peer->cdr = NULL;
01653 chan->cdr = bridge_cdr;
01654 } else if (chan->cdr) {
01655
01656 ast_cdr_init(bridge_cdr,chan);
01657
01658 ast_cdr_merge(bridge_cdr, chan->cdr);
01659 if (!ast_test_flag(chan->cdr, AST_CDR_FLAG_LOCKED))
01660 ast_cdr_discard(chan->cdr);
01661 chan->cdr = bridge_cdr;
01662 } else if (peer->cdr) {
01663
01664 ast_cdr_init(bridge_cdr,peer);
01665
01666 ast_cdr_merge(bridge_cdr, peer->cdr);
01667 if (!ast_test_flag(peer->cdr, AST_CDR_FLAG_LOCKED))
01668 ast_cdr_discard(peer->cdr);
01669 peer->cdr = NULL;
01670 peer->cdr = bridge_cdr;
01671 } else {
01672
01673 ast_cdr_init(bridge_cdr,chan);
01674 chan->cdr = bridge_cdr;
01675 }
01676 if (ast_strlen_zero(bridge_cdr->dstchannel)) {
01677 if (strcmp(bridge_cdr->channel, peer->name) != 0)
01678 ast_cdr_setdestchan(bridge_cdr, peer->name);
01679 else
01680 ast_cdr_setdestchan(bridge_cdr, chan->name);
01681 }
01682 }
01683 return res;
01684 }
01685
01686 static void post_manager_event(const char *s, char *parkingexten, struct ast_channel *chan)
01687 {
01688 manager_event(EVENT_FLAG_CALL, s,
01689 "Exten: %s\r\n"
01690 "Channel: %s\r\n"
01691 "CallerID: %s\r\n"
01692 "CallerIDName: %s\r\n"
01693 "Uniqueid: %s\r\n\r\n",
01694 parkingexten,
01695 chan->name,
01696 S_OR(chan->cid.cid_num, "<unknown>"),
01697 S_OR(chan->cid.cid_name, "<unknown>"),
01698 chan->uniqueid
01699 );
01700 }
01701
01702
01703 static void *do_parking_thread(void *ignore)
01704 {
01705 fd_set rfds, efds;
01706 FD_ZERO(&rfds);
01707 FD_ZERO(&efds);
01708
01709 for (;;) {
01710 struct parkeduser *pu, *pl, *pt = NULL;
01711 int ms = -1;
01712 int max = -1;
01713 fd_set nrfds, nefds;
01714 FD_ZERO(&nrfds);
01715 FD_ZERO(&nefds);
01716
01717 ast_mutex_lock(&parking_lock);
01718 pl = NULL;
01719 pu = parkinglot;
01720
01721 while (pu) {
01722 struct ast_channel *chan = pu->chan;
01723 int tms;
01724 int x;
01725 struct ast_context *con;
01726
01727 if (pu->notquiteyet) {
01728 pl = pu;
01729 pu = pu->next;
01730 continue;
01731 }
01732 tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
01733 if (tms > pu->parkingtime) {
01734 ast_indicate(chan, AST_CONTROL_UNHOLD);
01735
01736 if (pu->peername[0]) {
01737 char *peername = ast_strdupa(pu->peername);
01738 char *cp = strrchr(peername, '-');
01739 if (cp)
01740 *cp = 0;
01741 con = ast_context_find(parking_con_dial);
01742 if (!con) {
01743 con = ast_context_create(NULL, parking_con_dial, registrar);
01744 if (!con)
01745 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
01746 }
01747 if (con) {
01748 char returnexten[AST_MAX_EXTENSION];
01749 snprintf(returnexten, sizeof(returnexten), "%s||t", peername);
01750 ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), ast_free, registrar);
01751 }
01752 set_c_e_p(chan, parking_con_dial, peername, 1);
01753 } else {
01754
01755
01756 set_c_e_p(chan, pu->context, pu->exten, pu->priority);
01757 }
01758
01759 post_manager_event("ParkedCallTimeOut", pu->parkingexten, chan);
01760
01761 if (option_verbose > 1)
01762 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);
01763
01764 if (ast_pbx_start(chan)) {
01765 ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", chan->name);
01766 ast_hangup(chan);
01767 }
01768
01769 if (pl)
01770 pl->next = pu->next;
01771 else
01772 parkinglot = pu->next;
01773 pt = pu;
01774 pu = pu->next;
01775 con = ast_context_find(parking_con);
01776 if (con) {
01777 if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL))
01778 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01779 else
01780 notify_metermaids(pt->parkingexten, parking_con);
01781 } else
01782 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01783 free(pt);
01784 } else {
01785 for (x = 0; x < AST_MAX_FDS; x++) {
01786 struct ast_frame *f;
01787
01788 if (chan->fds[x] == -1 || (!FD_ISSET(chan->fds[x], &rfds) && !FD_ISSET(chan->fds[x], &efds)))
01789 continue;
01790
01791 if (FD_ISSET(chan->fds[x], &efds))
01792 ast_set_flag(chan, AST_FLAG_EXCEPTION);
01793 else
01794 ast_clear_flag(chan, AST_FLAG_EXCEPTION);
01795 chan->fdno = x;
01796
01797
01798 f = ast_read(chan);
01799 if (!f || (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_HANGUP)) {
01800 if (f)
01801 ast_frfree(f);
01802 post_manager_event("ParkedCallGiveUp", pu->parkingexten, chan);
01803
01804
01805 if (option_verbose > 1)
01806 ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", chan->name);
01807 ast_hangup(chan);
01808
01809 if (pl)
01810 pl->next = pu->next;
01811 else
01812 parkinglot = pu->next;
01813 pt = pu;
01814 pu = pu->next;
01815 con = ast_context_find(parking_con);
01816 if (con) {
01817 if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL))
01818 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01819 else
01820 notify_metermaids(pt->parkingexten, parking_con);
01821 } else
01822 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01823 free(pt);
01824 break;
01825 } else {
01826
01827 ast_frfree(f);
01828 if (pu->moh_trys < 3 && !chan->generatordata) {
01829 if (option_debug)
01830 ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source. Restarting.\n");
01831 ast_indicate_data(pu->chan, AST_CONTROL_HOLD,
01832 S_OR(parkmohclass, NULL),
01833 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
01834 pu->moh_trys++;
01835 }
01836 goto std;
01837 }
01838
01839 }
01840 if (x >= AST_MAX_FDS) {
01841 std: for (x=0; x<AST_MAX_FDS; x++) {
01842 if (chan->fds[x] > -1) {
01843 FD_SET(chan->fds[x], &nrfds);
01844 FD_SET(chan->fds[x], &nefds);
01845 if (chan->fds[x] > max)
01846 max = chan->fds[x];
01847 }
01848 }
01849
01850 if (tms < ms || ms < 0)
01851 ms = tms;
01852 pl = pu;
01853 pu = pu->next;
01854 }
01855 }
01856 }
01857 ast_mutex_unlock(&parking_lock);
01858 rfds = nrfds;
01859 efds = nefds;
01860 {
01861 struct timeval tv = ast_samp2tv(ms, 1000);
01862
01863 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
01864 }
01865 pthread_testcancel();
01866 }
01867 return NULL;
01868 }
01869
01870
01871 static int park_call_exec(struct ast_channel *chan, void *data)
01872 {
01873
01874
01875
01876 char *orig_chan_name = ast_strdupa(chan->name);
01877
01878
01879 int res = 0;
01880 struct ast_module_user *u;
01881
01882 u = ast_module_user_add(chan);
01883
01884
01885
01886 strcpy(chan->exten, "s");
01887 chan->priority = 1;
01888
01889 if (chan->_state != AST_STATE_UP)
01890 res = ast_answer(chan);
01891
01892 if (!res)
01893 res = ast_safe_sleep(chan, 1000);
01894
01895 if (!res)
01896 res = park_call_full(chan, NULL, 0, NULL, orig_chan_name);
01897
01898 ast_module_user_remove(u);
01899
01900 return !res ? AST_PBX_KEEPALIVE : res;
01901 }
01902
01903
01904 static int park_exec(struct ast_channel *chan, void *data)
01905 {
01906 int res = 0;
01907 struct ast_module_user *u;
01908 struct ast_channel *peer=NULL;
01909 struct parkeduser *pu, *pl=NULL;
01910 struct ast_context *con;
01911
01912 int park;
01913 struct ast_bridge_config config;
01914
01915 if (!data) {
01916 ast_log(LOG_WARNING, "Parkedcall requires an argument (extension number)\n");
01917 return -1;
01918 }
01919
01920 u = ast_module_user_add(chan);
01921
01922 park = atoi((char *)data);
01923 ast_mutex_lock(&parking_lock);
01924 pu = parkinglot;
01925 while(pu) {
01926 if (pu->parkingnum == park) {
01927 if (pl)
01928 pl->next = pu->next;
01929 else
01930 parkinglot = pu->next;
01931 break;
01932 }
01933 pl = pu;
01934 pu = pu->next;
01935 }
01936 ast_mutex_unlock(&parking_lock);
01937 if (pu) {
01938 peer = pu->chan;
01939 con = ast_context_find(parking_con);
01940 if (con) {
01941 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL))
01942 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01943 else
01944 notify_metermaids(pu->parkingexten, parking_con);
01945 } else
01946 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01947
01948 manager_event(EVENT_FLAG_CALL, "UnParkedCall",
01949 "Exten: %s\r\n"
01950 "Channel: %s\r\n"
01951 "From: %s\r\n"
01952 "CallerID: %s\r\n"
01953 "CallerIDName: %s\r\n"
01954 "Uniqueid: %s\r\n",
01955 pu->parkingexten, pu->chan->name, chan->name,
01956 S_OR(pu->chan->cid.cid_num, "<unknown>"),
01957 S_OR(pu->chan->cid.cid_name, "<unknown>"),
01958 pu->chan->uniqueid
01959 );
01960
01961 free(pu);
01962 }
01963
01964 if (chan->_state != AST_STATE_UP)
01965 ast_answer(chan);
01966
01967 if (peer) {
01968
01969
01970 if (!ast_strlen_zero(courtesytone)) {
01971 int error = 0;
01972 ast_indicate(peer, AST_CONTROL_UNHOLD);
01973 if (parkedplay == 0) {
01974 error = ast_stream_and_wait(chan, courtesytone, chan->language, "");
01975 } else if (parkedplay == 1) {
01976 error = ast_stream_and_wait(peer, courtesytone, chan->language, "");
01977 } else if (parkedplay == 2) {
01978 if (!ast_streamfile(chan, courtesytone, chan->language) &&
01979 !ast_streamfile(peer, courtesytone, chan->language)) {
01980
01981 res = ast_waitstream(chan, "");
01982 if (res >= 0)
01983 res = ast_waitstream(peer, "");
01984 if (res < 0)
01985 error = 1;
01986 }
01987 }
01988 if (error) {
01989 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
01990 ast_hangup(peer);
01991 ast_module_user_remove(u);
01992 return -1;
01993 }
01994 } else
01995 ast_indicate(peer, AST_CONTROL_UNHOLD);
01996
01997 res = ast_channel_make_compatible(chan, peer);
01998 if (res < 0) {
01999 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
02000 ast_hangup(peer);
02001 ast_module_user_remove(u);
02002 return -1;
02003 }
02004
02005
02006 if (option_verbose > 2)
02007 ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
02008
02009 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
02010 ast_cdr_setdestchan(chan->cdr, peer->name);
02011 memset(&config, 0, sizeof(struct ast_bridge_config));
02012 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
02013 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
02014 res = ast_bridge_call(chan, peer, &config);
02015
02016 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
02017 ast_cdr_setdestchan(chan->cdr, peer->name);
02018
02019
02020 if (res != AST_PBX_NO_HANGUP_PEER)
02021 ast_hangup(peer);
02022 ast_module_user_remove(u);
02023 return res;
02024 } else {
02025
02026 if (ast_stream_and_wait(chan, "pbx-invalidpark", chan->language, ""))
02027 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
02028 if (option_verbose > 2)
02029 ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
02030 res = -1;
02031 }
02032
02033 ast_module_user_remove(u);
02034
02035 return res;
02036 }
02037
02038 int ast_hold_call(struct ast_channel *chan, struct ast_channel *peer)
02039 {
02040
02041
02042 struct holdeduser *pu;
02043 pu = malloc(sizeof(struct holdeduser));
02044 if (pu) {
02045 memset(pu, 0, sizeof(pu));
02046 ast_mutex_lock(&holding_lock);
02047 chan->appl = "Holded Call";
02048 chan->data = NULL;
02049
02050 pu->chan = chan;
02051 strncpy(pu->uniqueid, chan->uniqueid, sizeof(pu->uniqueid));
02052 strncpy(pu->uniqueidpeer, peer->uniqueid, sizeof(pu->uniqueidpeer));
02053
02054 ast_moh_start(pu->chan, NULL, NULL);
02055 gettimeofday(&pu->start, NULL);
02056 pu->next = holdlist;
02057 holdlist = pu;
02058 ast_mutex_unlock(&holding_lock);
02059
02060 pthread_kill(holding_thread, SIGURG);
02061
02062 manager_event(EVENT_FLAG_CALL, "HoldedCall",
02063 "Channel1: %s\r\n"
02064 "Channel2: %s\r\n"
02065 "Uniqueid1: %s\r\n"
02066 "Uniqueid2: %s\r\n"
02067 ,pu->chan->name, peer->name, pu->chan->uniqueid, peer->uniqueid);
02068
02069 } else {
02070 ast_log(LOG_WARNING, "Out of memory\n");
02071 return -1;
02072 }
02073 return 0;
02074 }
02075
02076 int ast_masq_hold_call(struct ast_channel *rchan, struct ast_channel *peer)
02077 {
02078 struct ast_channel *chan;
02079 struct ast_frame *f;
02080
02081 chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Onhold/%s",rchan->name);
02082 if (chan) {
02083
02084 ast_string_field_build(chan, name, "Onhold/%s",rchan->name);
02085
02086 chan->readformat = rchan->readformat;
02087 chan->writeformat = rchan->writeformat;
02088 ast_channel_masquerade(chan, rchan);
02089
02090 strncpy(chan->context, rchan->context, sizeof(chan->context) - 1);
02091 strncpy(chan->exten, rchan->exten, sizeof(chan->exten) - 1);
02092 chan->priority = rchan->priority;
02093
02094 ast_string_field_build(chan, uniqueid, "%s",rchan->uniqueid);
02095
02096 f = ast_read(chan);
02097 if (f)
02098 ast_frfree(f);
02099 ast_hold_call(chan, peer);
02100 return -1;
02101 } else {
02102 ast_log(LOG_WARNING, "Unable to create holded channel\n");
02103 return -1;
02104 }
02105 return 0;
02106 }
02107
02108 int ast_retrieve_call(struct ast_channel *chan, char *uniqueid)
02109 {
02110 int res=-1, dres=-1;
02111 struct ast_channel *peer=NULL;
02112 struct ast_bridge_config config;
02113
02114 peer = ast_get_holded_call(uniqueid);
02115
02116
02117 if (chan->_state != AST_STATE_UP) {
02118 ast_answer(chan);
02119 }
02120
02121 if (peer) {
02122 ast_mutex_unlock(&peer->lock);
02123 ast_moh_stop(peer);
02124 res = ast_channel_make_compatible(chan, peer);
02125 if (res < 0) {
02126 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
02127 ast_hangup(peer);
02128 return -1;
02129 }
02130
02131
02132 if (option_verbose > 2)
02133 ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to holded call %s\n", chan->name, peer->name);
02134
02135 memset(&config,0,sizeof(struct ast_bridge_config));
02136 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
02137 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
02138 config.timelimit = 0;
02139 config.play_warning = 0;
02140 config.warning_freq = 0;
02141 config.warning_sound=NULL;
02142 res = ast_bridge_call(chan,peer,&config);
02143
02144
02145 if (res != AST_PBX_NO_HANGUP_PEER)
02146 ast_hangup(peer);
02147 return res;
02148 } else {
02149
02150 dres = ast_streamfile(chan, "pbx-invalidpark", chan->language);
02151 if (!dres)
02152 dres = ast_waitstream(chan, "");
02153 else {
02154 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
02155 dres = 0;
02156 }
02157 }
02158 return res;
02159 }
02160
02161 int ast_retrieve_call_to_death(char *uniqueid)
02162 {
02163 int res=-1;
02164 struct ast_channel *peer=NULL;
02165
02166 peer = ast_get_holded_call(uniqueid);
02167
02168 if (peer) {
02169 res=0;
02170 if (option_verbose > 2)
02171 ast_verbose(VERBOSE_PREFIX_3 "Channel %s removed from hold.\n", peer->name);
02172 ast_mutex_unlock(&peer->lock);
02173 ast_hangup(peer);
02174 } else {
02175 ast_log(LOG_WARNING, "Could not find channel with uniqueid %s to retrieve.\n", uniqueid);
02176 }
02177 return res;
02178 }
02179
02180 struct ast_channel *ast_get_holded_call(char *uniqueid)
02181 {
02182 int res=-1;
02183 struct ast_channel *peer=NULL;
02184 struct holdeduser *pu, *pl=NULL;
02185
02186 ast_mutex_lock(&holding_lock);
02187 pu = holdlist;
02188 while(pu) {
02189 if (!strncmp(uniqueid,pu->uniqueid,sizeof(pu->uniqueid))) {
02190 if (pl)
02191 pl->next = pu->next;
02192 else
02193 holdlist = pu->next;
02194 break;
02195 }
02196 pl = pu;
02197 pu = pu->next;
02198 }
02199 ast_mutex_unlock(&holding_lock);
02200 if (pu) {
02201 peer = ast_get_channel_by_uniqueid_locked(pu->uniqueid);
02202 free(pu);
02203 if (peer) {
02204 res=0;
02205 if (option_verbose > 2)
02206 ast_verbose(VERBOSE_PREFIX_3 "Channel %s removed from hold.\n", peer->name);
02207 ast_moh_stop(peer);
02208 return peer;
02209 } else {
02210 if (option_verbose > 2)
02211 ast_verbose(VERBOSE_PREFIX_3 "Could not find channel with uniqueid %s.\n", uniqueid);
02212 return NULL;
02213 }
02214 } else {
02215 ast_log(LOG_WARNING, "Could not find held channel with uniqueid %s to retrieve.\n", uniqueid);
02216 }
02217 return NULL;
02218 }
02219
02220
02221 static void *do_holding_thread(void *ignore)
02222 {
02223 int ms, tms, max;
02224 struct holdeduser *pu, *pl, *pt = NULL;
02225 struct timeval tv;
02226 struct ast_frame *f;
02227 int x;
02228 fd_set rfds, efds;
02229 fd_set nrfds, nefds;
02230 FD_ZERO(&rfds);
02231 FD_ZERO(&efds);
02232 for (;;) {
02233 ms = -1;
02234 max = -1;
02235 ast_mutex_lock(&holding_lock);
02236 pl = NULL;
02237 pu = holdlist;
02238 gettimeofday(&tv, NULL);
02239 FD_ZERO(&nrfds);
02240 FD_ZERO(&nefds);
02241 while(pu) {
02242 tms = (tv.tv_sec - pu->start.tv_sec) * 1000 + (tv.tv_usec - pu->start.tv_usec) / 1000;
02243 for (x=0;x<AST_MAX_FDS;x++) {
02244 if ((pu->chan->fds[x] > -1) && (FD_ISSET(pu->chan->fds[x], &rfds) || FD_ISSET(pu->chan->fds[x], &efds))) {
02245 if (FD_ISSET(pu->chan->fds[x], &efds))
02246 ast_set_flag(pu->chan, AST_FLAG_EXCEPTION);
02247 else
02248 ast_clear_flag(pu->chan, AST_FLAG_EXCEPTION);
02249 pu->chan->fdno = x;
02250
02251 f = ast_read(pu->chan);
02252 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
02253
02254 if (option_verbose > 1)
02255 ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being onhold\n", pu->chan->name);
02256 ast_hangup(pu->chan);
02257
02258
02259
02260 if (pl)
02261 pl->next = pu->next;
02262 else
02263 holdlist = pu->next;
02264 pt = pu;
02265 pu = pu->next;
02266 free(pt);
02267 break;
02268 } else {
02269
02270 ast_frfree(f);
02271 goto std;
02272 }
02273 }
02274 }
02275 if (x >= AST_MAX_FDS) {
02276 std: for (x=0;x<AST_MAX_FDS;x++) {
02277
02278 if (pu->chan->fds[x] > -1) {
02279 FD_SET(pu->chan->fds[x], &nrfds);
02280 FD_SET(pu->chan->fds[x], &nefds);
02281 if (pu->chan->fds[x] > max)
02282 max = pu->chan->fds[x];
02283 }
02284 }
02285
02286 if ((tms < ms) || (ms < 0))
02287 ms = tms;
02288 pl = pu;
02289 pu = pu->next;
02290 }
02291 }
02292 ast_mutex_unlock(&holding_lock);
02293 rfds = nrfds;
02294 efds = nefds;
02295 tv.tv_sec = ms / 1000;
02296 tv.tv_usec = (ms % 1000) * 1000;
02297
02298 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
02299 pthread_testcancel();
02300 }
02301 return NULL;
02302 }
02303
02304 static int retrieve_call_exec(struct ast_channel *chan, void *data) {
02305 int res=0;
02306 struct ast_module_user *u;
02307 char *uniqueid = (char *)data;
02308 u = ast_module_user_add(chan);
02309 res = ast_retrieve_call(chan, uniqueid);
02310 ast_module_user_remove(u);
02311 return res;
02312 }
02313
02314 static int handle_showfeatures(int fd, int argc, char *argv[])
02315 {
02316 int i;
02317 struct ast_call_feature *feature;
02318 char format[] = "%-25s %-7s %-7s\n";
02319
02320 ast_cli(fd, format, "Builtin Feature", "Default", "Current");
02321 ast_cli(fd, format, "---------------", "-------", "-------");
02322
02323 ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext());
02324
02325 ast_rwlock_rdlock(&features_lock);
02326 for (i = 0; i < FEATURES_COUNT; i++)
02327 ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
02328 ast_rwlock_unlock(&features_lock);
02329
02330 ast_cli(fd, "\n");
02331 ast_cli(fd, format, "Dynamic Feature", "Default", "Current");
02332 ast_cli(fd, format, "---------------", "-------", "-------");
02333 if (AST_LIST_EMPTY(&feature_list))
02334 ast_cli(fd, "(none)\n");
02335 else {
02336 AST_LIST_LOCK(&feature_list);
02337 AST_LIST_TRAVERSE(&feature_list, feature, feature_entry)
02338 ast_cli(fd, format, feature->sname, "no def", feature->exten);
02339 AST_LIST_UNLOCK(&feature_list);
02340 }
02341 ast_cli(fd, "\nCall parking\n");
02342 ast_cli(fd, "------------\n");
02343 ast_cli(fd,"%-20s: %s\n", "Parking extension", parking_ext);
02344 ast_cli(fd,"%-20s: %s\n", "Parking context", parking_con);
02345 ast_cli(fd,"%-20s: %d-%d\n", "Parked call extensions", parking_start, parking_stop);
02346 ast_cli(fd,"\n");
02347
02348 return RESULT_SUCCESS;
02349 }
02350
02351 static char showfeatures_help[] =
02352 "Usage: feature list\n"
02353 " Lists currently configured features.\n";
02354
02355 static int handle_parkedcalls(int fd, int argc, char *argv[])
02356 {
02357 struct parkeduser *cur;
02358 int numparked = 0;
02359
02360 ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
02361 , "Context", "Extension", "Pri", "Timeout");
02362
02363 ast_mutex_lock(&parking_lock);
02364
02365 for (cur = parkinglot; cur; cur = cur->next) {
02366 ast_cli(fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n"
02367 ,cur->parkingexten, cur->chan->name, cur->context, cur->exten
02368 ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
02369
02370 numparked++;
02371 }
02372 ast_mutex_unlock(&parking_lock);
02373 ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : "");
02374
02375
02376 return RESULT_SUCCESS;
02377 }
02378
02379 static char showparked_help[] =
02380 "Usage: show parkedcalls\n"
02381 " Lists currently parked calls.\n";
02382
02383 static struct ast_cli_entry cli_show_features_deprecated = {
02384 { "show", "features", NULL },
02385 handle_showfeatures, NULL,
02386 NULL };
02387
02388 static char showautoanswer_help[] =
02389 "Usage: show autoanswer\n"
02390 " Lists currently logged in autoanswer users.\n";
02391
02392
02393
02394 static int manager_parking_status( struct mansession *s, const struct message *m)
02395 {
02396 struct parkeduser *cur;
02397 const char *id = astman_get_header(m, "ActionID");
02398 char idText[256] = "";
02399
02400 if (!ast_strlen_zero(id))
02401 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
02402
02403 astman_send_ack(s, m, "Parked calls will follow");
02404
02405 ast_mutex_lock(&parking_lock);
02406
02407 for (cur = parkinglot; cur; cur = cur->next) {
02408 astman_append(s, "Event: ParkedCall\r\n"
02409 "Exten: %d\r\n"
02410 "Channel: %s\r\n"
02411 "From: %s\r\n"
02412 "Timeout: %ld\r\n"
02413 "CallerID: %s\r\n"
02414 "CallerIDName: %s\r\n"
02415 "Unqiueid: %s\r\n\r\n"
02416 "%s"
02417 "\r\n",
02418 cur->parkingnum, cur->chan->name, cur->peername,
02419 (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
02420 S_OR(cur->chan->cid.cid_num, ""),
02421 S_OR(cur->chan->cid.cid_name, ""), cur->chan->uniqueid,
02422 idText);
02423 }
02424
02425 astman_append(s,
02426 "Event: ParkedCallsComplete\r\n"
02427 "%s"
02428 "\r\n",idText);
02429
02430 ast_mutex_unlock(&parking_lock);
02431
02432 return RESULT_SUCCESS;
02433 }
02434
02435 static char mandescr_park[] =
02436 "Description: Park a channel.\n"
02437 "Variables: (Names marked with * are required)\n"
02438 " *Channel: Channel name to park\n"
02439 " *Channel2: Channel to announce park info to (and return to if timeout)\n"
02440 " Timeout: Number of milliseconds to wait before callback.\n";
02441
02442 static int manager_park(struct mansession *s, const struct message *m)
02443 {
02444 const char *channel = astman_get_header(m, "Channel");
02445 const char *channel2 = astman_get_header(m, "Channel2");
02446 const char *timeout = astman_get_header(m, "Timeout");
02447 char buf[BUFSIZ];
02448 int to = 0;
02449 int res = 0;
02450 int parkExt = 0;
02451 struct ast_channel *ch1, *ch2;
02452
02453 if (ast_strlen_zero(channel)) {
02454 astman_send_error(s, m, "Channel not specified");
02455 return 0;
02456 }
02457
02458 if (ast_strlen_zero(channel2)) {
02459 astman_send_error(s, m, "Channel2 not specified");
02460 return 0;
02461 }
02462
02463 ch1 = ast_get_channel_by_name_locked(channel);
02464 if (!ch1) {
02465 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
02466 astman_send_error(s, m, buf);
02467 return 0;
02468 }
02469
02470 ch2 = ast_get_channel_by_name_locked(channel2);
02471 if (!ch2) {
02472 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
02473 astman_send_error(s, m, buf);
02474 ast_channel_unlock(ch1);
02475 return 0;
02476 }
02477
02478 if (!ast_strlen_zero(timeout)) {
02479 sscanf(timeout, "%d", &to);
02480 }
02481
02482 res = ast_masq_park_call(ch1, ch2, to, &parkExt);
02483 if (!res) {
02484 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
02485 astman_send_ack(s, m, "Park successful");
02486 } else {
02487 astman_send_error(s, m, "Park failure");
02488 }
02489
02490 ast_channel_unlock(ch1);
02491 ast_channel_unlock(ch2);
02492
02493 return 0;
02494 }
02495
02496 static int handle_autoanswer(int fd, int argc, char *argv[])
02497 {
02498 struct aauser *cur;
02499
02500 ast_cli(fd, "%25s %10s %15s \n", "Channel"
02501 , "Extension", "Context");
02502
02503 ast_mutex_lock(&autoanswer_lock);
02504
02505 cur=aalot;
02506 while(cur) {
02507 ast_cli(fd, "%25s %10s %15s\n",cur->chan->name, cur->exten, cur->context);
02508
02509 cur = cur->next;
02510 }
02511
02512 ast_mutex_unlock(&autoanswer_lock);
02513
02514 return RESULT_SUCCESS;
02515 }
02516
02517 static struct ast_cli_entry cli_features[] = {
02518 { { "feature", "list", NULL },
02519 handle_showfeatures, "Lists configured features",
02520 showfeatures_help, NULL, &cli_show_features_deprecated },
02521
02522 { { "show", "parkedcalls", NULL },
02523 handle_parkedcalls, "Lists parked calls",
02524 showparked_help },
02525
02526 { { "show", "autoanswer", NULL },
02527 handle_autoanswer, "Lists autoanswer users",
02528 showautoanswer_help },
02529 };
02530 int ast_masq_autoanswer_login(struct ast_channel *rchan, void *data)
02531 {
02532 struct ast_channel *chan;
02533 struct ast_frame *f;
02534
02535 chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Autoanswer/%s", rchan->name);
02536 if (chan) {
02537
02538 ast_string_field_build(chan, name, "Autoanswer/%s",rchan->name);
02539
02540 chan->readformat = rchan->readformat;
02541 chan->writeformat = rchan->writeformat;
02542 ast_channel_masquerade(chan, rchan);
02543
02544 strncpy(chan->context, rchan->context, sizeof(chan->context) - 1);
02545 strncpy(chan->exten, rchan->exten, sizeof(chan->exten) - 1);
02546 chan->priority = rchan->priority;
02547
02548 ast_string_field_build(chan, uniqueid, "%s",rchan->uniqueid);
02549
02550 f = ast_read(chan);
02551 if (f)
02552 ast_frfree(f);
02553 ast_autoanswer_login(chan, data);
02554 } else {
02555 ast_log(LOG_WARNING, "Unable to create aa channel\n");
02556 return -1;
02557 }
02558 return 0;
02559 }
02560
02561 static int autoanswer_login_exec(struct ast_channel *chan, void *data)
02562 {
02563 int res=0;
02564 struct ast_module_user *u;
02565
02566 u = ast_module_user_add(chan);
02567 if (!data) {
02568 ast_log(LOG_WARNING, "AutoanswerLogin requires an argument (extension number)\n");
02569 return -1;
02570 }
02571 res = ast_masq_autoanswer_login(chan, data);
02572 ast_module_user_remove(u);
02573 return res;
02574 }
02575
02576 int ast_autoanswer_login(struct ast_channel *chan, void *data)
02577 {
02578
02579
02580 struct ast_context *con;
02581 char exten[AST_MAX_EXTENSION];
02582 struct aauser *pu,*pl = NULL;
02583 char *s, *stringp, *aacontext, *aaexten = NULL;
02584
02585 s = ast_strdupa((void *) data);
02586 stringp=s;
02587 aacontext = strsep(&stringp, "|");
02588 aaexten = strsep(&stringp, "|");
02589 if (!aaexten) {
02590 aaexten = aacontext;
02591 aacontext = NULL;
02592 }
02593 if (!aaexten) {
02594 ast_log(LOG_WARNING, "AutoanswerLogin requires at least an extension!\n");
02595 return -1;
02596 } else {
02597 if (!aacontext) {
02598 aacontext = "default";
02599 }
02600 }
02601
02602 ast_mutex_lock(&autoanswer_lock);
02603 pu = aalot;
02604 while(pu) {
02605 if ((!strncasecmp(pu->exten, aaexten, sizeof(pu->exten)-1)) && (!strncasecmp(pu->context, aacontext, sizeof(pu->context)-1))){
02606 if (pl)
02607 pl->next = pu->next;
02608 else
02609 aalot = pu->next;
02610 break;
02611 }
02612 pl = pu;
02613 pu = pu->next;
02614 }
02615 ast_mutex_unlock(&autoanswer_lock);
02616 if (pu) {
02617 ast_log(LOG_NOTICE, "Logout old Channel %s for %s@%s.\n",pu->chan->name, pu->exten, pu->context);
02618 manager_event(EVENT_FLAG_CALL, "AutoanswerLogout",
02619 "Channel: %s\r\n"
02620 "Uniqueid: %s\r\n"
02621 "Context: %s\r\n"
02622 "Exten: %s\r\n"
02623 ,pu->chan->name, pu->chan->uniqueid, pu->context, pu->exten);
02624 ast_hangup(pu->chan);
02625 free(pu);
02626 }
02627 pu = malloc(sizeof(struct aauser));
02628 if (pu) {
02629 memset(pu, 0, sizeof(pu));
02630 ast_mutex_lock(&autoanswer_lock);
02631 chan->appl = "Autoanswer";
02632 chan->data = NULL;
02633
02634 pu->chan = chan;
02635 if (chan->_state != AST_STATE_UP) {
02636 ast_answer(chan);
02637 }
02638
02639
02640 ast_moh_start(pu->chan, NULL, NULL);
02641 gettimeofday(&pu->start, NULL);
02642 strncpy(pu->exten, aaexten, sizeof(pu->exten)-1);
02643 strncpy(pu->context, aacontext, sizeof(pu->exten)-1);
02644 pu->next = aalot;
02645 aalot = pu;
02646 con = ast_context_find(aacontext);
02647 if (!con) {
02648 con = ast_context_create(NULL,aacontext, registrar);
02649 if (!con) {
02650 ast_log(LOG_ERROR, "Context '%s' does not exist and unable to create\n", aacontext);
02651 }
02652 }
02653 if (con) {
02654 snprintf(exten, sizeof(exten), "%s", aaexten);
02655 ast_add_extension2(con, 1, exten, 1, NULL, NULL, autoanswer, strdup((char *)data), free, registrar);
02656 }
02657
02658 ast_mutex_unlock(&autoanswer_lock);
02659
02660 pthread_kill(autoanswer_thread, SIGURG);
02661 if (option_verbose > 1)
02662 ast_verbose(VERBOSE_PREFIX_2 "Autoanswer login from %s for %s@%s.\n", pu->chan->name, pu->exten, pu->context);
02663 manager_event(EVENT_FLAG_CALL, "AutoanswerLogin",
02664 "Channel: %s\r\n"
02665 "Uniqueid: %s\r\n"
02666 "Context: %s\r\n"
02667 "Exten: %s\r\n"
02668 ,pu->chan->name, pu->chan->uniqueid, pu->context, pu->exten);
02669
02670 return 0;
02671 } else {
02672 ast_log(LOG_WARNING, "Out of memory\n");
02673 return -1;
02674 }
02675 return 0;
02676 }
02677
02678 static void autoanswer_reregister_extensions(void)
02679 {
02680 struct aauser *cur;
02681 struct ast_context *con;
02682 char exten[AST_MAX_EXTENSION];
02683 char args[AST_MAX_EXTENSION];
02684
02685 ast_mutex_lock(&autoanswer_lock);
02686
02687 cur=aalot;
02688 while(cur) {
02689 con = ast_context_find(cur->context);
02690 if (!con) {
02691 con = ast_context_create(NULL,cur->context, registrar);
02692 if (!con) {
02693 ast_log(LOG_ERROR, "Context '%s' does not exist and unable to create\n", cur->context);
02694 }
02695 }
02696 if (con) {
02697 snprintf(exten, sizeof(exten), "%s", cur->exten);
02698 snprintf(args, sizeof(args), "%s|%s", cur->context, cur->exten);
02699 ast_add_extension2(con, 1, exten, 1, NULL, NULL, autoanswer, strdup((char *)args), free, registrar);
02700 }
02701 cur = cur->next;
02702 }
02703
02704 ast_mutex_unlock(&autoanswer_lock);
02705 }
02706 static void *do_autoanswer_thread(void *ignore)
02707 {
02708 int ms, tms, max;
02709 struct ast_context *con;
02710 char exten[AST_MAX_EXTENSION];
02711 struct aauser *pu, *pl, *pt = NULL;
02712 struct timeval tv;
02713 struct ast_frame *f;
02714 int x;
02715 fd_set rfds, efds;
02716 fd_set nrfds, nefds;
02717 FD_ZERO(&rfds);
02718 FD_ZERO(&efds);
02719 for (;;) {
02720 ms = -1;
02721 max = -1;
02722 ast_mutex_lock(&autoanswer_lock);
02723 pl = NULL;
02724 pu = aalot;
02725 gettimeofday(&tv, NULL);
02726 FD_ZERO(&nrfds);
02727 FD_ZERO(&nefds);
02728 while(pu) {
02729 tms = (tv.tv_sec - pu->start.tv_sec) * 1000 + (tv.tv_usec - pu->start.tv_usec) / 1000;
02730 for (x=0;x<AST_MAX_FDS;x++) {
02731 if ((pu->chan->fds[x] > -1) && (FD_ISSET(pu->chan->fds[x], &rfds) || FD_ISSET(pu->chan->fds[x], &efds))) {
02732 if (FD_ISSET(pu->chan->fds[x], &efds))
02733 ast_set_flag(pu->chan, AST_FLAG_EXCEPTION);
02734 else
02735 ast_clear_flag(pu->chan, AST_FLAG_EXCEPTION);
02736 pu->chan->fdno = x;
02737
02738 f = ast_read(pu->chan);
02739 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
02740
02741 if (option_verbose > 1)
02742 ast_verbose(VERBOSE_PREFIX_2 "%s logged out of autoanswer app\n", pu->chan->name);
02743 manager_event(EVENT_FLAG_CALL, "AutoanswerLogout",
02744 "Channel: %s\r\n"
02745 "Uniqueid: %s\r\n"
02746 "Context: %s\r\n"
02747 "Exten: %s\r\n"
02748 ,pu->chan->name, pu->chan->uniqueid, pu->context, pu->exten);
02749 ast_hangup(pu->chan);
02750 con = ast_context_find(pu->context);
02751 if (con) {
02752 snprintf(exten, sizeof(exten), "%s", pu->exten);
02753 if (ast_context_remove_extension2(con, exten, 1, registrar))
02754 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
02755 } else {
02756 ast_log(LOG_WARNING, "Whoa, no %s context?\n", pu->exten);
02757 }
02758
02759 if (pl)
02760 pl->next = pu->next;
02761 else
02762 aalot = pu->next;
02763 pt = pu;
02764 pu = pu->next;
02765 free(pt);
02766 break;
02767 } else {
02768
02769 ast_frfree(f);
02770 goto std;
02771 }
02772 }
02773 }
02774 if (x >= AST_MAX_FDS) {
02775 std: for (x=0;x<AST_MAX_FDS;x++) {
02776
02777 if (pu->chan->fds[x] > -1) {
02778 FD_SET(pu->chan->fds[x], &nrfds);
02779 FD_SET(pu->chan->fds[x], &nefds);
02780 if (pu->chan->fds[x] > max)
02781 max = pu->chan->fds[x];
02782 }
02783 }
02784
02785 if ((tms < ms) || (ms < 0))
02786 ms = tms;
02787 pl = pu;
02788 pu = pu->next;
02789 }
02790 }
02791 ast_mutex_unlock(&autoanswer_lock);
02792 rfds = nrfds;
02793 efds = nefds;
02794 tv.tv_sec = ms / 1000;
02795 tv.tv_usec = (ms % 1000) * 1000;
02796
02797 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
02798 pthread_testcancel();
02799 }
02800 return NULL;
02801 }
02802
02803 static int autoanswer_exec(struct ast_channel *chan, void *data)
02804 {
02805 int res=0;
02806 struct ast_channel *peer=NULL;
02807 struct aauser *pu, *pl=NULL;
02808 struct ast_bridge_config config;
02809 char *s, *stringp, *aacontext, *aaexten = NULL;
02810 char datastring[80];
02811 struct ast_module_user *u;
02812
02813
02814 if (!data) {
02815 ast_log(LOG_WARNING, "Autoanswer requires an argument (extension number)\n");
02816 return -1;
02817 }
02818 s = ast_strdupa((void *) data);
02819 stringp=s;
02820 aacontext = strsep(&stringp, "|");
02821 aaexten = strsep(&stringp, "|");
02822 if (!aaexten) {
02823 aaexten = aacontext;
02824 aacontext = NULL;
02825 }
02826 if (!aaexten) {
02827 ast_log(LOG_WARNING, "AutoanswerLogin requires at least an extension!\n");
02828 return -1;
02829 } else {
02830 if (!aacontext) {
02831 aacontext = "default";
02832 }
02833 }
02834
02835 u = ast_module_user_add(chan);
02836 ast_mutex_lock(&autoanswer_lock);
02837 pu = aalot;
02838 while(pu) {
02839 if ((!strncasecmp(pu->exten, aaexten, sizeof(pu->exten)-1)) && (!strncasecmp(pu->context, aacontext, sizeof(pu->context)-1))){
02840 if (pl)
02841 pl->next = pu->next;
02842 else
02843 aalot = pu->next;
02844 break;
02845 }
02846 pl = pu;
02847 pu = pu->next;
02848 }
02849 ast_mutex_unlock(&autoanswer_lock);
02850 if (pu) {
02851 peer = pu->chan;
02852 free(pu);
02853 pu = NULL;
02854 }
02855
02856 if (chan->_state != AST_STATE_UP) {
02857 ast_answer(chan);
02858 }
02859
02860 if (peer) {
02861 ast_moh_stop(peer);
02862
02863 if (!ast_strlen_zero(courtesytone)) {
02864 if (!ast_streamfile(peer, courtesytone, peer->language)) {
02865 if (ast_waitstream(peer, "") < 0) {
02866 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
02867 ast_hangup(peer);
02868 return -1;
02869 }
02870 }
02871 }
02872
02873 res = ast_channel_make_compatible(chan, peer);
02874 if (res < 0) {
02875 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
02876 ast_hangup(peer);
02877 return -1;
02878 }
02879
02880
02881 if (option_verbose > 2)
02882 ast_verbose(VERBOSE_PREFIX_3 "Channel %s autoanswered %s\n", peer->name, chan->name);
02883 manager_event(EVENT_FLAG_CALL, "Autoanswer",
02884 "Channel: %s\r\n"
02885 "Uniqueid: %s\r\n"
02886 "Channel2: %s\r\n"
02887 "Uniqueid2: %s\r\n"
02888 "Context: %s\r\n"
02889 "Exten: %s\r\n"
02890 ,chan->name, chan->uniqueid, peer->name, peer->uniqueid, aacontext, aaexten);
02891
02892
02893 memset(&config,0,sizeof(struct ast_bridge_config));
02894 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
02895 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
02896 config.timelimit = 0;
02897 config.play_warning = 0;
02898 config.warning_freq = 0;
02899 config.warning_sound=NULL;
02900 res = ast_bridge_call(chan,peer,&config);
02901
02902 if (option_verbose > 2)
02903 ast_verbose(VERBOSE_PREFIX_3 "returning from bridge %s\n", peer->name);
02904
02905 snprintf(datastring, sizeof(datastring) - 1, "%s|%s", aacontext, aaexten);
02906 ast_autoanswer_login(peer, datastring);
02907 return res;
02908 } else {
02909 if (option_verbose > 2)
02910 ast_verbose(VERBOSE_PREFIX_3 "Nobody logged in for autoanswer %s@%s\n", aaexten, aacontext);
02911 res = -1;
02912 }
02913 ast_module_user_remove(u);
02914 return res;
02915 }
02916
02917
02918 int ast_pickup_call(struct ast_channel *chan)
02919 {
02920 struct ast_channel *cur = NULL;
02921 int res = -1;
02922
02923 while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
02924 if (!cur->pbx &&
02925 (cur != chan) &&
02926 (chan->pickupgroup & cur->callgroup) &&
02927 ((cur->_state == AST_STATE_RINGING) ||
02928 (cur->_state == AST_STATE_RING))) {
02929 break;
02930 }
02931 ast_channel_unlock(cur);
02932 }
02933 if (cur) {
02934 if (option_debug)
02935 ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
02936 res = ast_answer(chan);
02937 if (res)
02938 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
02939 res = ast_queue_control(chan, AST_CONTROL_ANSWER);
02940 if (res)
02941 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
02942 res = ast_channel_masquerade(cur, chan);
02943 if (res)
02944 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);
02945 ast_channel_unlock(cur);
02946 } else {
02947 if (option_debug)
02948 ast_log(LOG_DEBUG, "No call pickup possible...\n");
02949 }
02950 return res;
02951 }
02952
02953
02954 static void park_add_hints(char *context, int start, int stop)
02955 {
02956 int numext;
02957 char device[AST_MAX_EXTENSION];
02958 char exten[10];
02959
02960 for (numext = start; numext <= stop; numext++) {
02961 snprintf(exten, sizeof(exten), "%d", numext);
02962 snprintf(device, sizeof(device), "park:%s@%s", exten, context);
02963 ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
02964 }
02965 }
02966
02967
02968 static int load_config(void)
02969 {
02970 int start = 0, end = 0;
02971 int res;
02972 struct ast_context *con = NULL;
02973 struct ast_config *cfg = NULL;
02974 struct ast_variable *var = NULL;
02975 char old_parking_ext[AST_MAX_EXTENSION];
02976 char old_parking_con[AST_MAX_EXTENSION] = "";
02977
02978 if (!ast_strlen_zero(parking_con)) {
02979 strcpy(old_parking_ext, parking_ext);
02980 strcpy(old_parking_con, parking_con);
02981 }
02982
02983
02984 strcpy(parking_con, "parkedcalls");
02985 strcpy(parking_con_dial, "park-dial");
02986 strcpy(parking_ext, "700");
02987 strcpy(pickup_ext, "*8");
02988 strcpy(parkmohclass, "default");
02989 courtesytone[0] = '\0';
02990 strcpy(xfersound, "beep");
02991 strcpy(xferfailsound, "pbx-invalid");
02992 parking_start = 701;
02993 parking_stop = 750;
02994 parkfindnext = 0;
02995 adsipark = 0;
02996 parkaddhints = 0;
02997
02998 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
02999 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
03000 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
03001
03002 cfg = ast_config_load("features.conf");
03003 if (!cfg) {
03004 ast_log(LOG_WARNING,"Could not load features.conf\n");
03005 return AST_MODULE_LOAD_DECLINE;
03006 }
03007 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
03008 if (!strcasecmp(var->name, "parkext")) {
03009 ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
03010 } else if (!strcasecmp(var->name, "context")) {
03011 ast_copy_string(parking_con, var->value, sizeof(parking_con));
03012 } else if (!strcasecmp(var->name, "parkingtime")) {
03013 if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) {
03014 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
03015 parkingtime = DEFAULT_PARK_TIME;
03016 } else
03017 parkingtime = parkingtime * 1000;
03018 } else if (!strcasecmp(var->name, "parkpos")) {
03019 if (sscanf(var->value, "%d-%d", &start, &end) != 2) {
03020 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);
03021 } else {
03022 parking_start = start;
03023 parking_stop = end;
03024 }
03025 } else if (!strcasecmp(var->name, "findslot")) {
03026 parkfindnext = (!strcasecmp(var->value, "next"));
03027 } else if (!strcasecmp(var->name, "parkinghints")) {
03028 parkaddhints = ast_true(var->value);
03029 } else if (!strcasecmp(var->name, "adsipark")) {
03030 adsipark = ast_true(var->value);
03031 } else if (!strcasecmp(var->name, "transferdigittimeout")) {
03032 if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
03033 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
03034 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
03035 } else
03036 transferdigittimeout = transferdigittimeout * 1000;
03037 } else if (!strcasecmp(var->name, "featuredigittimeout")) {
03038 if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
03039 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
03040 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
03041 }
03042 } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) {
03043 if ((sscanf(var->value, "%d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) {
03044 ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value);
03045 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
03046 } else
03047 atxfernoanswertimeout = atxfernoanswertimeout * 1000;
03048 } else if (!strcasecmp(var->name, "courtesytone")) {
03049 ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
03050 } else if (!strcasecmp(var->name, "parkedplay")) {
03051 if (!strcasecmp(var->value, "both"))
03052 parkedplay = 2;
03053 else if (!strcasecmp(var->value, "parked"))
03054 parkedplay = 1;
03055 else
03056 parkedplay = 0;
03057 } else if (!strcasecmp(var->name, "xfersound")) {
03058 ast_copy_string(xfersound, var->value, sizeof(xfersound));
03059 } else if (!strcasecmp(var->name, "xferfailsound")) {
03060 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
03061 } else if (!strcasecmp(var->name, "pickupexten")) {
03062 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
03063 } else if (!strcasecmp(var->name, "parkedmusicclass")) {
03064 ast_copy_string(parkmohclass, var->value, sizeof(parkmohclass));
03065 }
03066 }
03067
03068 unmap_features();
03069 for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) {
03070 if (remap_feature(var->name, var->value))
03071 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
03072 }
03073
03074
03075 ast_unregister_features();
03076 for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) {
03077 char *tmp_val = ast_strdupa(var->value);
03078 char *exten, *activateon, *activatedby, *app, *app_args, *moh_class;
03079 struct ast_call_feature *feature;
03080
03081
03082
03083
03084
03085 exten = strsep(&tmp_val,",");
03086 activatedby = strsep(&tmp_val,",");
03087 app = strsep(&tmp_val,",");
03088 app_args = strsep(&tmp_val,",");
03089 moh_class = strsep(&tmp_val,",");
03090
03091 activateon = strsep(&activatedby, "/");
03092
03093
03094 if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) {
03095 ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",
03096 app, exten, activateon, var->name);
03097 continue;
03098 }
03099
03100 AST_LIST_LOCK(&feature_list);
03101 if ((feature = find_dynamic_feature(var->name))) {
03102 AST_LIST_UNLOCK(&feature_list);
03103 ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name);
03104 continue;
03105 }
03106 AST_LIST_UNLOCK(&feature_list);
03107
03108 if (!(feature = ast_calloc(1, sizeof(*feature))))
03109 continue;
03110
03111 ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN);
03112 ast_copy_string(feature->app, app, FEATURE_APP_LEN);
03113 ast_copy_string(feature->exten, exten, FEATURE_EXTEN_LEN);
03114
03115 if (app_args)
03116 ast_copy_string(feature->app_args, app_args, FEATURE_APP_ARGS_LEN);
03117
03118 if (moh_class)
03119 ast_copy_string(feature->moh_class, moh_class, FEATURE_MOH_LEN);
03120
03121 ast_copy_string(feature->exten, exten, sizeof(feature->exten));
03122 feature->operation = feature_exec_app;
03123 ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF);
03124
03125
03126 if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller"))
03127 ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF);
03128 else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee"))
03129 ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER);
03130 else {
03131 ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s',"
03132 " must be 'self', or 'peer'\n", var->name);
03133 continue;
03134 }
03135
03136 if (ast_strlen_zero(activatedby))
03137 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
03138 else if (!strcasecmp(activatedby, "caller"))
03139 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER);
03140 else if (!strcasecmp(activatedby, "callee"))
03141 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE);
03142 else if (!strcasecmp(activatedby, "both"))
03143 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
03144 else {
03145 ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s',"
03146 " must be 'caller', or 'callee', or 'both'\n", var->name);
03147 continue;
03148 }
03149
03150 ast_register_feature(feature);
03151
03152 if (option_verbose >= 1)
03153 ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, app, app_args, exten);
03154 }
03155 ast_config_destroy(cfg);
03156
03157
03158 if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) {
03159 if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar))
03160 notify_metermaids(old_parking_ext, old_parking_con);
03161 if (option_debug)
03162 ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
03163 }
03164
03165 if (!(con = ast_context_find(parking_con)) && !(con = ast_context_create(NULL, parking_con, registrar))) {
03166 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
03167 return -1;
03168 }
03169 res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar);
03170 if (parkaddhints)
03171 park_add_hints(parking_con, parking_start, parking_stop);
03172 if (!res)
03173 notify_metermaids(ast_parking_ext(), parking_con);
03174 return res;
03175
03176 }
03177
03178 static int reload(void)
03179 {
03180 autoanswer_reregister_extensions();
03181 return load_config();
03182 }
03183
03184 static int load_module(void)
03185 {
03186 int res;
03187
03188 memset(parking_ext, 0, sizeof(parking_ext));
03189 memset(parking_con, 0, sizeof(parking_con));
03190
03191 if ((res = load_config()))
03192 return res;
03193 ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
03194 ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
03195 ast_pthread_create(&holding_thread, NULL, do_holding_thread, NULL);
03196 res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
03197 if (!res)
03198 res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
03199 if (!res) {
03200 ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" );
03201 ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park,
03202 "Park a channel", mandescr_park);
03203 }
03204
03205 res |= ast_register_application(holdedcall, retrieve_call_exec, synopsis, descrip);
03206 ast_pthread_create(&autoanswer_thread, NULL, do_autoanswer_thread, NULL);
03207 if (!res)
03208 res |= ast_register_application(autoanswerlogin, autoanswer_login_exec, synopsis3, descrip3);
03209 if (!res)
03210 res |= ast_register_application(autoanswer, autoanswer_exec, synopsis4, descrip4);
03211
03212 res |= ast_devstate_prov_add("Park", metermaidstate);
03213
03214 return res;
03215 }
03216
03217
03218 static int unload_module(void)
03219 {
03220 ast_module_user_hangup_all();
03221
03222 ast_manager_unregister("ParkedCalls");
03223 ast_manager_unregister("Park");
03224 ast_cli_unregister_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
03225 ast_unregister_application(parkcall);
03226 ast_unregister_application(autoanswer);
03227 ast_unregister_application(autoanswerlogin);
03228 ast_unregister_application(holdedcall);
03229 ast_devstate_prov_del("Park");
03230 return ast_unregister_application(parkedcall);
03231 }
03232
03233 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Call Features Resource",
03234 .load = load_module,
03235 .unload = unload_module,
03236 .reload = reload,
03237 );