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