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