#include <pthread.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <netinet/in.h>
#include "asterisk.h"
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/options.h"
#include "asterisk/causes.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/app.h"
#include "asterisk/say.h"
#include "asterisk/features.h"
#include "asterisk/musiconhold.h"
#include "asterisk/config.h"
#include "asterisk/cli.h"
#include "asterisk/manager.h"
#include "asterisk/utils.h"
#include "asterisk/adsi.h"
#include "asterisk/monitor.h"
Go to the source code of this file.
Data Structures | |
struct | ast_bridge_thread_obj |
struct | parkeduser |
Defines | |
#define | AST_MAX_WATCHERS 256 |
#define | DEFAULT_FEATURE_DIGIT_TIMEOUT 500 |
#define | DEFAULT_PARK_TIME 45000 |
#define | DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000 |
#define | FEATURE_RETURN_HANGUP -1 |
#define | FEATURE_RETURN_NO_HANGUP_PEER AST_PBX_NO_HANGUP_PEER |
#define | FEATURE_RETURN_PASSDIGITS 21 |
#define | FEATURE_RETURN_PBX_KEEPALIVE AST_PBX_KEEPALIVE |
#define | FEATURE_RETURN_STOREDIGITS 22 |
#define | FEATURE_RETURN_SUCCESS 23 |
#define | FEATURE_RETURN_SUCCESSBREAK 0 |
#define | FEATURE_SENSE_CHAN (1 << 0) |
#define | FEATURE_SENSE_PEER (1 << 1) |
#define | FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0])) |
#define | FREE free |
Functions | |
static int | adsi_announce_park (struct ast_channel *chan, int parkingnum) |
int | ast_bridge_call (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config) |
Bridge a call, optionally allowing redirection. | |
static void * | ast_bridge_call_thread (void *data) |
static void | ast_bridge_call_thread_launch (void *data) |
static int | ast_feature_interpret (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) |
static struct ast_channel * | ast_feature_request_and_dial (struct ast_channel *caller, const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name) |
static | AST_LIST_HEAD_STATIC (feature_list, ast_call_feature) |
int | ast_masq_park_call (struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout) |
Park a call via a masqueraded channel. | |
AST_MUTEX_DEFINE_STATIC (parking_lock) | |
int | ast_park_call (struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout) |
Park a call and read back parked location. | |
char * | ast_parking_ext (void) |
Determine system parking extension Returns the call parking extension for drivers that provide special call parking help. | |
int | ast_pickup_call (struct ast_channel *chan) |
Pickup a call. | |
char * | ast_pickup_ext (void) |
Determine system call pickup extension. | |
void | ast_register_feature (struct ast_call_feature *feature) |
register new feature into feature_set | |
void | ast_unregister_feature (struct ast_call_feature *feature) |
unregister feature from feature_set | |
static void | ast_unregister_features (void) |
static int | builtin_atxfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) |
static int | builtin_automonitor (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) |
static int | builtin_blindtransfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) |
static int | builtin_disconnect (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) |
static void | check_goto_on_transfer (struct ast_channel *chan) |
char * | description (void) |
Provides a description of the module. | |
static void * | do_parking_thread (void *ignore) |
static int | feature_exec_app (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) |
static struct ast_call_feature * | find_feature (char *name) |
static int | handle_parkedcalls (int fd, int argc, char *argv[]) |
static int | handle_showfeatures (int fd, int argc, char *argv[]) |
char * | key () |
Returns the ASTERISK_GPL_KEY. | |
static int | load_config (void) |
int | load_module (void) |
Initialize the module. | |
static int | manager_parking_status (struct mansession *s, struct message *m) |
static int | park_call_exec (struct ast_channel *chan, void *data) |
static int | park_exec (struct ast_channel *chan, void *data) |
int | reload (void) |
Reload stuff. | |
static int | remap_feature (const char *name, const char *value) |
static void | set_config_flags (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config) |
int | unload_module (void) |
Cleanup all module structures, sockets, etc. | |
static void | unmap_features (void) |
int | usecount (void) |
Provides a usecount. | |
Variables | |
static int | adsipark |
ast_call_feature | builtin_features [] |
static char | courtesytone [256] |
static char * | descrip |
static char * | descrip2 |
static int | featuredigittimeout |
LOCAL_USER_DECL | |
static struct ast_app * | monitor_app = NULL |
static int | monitor_ok = 1 |
static char * | parkcall = "Park" |
static char * | parkedcall = "ParkedCall" |
static int | parkfindnext |
static char | parking_con [AST_MAX_EXTENSION] |
static char | parking_con_dial [AST_MAX_EXTENSION] |
static char | parking_ext [AST_MAX_EXTENSION] |
static int | parking_offset |
static int | parking_start |
static int | parking_stop |
static pthread_t | parking_thread |
static struct parkeduser * | parkinglot |
static int | parkingtime = DEFAULT_PARK_TIME |
static char | pickup_ext [AST_MAX_EXTENSION] |
static char * | registrar = "res_features" |
static struct ast_cli_entry | showfeatures |
static char | showfeatures_help [] |
static struct ast_cli_entry | showparked |
static char | showparked_help [] |
STANDARD_LOCAL_USER | |
static char * | synopsis = "Answer a parked call" |
static char * | synopsis2 = "Park yourself" |
static int | transferdigittimeout |
static char | xferfailsound [256] |
static char | xfersound [256] |
Definition in file res_features.c.
|
Definition at line 73 of file res_features.c. |
|
Definition at line 71 of file res_features.c. Referenced by load_config(). |
|
Definition at line 69 of file res_features.c. Referenced by load_config(). |
|
Definition at line 70 of file res_features.c. Referenced by load_config(). |
|
Definition at line 435 of file res_features.c. Referenced by builtin_disconnect(). |
|
Definition at line 438 of file res_features.c. Referenced by feature_exec_app(). |
|
Definition at line 439 of file res_features.c. Referenced by ast_feature_interpret(). |
|
Definition at line 437 of file res_features.c. Referenced by feature_exec_app(). |
|
Definition at line 440 of file res_features.c. |
|
Definition at line 441 of file res_features.c. Referenced by builtin_atxfer(), builtin_automonitor(), builtin_blindtransfer(), and feature_exec_app(). |
|
Definition at line 436 of file res_features.c. Referenced by feature_exec_app(). |
|
Definition at line 443 of file res_features.c. Referenced by ast_feature_interpret(). |
|
Definition at line 444 of file res_features.c. Referenced by builtin_atxfer(), and builtin_blindtransfer(). |
|
Definition at line 862 of file res_features.c. Referenced by ast_feature_interpret(), ast_feature_request_and_dial(), remap_feature(), set_config_flags(), and unmap_features(). |
|
Definition at line 66 of file res_features.c. |
|
Definition at line 259 of file res_features.c. References ADSI_JUST_CENT, adsi_load_session(), adsi_print(), and justify. 00260 { 00261 int res; 00262 int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT}; 00263 char tmp[256]; 00264 char *message[5] = {NULL, NULL, NULL, NULL, NULL}; 00265 00266 snprintf(tmp, sizeof(tmp), "Parked on %d", parkingnum); 00267 message[0] = tmp; 00268 res = adsi_load_session(chan, NULL, 0, 1); 00269 if (res == -1) { 00270 return res; 00271 } 00272 return adsi_print(chan, message, justify, 1); 00273 }
|
|
Bridge a call, optionally allowing redirection.
Definition at line 1264 of file res_features.c. References ast_channel::appl, ast_answer(), ast_cdr_appenduserfield(), ast_cdr_setuserfield(), ast_channel_bridge(), ast_frfree(), ast_log(), ast_strlen_zero(), ast_channel::cdr, config, ast_channel::data, FEATURE_MAX_LEN, free, LOG_DEBUG, monitor_app, ast_channel::name, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), set_config_flags(), and ast_cdr::userfield. Referenced by ast_bridge_call_thread(), builtin_atxfer(), and park_exec(). 01265 { 01266 /* Copy voice back and forth between the two channels. Give the peer 01267 the ability to transfer calls with '#<extension' syntax. */ 01268 struct ast_frame *f; 01269 struct ast_channel *who; 01270 char chan_featurecode[FEATURE_MAX_LEN + 1]=""; 01271 char peer_featurecode[FEATURE_MAX_LEN + 1]=""; 01272 int res; 01273 int diff; 01274 int hasfeatures=0; 01275 int hadfeatures=0; 01276 struct ast_option_header *aoh; 01277 struct ast_bridge_config backup_config; 01278 char *monitor_exec; 01279 01280 memset(&backup_config, 0, sizeof(backup_config)); 01281 01282 config->start_time = ast_tvnow(); 01283 01284 if (chan && peer) { 01285 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name); 01286 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name); 01287 } else if (chan) 01288 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL); 01289 01290 if (monitor_ok) { 01291 if (!monitor_app) { 01292 if (!(monitor_app = pbx_findapp("Monitor"))) 01293 monitor_ok=0; 01294 } 01295 if (monitor_app) { 01296 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 01297 pbx_exec(chan, monitor_app, monitor_exec, 1); 01298 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR"))) 01299 pbx_exec(peer, monitor_app, monitor_exec, 1); 01300 } 01301 } 01302 01303 set_config_flags(chan, peer, config); 01304 config->firstpass = 1; 01305 01306 /* Answer if need be */ 01307 if (ast_answer(chan)) 01308 return -1; 01309 peer->appl = "Bridged Call"; 01310 peer->data = chan->name; 01311 01312 /* copy the userfield from the B-leg to A-leg if applicable */ 01313 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) { 01314 char tmp[256]; 01315 if (!ast_strlen_zero(chan->cdr->userfield)) { 01316 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield); 01317 ast_cdr_appenduserfield(chan, tmp); 01318 } else 01319 ast_cdr_setuserfield(chan, peer->cdr->userfield); 01320 /* free the peer's cdr without ast_cdr_free complaining */ 01321 free(peer->cdr); 01322 peer->cdr = NULL; 01323 } 01324 for (;;) { 01325 res = ast_channel_bridge(chan, peer, config, &f, &who); 01326 01327 if (config->feature_timer) { 01328 /* Update time limit for next pass */ 01329 diff = ast_tvdiff_ms(ast_tvnow(), config->start_time); 01330 config->feature_timer -= diff; 01331 if (hasfeatures) { 01332 /* Running on backup config, meaning a feature might be being 01333 activated, but that's no excuse to keep things going 01334 indefinitely! */ 01335 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) { 01336 ast_log(LOG_DEBUG, "Timed out, realtime this time!\n"); 01337 config->feature_timer = 0; 01338 who = chan; 01339 if (f) 01340 ast_frfree(f); 01341 f = NULL; 01342 res = 0; 01343 } else if (config->feature_timer <= 0) { 01344 /* Not *really* out of time, just out of time for 01345 digits to come in for features. */ 01346 ast_log(LOG_DEBUG, "Timed out for feature!\n"); 01347 if (!ast_strlen_zero(peer_featurecode)) { 01348 ast_dtmf_stream(chan, peer, peer_featurecode, 0); 01349 memset(peer_featurecode, 0, sizeof(peer_featurecode)); 01350 } 01351 if (!ast_strlen_zero(chan_featurecode)) { 01352 ast_dtmf_stream(peer, chan, chan_featurecode, 0); 01353 memset(chan_featurecode, 0, sizeof(chan_featurecode)); 01354 } 01355 if (f) 01356 ast_frfree(f); 01357 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 01358 if (!hasfeatures) { 01359 /* Restore original (possibly time modified) bridge config */ 01360 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 01361 memset(&backup_config, 0, sizeof(backup_config)); 01362 } 01363 hadfeatures = hasfeatures; 01364 /* Continue as we were */ 01365 continue; 01366 } else if (!f) { 01367 /* The bridge returned without a frame and there is a feature in progress. 01368 * However, we don't think the feature has quite yet timed out, so just 01369 * go back into the bridge. */ 01370 continue; 01371 } 01372 } else { 01373 if (config->feature_timer <=0) { 01374 /* We ran out of time */ 01375 config->feature_timer = 0; 01376 who = chan; 01377 if (f) 01378 ast_frfree(f); 01379 f = NULL; 01380 res = 0; 01381 } 01382 } 01383 } 01384 if (res < 0) { 01385 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name); 01386 return -1; 01387 } 01388 01389 if (!f || ((f->frametype == AST_FRAME_CONTROL) && ((f->subclass == AST_CONTROL_HANGUP) || (f->subclass == AST_CONTROL_BUSY) || 01390 (f->subclass == AST_CONTROL_CONGESTION)))) { 01391 res = -1; 01392 break; 01393 } 01394 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_RINGING)) { 01395 if (who == chan) 01396 ast_indicate(peer, AST_CONTROL_RINGING); 01397 else 01398 ast_indicate(chan, AST_CONTROL_RINGING); 01399 } 01400 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == -1)) { 01401 if (who == chan) 01402 ast_indicate(peer, -1); 01403 else 01404 ast_indicate(chan, -1); 01405 } 01406 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_FLASH)) { 01407 if (who == chan) 01408 ast_indicate(peer, AST_CONTROL_FLASH); 01409 else 01410 ast_indicate(chan, AST_CONTROL_FLASH); 01411 } 01412 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_OPTION)) { 01413 aoh = f->data; 01414 /* Forward option Requests */ 01415 if (aoh && (aoh->flag == AST_OPTION_FLAG_REQUEST)) { 01416 if (who == chan) 01417 ast_channel_setoption(peer, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0); 01418 else 01419 ast_channel_setoption(chan, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0); 01420 } 01421 } 01422 /* check for '*', if we find it it's time to disconnect */ 01423 if (f && (f->frametype == AST_FRAME_DTMF)) { 01424 char *featurecode; 01425 int sense; 01426 struct ast_channel *other; 01427 01428 hadfeatures = hasfeatures; 01429 /* This cannot overrun because the longest feature is one shorter than our buffer */ 01430 if (who == chan) { 01431 other = peer; 01432 sense = FEATURE_SENSE_CHAN; 01433 featurecode = chan_featurecode; 01434 } else { 01435 other = chan; 01436 sense = FEATURE_SENSE_PEER; 01437 featurecode = peer_featurecode; 01438 } 01439 featurecode[strlen(featurecode)] = f->subclass; 01440 /* Get rid of the frame before we start doing "stuff" with the channels */ 01441 ast_frfree(f); 01442 f = NULL; 01443 config->feature_timer = backup_config.feature_timer; 01444 res = ast_feature_interpret(chan, peer, config, featurecode, sense); 01445 switch(res) { 01446 case FEATURE_RETURN_PASSDIGITS: 01447 ast_dtmf_stream(other, who, featurecode, 0); 01448 /* Fall through */ 01449 case FEATURE_RETURN_SUCCESS: 01450 memset(featurecode, 0, sizeof(chan_featurecode)); 01451 break; 01452 } 01453 if (res >= FEATURE_RETURN_PASSDIGITS) { 01454 res = 0; 01455 } else 01456 break; 01457 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 01458 if (hadfeatures && !hasfeatures) { 01459 /* Restore backup */ 01460 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 01461 memset(&backup_config, 0, sizeof(struct ast_bridge_config)); 01462 } else if (hasfeatures) { 01463 if (!hadfeatures) { 01464 /* Backup configuration */ 01465 memcpy(&backup_config, config, sizeof(struct ast_bridge_config)); 01466 /* Setup temporary config options */ 01467 config->play_warning = 0; 01468 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); 01469 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); 01470 config->warning_freq = 0; 01471 config->warning_sound = NULL; 01472 config->end_sound = NULL; 01473 config->start_sound = NULL; 01474 config->firstpass = 0; 01475 } 01476 config->start_time = ast_tvnow(); 01477 config->feature_timer = featuredigittimeout; 01478 ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer); 01479 } 01480 } 01481 if (f) 01482 ast_frfree(f); 01483 } 01484 return res; 01485 }
|
|
Definition at line 217 of file res_features.c. References ast_channel::appl, ast_bridge_call(), ast_cdr_reset(), ast_cdr_setdestchan(), ast_hangup(), ast_bridge_thread_obj::bconfig, ast_channel::cdr, ast_bridge_thread_obj::chan, ast_channel::data, free, ast_channel::name, and ast_bridge_thread_obj::peer. Referenced by ast_bridge_call_thread_launch(). 00218 { 00219 struct ast_bridge_thread_obj *tobj = data; 00220 00221 tobj->chan->appl = "Transferred Call"; 00222 tobj->chan->data = tobj->peer->name; 00223 tobj->peer->appl = "Transferred Call"; 00224 tobj->peer->data = tobj->chan->name; 00225 if (tobj->chan->cdr) { 00226 ast_cdr_reset(tobj->chan->cdr, NULL); 00227 ast_cdr_setdestchan(tobj->chan->cdr, tobj->peer->name); 00228 } 00229 if (tobj->peer->cdr) { 00230 ast_cdr_reset(tobj->peer->cdr, NULL); 00231 ast_cdr_setdestchan(tobj->peer->cdr, tobj->chan->name); 00232 } 00233 00234 ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig); 00235 ast_hangup(tobj->chan); 00236 ast_hangup(tobj->peer); 00237 tobj->chan = tobj->peer = NULL; 00238 free(tobj); 00239 tobj=NULL; 00240 return NULL; 00241 }
|
|
Definition at line 243 of file res_features.c. References ast_bridge_call_thread(), and ast_pthread_create. Referenced by builtin_atxfer(). 00244 { 00245 pthread_t thread; 00246 pthread_attr_t attr; 00247 struct sched_param sched; 00248 00249 pthread_attr_init(&attr); 00250 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 00251 ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data); 00252 pthread_attr_destroy(&attr); 00253 memset(&sched, 0, sizeof(sched)); 00254 pthread_setschedparam(thread, SCHED_RR, &sched); 00255 }
|
|
Definition at line 987 of file res_features.c. References ast_copy_flags, AST_FLAGS_ALL, ast_log(), ast_strlen_zero(), ast_test_flag, builtin_features, config, ast_call_feature::feature_mask, FEATURE_RETURN_PASSDIGITS, FEATURE_SENSE_CHAN, features, FEATURES_COUNT, LOG_DEBUG, ast_channel::name, ast_call_feature::operation, and pbx_builtin_getvar_helper(). 00988 { 00989 int x; 00990 struct ast_flags features; 00991 int res = FEATURE_RETURN_PASSDIGITS; 00992 struct ast_call_feature *feature; 00993 char *dynamic_features=pbx_builtin_getvar_helper(chan,"DYNAMIC_FEATURES"); 00994 00995 if (sense == FEATURE_SENSE_CHAN) 00996 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL); 00997 else 00998 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL); 00999 ast_log(LOG_DEBUG, "Feature interpret: chan=%s, peer=%s, sense=%d, features=%d\n", chan->name, peer->name, sense, features.flags); 01000 01001 for (x=0; x < FEATURES_COUNT; x++) { 01002 if ((ast_test_flag(&features, builtin_features[x].feature_mask)) && 01003 !ast_strlen_zero(builtin_features[x].exten)) { 01004 /* Feature is up for consideration */ 01005 if (!strcmp(builtin_features[x].exten, code)) { 01006 res = builtin_features[x].operation(chan, peer, config, code, sense); 01007 break; 01008 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) { 01009 if (res == FEATURE_RETURN_PASSDIGITS) 01010 res = FEATURE_RETURN_STOREDIGITS; 01011 } 01012 } 01013 } 01014 01015 01016 if (!ast_strlen_zero(dynamic_features)) { 01017 char *tmp = ast_strdupa(dynamic_features); 01018 char *tok; 01019 01020 if (!tmp) 01021 return res; 01022 01023 while ((tok = strsep(&tmp, "#")) != NULL) { 01024 feature = find_feature(tok); 01025 01026 if (feature) { 01027 /* Feature is up for consideration */ 01028 if (!strcmp(feature->exten, code)) { 01029 if (option_verbose > 2) 01030 ast_verbose(VERBOSE_PREFIX_3 " Feature Found: %s exten: %s\n",feature->sname, tok); 01031 if (sense == FEATURE_SENSE_CHAN) 01032 res = feature->operation(chan, peer, config, code, sense); 01033 else 01034 res = feature->operation(peer, chan, config, code, sense); 01035 break; 01036 } else if (!strncmp(feature->exten, code, strlen(code))) { 01037 res = FEATURE_RETURN_STOREDIGITS; 01038 } 01039 } 01040 } 01041 } 01042 01043 return res; 01044 }
|
|
Definition at line 1091 of file res_features.c. References ast_channel::_softhangup, ast_call(), ast_channel_inherit_variables(), ast_check_hangup(), AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_HANGUP, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_TEXT, ast_frfree(), ast_indicate(), ast_log(), ast_read(), ast_request(), ast_set_callerid(), AST_STATE_UP, ast_verbose(), ast_waitfor_n(), builtin_features, ast_call_feature::exten, FEATURES_COUNT, ast_frame::frametype, LOG_NOTICE, option_verbose, ast_frame::subclass, and VERBOSE_PREFIX_3. Referenced by builtin_atxfer(). 01092 { 01093 int state = 0; 01094 int cause = 0; 01095 int to; 01096 struct ast_channel *chan; 01097 struct ast_channel *monitor_chans[2]; 01098 struct ast_channel *active_channel; 01099 struct ast_frame *f = NULL; 01100 int res = 0, ready = 0; 01101 01102 if ((chan = ast_request(type, format, data, &cause))) { 01103 ast_set_callerid(chan, cid_num, cid_name, cid_num); 01104 ast_channel_inherit_variables(caller, chan); 01105 if (!ast_call(chan, data, timeout)) { 01106 struct timeval started; 01107 int x, len = 0; 01108 char *disconnect_code = NULL, *dialed_code = NULL; 01109 01110 ast_indicate(caller, AST_CONTROL_RINGING); 01111 /* support dialing of the featuremap disconnect code while performing an attended tranfer */ 01112 for (x=0; x < FEATURES_COUNT; x++) { 01113 if (strcasecmp(builtin_features[x].sname, "disconnect")) 01114 continue; 01115 01116 disconnect_code = builtin_features[x].exten; 01117 len = strlen(disconnect_code) + 1; 01118 dialed_code = alloca(len); 01119 memset(dialed_code, 0, len); 01120 break; 01121 } 01122 x = 0; 01123 started = ast_tvnow(); 01124 to = timeout; 01125 while (!ast_check_hangup(caller) && timeout && (chan->_state != AST_STATE_UP)) { 01126 monitor_chans[0] = caller; 01127 monitor_chans[1] = chan; 01128 active_channel = ast_waitfor_n(monitor_chans, 2, &to); 01129 01130 /* see if the timeout has been violated */ 01131 if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) { 01132 state = AST_CONTROL_UNHOLD; 01133 ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n"); 01134 break; /*doh! timeout*/ 01135 } 01136 01137 if (!active_channel) { 01138 continue; 01139 } 01140 01141 if (chan && (chan == active_channel)){ 01142 f = ast_read(chan); 01143 if (f == NULL) { /*doh! where'd he go?*/ 01144 state = AST_CONTROL_HANGUP; 01145 res = 0; 01146 break; 01147 } 01148 01149 if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) { 01150 if (f->subclass == AST_CONTROL_RINGING) { 01151 state = f->subclass; 01152 if (option_verbose > 2) 01153 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", chan->name); 01154 ast_indicate(caller, AST_CONTROL_RINGING); 01155 } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) { 01156 state = f->subclass; 01157 if (option_verbose > 2) 01158 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", chan->name); 01159 ast_indicate(caller, AST_CONTROL_BUSY); 01160 ast_frfree(f); 01161 f = NULL; 01162 break; 01163 } else if (f->subclass == AST_CONTROL_ANSWER) { 01164 /* This is what we are hoping for */ 01165 state = f->subclass; 01166 ast_frfree(f); 01167 f = NULL; 01168 ready=1; 01169 break; 01170 } else { 01171 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass); 01172 } 01173 /* else who cares */ 01174 } 01175 01176 } else if (caller && (active_channel == caller)) { 01177 f = ast_read(caller); 01178 if (f == NULL) { /*doh! where'd he go?*/ 01179 if (caller->_softhangup && !chan->_softhangup) { 01180 /* make this a blind transfer */ 01181 ready = 1; 01182 break; 01183 } 01184 state = AST_CONTROL_HANGUP; 01185 res = 0; 01186 break; 01187 } 01188 01189 if (f->frametype == AST_FRAME_DTMF) { 01190 dialed_code[x++] = f->subclass; 01191 dialed_code[x] = '\0'; 01192 if (strlen(dialed_code) == len) { 01193 x = 0; 01194 } else if (x && strncmp(dialed_code, disconnect_code, x)) { 01195 x = 0; 01196 dialed_code[x] = '\0'; 01197 } 01198 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) { 01199 /* Caller Canceled the call */ 01200 state = AST_CONTROL_UNHOLD; 01201 ast_frfree(f); 01202 f = NULL; 01203 break; 01204 } 01205 } 01206 } 01207 if (f) { 01208 ast_frfree(f); 01209 } 01210 } 01211 } else 01212 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data); 01213 } else { 01214 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data); 01215 switch(cause) { 01216 case AST_CAUSE_BUSY: 01217 state = AST_CONTROL_BUSY; 01218 break; 01219 case AST_CAUSE_CONGESTION: 01220 state = AST_CONTROL_CONGESTION; 01221 break; 01222 } 01223 } 01224 01225 ast_indicate(caller, -1); 01226 if (chan && ready) { 01227 if (chan->_state == AST_STATE_UP) 01228 state = AST_CONTROL_ANSWER; 01229 res = 0; 01230 } else if(chan) { 01231 res = -1; 01232 ast_hangup(chan); 01233 chan = NULL; 01234 } else { 01235 res = -1; 01236 } 01237 01238 if (outstate) 01239 *outstate = state; 01240 01241 if (chan && res <= 0) { 01242 if (!chan->cdr) { 01243 chan->cdr = ast_cdr_alloc(); 01244 } 01245 if (chan->cdr) { 01246 char tmp[256]; 01247 ast_cdr_init(chan->cdr, chan); 01248 snprintf(tmp, 256, "%s/%s", type, (char *)data); 01249 ast_cdr_setapp(chan->cdr,"Dial",tmp); 01250 ast_cdr_update(chan); 01251 ast_cdr_start(chan->cdr); 01252 ast_cdr_end(chan->cdr); 01253 /* If the cause wasn't handled properly */ 01254 if (ast_cdr_disposition(chan->cdr,chan->hangupcause)) 01255 ast_cdr_failed(chan->cdr); 01256 } else { 01257 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n"); 01258 } 01259 } 01260 01261 return chan; 01262 }
|
|
|
|
Park a call via a masqueraded channel.
Definition at line 401 of file res_features.c. References ast_channel_alloc(), ast_channel_masquerade(), ast_frfree(), ast_log(), ast_park_call(), ast_read(), ast_channel::context, ast_channel::exten, LOG_WARNING, ast_channel::name, ast_channel::priority, ast_channel::readformat, and ast_channel::writeformat. Referenced by mgcp_ss(), parkandannounce_exec(), skinny_ss(), and ss_thread(). 00402 { 00403 struct ast_channel *chan; 00404 struct ast_frame *f; 00405 00406 /* Make a new, fake channel that we'll use to masquerade in the real one */ 00407 chan = ast_channel_alloc(0); 00408 if (chan) { 00409 /* Let us keep track of the channel name */ 00410 snprintf(chan->name, sizeof (chan->name), "Parked/%s",rchan->name); 00411 00412 /* Make formats okay */ 00413 chan->readformat = rchan->readformat; 00414 chan->writeformat = rchan->writeformat; 00415 ast_channel_masquerade(chan, rchan); 00416 00417 /* Setup the extensions and such */ 00418 ast_copy_string(chan->context, rchan->context, sizeof(chan->context)); 00419 ast_copy_string(chan->exten, rchan->exten, sizeof(chan->exten)); 00420 chan->priority = rchan->priority; 00421 00422 /* Make the masq execute */ 00423 f = ast_read(chan); 00424 if (f) 00425 ast_frfree(f); 00426 ast_park_call(chan, peer, timeout, extout); 00427 } else { 00428 ast_log(LOG_WARNING, "Unable to create parked channel\n"); 00429 return -1; 00430 } 00431 return 0; 00432 }
|
|
|
|
Park a call and read back parked location.
Definition at line 278 of file res_features.c. References ast_log(), AST_MAX_EXTENSION, ast_mutex_lock(), exten, LOG_WARNING, malloc, parkeduser::next, parkinglot, and parkeduser::parkingnum. Referenced by ast_masq_park_call(), builtin_blindtransfer(), iax_park_thread(), park_call_exec(), and sip_park_thread(). 00279 { 00280 struct parkeduser *pu, *cur; 00281 int i,x,parking_range; 00282 char exten[AST_MAX_EXTENSION]; 00283 struct ast_context *con; 00284 00285 pu = malloc(sizeof(struct parkeduser)); 00286 if (!pu) { 00287 ast_log(LOG_WARNING, "Out of memory\n"); 00288 return -1; 00289 } 00290 memset(pu, 0, sizeof(struct parkeduser)); 00291 ast_mutex_lock(&parking_lock); 00292 parking_range = parking_stop - parking_start+1; 00293 for (i = 0; i < parking_range; i++) { 00294 x = (i + parking_offset) % parking_range + parking_start; 00295 cur = parkinglot; 00296 while(cur) { 00297 if (cur->parkingnum == x) 00298 break; 00299 cur = cur->next; 00300 } 00301 if (!cur) 00302 break; 00303 } 00304 00305 if (!(i < parking_range)) { 00306 ast_log(LOG_WARNING, "No more parking spaces\n"); 00307 free(pu); 00308 ast_mutex_unlock(&parking_lock); 00309 return -1; 00310 } 00311 if (parkfindnext) 00312 parking_offset = x - parking_start + 1; 00313 chan->appl = "Parked Call"; 00314 chan->data = NULL; 00315 00316 pu->chan = chan; 00317 /* Start music on hold */ 00318 if (chan != peer) { 00319 ast_indicate(pu->chan, AST_CONTROL_HOLD); 00320 ast_moh_start(pu->chan, NULL); 00321 } 00322 pu->start = ast_tvnow(); 00323 pu->parkingnum = x; 00324 if (timeout > 0) 00325 pu->parkingtime = timeout; 00326 else 00327 pu->parkingtime = parkingtime; 00328 if (extout) 00329 *extout = x; 00330 if (peer) 00331 ast_copy_string(pu->peername, peer->name, sizeof(pu->peername)); 00332 00333 /* Remember what had been dialed, so that if the parking 00334 expires, we try to come back to the same place */ 00335 if (!ast_strlen_zero(chan->macrocontext)) 00336 ast_copy_string(pu->context, chan->macrocontext, sizeof(pu->context)); 00337 else 00338 ast_copy_string(pu->context, chan->context, sizeof(pu->context)); 00339 if (!ast_strlen_zero(chan->macroexten)) 00340 ast_copy_string(pu->exten, chan->macroexten, sizeof(pu->exten)); 00341 else 00342 ast_copy_string(pu->exten, chan->exten, sizeof(pu->exten)); 00343 if (chan->macropriority) 00344 pu->priority = chan->macropriority; 00345 else 00346 pu->priority = chan->priority; 00347 pu->next = parkinglot; 00348 parkinglot = pu; 00349 /* If parking a channel directly, don't quiet yet get parking running on it */ 00350 if (peer == chan) 00351 pu->notquiteyet = 1; 00352 ast_mutex_unlock(&parking_lock); 00353 /* Wake up the (presumably select()ing) thread */ 00354 pthread_kill(parking_thread, SIGURG); 00355 if (option_verbose > 1) 00356 ast_verbose(VERBOSE_PREFIX_2 "Parked %s on %d. Will timeout back to extension [%s] %s, %d in %d seconds\n", pu->chan->name, pu->parkingnum, pu->context, pu->exten, pu->priority, (pu->parkingtime/1000)); 00357 00358 manager_event(EVENT_FLAG_CALL, "ParkedCall", 00359 "Exten: %d\r\n" 00360 "Channel: %s\r\n" 00361 "From: %s\r\n" 00362 "Timeout: %ld\r\n" 00363 "CallerID: %s\r\n" 00364 "CallerIDName: %s\r\n" 00365 ,pu->parkingnum, pu->chan->name, peer ? peer->name : "" 00366 ,(long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL) 00367 ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>") 00368 ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>") 00369 ); 00370 00371 if (peer) { 00372 if (adsipark && adsi_available(peer)) { 00373 adsi_announce_park(peer, pu->parkingnum); 00374 } 00375 if (adsipark && adsi_available(peer)) { 00376 adsi_unload_session(peer); 00377 } 00378 } 00379 con = ast_context_find(parking_con); 00380 if (!con) { 00381 con = ast_context_create(NULL, parking_con, registrar); 00382 if (!con) { 00383 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con); 00384 } 00385 } 00386 if (con) { 00387 snprintf(exten, sizeof(exten), "%d", x); 00388 ast_add_extension2(con, 1, exten, 1, NULL, NULL, parkedcall, strdup(exten), FREE, registrar); 00389 } 00390 if (peer) 00391 ast_say_digits(peer, pu->parkingnum, "", peer->language); 00392 if (pu->notquiteyet) { 00393 /* Wake up parking thread if we're really done */ 00394 ast_moh_start(pu->chan, NULL); 00395 pu->notquiteyet = 0; 00396 pthread_kill(parking_thread, SIGURG); 00397 } 00398 return 0; 00399 }
|
|
Determine system parking extension Returns the call parking extension for drivers that provide special call parking help.
Definition at line 163 of file res_features.c. Referenced by builtin_blindtransfer(), dp_lookup(), get_refer_info(), handle_request_refer(), load_config(), mgcp_ss(), skinny_ss(), socket_read(), and ss_thread(). 00164 { 00165 return parking_ext; 00166 }
|
|
Pickup a call.
Definition at line 1931 of file res_features.c. References ast_channel::_state, ast_answer(), ast_channel_masquerade(), ast_channel_walk_locked(), AST_CONTROL_ANSWER, ast_log(), ast_mutex_unlock(), ast_queue_control(), AST_STATE_RING, AST_STATE_RINGING, ast_channel::callgroup, ast_channel::lock, LOG_DEBUG, LOG_WARNING, ast_channel::name, option_debug, ast_channel::pbx, and ast_channel::pickupgroup. Referenced by cb_events(), handle_request_invite(), mgcp_ss(), monitor_handle_notowned(), skinny_ss(), and ss_thread(). 01932 { 01933 struct ast_channel *cur = NULL; 01934 int res = -1; 01935 01936 while ( (cur = ast_channel_walk_locked(cur)) != NULL) { 01937 if (!cur->pbx && 01938 (cur != chan) && 01939 (chan->pickupgroup & cur->callgroup) && 01940 ((cur->_state == AST_STATE_RINGING) || 01941 (cur->_state == AST_STATE_RING))) { 01942 break; 01943 } 01944 ast_mutex_unlock(&cur->lock); 01945 } 01946 if (cur) { 01947 if (option_debug) 01948 ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name); 01949 res = ast_answer(chan); 01950 if (res) 01951 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name); 01952 res = ast_queue_control(chan, AST_CONTROL_ANSWER); 01953 if (res) 01954 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name); 01955 res = ast_channel_masquerade(cur, chan); 01956 if (res) 01957 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */ 01958 ast_mutex_unlock(&cur->lock); 01959 } else { 01960 if (option_debug) 01961 ast_log(LOG_DEBUG, "No call pickup possible...\n"); 01962 } 01963 return res; 01964 }
|
|
Determine system call pickup extension.
Definition at line 168 of file res_features.c. Referenced by cb_events(), get_destination(), handle_request_invite(), handle_showfeatures(), mgcp_ss(), monitor_handle_notowned(), skinny_ss(), and ss_thread(). 00169 { 00170 return pickup_ext; 00171 }
|
|
register new feature into feature_set
Definition at line 875 of file res_features.c. References AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_verbose(), LOG_NOTICE, option_verbose, ast_call_feature::sname, and VERBOSE_PREFIX_2. Referenced by load_config(). 00876 { 00877 if (!feature) { 00878 ast_log(LOG_NOTICE,"You didn't pass a feature!\n"); 00879 return; 00880 } 00881 00882 AST_LIST_LOCK(&feature_list); 00883 AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry); 00884 AST_LIST_UNLOCK(&feature_list); 00885 00886 if (option_verbose >= 2) 00887 ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname); 00888 }
|
|
unregister feature from feature_set
Definition at line 891 of file res_features.c. References AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, and free. 00892 { 00893 if (!feature) return; 00894 00895 AST_LIST_LOCK(&feature_list); 00896 AST_LIST_REMOVE(&feature_list,feature,feature_entry); 00897 AST_LIST_UNLOCK(&feature_list); 00898 free(feature); 00899 }
|
|
Definition at line 901 of file res_features.c. References AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, and free. Referenced by load_config(). 00902 { 00903 struct ast_call_feature *feature; 00904 00905 AST_LIST_LOCK(&feature_list); 00906 while ((feature = AST_LIST_REMOVE_HEAD(&feature_list,feature_entry))) 00907 free(feature); 00908 AST_LIST_UNLOCK(&feature_list); 00909 }
|
|
Definition at line 666 of file res_features.c. References ast_channel::_softhangup, ast_channel::_state, ast_app_dtget(), ast_autoservice_start(), ast_autoservice_stop(), ast_best_codec(), ast_bridge_call(), ast_bridge_call_thread_launch(), ast_channel_alloc(), ast_channel_make_compatible(), ast_channel_masquerade(), ast_check_hangup(), ast_clear_flag, AST_CONTROL_BUSY, AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, AST_DIGIT_ANY, ast_exists_extension(), ast_explicit_goto(), AST_FEATURE_DISCONNECT, ast_feature_request_and_dial(), AST_FLAGS_ALL, ast_frfree(), ast_hangup(), ast_indicate(), ast_log(), ast_moh_start(), ast_moh_stop(), ast_read(), ast_set_flag, AST_STATE_UP, ast_streamfile(), ast_strlen_zero(), ast_waitfordigit(), ast_waitstream(), ast_bridge_thread_obj::bconfig, ast_bridge_thread_obj::chan, cid_name, cid_num, config, ast_channel::context, ast_channel::exten, FEATURE_RETURN_SUCCESS, FEATURE_SENSE_PEER, ast_bridge_config::features_callee, ast_bridge_config::features_caller, ast_channel::language, LOG_DEBUG, LOG_WARNING, ast_channel::macrocontext, malloc, ast_channel::name, pbx_builtin_getvar_helper(), ast_bridge_thread_obj::peer, ast_channel::priority, ast_channel::readformat, and ast_channel::writeformat. 00667 { 00668 struct ast_channel *transferer; 00669 struct ast_channel *transferee; 00670 struct ast_channel *newchan, *xferchan=NULL; 00671 int outstate=0; 00672 struct ast_bridge_config bconfig; 00673 char *transferer_real_context; 00674 char xferto[256],dialstr[265]; 00675 char *cid_num; 00676 char *cid_name; 00677 int res; 00678 struct ast_frame *f = NULL; 00679 struct ast_bridge_thread_obj *tobj; 00680 00681 ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) XXX\n", chan->name, peer->name, sense); 00682 if (sense == FEATURE_SENSE_PEER) { 00683 transferer = peer; 00684 transferee = chan; 00685 } else { 00686 transferer = chan; 00687 transferee = peer; 00688 } 00689 if (!(transferer_real_context=pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT")) && 00690 !(transferer_real_context=pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"))) { 00691 /* Use the non-macro context to transfer the call */ 00692 if (!ast_strlen_zero(transferer->macrocontext)) 00693 transferer_real_context = transferer->macrocontext; 00694 else 00695 transferer_real_context = transferer->context; 00696 } 00697 /* Start autoservice on chan while we talk 00698 to the originator */ 00699 ast_indicate(transferee, AST_CONTROL_HOLD); 00700 ast_autoservice_start(transferee); 00701 ast_moh_start(transferee, NULL); 00702 memset(xferto, 0, sizeof(xferto)); 00703 /* Transfer */ 00704 if ((res = ast_streamfile(transferer, "pbx-transfer", transferer->language))) { 00705 ast_moh_stop(transferee); 00706 ast_autoservice_stop(transferee); 00707 ast_indicate(transferee, AST_CONTROL_UNHOLD); 00708 return res; 00709 } 00710 if ((res=ast_waitstream(transferer, AST_DIGIT_ANY)) < 0) { 00711 ast_moh_stop(transferee); 00712 ast_autoservice_stop(transferee); 00713 ast_indicate(transferee, AST_CONTROL_UNHOLD); 00714 return res; 00715 } else if(res > 0) { 00716 /* If they've typed a digit already, handle it */ 00717 xferto[0] = (char) res; 00718 } 00719 if ((ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout))) { 00720 cid_num = transferer->cid.cid_num; 00721 cid_name = transferer->cid.cid_name; 00722 if (ast_exists_extension(transferer, transferer_real_context,xferto, 1, cid_num)) { 00723 snprintf(dialstr, sizeof(dialstr), "%s@%s/n", xferto, transferer_real_context); 00724 newchan = ast_feature_request_and_dial(transferer, "Local", ast_best_codec(transferer->nativeformats), dialstr, 15000, &outstate, cid_num, cid_name); 00725 ast_indicate(transferer, -1); 00726 if (newchan) { 00727 res = ast_channel_make_compatible(transferer, newchan); 00728 if (res < 0) { 00729 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", transferer->name, newchan->name); 00730 ast_hangup(newchan); 00731 return -1; 00732 } 00733 memset(&bconfig,0,sizeof(struct ast_bridge_config)); 00734 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT); 00735 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT); 00736 res = ast_bridge_call(transferer,newchan,&bconfig); 00737 if (newchan->_softhangup || newchan->_state != AST_STATE_UP || !transferer->_softhangup) { 00738 ast_hangup(newchan); 00739 if (f) { 00740 ast_frfree(f); 00741 f = NULL; 00742 } 00743 if (!ast_strlen_zero(xfersound) && !ast_streamfile(transferer, xfersound, transferer->language)) { 00744 if (ast_waitstream(transferer, "") < 0) { 00745 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 00746 } 00747 } 00748 ast_moh_stop(transferee); 00749 ast_autoservice_stop(transferee); 00750 ast_indicate(transferee, AST_CONTROL_UNHOLD); 00751 transferer->_softhangup = 0; 00752 return FEATURE_RETURN_SUCCESS; 00753 } 00754 00755 res = ast_channel_make_compatible(transferee, newchan); 00756 if (res < 0) { 00757 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", transferee->name, newchan->name); 00758 ast_hangup(newchan); 00759 return -1; 00760 } 00761 00762 00763 ast_moh_stop(transferee); 00764 00765 if ((ast_autoservice_stop(transferee) < 0) 00766 || (ast_waitfordigit(transferee, 100) < 0) 00767 || (ast_waitfordigit(newchan, 100) < 0) 00768 || ast_check_hangup(transferee) 00769 || ast_check_hangup(newchan)) { 00770 ast_hangup(newchan); 00771 res = -1; 00772 return -1; 00773 } 00774 00775 if ((xferchan = ast_channel_alloc(0))) { 00776 snprintf(xferchan->name, sizeof (xferchan->name), "Transfered/%s",transferee->name); 00777 /* Make formats okay */ 00778 xferchan->readformat = transferee->readformat; 00779 xferchan->writeformat = transferee->writeformat; 00780 ast_channel_masquerade(xferchan, transferee); 00781 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority); 00782 xferchan->_state = AST_STATE_UP; 00783 ast_clear_flag(xferchan, AST_FLAGS_ALL); 00784 xferchan->_softhangup = 0; 00785 00786 if ((f = ast_read(xferchan))) { 00787 ast_frfree(f); 00788 f = NULL; 00789 } 00790 00791 } else { 00792 ast_hangup(newchan); 00793 return -1; 00794 } 00795 00796 newchan->_state = AST_STATE_UP; 00797 ast_clear_flag(newchan, AST_FLAGS_ALL); 00798 newchan->_softhangup = 0; 00799 00800 tobj = malloc(sizeof(struct ast_bridge_thread_obj)); 00801 if (tobj) { 00802 memset(tobj,0,sizeof(struct ast_bridge_thread_obj)); 00803 tobj->chan = xferchan; 00804 tobj->peer = newchan; 00805 tobj->bconfig = *config; 00806 00807 if (!ast_strlen_zero(xfersound) && !ast_streamfile(newchan, xfersound, newchan->language)) { 00808 if (ast_waitstream(newchan, "") < 0) { 00809 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 00810 } 00811 } 00812 ast_bridge_call_thread_launch(tobj); 00813 } else { 00814 ast_log(LOG_WARNING, "Out of memory!\n"); 00815 ast_hangup(xferchan); 00816 ast_hangup(newchan); 00817 } 00818 return -1; 00819 00820 } else { 00821 ast_moh_stop(transferee); 00822 ast_autoservice_stop(transferee); 00823 ast_indicate(transferee, AST_CONTROL_UNHOLD); 00824 /* any reason besides user requested cancel and busy triggers the failed sound */ 00825 if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY && !ast_strlen_zero(xferfailsound)) { 00826 res = ast_streamfile(transferer, xferfailsound, transferer->language); 00827 if (!res && (ast_waitstream(transferer, "") < 0)) { 00828 return -1; 00829 } 00830 } 00831 return FEATURE_RETURN_SUCCESS; 00832 } 00833 } else { 00834 ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context); 00835 ast_moh_stop(transferee); 00836 ast_autoservice_stop(transferee); 00837 ast_indicate(transferee, AST_CONTROL_UNHOLD); 00838 res = ast_streamfile(transferer, "beeperr", transferer->language); 00839 if (!res && (ast_waitstream(transferer, "") < 0)) { 00840 return -1; 00841 } 00842 } 00843 } else { 00844 ast_log(LOG_WARNING, "Did not read data.\n"); 00845 ast_moh_stop(transferee); 00846 ast_autoservice_stop(transferee); 00847 ast_indicate(transferee, AST_CONTROL_UNHOLD); 00848 res = ast_streamfile(transferer, "beeperr", transferer->language); 00849 if (ast_waitstream(transferer, "") < 0) { 00850 return -1; 00851 } 00852 } 00853 ast_moh_stop(transferee); 00854 ast_autoservice_stop(transferee); 00855 ast_indicate(transferee, AST_CONTROL_UNHOLD); 00856 00857 return FEATURE_RETURN_SUCCESS; 00858 }
|
|
Definition at line 447 of file res_features.c. References ast_autoservice_start(), ast_autoservice_stop(), ast_log(), ast_monitor_stop(), ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_verbose(), ast_waitstream(), ast_channel::cid, ast_callerid::cid_num, FEATURE_RETURN_SUCCESS, ast_channel::language, LOG_ERROR, LOG_NOTICE, LOG_WARNING, monitor_app, ast_channel::name, option_verbose, pbx_builtin_getvar_helper(), pbx_exec(), pbx_findapp(), and VERBOSE_PREFIX_3. 00448 { 00449 char *touch_monitor = NULL, *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_format = NULL; 00450 int x = 0; 00451 size_t len; 00452 struct ast_channel *caller_chan = NULL, *callee_chan = NULL; 00453 00454 00455 if(sense == 2) { 00456 caller_chan = peer; 00457 callee_chan = chan; 00458 } else { 00459 callee_chan = peer; 00460 caller_chan = chan; 00461 } 00462 00463 if (!monitor_ok) { 00464 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); 00465 return -1; 00466 } 00467 00468 if (!monitor_app) { 00469 if (!(monitor_app = pbx_findapp("Monitor"))) { 00470 monitor_ok=0; 00471 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); 00472 return -1; 00473 } 00474 } 00475 if (!ast_strlen_zero(courtesytone)) { 00476 if (ast_autoservice_start(callee_chan)) 00477 return -1; 00478 if (!ast_streamfile(caller_chan, courtesytone, caller_chan->language)) { 00479 if (ast_waitstream(caller_chan, "") < 0) { 00480 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); 00481 ast_autoservice_stop(callee_chan); 00482 return -1; 00483 } 00484 } 00485 if (ast_autoservice_stop(callee_chan)) 00486 return -1; 00487 } 00488 00489 if (callee_chan->monitor) { 00490 if (option_verbose > 3) 00491 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to stop recording call.\n", code); 00492 ast_monitor_stop(callee_chan, 1); 00493 return FEATURE_RETURN_SUCCESS; 00494 } 00495 00496 if (caller_chan && callee_chan) { 00497 touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT"); 00498 if (!touch_format) 00499 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT"); 00500 00501 touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR"); 00502 if (!touch_monitor) 00503 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR"); 00504 00505 if (touch_monitor) { 00506 len = strlen(touch_monitor) + 50; 00507 args = alloca(len); 00508 snprintf(args, len, "%s|auto-%ld-%s|m", (touch_format) ? touch_format : "wav", time(NULL), touch_monitor); 00509 } else { 00510 caller_chan_id = ast_strdupa(caller_chan->cid.cid_num ? caller_chan->cid.cid_num : caller_chan->name); 00511 callee_chan_id = ast_strdupa(callee_chan->cid.cid_num ? callee_chan->cid.cid_num : callee_chan->name); 00512 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50; 00513 args = alloca(len); 00514 snprintf(args, len, "%s|auto-%ld-%s-%s|m", (touch_format) ? touch_format : "wav", time(NULL), caller_chan_id, callee_chan_id); 00515 } 00516 00517 for( x = 0; x < strlen(args); x++) 00518 if (args[x] == '/') 00519 args[x] = '-'; 00520 00521 if (option_verbose > 3) 00522 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call. filename: %s\n", code, args); 00523 00524 pbx_exec(callee_chan, monitor_app, args, 1); 00525 00526 return FEATURE_RETURN_SUCCESS; 00527 } 00528 00529 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n"); 00530 return -1; 00531 }
|
|
Definition at line 540 of file res_features.c. References ast_app_dtget(), ast_async_goto(), ast_autoservice_start(), ast_autoservice_stop(), AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, AST_DIGIT_ANY, ast_exists_extension(), ast_indicate(), ast_log(), ast_moh_start(), ast_moh_stop(), ast_park_call(), ast_parking_ext(), AST_PBX_KEEPALIVE, AST_PBX_NO_HANGUP_PEER, ast_stopstream(), ast_streamfile(), ast_strlen_zero(), ast_verbose(), ast_waitstream(), check_goto_on_transfer(), ast_channel::cid, ast_callerid::cid_num, ast_channel::context, ast_channel::exten, FEATURE_RETURN_SUCCESS, FEATURE_SENSE_PEER, ast_channel::language, LOG_WARNING, ast_channel::macrocontext, ast_channel::name, option_verbose, ast_channel::pbx, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), ast_channel::priority, VERBOSE_PREFIX_2, and VERBOSE_PREFIX_3. 00541 { 00542 struct ast_channel *transferer; 00543 struct ast_channel *transferee; 00544 char *transferer_real_context; 00545 char newext[256]; 00546 int res; 00547 00548 if (sense == FEATURE_SENSE_PEER) { 00549 transferer = peer; 00550 transferee = chan; 00551 } else { 00552 transferer = chan; 00553 transferee = peer; 00554 } 00555 if (!(transferer_real_context = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT")) && 00556 !(transferer_real_context = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"))) { 00557 /* Use the non-macro context to transfer the call */ 00558 if (!ast_strlen_zero(transferer->macrocontext)) 00559 transferer_real_context = transferer->macrocontext; 00560 else 00561 transferer_real_context = transferer->context; 00562 } 00563 /* Start autoservice on chan while we talk 00564 to the originator */ 00565 ast_indicate(transferee, AST_CONTROL_HOLD); 00566 ast_autoservice_start(transferee); 00567 ast_moh_start(transferee, NULL); 00568 00569 memset(newext, 0, sizeof(newext)); 00570 00571 /* Transfer */ 00572 if ((res=ast_streamfile(transferer, "pbx-transfer", transferer->language))) { 00573 ast_moh_stop(transferee); 00574 ast_autoservice_stop(transferee); 00575 ast_indicate(transferee, AST_CONTROL_UNHOLD); 00576 return res; 00577 } 00578 if ((res=ast_waitstream(transferer, AST_DIGIT_ANY)) < 0) { 00579 ast_moh_stop(transferee); 00580 ast_autoservice_stop(transferee); 00581 ast_indicate(transferee, AST_CONTROL_UNHOLD); 00582 return res; 00583 } else if (res > 0) { 00584 /* If they've typed a digit already, handle it */ 00585 newext[0] = (char) res; 00586 } 00587 00588 ast_stopstream(transferer); 00589 res = ast_app_dtget(transferer, transferer_real_context, newext, sizeof(newext), 100, transferdigittimeout); 00590 if (res < 0) { 00591 ast_moh_stop(transferee); 00592 ast_autoservice_stop(transferee); 00593 ast_indicate(transferee, AST_CONTROL_UNHOLD); 00594 return res; 00595 } 00596 if (!strcmp(newext, ast_parking_ext())) { 00597 ast_moh_stop(transferee); 00598 00599 res = ast_autoservice_stop(transferee); 00600 ast_indicate(transferee, AST_CONTROL_UNHOLD); 00601 if (res) 00602 res = -1; 00603 else if (!ast_park_call(transferee, transferer, 0, NULL)) { 00604 /* We return non-zero, but tell the PBX not to hang the channel when 00605 the thread dies -- We have to be careful now though. We are responsible for 00606 hanging up the channel, else it will never be hung up! */ 00607 00608 if (transferer == peer) 00609 res = AST_PBX_KEEPALIVE; 00610 else 00611 res = AST_PBX_NO_HANGUP_PEER; 00612 return res; 00613 } else { 00614 ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name); 00615 } 00616 /* XXX Maybe we should have another message here instead of invalid extension XXX */ 00617 } else if (ast_exists_extension(transferee, transferer_real_context, newext, 1, transferer->cid.cid_num)) { 00618 pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", chan->name); 00619 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", peer->name); 00620 ast_moh_stop(transferee); 00621 res=ast_autoservice_stop(transferee); 00622 ast_indicate(transferee, AST_CONTROL_UNHOLD); 00623 if (!transferee->pbx) { 00624 /* Doh! Use our handy async_goto functions */ 00625 if (option_verbose > 2) 00626 ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n" 00627 ,transferee->name, newext, transferer_real_context); 00628 if (ast_async_goto(transferee, transferer_real_context, newext, 1)) 00629 ast_log(LOG_WARNING, "Async goto failed :-(\n"); 00630 res = -1; 00631 } else { 00632 /* Set the channel's new extension, since it exists, using transferer context */ 00633 ast_copy_string(transferee->exten, newext, sizeof(transferee->exten)); 00634 ast_copy_string(transferee->context, transferer_real_context, sizeof(transferee->context)); 00635 transferee->priority = 0; 00636 } 00637 check_goto_on_transfer(transferer); 00638 return res; 00639 } else { 00640 if (option_verbose > 2) 00641 ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", newext, transferer_real_context); 00642 } 00643 if (!ast_strlen_zero(xferfailsound)) 00644 res = ast_streamfile(transferer, xferfailsound, transferer->language); 00645 else 00646 res = 0; 00647 if (res) { 00648 ast_moh_stop(transferee); 00649 ast_autoservice_stop(transferee); 00650 ast_indicate(transferee, AST_CONTROL_UNHOLD); 00651 return res; 00652 } 00653 res = ast_waitstream(transferer, AST_DIGIT_ANY); 00654 ast_stopstream(transferer); 00655 ast_moh_stop(transferee); 00656 res = ast_autoservice_stop(transferee); 00657 ast_indicate(transferee, AST_CONTROL_UNHOLD); 00658 if (res) { 00659 if (option_verbose > 1) 00660 ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name); 00661 return res; 00662 } 00663 return FEATURE_RETURN_SUCCESS; 00664 }
|
|
Definition at line 533 of file res_features.c. References ast_verbose(), FEATURE_RETURN_HANGUP, option_verbose, and VERBOSE_PREFIX_3. 00534 { 00535 if (option_verbose > 3) 00536 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code); 00537 return FEATURE_RETURN_HANGUP; 00538 }
|
|
Definition at line 180 of file res_features.c. References ast_channel::_softhangup, ast_channel::_state, ast_channel_alloc(), ast_channel_masquerade(), ast_clear_flag, AST_FLAGS_ALL, ast_frfree(), ast_hangup(), ast_parseable_goto(), ast_pbx_start(), ast_read(), AST_STATE_UP, ast_strlen_zero(), ast_channel::name, pbx_builtin_getvar_helper(), ast_channel::readformat, and ast_channel::writeformat. Referenced by builtin_blindtransfer(). 00181 { 00182 struct ast_channel *xferchan; 00183 char *goto_on_transfer; 00184 00185 goto_on_transfer = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR"); 00186 00187 if (!ast_strlen_zero(goto_on_transfer) && (xferchan = ast_channel_alloc(0))) { 00188 char *x; 00189 struct ast_frame *f; 00190 00191 for (x = goto_on_transfer; x && *x; x++) 00192 if (*x == '^') 00193 *x = '|'; 00194 00195 strcpy(xferchan->name, chan->name); 00196 /* Make formats okay */ 00197 xferchan->readformat = chan->readformat; 00198 xferchan->writeformat = chan->writeformat; 00199 ast_channel_masquerade(xferchan, chan); 00200 ast_parseable_goto(xferchan, goto_on_transfer); 00201 xferchan->_state = AST_STATE_UP; 00202 ast_clear_flag(xferchan, AST_FLAGS_ALL); 00203 xferchan->_softhangup = 0; 00204 if ((f = ast_read(xferchan))) { 00205 ast_frfree(f); 00206 f = NULL; 00207 ast_pbx_start(xferchan); 00208 } else { 00209 ast_hangup(xferchan); 00210 } 00211 } 00212 }
|
|
Provides a description of the module.
Definition at line 2182 of file res_features.c.
|
|
Definition at line 1487 of file res_features.c. References ast_add_extension2(), ast_clear_flag, ast_context_create(), ast_context_find(), ast_context_remove_extension2(), AST_CONTROL_HANGUP, AST_CONTROL_UNHOLD, AST_FLAG_EXCEPTION, AST_FRAME_CONTROL, ast_frfree(), ast_hangup(), ast_indicate(), ast_log(), AST_MAX_EXTENSION, AST_MAX_FDS, ast_moh_start(), ast_moh_stop(), ast_mutex_lock(), ast_pbx_start(), ast_read(), ast_set_flag, ast_strdupa, ast_verbose(), parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, parkeduser::context, ast_channel::context, EVENT_FLAG_CALL, parkeduser::exten, ast_channel::exten, ast_channel::fdno, ast_channel::fds, ast_frame::frametype, free, FREE, ast_channel::generatordata, LOG_DEBUG, LOG_ERROR, LOG_WARNING, manager_event(), parkeduser::moh_trys, ast_channel::name, parkeduser::next, parkeduser::notquiteyet, option_verbose, parkinglot, parkeduser::parkingnum, parkeduser::parkingtime, parkeduser::peername, parkeduser::priority, ast_channel::priority, parkeduser::start, strdup, ast_frame::subclass, and VERBOSE_PREFIX_2. Referenced by load_module(). 01488 { 01489 int ms, tms, max; 01490 struct parkeduser *pu, *pl, *pt = NULL; 01491 struct timeval tv; 01492 struct ast_frame *f; 01493 char exten[AST_MAX_EXTENSION]; 01494 char *peername,*cp; 01495 char returnexten[AST_MAX_EXTENSION]; 01496 struct ast_context *con; 01497 int x; 01498 fd_set rfds, efds; 01499 fd_set nrfds, nefds; 01500 FD_ZERO(&rfds); 01501 FD_ZERO(&efds); 01502 01503 for (;;) { 01504 ms = -1; 01505 max = -1; 01506 ast_mutex_lock(&parking_lock); 01507 pl = NULL; 01508 pu = parkinglot; 01509 FD_ZERO(&nrfds); 01510 FD_ZERO(&nefds); 01511 while(pu) { 01512 if (pu->notquiteyet) { 01513 /* Pretend this one isn't here yet */ 01514 pl = pu; 01515 pu = pu->next; 01516 continue; 01517 } 01518 tms = ast_tvdiff_ms(ast_tvnow(), pu->start); 01519 if (tms > pu->parkingtime) { 01520 /* Stop music on hold */ 01521 ast_moh_stop(pu->chan); 01522 ast_indicate(pu->chan, AST_CONTROL_UNHOLD); 01523 /* Get chan, exten from derived kludge */ 01524 if (pu->peername[0]) { 01525 peername = ast_strdupa(pu->peername); 01526 cp = strrchr(peername, '-'); 01527 if (cp) 01528 *cp = 0; 01529 con = ast_context_find(parking_con_dial); 01530 if (!con) { 01531 con = ast_context_create(NULL, parking_con_dial, registrar); 01532 if (!con) { 01533 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial); 01534 } 01535 } 01536 if (con) { 01537 snprintf(returnexten, sizeof(returnexten), "%s||t", peername); 01538 ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), FREE, registrar); 01539 } 01540 ast_copy_string(pu->chan->exten, peername, sizeof(pu->chan->exten)); 01541 ast_copy_string(pu->chan->context, parking_con_dial, sizeof(pu->chan->context)); 01542 pu->chan->priority = 1; 01543 01544 } else { 01545 /* They've been waiting too long, send them back to where they came. Theoretically they 01546 should have their original extensions and such, but we copy to be on the safe side */ 01547 ast_copy_string(pu->chan->exten, pu->exten, sizeof(pu->chan->exten)); 01548 ast_copy_string(pu->chan->context, pu->context, sizeof(pu->chan->context)); 01549 pu->chan->priority = pu->priority; 01550 } 01551 01552 manager_event(EVENT_FLAG_CALL, "ParkedCallTimeOut", 01553 "Exten: %d\r\n" 01554 "Channel: %s\r\n" 01555 "CallerID: %s\r\n" 01556 "CallerIDName: %s\r\n" 01557 ,pu->parkingnum, pu->chan->name 01558 ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>") 01559 ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>") 01560 ); 01561 01562 if (option_verbose > 1) 01563 ast_verbose(VERBOSE_PREFIX_2 "Timeout for %s parked on %d. Returning to %s,%s,%d\n", pu->chan->name, pu->parkingnum, pu->chan->context, pu->chan->exten, pu->chan->priority); 01564 /* Start up the PBX, or hang them up */ 01565 if (ast_pbx_start(pu->chan)) { 01566 ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name); 01567 ast_hangup(pu->chan); 01568 } 01569 /* And take them out of the parking lot */ 01570 if (pl) 01571 pl->next = pu->next; 01572 else 01573 parkinglot = pu->next; 01574 pt = pu; 01575 pu = pu->next; 01576 con = ast_context_find(parking_con); 01577 if (con) { 01578 snprintf(exten, sizeof(exten), "%d", pt->parkingnum); 01579 if (ast_context_remove_extension2(con, exten, 1, NULL)) 01580 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 01581 } else 01582 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 01583 free(pt); 01584 } else { 01585 for (x = 0; x < AST_MAX_FDS; x++) { 01586 if ((pu->chan->fds[x] > -1) && (FD_ISSET(pu->chan->fds[x], &rfds) || FD_ISSET(pu->chan->fds[x], &efds))) { 01587 if (FD_ISSET(pu->chan->fds[x], &efds)) 01588 ast_set_flag(pu->chan, AST_FLAG_EXCEPTION); 01589 else 01590 ast_clear_flag(pu->chan, AST_FLAG_EXCEPTION); 01591 pu->chan->fdno = x; 01592 /* See if they need servicing */ 01593 f = ast_read(pu->chan); 01594 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) { 01595 if (f) 01596 ast_frfree(f); 01597 manager_event(EVENT_FLAG_CALL, "ParkedCallGiveUp", 01598 "Exten: %d\r\n" 01599 "Channel: %s\r\n" 01600 "CallerID: %s\r\n" 01601 "CallerIDName: %s\r\n" 01602 ,pu->parkingnum, pu->chan->name 01603 ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>") 01604 ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>") 01605 ); 01606 01607 /* There's a problem, hang them up*/ 01608 if (option_verbose > 1) 01609 ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", pu->chan->name); 01610 ast_hangup(pu->chan); 01611 /* And take them out of the parking lot */ 01612 if (pl) 01613 pl->next = pu->next; 01614 else 01615 parkinglot = pu->next; 01616 pt = pu; 01617 pu = pu->next; 01618 con = ast_context_find(parking_con); 01619 if (con) { 01620 snprintf(exten, sizeof(exten), "%d", pt->parkingnum); 01621 if (ast_context_remove_extension2(con, exten, 1, NULL)) 01622 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 01623 } else 01624 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 01625 free(pt); 01626 break; 01627 } else { 01628 /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */ 01629 ast_frfree(f); 01630 if (pu->moh_trys < 3 && !pu->chan->generatordata) { 01631 ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source. Restarting.\n"); 01632 ast_moh_start(pu->chan, NULL); 01633 pu->moh_trys++; 01634 } 01635 goto std; /* XXX Ick: jumping into an else statement??? XXX */ 01636 } 01637 } 01638 } 01639 if (x >= AST_MAX_FDS) { 01640 std: for (x=0; x<AST_MAX_FDS; x++) { 01641 /* Keep this one for next one */ 01642 if (pu->chan->fds[x] > -1) { 01643 FD_SET(pu->chan->fds[x], &nrfds); 01644 FD_SET(pu->chan->fds[x], &nefds); 01645 if (pu->chan->fds[x] > max) 01646 max = pu->chan->fds[x]; 01647 } 01648 } 01649 /* Keep track of our longest wait */ 01650 if ((tms < ms) || (ms < 0)) 01651 ms = tms; 01652 pl = pu; 01653 pu = pu->next; 01654 } 01655 } 01656 } 01657 ast_mutex_unlock(&parking_lock); 01658 rfds = nrfds; 01659 efds = nefds; 01660 tv = ast_samp2tv(ms, 1000); 01661 /* Wait for something to happen */ 01662 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL); 01663 pthread_testcancel(); 01664 } 01665 return NULL; /* Never reached */ 01666 }
|
|
Definition at line 927 of file res_features.c. References ast_call_feature::app, app, ast_call_feature::app_args, AST_FEATURE_FLAG_CALLEE, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_PBX_KEEPALIVE, AST_PBX_NO_HANGUP_PEER, ast_test_flag, ast_call_feature::exten, FEATURE_RETURN_NO_HANGUP_PEER, FEATURE_RETURN_PBX_KEEPALIVE, FEATURE_RETURN_SUCCESS, FEATURE_RETURN_SUCCESSBREAK, LOG_NOTICE, LOG_WARNING, pbx_exec(), and pbx_findapp(). Referenced by load_config(). 00928 { 00929 struct ast_app *app; 00930 struct ast_call_feature *feature; 00931 int res; 00932 00933 AST_LIST_LOCK(&feature_list); 00934 AST_LIST_TRAVERSE(&feature_list,feature,feature_entry) { 00935 if (!strcasecmp(feature->exten,code)) break; 00936 } 00937 AST_LIST_UNLOCK(&feature_list); 00938 00939 if (!feature) { /* shouldn't ever happen! */ 00940 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n"); 00941 return -1; 00942 } 00943 00944 app = pbx_findapp(feature->app); 00945 if (app) { 00946 struct ast_channel *work = chan; 00947 if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLEE)) 00948 work = peer; 00949 res = pbx_exec(work, app, feature->app_args, 1); 00950 if (res == AST_PBX_KEEPALIVE) 00951 return FEATURE_RETURN_PBX_KEEPALIVE; 00952 else if (res == AST_PBX_NO_HANGUP_PEER) 00953 return FEATURE_RETURN_NO_HANGUP_PEER; 00954 else if (res) 00955 return FEATURE_RETURN_SUCCESSBREAK; 00956 } else { 00957 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app); 00958 return -2; 00959 } 00960 00961 return FEATURE_RETURN_SUCCESS; 00962 }
|
|
Definition at line 912 of file res_features.c. References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, and ast_call_feature::sname. Referenced by load_config(). 00913 { 00914 struct ast_call_feature *tmp; 00915 00916 AST_LIST_LOCK(&feature_list); 00917 AST_LIST_TRAVERSE(&feature_list, tmp, feature_entry) { 00918 if (!strcasecmp(tmp->sname, name)) 00919 break; 00920 } 00921 AST_LIST_UNLOCK(&feature_list); 00922 00923 return tmp; 00924 }
|
|
Definition at line 1854 of file res_features.c. References ast_cli(), ast_mutex_lock(), ast_mutex_unlock(), parkeduser::chan, parkeduser::context, parkeduser::exten, ast_channel::name, parkeduser::next, parkinglot, parkeduser::parkingnum, parkeduser::parkingtime, parkeduser::priority, RESULT_SUCCESS, and parkeduser::start. 01855 { 01856 struct parkeduser *cur; 01857 int numparked = 0; 01858 01859 ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel" 01860 , "Context", "Extension", "Pri", "Timeout"); 01861 01862 ast_mutex_lock(&parking_lock); 01863 01864 cur = parkinglot; 01865 while(cur) { 01866 ast_cli(fd, "%4d %25s (%-15s %-12s %-4d) %6lds\n" 01867 ,cur->parkingnum, cur->chan->name, cur->context, cur->exten 01868 ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL)); 01869 01870 cur = cur->next; 01871 numparked++; 01872 } 01873 ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : ""); 01874 01875 ast_mutex_unlock(&parking_lock); 01876 01877 return RESULT_SUCCESS; 01878 }
|
|
Definition at line 1806 of file res_features.c. References ast_cli(), ast_pickup_ext(), builtin_features, ast_call_feature::default_exten, ast_call_feature::fname, and format. 01807 { 01808 int i; 01809 int fcount; 01810 struct ast_call_feature *feature; 01811 char format[] = "%-25s %-7s %-7s\n"; 01812 01813 ast_cli(fd, format, "Builtin Feature", "Default", "Current"); 01814 ast_cli(fd, format, "---------------", "-------", "-------"); 01815 01816 ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */ 01817 01818 fcount = sizeof(builtin_features) / sizeof(builtin_features[0]); 01819 01820 for (i = 0; i < fcount; i++) 01821 { 01822 ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten); 01823 } 01824 ast_cli(fd, "\n"); 01825 ast_cli(fd, format, "Dynamic Feature", "Default", "Current"); 01826 ast_cli(fd, format, "---------------", "-------", "-------"); 01827 if (AST_LIST_EMPTY(&feature_list)) { 01828 ast_cli(fd, "(none)\n"); 01829 } 01830 else { 01831 AST_LIST_LOCK(&feature_list); 01832 AST_LIST_TRAVERSE(&feature_list, feature, feature_entry) { 01833 ast_cli(fd, format, feature->sname, "no def", feature->exten); 01834 } 01835 AST_LIST_UNLOCK(&feature_list); 01836 } 01837 ast_cli(fd, "\nCall parking\n"); 01838 ast_cli(fd, "------------\n"); 01839 ast_cli(fd,"%-20s: %s\n", "Parking extension", parking_ext); 01840 ast_cli(fd,"%-20s: %s\n", "Parking context", parking_con); 01841 ast_cli(fd,"%-20s: %d-%d\n", "Parked call extensions", parking_start, parking_stop); 01842 ast_cli(fd,"\n"); 01843 01844 return RESULT_SUCCESS; 01845 }
|
|
Returns the ASTERISK_GPL_KEY. This returns the ASTERISK_GPL_KEY, signifiying that you agree to the terms of the GPL stated in the ASTERISK_GPL_KEY. Your module will not load if it does not return the EXACT message:
char *key(void) { return ASTERISK_GPL_KEY; }
Definition at line 2200 of file res_features.c. References ASTERISK_GPL_KEY. 02201 { 02202 return ASTERISK_GPL_KEY; 02203 }
|
|
Definition at line 1966 of file res_features.c. References ast_call_feature::app, app, ast_call_feature::app_args, ast_add_extension2(), ast_config_destroy(), ast_config_load(), ast_context_create(), ast_context_find(), ast_context_remove_extension2(), AST_FEATURE_FLAG_CALLEE, AST_FEATURE_FLAG_CALLER, AST_FEATURE_FLAG_NEEDSDTMF, ast_log(), AST_MAX_EXTENSION, ast_parking_ext(), ast_register_feature(), ast_set_flag, ast_strlen_zero(), ast_true(), ast_unregister_features(), ast_variable_browse(), ast_verbose(), cfg, DEFAULT_FEATURE_DIGIT_TIMEOUT, DEFAULT_PARK_TIME, DEFAULT_TRANSFER_DIGIT_TIMEOUT, ast_call_feature::exten, FEATURE_APP_ARGS_LEN, FEATURE_APP_LEN, feature_exec_app(), FEATURE_EXTEN_LEN, FEATURE_SNAME_LEN, find_feature(), FREE, free, LOG_DEBUG, LOG_ERROR, LOG_NOTICE, LOG_WARNING, malloc, ast_call_feature::operation, option_verbose, remap_feature(), ast_call_feature::sname, strdup, strsep(), unmap_features(), var, and VERBOSE_PREFIX_2. 01967 { 01968 int start = 0, end = 0; 01969 struct ast_context *con = NULL; 01970 struct ast_config *cfg = NULL; 01971 struct ast_variable *var = NULL; 01972 char old_parking_ext[AST_MAX_EXTENSION]; 01973 char old_parking_con[AST_MAX_EXTENSION] = ""; 01974 01975 if (!ast_strlen_zero(parking_con)) { 01976 strcpy(old_parking_ext, parking_ext); 01977 strcpy(old_parking_con, parking_con); 01978 } 01979 01980 /* Reset to defaults */ 01981 strcpy(parking_con, "parkedcalls"); 01982 strcpy(parking_con_dial, "park-dial"); 01983 strcpy(parking_ext, "700"); 01984 strcpy(pickup_ext, "*8"); 01985 courtesytone[0] = '\0'; 01986 strcpy(xfersound, "beep"); 01987 strcpy(xferfailsound, "pbx-invalid"); 01988 parking_start = 701; 01989 parking_stop = 750; 01990 parkfindnext = 0; 01991 adsipark = 0; 01992 01993 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 01994 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 01995 01996 cfg = ast_config_load("features.conf"); 01997 if (!cfg) { 01998 cfg = ast_config_load("parking.conf"); 01999 if (cfg) 02000 ast_log(LOG_NOTICE, "parking.conf is deprecated in favor of 'features.conf'. Please rename it.\n"); 02001 } 02002 if (cfg) { 02003 var = ast_variable_browse(cfg, "general"); 02004 while(var) { 02005 if (!strcasecmp(var->name, "parkext")) { 02006 ast_copy_string(parking_ext, var->value, sizeof(parking_ext)); 02007 } else if (!strcasecmp(var->name, "context")) { 02008 ast_copy_string(parking_con, var->value, sizeof(parking_con)); 02009 } else if (!strcasecmp(var->name, "parkingtime")) { 02010 if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) { 02011 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value); 02012 parkingtime = DEFAULT_PARK_TIME; 02013 } else 02014 parkingtime = parkingtime * 1000; 02015 } else if (!strcasecmp(var->name, "parkpos")) { 02016 if (sscanf(var->value, "%d-%d", &start, &end) != 2) { 02017 ast_log(LOG_WARNING, "Format for parking positions is a-b, where a and b are numbers at line %d of parking.conf\n", var->lineno); 02018 } else { 02019 parking_start = start; 02020 parking_stop = end; 02021 } 02022 } else if (!strcasecmp(var->name, "findslot")) { 02023 parkfindnext = (!strcasecmp(var->value, "next")); 02024 } else if (!strcasecmp(var->name, "adsipark")) { 02025 adsipark = ast_true(var->value); 02026 } else if (!strcasecmp(var->name, "transferdigittimeout")) { 02027 if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) { 02028 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value); 02029 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 02030 } else 02031 transferdigittimeout = transferdigittimeout * 1000; 02032 } else if (!strcasecmp(var->name, "featuredigittimeout")) { 02033 if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) { 02034 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value); 02035 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 02036 } 02037 } else if (!strcasecmp(var->name, "courtesytone")) { 02038 ast_copy_string(courtesytone, var->value, sizeof(courtesytone)); 02039 } else if (!strcasecmp(var->name, "xfersound")) { 02040 ast_copy_string(xfersound, var->value, sizeof(xfersound)); 02041 } else if (!strcasecmp(var->name, "xferfailsound")) { 02042 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound)); 02043 } else if (!strcasecmp(var->name, "pickupexten")) { 02044 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext)); 02045 } 02046 var = var->next; 02047 } 02048 02049 unmap_features(); 02050 var = ast_variable_browse(cfg, "featuremap"); 02051 while(var) { 02052 if (remap_feature(var->name, var->value)) 02053 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name); 02054 var = var->next; 02055 } 02056 02057 /* Map a key combination to an application*/ 02058 ast_unregister_features(); 02059 var = ast_variable_browse(cfg, "applicationmap"); 02060 while(var) { 02061 char *tmp_val=strdup(var->value); 02062 char *exten, *party=NULL, *app=NULL, *app_args=NULL; 02063 02064 if (!tmp_val) { 02065 ast_log(LOG_ERROR, "res_features: strdup failed\n"); 02066 continue; 02067 } 02068 02069 02070 exten=strsep(&tmp_val,","); 02071 if (exten) party=strsep(&tmp_val,","); 02072 if (party) app=strsep(&tmp_val,","); 02073 02074 if (app) app_args=strsep(&tmp_val,","); 02075 02076 if (!(app && strlen(app)) || !(exten && strlen(exten)) || !(party && strlen(party)) || !(var->name && strlen(var->name))) { 02077 ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",app,exten,party,var->name); 02078 free(tmp_val); 02079 var = var->next; 02080 continue; 02081 } 02082 02083 { 02084 struct ast_call_feature *feature=find_feature(var->name); 02085 int mallocd=0; 02086 02087 if (!feature) { 02088 feature=malloc(sizeof(struct ast_call_feature)); 02089 mallocd=1; 02090 } 02091 if (!feature) { 02092 ast_log(LOG_NOTICE, "Malloc failed at feature mapping\n"); 02093 free(tmp_val); 02094 var = var->next; 02095 continue; 02096 } 02097 02098 memset(feature,0,sizeof(struct ast_call_feature)); 02099 ast_copy_string(feature->sname,var->name,FEATURE_SNAME_LEN); 02100 ast_copy_string(feature->app,app,FEATURE_APP_LEN); 02101 ast_copy_string(feature->exten, exten,FEATURE_EXTEN_LEN); 02102 free(tmp_val); 02103 02104 if (app_args) 02105 ast_copy_string(feature->app_args,app_args,FEATURE_APP_ARGS_LEN); 02106 02107 ast_copy_string(feature->exten, exten,sizeof(feature->exten)); 02108 feature->operation=feature_exec_app; 02109 ast_set_flag(feature,AST_FEATURE_FLAG_NEEDSDTMF); 02110 02111 if (!strcasecmp(party,"caller")) 02112 ast_set_flag(feature,AST_FEATURE_FLAG_CALLER); 02113 else if (!strcasecmp(party, "callee")) 02114 ast_set_flag(feature,AST_FEATURE_FLAG_CALLEE); 02115 else { 02116 ast_log(LOG_NOTICE, "Invalid party specification for feature '%s', must be caller, or callee\n", var->name); 02117 var = var->next; 02118 continue; 02119 } 02120 02121 ast_register_feature(feature); 02122 02123 if (option_verbose >=1) ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s' with code '%s'\n", var->name, app, exten); 02124 } 02125 var = var->next; 02126 } 02127 } 02128 ast_config_destroy(cfg); 02129 02130 /* Remove the old parking extension */ 02131 if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) { 02132 ast_context_remove_extension2(con, old_parking_ext, 1, registrar); 02133 ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con); 02134 } 02135 02136 if (!(con = ast_context_find(parking_con))) { 02137 if (!(con = ast_context_create(NULL, parking_con, registrar))) { 02138 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con); 02139 return -1; 02140 } 02141 } 02142 return ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, strdup(""), FREE, registrar); 02143 }
|
|
Initialize the module. Initialize the Agents module. This function is being called by Asterisk when loading the module. Among other thing it registers applications, cli commands and reads the cofiguration file.
Definition at line 2149 of file res_features.c. References ast_cli_register(), ast_manager_register, ast_pthread_create, ast_register_application(), do_parking_thread(), load_config(), manager_parking_status(), park_call_exec(), park_exec(), showfeatures, and showparked. 02150 { 02151 int res; 02152 02153 memset(parking_ext, 0, sizeof(parking_ext)); 02154 memset(parking_con, 0, sizeof(parking_con)); 02155 02156 if ((res = load_config())) 02157 return res; 02158 ast_cli_register(&showparked); 02159 ast_cli_register(&showfeatures); 02160 ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL); 02161 res = ast_register_application(parkedcall, park_exec, synopsis, descrip); 02162 if (!res) 02163 res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2); 02164 if (!res) { 02165 ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" ); 02166 } 02167 return res; 02168 }
|
|
Definition at line 1888 of file res_features.c. References ast_cli(), ast_mutex_lock(), ast_mutex_unlock(), ast_strlen_zero(), astman_get_header(), astman_send_ack(), parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, ast_channel::name, parkeduser::next, parkinglot, parkeduser::parkingnum, parkeduser::parkingtime, RESULT_SUCCESS, s, and parkeduser::start. Referenced by load_module(). 01889 { 01890 struct parkeduser *cur; 01891 char *id = astman_get_header(m,"ActionID"); 01892 char idText[256] = ""; 01893 01894 if (!ast_strlen_zero(id)) 01895 snprintf(idText,256,"ActionID: %s\r\n",id); 01896 01897 astman_send_ack(s, m, "Parked calls will follow"); 01898 01899 ast_mutex_lock(&parking_lock); 01900 01901 cur=parkinglot; 01902 while(cur) { 01903 ast_cli(s->fd, "Event: ParkedCall\r\n" 01904 "Exten: %d\r\n" 01905 "Channel: %s\r\n" 01906 "Timeout: %ld\r\n" 01907 "CallerID: %s\r\n" 01908 "CallerIDName: %s\r\n" 01909 "%s" 01910 "\r\n" 01911 ,cur->parkingnum, cur->chan->name 01912 ,(long)cur->start.tv_sec + (long)(cur->parkingtime/1000) - (long)time(NULL) 01913 ,(cur->chan->cid.cid_num ? cur->chan->cid.cid_num : "") 01914 ,(cur->chan->cid.cid_name ? cur->chan->cid.cid_name : "") 01915 ,idText); 01916 01917 cur = cur->next; 01918 } 01919 01920 ast_cli(s->fd, 01921 "Event: ParkedCallsComplete\r\n" 01922 "%s" 01923 "\r\n",idText); 01924 01925 ast_mutex_unlock(&parking_lock); 01926 01927 return RESULT_SUCCESS; 01928 }
|
|
Definition at line 1668 of file res_features.c. References ast_channel::_state, ast_answer(), ast_park_call(), AST_PBX_KEEPALIVE, ast_safe_sleep(), AST_STATE_UP, localuser::chan, ast_channel::exten, LOCAL_USER_ADD, LOCAL_USER_REMOVE, and ast_channel::priority. Referenced by load_module(). 01669 { 01670 /* Data is unused at the moment but could contain a parking 01671 lot context eventually */ 01672 int res=0; 01673 struct localuser *u; 01674 LOCAL_USER_ADD(u); 01675 /* Setup the exten/priority to be s/1 since we don't know 01676 where this call should return */ 01677 strcpy(chan->exten, "s"); 01678 chan->priority = 1; 01679 if (chan->_state != AST_STATE_UP) 01680 res = ast_answer(chan); 01681 if (!res) 01682 res = ast_safe_sleep(chan, 1000); 01683 if (!res) 01684 res = ast_park_call(chan, chan, 0, NULL); 01685 LOCAL_USER_REMOVE(u); 01686 if (!res) 01687 res = AST_PBX_KEEPALIVE; 01688 return res; 01689 }
|
|
Definition at line 1691 of file res_features.c. References ast_channel::_state, ast_answer(), ast_bridge_call(), ast_channel_make_compatible(), ast_context_find(), ast_context_remove_extension2(), AST_CONTROL_UNHOLD, AST_FEATURE_REDIRECT, ast_hangup(), ast_indicate(), ast_log(), AST_MAX_EXTENSION, ast_moh_stop(), ast_mutex_lock(), ast_mutex_unlock(), AST_PBX_NO_HANGUP_PEER, ast_set_flag, AST_STATE_UP, ast_streamfile(), ast_strlen_zero(), ast_verbose(), ast_waitstream(), parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, config, EVENT_FLAG_CALL, free, ast_channel::language, LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_WARNING, manager_event(), ast_channel::name, parkeduser::next, option_verbose, parkinglot, parkeduser::parkingnum, and VERBOSE_PREFIX_3. Referenced by load_module(). 01692 { 01693 int res=0; 01694 struct localuser *u; 01695 struct ast_channel *peer=NULL; 01696 struct parkeduser *pu, *pl=NULL; 01697 char exten[AST_MAX_EXTENSION]; 01698 struct ast_context *con; 01699 int park; 01700 int dres; 01701 struct ast_bridge_config config; 01702 01703 if (!data) { 01704 ast_log(LOG_WARNING, "Park requires an argument (extension number)\n"); 01705 return -1; 01706 } 01707 LOCAL_USER_ADD(u); 01708 park = atoi((char *)data); 01709 ast_mutex_lock(&parking_lock); 01710 pu = parkinglot; 01711 while(pu) { 01712 if (pu->parkingnum == park) { 01713 if (pl) 01714 pl->next = pu->next; 01715 else 01716 parkinglot = pu->next; 01717 break; 01718 } 01719 pl = pu; 01720 pu = pu->next; 01721 } 01722 ast_mutex_unlock(&parking_lock); 01723 if (pu) { 01724 peer = pu->chan; 01725 con = ast_context_find(parking_con); 01726 if (con) { 01727 snprintf(exten, sizeof(exten), "%d", pu->parkingnum); 01728 if (ast_context_remove_extension2(con, exten, 1, NULL)) 01729 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 01730 } else 01731 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 01732 01733 manager_event(EVENT_FLAG_CALL, "UnParkedCall", 01734 "Exten: %d\r\n" 01735 "Channel: %s\r\n" 01736 "From: %s\r\n" 01737 "CallerID: %s\r\n" 01738 "CallerIDName: %s\r\n" 01739 ,pu->parkingnum, pu->chan->name, chan->name 01740 ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>") 01741 ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>") 01742 ); 01743 01744 free(pu); 01745 } 01746 /* JK02: it helps to answer the channel if not already up */ 01747 if (chan->_state != AST_STATE_UP) { 01748 ast_answer(chan); 01749 } 01750 01751 if (peer) { 01752 /* Play a courtesy beep in the calling channel to prefix the bridge connecting */ 01753 if (!ast_strlen_zero(courtesytone)) { 01754 if (!ast_streamfile(chan, courtesytone, chan->language)) { 01755 if (ast_waitstream(chan, "") < 0) { 01756 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); 01757 ast_hangup(peer); 01758 return -1; 01759 } 01760 } 01761 } 01762 01763 ast_moh_stop(peer); 01764 ast_indicate(peer, AST_CONTROL_UNHOLD); 01765 res = ast_channel_make_compatible(chan, peer); 01766 if (res < 0) { 01767 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name); 01768 ast_hangup(peer); 01769 return -1; 01770 } 01771 /* This runs sorta backwards, since we give the incoming channel control, as if it 01772 were the person called. */ 01773 if (option_verbose > 2) 01774 ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park); 01775 01776 memset(&config, 0, sizeof(struct ast_bridge_config)); 01777 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT); 01778 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT); 01779 config.timelimit = 0; 01780 config.play_warning = 0; 01781 config.warning_freq = 0; 01782 config.warning_sound=NULL; 01783 res = ast_bridge_call(chan, peer, &config); 01784 01785 /* Simulate the PBX hanging up */ 01786 if (res != AST_PBX_NO_HANGUP_PEER) 01787 ast_hangup(peer); 01788 return res; 01789 } else { 01790 /* XXX Play a message XXX */ 01791 dres = ast_streamfile(chan, "pbx-invalidpark", chan->language); 01792 if (!dres) 01793 dres = ast_waitstream(chan, ""); 01794 else { 01795 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name); 01796 dres = 0; 01797 } 01798 if (option_verbose > 2) 01799 ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park); 01800 res = -1; 01801 } 01802 LOCAL_USER_REMOVE(u); 01803 return res; 01804 }
|
|
Reload stuff. This function is where any reload routines take place. Re-read config files, change signalling, whatever is appropriate on a reload.
Definition at line 2145 of file res_features.c. References load_config(). 02145 { 02146 return load_config(); 02147 }
|
|
Definition at line 971 of file res_features.c. References ast_verbose(), builtin_features, FEATURES_COUNT, option_verbose, and VERBOSE_PREFIX_2. Referenced by load_config(). 00972 { 00973 int x; 00974 int res = -1; 00975 for (x = 0; x < FEATURES_COUNT; x++) { 00976 if (!strcasecmp(name, builtin_features[x].sname)) { 00977 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten)); 00978 if (option_verbose > 1) 00979 ast_verbose(VERBOSE_PREFIX_2 "Remapping feature %s (%s) to sequence '%s'\n", builtin_features[x].fname, builtin_features[x].sname, builtin_features[x].exten); 00980 res = 0; 00981 } else if (!strcmp(value, builtin_features[x].exten)) 00982 ast_log(LOG_WARNING, "Sequence '%s' already mapped to function %s (%s) while assigning to %s\n", value, builtin_features[x].fname, builtin_features[x].sname, name); 00983 } 00984 return res; 00985 }
|
|
Definition at line 1046 of file res_features.c. References AST_BRIDGE_DTMF_CHANNEL_0, AST_BRIDGE_DTMF_CHANNEL_1, ast_clear_flag, AST_FEATURE_FLAG_NEEDSDTMF, AST_FLAGS_ALL, ast_set_flag, ast_test_flag, builtin_features, config, ast_call_feature::feature_mask, and FEATURES_COUNT. Referenced by ast_bridge_call(). 01047 { 01048 int x; 01049 01050 ast_clear_flag(config, AST_FLAGS_ALL); 01051 for (x = 0; x < FEATURES_COUNT; x++) { 01052 if (ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF)) { 01053 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask)) 01054 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 01055 01056 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask)) 01057 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 01058 } 01059 } 01060 01061 if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) { 01062 char *dynamic_features; 01063 01064 dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"); 01065 01066 if (dynamic_features) { 01067 char *tmp = ast_strdupa(dynamic_features); 01068 char *tok; 01069 struct ast_call_feature *feature; 01070 01071 if (!tmp) { 01072 return; 01073 } 01074 01075 /* while we have a feature */ 01076 while (NULL != (tok = strsep(&tmp, "#"))) { 01077 if ((feature = find_feature(tok))) { 01078 if (ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) { 01079 if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLER)) 01080 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 01081 if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLEE)) 01082 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 01083 } 01084 } 01085 } 01086 } 01087 } 01088 }
|
|
Cleanup all module structures, sockets, etc. Standard module functions ... Definition at line 2171 of file res_features.c. References ast_cli_unregister(), ast_manager_unregister(), ast_unregister_application(), showfeatures, showparked, and STANDARD_HANGUP_LOCALUSERS. 02172 { 02173 STANDARD_HANGUP_LOCALUSERS; 02174 02175 ast_manager_unregister("ParkedCalls"); 02176 ast_cli_unregister(&showfeatures); 02177 ast_cli_unregister(&showparked); 02178 ast_unregister_application(parkcall); 02179 return ast_unregister_application(parkedcall); 02180 }
|
|
Definition at line 964 of file res_features.c. References builtin_features, and FEATURES_COUNT. Referenced by load_config(). 00965 { 00966 int x; 00967 for (x = 0; x < FEATURES_COUNT; x++) 00968 strcpy(builtin_features[x].exten, builtin_features[x].default_exten); 00969 }
|
|
Provides a usecount. This function will be called by various parts of asterisk. Basically, all it has to do is to return a usecount when called. You will need to maintain your usecount within the module somewhere. The usecount should be how many channels provided by this module are in use.
Definition at line 2187 of file res_features.c. References STANDARD_USECOUNT. 02188 { 02189 /* Never allow parking to be unloaded because it will 02190 unresolve needed symbols in the dialer */ 02191 #if 0 02192 int res; 02193 STANDARD_USECOUNT(res); 02194 return res; 02195 #else 02196 return 1; 02197 #endif 02198 }
|
|
Definition at line 106 of file res_features.c. |
|
Definition at line 863 of file res_features.c. Referenced by ast_feature_interpret(), ast_feature_request_and_dial(), handle_showfeatures(), remap_feature(), set_config_flags(), and unmap_features(). |
|
Definition at line 92 of file res_features.c. |
|
Initial value: "ParkedCall(exten):" "Used to connect to a parked call. This application is always\n" "registered internally and does not need to be explicitly added\n" "into the dialplan, although you should include the 'parkedcalls'\n" "context.\n" Definition at line 118 of file res_features.c. |
|
Definition at line 128 of file res_features.c. |
|
Definition at line 109 of file res_features.c. |
|
Definition at line 161 of file res_features.c. |
|
Definition at line 135 of file res_features.c. Referenced by ast_bridge_call(), and builtin_automonitor(). |
|
Definition at line 136 of file res_features.c. |
|
Definition at line 124 of file res_features.c. |
|
Definition at line 75 of file res_features.c. |
|
Definition at line 104 of file res_features.c. |
|
Definition at line 81 of file res_features.c. |
|
Definition at line 84 of file res_features.c. |
|
Definition at line 87 of file res_features.c. |
|
Definition at line 102 of file res_features.c. |
|
Definition at line 97 of file res_features.c. |
|
Definition at line 100 of file res_features.c. |
|
Definition at line 157 of file res_features.c. |
|
Definition at line 153 of file res_features.c. Referenced by ast_park_call(), do_parking_thread(), handle_parkedcalls(), manager_parking_status(), and park_exec(). |
|
Definition at line 78 of file res_features.c. |
|
Definition at line 89 of file res_features.c. |
|
Definition at line 114 of file res_features.c. |
|
Initial value: { { "show", "features", NULL }, handle_showfeatures, "Lists configured features", showfeatures_help } Definition at line 1851 of file res_features.c. Referenced by load_module(), and unload_module(). |
|
Initial value: "Usage: show features\n" " Lists currently configured features.\n" Definition at line 1847 of file res_features.c. |
|
Initial value: { { "show", "parkedcalls", NULL }, handle_parkedcalls, "Lists parked calls", showparked_help } Definition at line 1884 of file res_features.c. Referenced by load_module(), and unload_module(). |
|
Initial value: "Usage: show parkedcalls\n" " Lists currently parked calls.\n" Definition at line 1880 of file res_features.c. |
|
Definition at line 159 of file res_features.c. |
|
Definition at line 116 of file res_features.c. |
|
Definition at line 126 of file res_features.c. |
|
Definition at line 108 of file res_features.c. |
|
Definition at line 94 of file res_features.c. |
|
Definition at line 93 of file res_features.c. |