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