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