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