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