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