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