#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 | |
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. | |
void * | ast_bridge_call_thread (void *data) |
void | ast_bridge_call_thread_launch (void *data) |
int | ast_feature_interpret (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) |
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) |
AST_LIST_HEAD (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_unregister_feature (struct ast_call_feature *feature) |
unregister feature from feature_set | |
void | ast_unregister_features (void) |
int | builtin_atxfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) |
int | builtin_automonitor (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) |
int | builtin_blindtransfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) |
int | builtin_disconnect (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) |
void | check_goto_on_transfer (struct ast_channel *chan) |
char * | description (void) |
Provides a description of the module. | |
void * | do_parking_thread (void *ignore) |
int | feature_exec_app (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) |
ast_call_feature * | find_feature (char *name) |
int | handle_parkedcalls (int fd, int argc, char *argv[]) |
int | handle_showfeatures (int fd, int argc, char *argv[]) |
char * | key () |
Returns the ASTERISK_GPL_KEY. | |
int | load_config (void) |
int | load_module (void) |
Initialize the module. | |
int | manager_parking_status (struct mansession *s, struct message *m) |
int | park_call_exec (struct ast_channel *chan, void *data) |
int | park_exec (struct ast_channel *chan, void *data) |
int | reload (void) |
Reload stuff. | |
int | remap_feature (const char *name, const char *value) |
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. | |
void | unmap_features (void) |
int | usecount (void) |
Provides a usecount. | |
Variables | |
int | adsipark |
ast_call_feature | builtin_features [] |
char | courtesytone [256] |
char * | descrip |
char * | descrip2 |
int | featuredigittimeout |
LOCAL_USER_DECL | |
ast_app * | monitor_app = NULL |
int | monitor_ok = 1 |
char * | parkcall = "Park" |
char * | parkedcall = "ParkedCall" |
int | parkfindnext |
char | parking_con [AST_MAX_EXTENSION] |
char | parking_con_dial [AST_MAX_EXTENSION] |
char | parking_ext [AST_MAX_EXTENSION] |
int | parking_offset |
int | parking_start |
int | parking_stop |
pthread_t | parking_thread |
parkeduser * | parkinglot |
int | parkingtime = DEFAULT_PARK_TIME |
char | pickup_ext [AST_MAX_EXTENSION] |
char * | registrar = "res_features" |
ast_cli_entry | showfeatures |
char | showfeatures_help [] |
ast_cli_entry | showparked |
char | showparked_help [] |
STANDARD_LOCAL_USER | |
char * | synopsis = "Answer a parked call" |
char * | synopsis2 = "Park yourself" |
int | transferdigittimeout |
char | xferfailsound [256] |
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. |
|
Definition at line 69 of file res_features.c. |
|
Definition at line 70 of file res_features.c. |
|
Definition at line 435 of file res_features.c. |
|
Definition at line 438 of file res_features.c. |
|
Definition at line 439 of file res_features.c. Referenced by ast_bridge_call(). |
|
Definition at line 437 of file res_features.c. |
|
Definition at line 440 of file res_features.c. |
|
Definition at line 441 of file res_features.c. Referenced by ast_bridge_call(). |
|
Definition at line 436 of file res_features.c. |
|
Definition at line 443 of file res_features.c. |
|
Definition at line 444 of file res_features.c. |
|
Definition at line 859 of file res_features.c. |
|
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(), and adsi_print(). Referenced by ast_park_call(). 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 1251 of file res_features.c. References ast_channel::appl, ast_answer(), ast_cdr_appenduserfield(), ast_cdr_setuserfield(), ast_channel_bridge(), ast_channel_setoption(), ast_clear_flag, AST_CONTROL_FLASH, AST_CONTROL_RINGING, ast_dtmf_stream(), ast_feature_interpret(), AST_FEATURE_PLAY_WARNING, ast_frfree(), ast_indicate(), ast_log(), ast_strlen_zero(), ast_channel::cdr, ast_option_header::data, ast_frame::data, ast_channel::data, ast_frame::datalen, ast_bridge_config::end_sound, FEATURE_MAX_LEN, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_SUCCESS, ast_bridge_config::feature_timer, ast_bridge_config::features_callee, ast_bridge_config::features_caller, ast_bridge_config::firstpass, ast_option_header::flag, ast_frame::frametype, free, LOG_DEBUG, LOG_WARNING, monitor_app, monitor_ok, ast_channel::name, ast_option_header::option, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), ast_bridge_config::play_warning, set_config_flags(), ast_bridge_config::start_sound, ast_bridge_config::start_time, ast_frame::subclass, ast_cdr::userfield, ast_bridge_config::warning_freq, and ast_bridge_config::warning_sound. Referenced by ast_bridge_call_thread(), builtin_atxfer(), dial_exec_full(), park_exec(), and try_calling(). 01252 { 01253 /* Copy voice back and forth between the two channels. Give the peer 01254 the ability to transfer calls with '#<extension' syntax. */ 01255 struct ast_frame *f; 01256 struct ast_channel *who; 01257 char chan_featurecode[FEATURE_MAX_LEN + 1]=""; 01258 char peer_featurecode[FEATURE_MAX_LEN + 1]=""; 01259 int res; 01260 int diff; 01261 int hasfeatures=0; 01262 int hadfeatures=0; 01263 struct ast_option_header *aoh; 01264 struct timeval start = { 0 , 0 }; 01265 struct ast_bridge_config backup_config; 01266 char *monitor_exec; 01267 01268 memset(&backup_config, 0, sizeof(backup_config)); 01269 01270 config->start_time = ast_tvnow(); 01271 01272 if (chan && peer) { 01273 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name); 01274 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name); 01275 } else if (chan) 01276 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL); 01277 01278 if (monitor_ok) { 01279 if (!monitor_app) { 01280 if (!(monitor_app = pbx_findapp("Monitor"))) 01281 monitor_ok=0; 01282 } 01283 if (monitor_app) { 01284 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 01285 pbx_exec(chan, monitor_app, monitor_exec, 1); 01286 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR"))) 01287 pbx_exec(peer, monitor_app, monitor_exec, 1); 01288 } 01289 } 01290 01291 set_config_flags(chan, peer, config); 01292 config->firstpass = 1; 01293 01294 /* Answer if need be */ 01295 if (ast_answer(chan)) 01296 return -1; 01297 peer->appl = "Bridged Call"; 01298 peer->data = chan->name; 01299 01300 /* copy the userfield from the B-leg to A-leg if applicable */ 01301 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) { 01302 char tmp[256]; 01303 if (!ast_strlen_zero(chan->cdr->userfield)) { 01304 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield); 01305 ast_cdr_appenduserfield(chan, tmp); 01306 } else 01307 ast_cdr_setuserfield(chan, peer->cdr->userfield); 01308 /* free the peer's cdr without ast_cdr_free complaining */ 01309 free(peer->cdr); 01310 peer->cdr = NULL; 01311 } 01312 for (;;) { 01313 if (config->feature_timer) 01314 start = ast_tvnow(); 01315 01316 res = ast_channel_bridge(chan, peer, config, &f, &who); 01317 01318 if (config->feature_timer) { 01319 /* Update time limit for next pass */ 01320 diff = ast_tvdiff_ms(ast_tvnow(), start); 01321 config->feature_timer -= diff; 01322 if (hasfeatures) { 01323 /* Running on backup config, meaning a feature might be being 01324 activated, but that's no excuse to keep things going 01325 indefinitely! */ 01326 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) { 01327 ast_log(LOG_DEBUG, "Timed out, realtime this time!\n"); 01328 config->feature_timer = 0; 01329 who = chan; 01330 if (f) 01331 ast_frfree(f); 01332 f = NULL; 01333 res = 0; 01334 } else if (config->feature_timer <= 0) { 01335 /* Not *really* out of time, just out of time for 01336 digits to come in for features. */ 01337 ast_log(LOG_DEBUG, "Timed out for feature!\n"); 01338 if (!ast_strlen_zero(peer_featurecode)) { 01339 ast_dtmf_stream(chan, peer, peer_featurecode, 0); 01340 memset(peer_featurecode, 0, sizeof(peer_featurecode)); 01341 } 01342 if (!ast_strlen_zero(chan_featurecode)) { 01343 ast_dtmf_stream(peer, chan, chan_featurecode, 0); 01344 memset(chan_featurecode, 0, sizeof(chan_featurecode)); 01345 } 01346 if (f) 01347 ast_frfree(f); 01348 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 01349 if (!hasfeatures) { 01350 /* Restore original (possibly time modified) bridge config */ 01351 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 01352 memset(&backup_config, 0, sizeof(backup_config)); 01353 } 01354 hadfeatures = hasfeatures; 01355 /* Continue as we were */ 01356 continue; 01357 } 01358 } else { 01359 if (config->feature_timer <=0) { 01360 /* We ran out of time */ 01361 config->feature_timer = 0; 01362 who = chan; 01363 if (f) 01364 ast_frfree(f); 01365 f = NULL; 01366 res = 0; 01367 } 01368 } 01369 } 01370 if (res < 0) { 01371 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name); 01372 return -1; 01373 } 01374 01375 if (!f || ((f->frametype == AST_FRAME_CONTROL) && ((f->subclass == AST_CONTROL_HANGUP) || (f->subclass == AST_CONTROL_BUSY) || 01376 (f->subclass == AST_CONTROL_CONGESTION)))) { 01377 res = -1; 01378 break; 01379 } 01380 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_RINGING)) { 01381 if (who == chan) 01382 ast_indicate(peer, AST_CONTROL_RINGING); 01383 else 01384 ast_indicate(chan, AST_CONTROL_RINGING); 01385 } 01386 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == -1)) { 01387 if (who == chan) 01388 ast_indicate(peer, -1); 01389 else 01390 ast_indicate(chan, -1); 01391 } 01392 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_FLASH)) { 01393 if (who == chan) 01394 ast_indicate(peer, AST_CONTROL_FLASH); 01395 else 01396 ast_indicate(chan, AST_CONTROL_FLASH); 01397 } 01398 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_OPTION)) { 01399 aoh = f->data; 01400 /* Forward option Requests */ 01401 if (aoh && (aoh->flag == AST_OPTION_FLAG_REQUEST)) { 01402 if (who == chan) 01403 ast_channel_setoption(peer, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0); 01404 else 01405 ast_channel_setoption(chan, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0); 01406 } 01407 } 01408 /* check for '*', if we find it it's time to disconnect */ 01409 if (f && (f->frametype == AST_FRAME_DTMF)) { 01410 char *featurecode; 01411 int sense; 01412 struct ast_channel *other; 01413 01414 hadfeatures = hasfeatures; 01415 /* This cannot overrun because the longest feature is one shorter than our buffer */ 01416 if (who == chan) { 01417 other = peer; 01418 sense = FEATURE_SENSE_CHAN; 01419 featurecode = chan_featurecode; 01420 } else { 01421 other = chan; 01422 sense = FEATURE_SENSE_PEER; 01423 featurecode = peer_featurecode; 01424 } 01425 featurecode[strlen(featurecode)] = f->subclass; 01426 config->feature_timer = backup_config.feature_timer; 01427 res = ast_feature_interpret(chan, peer, config, featurecode, sense); 01428 switch(res) { 01429 case FEATURE_RETURN_PASSDIGITS: 01430 ast_dtmf_stream(other, who, featurecode, 0); 01431 /* Fall through */ 01432 case FEATURE_RETURN_SUCCESS: 01433 memset(featurecode, 0, sizeof(chan_featurecode)); 01434 break; 01435 } 01436 if (res >= FEATURE_RETURN_PASSDIGITS) { 01437 res = 0; 01438 } else { 01439 ast_frfree(f); 01440 break; 01441 } 01442 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 01443 if (hadfeatures && !hasfeatures) { 01444 /* Restore backup */ 01445 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 01446 memset(&backup_config, 0, sizeof(struct ast_bridge_config)); 01447 } else if (hasfeatures) { 01448 if (!hadfeatures) { 01449 /* Backup configuration */ 01450 memcpy(&backup_config, config, sizeof(struct ast_bridge_config)); 01451 /* Setup temporary config options */ 01452 config->play_warning = 0; 01453 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); 01454 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); 01455 config->warning_freq = 0; 01456 config->warning_sound = NULL; 01457 config->end_sound = NULL; 01458 config->start_sound = NULL; 01459 config->firstpass = 0; 01460 } 01461 config->feature_timer = featuredigittimeout; 01462 ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer); 01463 } 01464 } 01465 if (f) 01466 ast_frfree(f); 01467 } 01468 return res; 01469 }
|
|
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 980 of file res_features.c. References ast_copy_flags, AST_FLAGS_ALL, ast_log(), ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_verbose(), builtin_features, ast_call_feature::exten, ast_bridge_config::features_callee, ast_bridge_config::features_caller, find_feature(), ast_flags::flags, LOG_DEBUG, ast_channel::name, ast_call_feature::operation, option_verbose, pbx_builtin_getvar_helper(), ast_call_feature::sname, strsep(), and VERBOSE_PREFIX_3. Referenced by ast_bridge_call(). 00981 { 00982 int x; 00983 struct ast_flags features; 00984 int res = FEATURE_RETURN_PASSDIGITS; 00985 struct ast_call_feature *feature; 00986 char *dynamic_features=pbx_builtin_getvar_helper(chan,"DYNAMIC_FEATURES"); 00987 00988 if (sense == FEATURE_SENSE_CHAN) 00989 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL); 00990 else 00991 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL); 00992 ast_log(LOG_DEBUG, "Feature interpret: chan=%s, peer=%s, sense=%d, features=%d\n", chan->name, peer->name, sense, features.flags); 00993 00994 for (x=0; x < FEATURES_COUNT; x++) { 00995 if ((ast_test_flag(&features, builtin_features[x].feature_mask)) && 00996 !ast_strlen_zero(builtin_features[x].exten)) { 00997 /* Feature is up for consideration */ 00998 if (!strcmp(builtin_features[x].exten, code)) { 00999 res = builtin_features[x].operation(chan, peer, config, code, sense); 01000 break; 01001 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) { 01002 if (res == FEATURE_RETURN_PASSDIGITS) 01003 res = FEATURE_RETURN_STOREDIGITS; 01004 } 01005 } 01006 } 01007 01008 01009 if (!ast_strlen_zero(dynamic_features)) { 01010 char *tmp = ast_strdupa(dynamic_features); 01011 char *tok; 01012 01013 if (!tmp) 01014 return res; 01015 01016 while ((tok = strsep(&tmp, "#")) != NULL) { 01017 feature = find_feature(tok); 01018 01019 if (feature) { 01020 /* Feature is up for consideration */ 01021 if (!strcmp(feature->exten, code)) { 01022 if (option_verbose > 2) 01023 ast_verbose(VERBOSE_PREFIX_3 " Feature Found: %s exten: %s\n",feature->sname, tok); 01024 res = feature->operation(chan, peer, config, code, sense); 01025 break; 01026 } else if (!strncmp(feature->exten, code, strlen(code))) { 01027 res = FEATURE_RETURN_STOREDIGITS; 01028 } 01029 } 01030 } 01031 } 01032 01033 return res; 01034 }
|
|
Definition at line 1081 of file res_features.c. References ast_channel::_softhangup, ast_channel::_state, ast_call(), AST_CAUSE_BUSY, AST_CAUSE_CONGESTION, ast_cdr_alloc(), ast_cdr_disposition(), ast_cdr_end(), ast_cdr_failed(), ast_cdr_init(), ast_cdr_setapp(), ast_cdr_start(), ast_cdr_update(), ast_channel_inherit_variables(), ast_check_hangup(), AST_CONTROL_RINGING, AST_FRAME_CONTROL, AST_FRAME_DTMF, ast_frfree(), ast_hangup(), ast_indicate(), ast_log(), ast_read(), ast_request(), ast_set_callerid(), ast_verbose(), ast_waitfor_n(), builtin_features, ast_channel::cdr, ast_call_feature::exten, ast_frame::frametype, ast_channel::hangupcause, LOG_NOTICE, LOG_WARNING, option_verbose, ast_frame::subclass, type, and VERBOSE_PREFIX_3. Referenced by builtin_atxfer(). 01082 { 01083 int state = 0; 01084 int cause = 0; 01085 int to; 01086 struct ast_channel *chan; 01087 struct ast_channel *monitor_chans[2]; 01088 struct ast_channel *active_channel; 01089 struct ast_frame *f = NULL; 01090 int res = 0, ready = 0; 01091 01092 if ((chan = ast_request(type, format, data, &cause))) { 01093 ast_set_callerid(chan, cid_num, cid_name, cid_num); 01094 ast_channel_inherit_variables(caller, chan); 01095 if (!ast_call(chan, data, timeout)) { 01096 struct timeval started; 01097 int x, len = 0; 01098 char *disconnect_code = NULL, *dialed_code = NULL; 01099 01100 ast_indicate(caller, AST_CONTROL_RINGING); 01101 /* support dialing of the featuremap disconnect code while performing an attended tranfer */ 01102 for (x=0; x < FEATURES_COUNT; x++) { 01103 if (strcasecmp(builtin_features[x].sname, "disconnect")) 01104 continue; 01105 01106 disconnect_code = builtin_features[x].exten; 01107 len = strlen(disconnect_code) + 1; 01108 dialed_code = alloca(len); 01109 memset(dialed_code, 0, len); 01110 break; 01111 } 01112 x = 0; 01113 started = ast_tvnow(); 01114 to = timeout; 01115 while (!ast_check_hangup(caller) && timeout && (chan->_state != AST_STATE_UP)) { 01116 monitor_chans[0] = caller; 01117 monitor_chans[1] = chan; 01118 active_channel = ast_waitfor_n(monitor_chans, 2, &to); 01119 01120 /* see if the timeout has been violated */ 01121 if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) { 01122 state = AST_CONTROL_UNHOLD; 01123 ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n"); 01124 break; /*doh! timeout*/ 01125 } 01126 01127 if (!active_channel) { 01128 continue; 01129 } 01130 01131 if (chan && (chan == active_channel)){ 01132 f = ast_read(chan); 01133 if (f == NULL) { /*doh! where'd he go?*/ 01134 state = AST_CONTROL_HANGUP; 01135 res = 0; 01136 break; 01137 } 01138 01139 if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) { 01140 if (f->subclass == AST_CONTROL_RINGING) { 01141 state = f->subclass; 01142 if (option_verbose > 2) 01143 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", chan->name); 01144 ast_indicate(caller, AST_CONTROL_RINGING); 01145 } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) { 01146 state = f->subclass; 01147 ast_frfree(f); 01148 f = NULL; 01149 break; 01150 } else if (f->subclass == AST_CONTROL_ANSWER) { 01151 /* This is what we are hoping for */ 01152 state = f->subclass; 01153 ast_frfree(f); 01154 f = NULL; 01155 ready=1; 01156 break; 01157 } else { 01158 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass); 01159 } 01160 /* else who cares */ 01161 } 01162 01163 } else if (caller && (active_channel == caller)) { 01164 f = ast_read(caller); 01165 if (f == NULL) { /*doh! where'd he go?*/ 01166 if (caller->_softhangup && !chan->_softhangup) { 01167 /* make this a blind transfer */ 01168 ready = 1; 01169 break; 01170 } 01171 state = AST_CONTROL_HANGUP; 01172 res = 0; 01173 break; 01174 } 01175 01176 if (f->frametype == AST_FRAME_DTMF) { 01177 dialed_code[x++] = f->subclass; 01178 dialed_code[x] = '\0'; 01179 if (strlen(dialed_code) == len) { 01180 x = 0; 01181 } else if (x && strncmp(dialed_code, disconnect_code, x)) { 01182 x = 0; 01183 dialed_code[x] = '\0'; 01184 } 01185 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) { 01186 /* Caller Canceled the call */ 01187 state = AST_CONTROL_UNHOLD; 01188 ast_frfree(f); 01189 f = NULL; 01190 break; 01191 } 01192 } 01193 } 01194 if (f) { 01195 ast_frfree(f); 01196 } 01197 } 01198 } else 01199 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data); 01200 } else { 01201 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data); 01202 switch(cause) { 01203 case AST_CAUSE_BUSY: 01204 state = AST_CONTROL_BUSY; 01205 break; 01206 case AST_CAUSE_CONGESTION: 01207 state = AST_CONTROL_CONGESTION; 01208 break; 01209 } 01210 } 01211 01212 ast_indicate(caller, -1); 01213 if (chan && ready) { 01214 if (chan->_state == AST_STATE_UP) 01215 state = AST_CONTROL_ANSWER; 01216 res = 0; 01217 } else if(chan) { 01218 res = -1; 01219 ast_hangup(chan); 01220 chan = NULL; 01221 } else { 01222 res = -1; 01223 } 01224 01225 if (outstate) 01226 *outstate = state; 01227 01228 if (chan && res <= 0) { 01229 if (!chan->cdr) { 01230 chan->cdr = ast_cdr_alloc(); 01231 } 01232 if (chan->cdr) { 01233 char tmp[256]; 01234 ast_cdr_init(chan->cdr, chan); 01235 snprintf(tmp, 256, "%s/%s", type, (char *)data); 01236 ast_cdr_setapp(chan->cdr,"Dial",tmp); 01237 ast_cdr_update(chan); 01238 ast_cdr_start(chan->cdr); 01239 ast_cdr_end(chan->cdr); 01240 /* If the cause wasn't handled properly */ 01241 if (ast_cdr_disposition(chan->cdr,chan->hangupcause)) 01242 ast_cdr_failed(chan->cdr); 01243 } else { 01244 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n"); 01245 } 01246 } 01247 01248 return chan; 01249 }
|
|
Definition at line 869 of file res_features.c. References AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_verbose(), LOG_NOTICE, option_verbose, and VERBOSE_PREFIX_2. 00873 { 00874 if (!feature) { 00875 ast_log(LOG_NOTICE,"You didn't pass a feature!\n"); 00876 return; 00877 } 00878 00879 AST_LIST_LOCK(&feature_list); 00880 AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry); 00881 AST_LIST_UNLOCK(&feature_list); 00882 00883 if (option_verbose >= 2) 00884 ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname); 00885 }
|
|
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(), rpt_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 adsi_announce_park(), adsi_available(), adsi_unload_session(), adsipark, ast_channel::appl, ast_add_extension2(), ast_context_create(), ast_context_find(), AST_CONTROL_HOLD, ast_indicate(), ast_log(), ast_moh_start(), ast_mutex_lock(), ast_mutex_unlock(), ast_say_digits(), ast_strlen_zero(), ast_verbose(), parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, ast_channel::context, parkeduser::context, ast_channel::data, EVENT_FLAG_CALL, ast_channel::exten, parkeduser::exten, FREE, free, ast_channel::language, LOG_ERROR, LOG_WARNING, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::macropriority, malloc, manager_event(), ast_channel::name, parkeduser::next, parkeduser::notquiteyet, option_verbose, parkedcall, parking_con, parking_offset, parking_start, parking_stop, parking_thread, parkinglot, parkeduser::parkingnum, parkeduser::parkingtime, parkeduser::peername, ast_channel::priority, parkeduser::priority, registrar, parkeduser::start, strdup, and VERBOSE_PREFIX_2. 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->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 1915 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_channel::callgroup, ast_channel::lock, LOG_DEBUG, LOG_WARNING, ast_channel::name, ast_channel::pbx, and ast_channel::pickupgroup. Referenced by cb_events(), handle_request_invite(), mgcp_ss(), monitor_handle_notowned(), skinny_ss(), and ss_thread(). 01916 { 01917 struct ast_channel *cur = NULL; 01918 int res = -1; 01919 01920 while ( (cur = ast_channel_walk_locked(cur)) != NULL) { 01921 if (!cur->pbx && 01922 (cur != chan) && 01923 (chan->pickupgroup & cur->callgroup) && 01924 ((cur->_state == AST_STATE_RINGING) || 01925 (cur->_state == AST_STATE_RING))) { 01926 break; 01927 } 01928 ast_mutex_unlock(&cur->lock); 01929 } 01930 if (cur) { 01931 if (option_debug) 01932 ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name); 01933 res = ast_answer(chan); 01934 if (res) 01935 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name); 01936 res = ast_queue_control(chan, AST_CONTROL_ANSWER); 01937 if (res) 01938 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name); 01939 res = ast_channel_masquerade(cur, chan); 01940 if (res) 01941 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */ 01942 ast_mutex_unlock(&cur->lock); 01943 } else { 01944 if (option_debug) 01945 ast_log(LOG_DEBUG, "No call pickup possible...\n"); 01946 } 01947 return res; 01948 }
|
|
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 }
|
|
unregister feature from feature_set
Definition at line 888 of file res_features.c. References AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, and free. 00889 { 00890 if (!feature) return; 00891 00892 AST_LIST_LOCK(&feature_list); 00893 AST_LIST_REMOVE(&feature_list,feature,feature_entry); 00894 AST_LIST_UNLOCK(&feature_list); 00895 free(feature); 00896 }
|
|
Definition at line 898 of file res_features.c. References AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, and free. Referenced by load_config(). 00899 { 00900 struct ast_call_feature *feature; 00901 00902 AST_LIST_LOCK(&feature_list); 00903 while ((feature = AST_LIST_REMOVE_HEAD(&feature_list,feature_entry))) 00904 free(feature); 00905 AST_LIST_UNLOCK(&feature_list); 00906 }
|
|
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, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, ast_channel::context, ast_channel::exten, ast_bridge_config::features_callee, ast_bridge_config::features_caller, ast_channel::language, LOG_DEBUG, LOG_WARNING, ast_channel::macrocontext, malloc, ast_channel::name, ast_channel::nativeformats, pbx_builtin_getvar_helper(), ast_bridge_thread_obj::peer, ast_channel::priority, ast_channel::readformat, transferdigittimeout, ast_channel::writeformat, xferfailsound, and xfersound. 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 courtesy tone!\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 courtesy tone!\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 res = ast_streamfile(transferer, "beeperr", transferer->language); 00846 if (ast_waitstream(transferer, "") < 0) { 00847 return -1; 00848 } 00849 } 00850 ast_moh_stop(transferee); 00851 ast_autoservice_stop(transferee); 00852 ast_indicate(transferee, AST_CONTROL_UNHOLD); 00853 00854 return FEATURE_RETURN_SUCCESS; 00855 }
|
|
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, courtesytone, ast_channel::language, LOG_ERROR, LOG_NOTICE, LOG_WARNING, monitor_app, monitor_ok, 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_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, 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, transferdigittimeout, VERBOSE_PREFIX_2, VERBOSE_PREFIX_3, and xferfailsound. 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, transferee->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(), 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_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 2166 of file res_features.c. 02167 { 02168 return "Call Features Resource"; 02169 }
|
|
Definition at line 1471 of file res_features.c. References ast_add_extension2(), ast_clear_flag, ast_context_create(), ast_context_find(), ast_context_remove_extension2(), AST_CONTROL_UNHOLD, AST_FLAG_EXCEPTION, ast_frfree(), ast_hangup(), ast_indicate(), ast_log(), ast_moh_start(), ast_moh_stop(), ast_mutex_lock(), ast_mutex_unlock(), ast_pbx_start(), ast_read(), ast_select(), 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, parking_con, parking_con_dial, parkinglot, parkeduser::parkingnum, parkeduser::parkingtime, parkeduser::peername, parkeduser::priority, ast_channel::priority, registrar, parkeduser::start, strdup, ast_frame::subclass, tv, and VERBOSE_PREFIX_2. Referenced by load_module(). 01472 { 01473 int ms, tms, max; 01474 struct parkeduser *pu, *pl, *pt = NULL; 01475 struct timeval tv; 01476 struct ast_frame *f; 01477 char exten[AST_MAX_EXTENSION]; 01478 char *peername,*cp; 01479 char returnexten[AST_MAX_EXTENSION]; 01480 struct ast_context *con; 01481 int x; 01482 fd_set rfds, efds; 01483 fd_set nrfds, nefds; 01484 FD_ZERO(&rfds); 01485 FD_ZERO(&efds); 01486 01487 for (;;) { 01488 ms = -1; 01489 max = -1; 01490 ast_mutex_lock(&parking_lock); 01491 pl = NULL; 01492 pu = parkinglot; 01493 FD_ZERO(&nrfds); 01494 FD_ZERO(&nefds); 01495 while(pu) { 01496 if (pu->notquiteyet) { 01497 /* Pretend this one isn't here yet */ 01498 pl = pu; 01499 pu = pu->next; 01500 continue; 01501 } 01502 tms = ast_tvdiff_ms(ast_tvnow(), pu->start); 01503 if (tms > pu->parkingtime) { 01504 /* Stop music on hold */ 01505 ast_moh_stop(pu->chan); 01506 ast_indicate(pu->chan, AST_CONTROL_UNHOLD); 01507 /* Get chan, exten from derived kludge */ 01508 if (pu->peername[0]) { 01509 peername = ast_strdupa(pu->peername); 01510 cp = strrchr(peername, '-'); 01511 if (cp) 01512 *cp = 0; 01513 con = ast_context_find(parking_con_dial); 01514 if (!con) { 01515 con = ast_context_create(NULL, parking_con_dial, registrar); 01516 if (!con) { 01517 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial); 01518 } 01519 } 01520 if (con) { 01521 snprintf(returnexten, sizeof(returnexten), "%s||t", peername); 01522 ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), FREE, registrar); 01523 } 01524 ast_copy_string(pu->chan->exten, peername, sizeof(pu->chan->exten)); 01525 ast_copy_string(pu->chan->context, parking_con_dial, sizeof(pu->chan->context)); 01526 pu->chan->priority = 1; 01527 01528 } else { 01529 /* They've been waiting too long, send them back to where they came. Theoretically they 01530 should have their original extensions and such, but we copy to be on the safe side */ 01531 ast_copy_string(pu->chan->exten, pu->exten, sizeof(pu->chan->exten)); 01532 ast_copy_string(pu->chan->context, pu->context, sizeof(pu->chan->context)); 01533 pu->chan->priority = pu->priority; 01534 } 01535 01536 manager_event(EVENT_FLAG_CALL, "ParkedCallTimeOut", 01537 "Exten: %d\r\n" 01538 "Channel: %s\r\n" 01539 "CallerID: %s\r\n" 01540 "CallerIDName: %s\r\n" 01541 ,pu->parkingnum, pu->chan->name 01542 ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>") 01543 ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>") 01544 ); 01545 01546 if (option_verbose > 1) 01547 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); 01548 /* Start up the PBX, or hang them up */ 01549 if (ast_pbx_start(pu->chan)) { 01550 ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name); 01551 ast_hangup(pu->chan); 01552 } 01553 /* And take them out of the parking lot */ 01554 if (pl) 01555 pl->next = pu->next; 01556 else 01557 parkinglot = pu->next; 01558 pt = pu; 01559 pu = pu->next; 01560 con = ast_context_find(parking_con); 01561 if (con) { 01562 snprintf(exten, sizeof(exten), "%d", pt->parkingnum); 01563 if (ast_context_remove_extension2(con, exten, 1, NULL)) 01564 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 01565 } else 01566 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 01567 free(pt); 01568 } else { 01569 for (x = 0; x < AST_MAX_FDS; x++) { 01570 if ((pu->chan->fds[x] > -1) && (FD_ISSET(pu->chan->fds[x], &rfds) || FD_ISSET(pu->chan->fds[x], &efds))) { 01571 if (FD_ISSET(pu->chan->fds[x], &efds)) 01572 ast_set_flag(pu->chan, AST_FLAG_EXCEPTION); 01573 else 01574 ast_clear_flag(pu->chan, AST_FLAG_EXCEPTION); 01575 pu->chan->fdno = x; 01576 /* See if they need servicing */ 01577 f = ast_read(pu->chan); 01578 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) { 01579 if (f) 01580 ast_frfree(f); 01581 manager_event(EVENT_FLAG_CALL, "ParkedCallGiveUp", 01582 "Exten: %d\r\n" 01583 "Channel: %s\r\n" 01584 "CallerID: %s\r\n" 01585 "CallerIDName: %s\r\n" 01586 ,pu->parkingnum, pu->chan->name 01587 ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>") 01588 ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>") 01589 ); 01590 01591 /* There's a problem, hang them up*/ 01592 if (option_verbose > 1) 01593 ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", pu->chan->name); 01594 ast_hangup(pu->chan); 01595 /* And take them out of the parking lot */ 01596 if (pl) 01597 pl->next = pu->next; 01598 else 01599 parkinglot = pu->next; 01600 pt = pu; 01601 pu = pu->next; 01602 con = ast_context_find(parking_con); 01603 if (con) { 01604 snprintf(exten, sizeof(exten), "%d", pt->parkingnum); 01605 if (ast_context_remove_extension2(con, exten, 1, NULL)) 01606 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 01607 } else 01608 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 01609 free(pt); 01610 break; 01611 } else { 01612 /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */ 01613 ast_frfree(f); 01614 if (pu->moh_trys < 3 && !pu->chan->generatordata) { 01615 ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source. Restarting.\n"); 01616 ast_moh_start(pu->chan, NULL); 01617 pu->moh_trys++; 01618 } 01619 goto std; /* XXX Ick: jumping into an else statement??? XXX */ 01620 } 01621 } 01622 } 01623 if (x >= AST_MAX_FDS) { 01624 std: for (x=0; x<AST_MAX_FDS; x++) { 01625 /* Keep this one for next one */ 01626 if (pu->chan->fds[x] > -1) { 01627 FD_SET(pu->chan->fds[x], &nrfds); 01628 FD_SET(pu->chan->fds[x], &nefds); 01629 if (pu->chan->fds[x] > max) 01630 max = pu->chan->fds[x]; 01631 } 01632 } 01633 /* Keep track of our longest wait */ 01634 if ((tms < ms) || (ms < 0)) 01635 ms = tms; 01636 pl = pu; 01637 pu = pu->next; 01638 } 01639 } 01640 } 01641 ast_mutex_unlock(&parking_lock); 01642 rfds = nrfds; 01643 efds = nefds; 01644 tv = ast_samp2tv(ms, 1000); 01645 /* Wait for something to happen */ 01646 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL); 01647 pthread_testcancel(); 01648 } 01649 return NULL; /* Never reached */ 01650 }
|
|
Definition at line 924 of file res_features.c. References ast_call_feature::app, ast_call_feature::app_args, AST_FEATURE_FLAG_CALLEE, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_test_flag, ast_call_feature::exten, LOG_NOTICE, LOG_WARNING, pbx_exec(), and pbx_findapp(). 00925 { 00926 struct ast_app *app; 00927 struct ast_call_feature *feature; 00928 int res; 00929 00930 AST_LIST_LOCK(&feature_list); 00931 AST_LIST_TRAVERSE(&feature_list,feature,feature_entry) { 00932 if (!strcasecmp(feature->exten,code)) break; 00933 } 00934 AST_LIST_UNLOCK(&feature_list); 00935 00936 if (!feature) { /* shouldn't ever happen! */ 00937 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n"); 00938 return -1; 00939 } 00940 00941 app = pbx_findapp(feature->app); 00942 if (app) { 00943 struct ast_channel *work = chan; 00944 if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLEE)) 00945 work = peer; 00946 res = pbx_exec(work, app, feature->app_args, 1); 00947 if (res < 0) 00948 return res; 00949 } else { 00950 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app); 00951 return -2; 00952 } 00953 00954 return FEATURE_RETURN_SUCCESS; 00955 }
|
|
Definition at line 909 of file res_features.c. References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, name, and ast_call_feature::sname. Referenced by ast_feature_interpret(), load_config(), and set_config_flags(). 00910 { 00911 struct ast_call_feature *tmp; 00912 00913 AST_LIST_LOCK(&feature_list); 00914 AST_LIST_TRAVERSE(&feature_list, tmp, feature_entry) { 00915 if (!strcasecmp(tmp->sname, name)) 00916 break; 00917 } 00918 AST_LIST_UNLOCK(&feature_list); 00919 00920 return tmp; 00921 }
|
|
Definition at line 1838 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, parkeduser::parkingnum, parkeduser::parkingtime, parkeduser::priority, and parkeduser::start. 01839 { 01840 struct parkeduser *cur; 01841 int numparked = 0; 01842 01843 ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel" 01844 , "Context", "Extension", "Pri", "Timeout"); 01845 01846 ast_mutex_lock(&parking_lock); 01847 01848 cur = parkinglot; 01849 while(cur) { 01850 ast_cli(fd, "%4d %25s (%-15s %-12s %-4d) %6lds\n" 01851 ,cur->parkingnum, cur->chan->name, cur->context, cur->exten 01852 ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL)); 01853 01854 cur = cur->next; 01855 numparked++; 01856 } 01857 ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : ""); 01858 01859 ast_mutex_unlock(&parking_lock); 01860 01861 return RESULT_SUCCESS; 01862 }
|
|
Definition at line 1790 of file res_features.c. References ast_cli(), AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_pickup_ext(), builtin_features, ast_call_feature::exten, parking_con, parking_ext, parking_start, parking_stop, and ast_call_feature::sname. 01791 { 01792 int i; 01793 int fcount; 01794 struct ast_call_feature *feature; 01795 char format[] = "%-25s %-7s %-7s\n"; 01796 01797 ast_cli(fd, format, "Builtin Feature", "Default", "Current"); 01798 ast_cli(fd, format, "---------------", "-------", "-------"); 01799 01800 ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */ 01801 01802 fcount = sizeof(builtin_features) / sizeof(builtin_features[0]); 01803 01804 for (i = 0; i < fcount; i++) 01805 { 01806 ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten); 01807 } 01808 ast_cli(fd, "\n"); 01809 ast_cli(fd, format, "Dynamic Feature", "Default", "Current"); 01810 ast_cli(fd, format, "---------------", "-------", "-------"); 01811 if (AST_LIST_EMPTY(&feature_list)) { 01812 ast_cli(fd, "(none)\n"); 01813 } 01814 else { 01815 AST_LIST_LOCK(&feature_list); 01816 AST_LIST_TRAVERSE(&feature_list, feature, feature_entry) { 01817 ast_cli(fd, format, feature->sname, "no def", feature->exten); 01818 } 01819 AST_LIST_UNLOCK(&feature_list); 01820 } 01821 ast_cli(fd, "\nCall parking\n"); 01822 ast_cli(fd, "------------\n"); 01823 ast_cli(fd,"%-20s: %s\n", "Parking extension", parking_ext); 01824 ast_cli(fd,"%-20s: %s\n", "Parking context", parking_con); 01825 ast_cli(fd,"%-20s: %d-%d\n", "Parked call extensions", parking_start, parking_stop); 01826 ast_cli(fd,"\n"); 01827 01828 return RESULT_SUCCESS; 01829 }
|
|
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 2184 of file res_features.c. 02185 {
02186 return ASTERISK_GPL_KEY;
02187 }
|
|
Definition at line 1950 of file res_features.c. References adsipark, ast_call_feature::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_parking_ext(), ast_register_feature(), ast_set_flag, ast_strlen_zero(), ast_true(), ast_unregister_features(), ast_variable_browse(), ast_verbose(), cfg, courtesytone, ast_call_feature::exten, FEATURE_APP_ARGS_LEN, FEATURE_APP_LEN, FEATURE_EXTEN_LEN, FEATURE_SNAME_LEN, featuredigittimeout, find_feature(), FREE, free, ast_variable::lineno, LOG_DEBUG, LOG_ERROR, LOG_NOTICE, LOG_WARNING, malloc, ast_variable::name, ast_variable::next, ast_call_feature::operation, option_verbose, parkcall, parkfindnext, parking_con, parking_con_dial, parking_ext, parking_start, parking_stop, parkingtime, pickup_ext, registrar, remap_feature(), ast_call_feature::sname, strdup, strsep(), transferdigittimeout, unmap_features(), ast_variable::value, var, VERBOSE_PREFIX_2, xferfailsound, and xfersound. 01951 { 01952 int start = 0, end = 0; 01953 struct ast_context *con = NULL; 01954 struct ast_config *cfg = NULL; 01955 struct ast_variable *var = NULL; 01956 char old_parking_ext[AST_MAX_EXTENSION]; 01957 char old_parking_con[AST_MAX_EXTENSION] = ""; 01958 01959 if (!ast_strlen_zero(parking_con)) { 01960 strcpy(old_parking_ext, parking_ext); 01961 strcpy(old_parking_con, parking_con); 01962 } 01963 01964 /* Reset to defaults */ 01965 strcpy(parking_con, "parkedcalls"); 01966 strcpy(parking_con_dial, "park-dial"); 01967 strcpy(parking_ext, "700"); 01968 strcpy(pickup_ext, "*8"); 01969 courtesytone[0] = '\0'; 01970 strcpy(xfersound, "beep"); 01971 strcpy(xferfailsound, "pbx-invalid"); 01972 parking_start = 701; 01973 parking_stop = 750; 01974 parkfindnext = 0; 01975 01976 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 01977 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 01978 01979 cfg = ast_config_load("features.conf"); 01980 if (!cfg) { 01981 cfg = ast_config_load("parking.conf"); 01982 if (cfg) 01983 ast_log(LOG_NOTICE, "parking.conf is deprecated in favor of 'features.conf'. Please rename it.\n"); 01984 } 01985 if (cfg) { 01986 var = ast_variable_browse(cfg, "general"); 01987 while(var) { 01988 if (!strcasecmp(var->name, "parkext")) { 01989 ast_copy_string(parking_ext, var->value, sizeof(parking_ext)); 01990 } else if (!strcasecmp(var->name, "context")) { 01991 ast_copy_string(parking_con, var->value, sizeof(parking_con)); 01992 } else if (!strcasecmp(var->name, "parkingtime")) { 01993 if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) { 01994 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value); 01995 parkingtime = DEFAULT_PARK_TIME; 01996 } else 01997 parkingtime = parkingtime * 1000; 01998 } else if (!strcasecmp(var->name, "parkpos")) { 01999 if (sscanf(var->value, "%d-%d", &start, &end) != 2) { 02000 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); 02001 } else { 02002 parking_start = start; 02003 parking_stop = end; 02004 } 02005 } else if (!strcasecmp(var->name, "findslot")) { 02006 parkfindnext = (!strcasecmp(var->value, "next")); 02007 } else if (!strcasecmp(var->name, "adsipark")) { 02008 adsipark = ast_true(var->value); 02009 } else if (!strcasecmp(var->name, "transferdigittimeout")) { 02010 if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) { 02011 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value); 02012 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 02013 } else 02014 transferdigittimeout = transferdigittimeout * 1000; 02015 } else if (!strcasecmp(var->name, "featuredigittimeout")) { 02016 if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) { 02017 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value); 02018 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 02019 } 02020 } else if (!strcasecmp(var->name, "courtesytone")) { 02021 ast_copy_string(courtesytone, var->value, sizeof(courtesytone)); 02022 } else if (!strcasecmp(var->name, "xfersound")) { 02023 ast_copy_string(xfersound, var->value, sizeof(xfersound)); 02024 } else if (!strcasecmp(var->name, "xferfailsound")) { 02025 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound)); 02026 } else if (!strcasecmp(var->name, "pickupexten")) { 02027 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext)); 02028 } 02029 var = var->next; 02030 } 02031 02032 unmap_features(); 02033 var = ast_variable_browse(cfg, "featuremap"); 02034 while(var) { 02035 if (remap_feature(var->name, var->value)) 02036 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name); 02037 var = var->next; 02038 } 02039 02040 /* Map a key combination to an application*/ 02041 ast_unregister_features(); 02042 var = ast_variable_browse(cfg, "applicationmap"); 02043 while(var) { 02044 char *tmp_val=strdup(var->value); 02045 char *exten, *party=NULL, *app=NULL, *app_args=NULL; 02046 02047 if (!tmp_val) { 02048 ast_log(LOG_ERROR, "res_features: strdup failed"); 02049 continue; 02050 } 02051 02052 02053 exten=strsep(&tmp_val,","); 02054 if (exten) party=strsep(&tmp_val,","); 02055 if (party) app=strsep(&tmp_val,","); 02056 02057 if (app) app_args=strsep(&tmp_val,","); 02058 02059 if (!(app && strlen(app)) || !(exten && strlen(exten)) || !(party && strlen(party)) || !(var->name && strlen(var->name))) { 02060 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); 02061 free(tmp_val); 02062 var = var->next; 02063 continue; 02064 } 02065 02066 { 02067 struct ast_call_feature *feature=find_feature(var->name); 02068 int mallocd=0; 02069 02070 if (!feature) { 02071 feature=malloc(sizeof(struct ast_call_feature)); 02072 mallocd=1; 02073 } 02074 if (!feature) { 02075 ast_log(LOG_NOTICE, "Malloc failed at feature mapping\n"); 02076 free(tmp_val); 02077 var = var->next; 02078 continue; 02079 } 02080 02081 memset(feature,0,sizeof(struct ast_call_feature)); 02082 ast_copy_string(feature->sname,var->name,FEATURE_SNAME_LEN); 02083 ast_copy_string(feature->app,app,FEATURE_APP_LEN); 02084 ast_copy_string(feature->exten, exten,FEATURE_EXTEN_LEN); 02085 free(tmp_val); 02086 02087 if (app_args) 02088 ast_copy_string(feature->app_args,app_args,FEATURE_APP_ARGS_LEN); 02089 02090 ast_copy_string(feature->exten, exten,sizeof(feature->exten)); 02091 feature->operation=feature_exec_app; 02092 ast_set_flag(feature,AST_FEATURE_FLAG_NEEDSDTMF); 02093 02094 if (!strcasecmp(party,"caller")) 02095 ast_set_flag(feature,AST_FEATURE_FLAG_CALLER); 02096 else if (!strcasecmp(party, "callee")) 02097 ast_set_flag(feature,AST_FEATURE_FLAG_CALLEE); 02098 else { 02099 ast_log(LOG_NOTICE, "Invalid party specification for feature '%s', must be caller, or callee\n", var->name); 02100 var = var->next; 02101 continue; 02102 } 02103 02104 ast_register_feature(feature); 02105 02106 if (option_verbose >=1) ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s' with code '%s'\n", var->name, app, exten); 02107 } 02108 var = var->next; 02109 } 02110 } 02111 ast_config_destroy(cfg); 02112 02113 /* Remove the old parking extension */ 02114 if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) { 02115 ast_context_remove_extension2(con, old_parking_ext, 1, registrar); 02116 ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con); 02117 } 02118 02119 if (!(con = ast_context_find(parking_con))) { 02120 if (!(con = ast_context_create(NULL, parking_con, registrar))) { 02121 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con); 02122 return -1; 02123 } 02124 } 02125 return ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, strdup(""), FREE, registrar); 02126 }
|
|
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 2132 of file res_features.c. References ast_cli_register(), AST_LIST_HEAD_INIT, ast_manager_register, ast_pthread_create, ast_register_application(), descrip, descrip2, do_parking_thread(), load_config(), manager_parking_status(), park_call_exec(), park_exec(), parkcall, parkedcall, parking_con, parking_ext, parking_thread, showfeatures, showparked, synopsis, and synopsis2. 02133 { 02134 int res; 02135 02136 AST_LIST_HEAD_INIT(&feature_list); 02137 memset(parking_ext, 0, sizeof(parking_ext)); 02138 memset(parking_con, 0, sizeof(parking_con)); 02139 02140 if ((res = load_config())) 02141 return res; 02142 ast_cli_register(&showparked); 02143 ast_cli_register(&showfeatures); 02144 ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL); 02145 res = ast_register_application(parkedcall, park_exec, synopsis, descrip); 02146 if (!res) 02147 res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2); 02148 if (!res) { 02149 ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" ); 02150 } 02151 return res; 02152 }
|
|
Definition at line 1872 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, mansession::fd, ast_channel::name, parkeduser::next, parkeduser::parkingnum, parkeduser::parkingtime, s, and parkeduser::start. Referenced by load_module(). 01873 { 01874 struct parkeduser *cur; 01875 char *id = astman_get_header(m,"ActionID"); 01876 char idText[256] = ""; 01877 01878 if (!ast_strlen_zero(id)) 01879 snprintf(idText,256,"ActionID: %s\r\n",id); 01880 01881 astman_send_ack(s, m, "Parked calls will follow"); 01882 01883 ast_mutex_lock(&parking_lock); 01884 01885 cur=parkinglot; 01886 while(cur) { 01887 ast_cli(s->fd, "Event: ParkedCall\r\n" 01888 "Exten: %d\r\n" 01889 "Channel: %s\r\n" 01890 "Timeout: %ld\r\n" 01891 "CallerID: %s\r\n" 01892 "CallerIDName: %s\r\n" 01893 "%s" 01894 "\r\n" 01895 ,cur->parkingnum, cur->chan->name 01896 ,(long)cur->start.tv_sec + (long)(cur->parkingtime/1000) - (long)time(NULL) 01897 ,(cur->chan->cid.cid_num ? cur->chan->cid.cid_num : "") 01898 ,(cur->chan->cid.cid_name ? cur->chan->cid.cid_name : "") 01899 ,idText); 01900 01901 cur = cur->next; 01902 } 01903 01904 ast_cli(s->fd, 01905 "Event: ParkedCallsComplete\r\n" 01906 "%s" 01907 "\r\n",idText); 01908 01909 ast_mutex_unlock(&parking_lock); 01910 01911 return RESULT_SUCCESS; 01912 }
|
|
Definition at line 1652 of file res_features.c. References ast_channel::_state, ast_answer(), ast_park_call(), ast_safe_sleep(), ast_channel::exten, LOCAL_USER_ADD, LOCAL_USER_REMOVE, and ast_channel::priority. Referenced by load_module(). 01653 { 01654 /* Data is unused at the moment but could contain a parking 01655 lot context eventually */ 01656 int res=0; 01657 struct localuser *u; 01658 LOCAL_USER_ADD(u); 01659 /* Setup the exten/priority to be s/1 since we don't know 01660 where this call should return */ 01661 strcpy(chan->exten, "s"); 01662 chan->priority = 1; 01663 if (chan->_state != AST_STATE_UP) 01664 res = ast_answer(chan); 01665 if (!res) 01666 res = ast_safe_sleep(chan, 1000); 01667 if (!res) 01668 res = ast_park_call(chan, chan, 0, NULL); 01669 LOCAL_USER_REMOVE(u); 01670 if (!res) 01671 res = AST_PBX_KEEPALIVE; 01672 return res; 01673 }
|
|
Definition at line 1675 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_moh_stop(), ast_mutex_lock(), ast_mutex_unlock(), ast_set_flag, ast_streamfile(), ast_strlen_zero(), ast_verbose(), ast_waitstream(), parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, courtesytone, EVENT_FLAG_CALL, ast_bridge_config::features_callee, ast_bridge_config::features_caller, free, ast_channel::language, LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_WARNING, manager_event(), ast_channel::name, parkeduser::next, option_verbose, parking_con, parkinglot, parkeduser::parkingnum, ast_bridge_config::play_warning, ast_bridge_config::timelimit, VERBOSE_PREFIX_3, ast_bridge_config::warning_freq, and ast_bridge_config::warning_sound. Referenced by load_module(). 01676 { 01677 int res=0; 01678 struct localuser *u; 01679 struct ast_channel *peer=NULL; 01680 struct parkeduser *pu, *pl=NULL; 01681 char exten[AST_MAX_EXTENSION]; 01682 struct ast_context *con; 01683 int park; 01684 int dres; 01685 struct ast_bridge_config config; 01686 01687 if (!data) { 01688 ast_log(LOG_WARNING, "Park requires an argument (extension number)\n"); 01689 return -1; 01690 } 01691 LOCAL_USER_ADD(u); 01692 park = atoi((char *)data); 01693 ast_mutex_lock(&parking_lock); 01694 pu = parkinglot; 01695 while(pu) { 01696 if (pu->parkingnum == park) { 01697 if (pl) 01698 pl->next = pu->next; 01699 else 01700 parkinglot = pu->next; 01701 break; 01702 } 01703 pl = pu; 01704 pu = pu->next; 01705 } 01706 ast_mutex_unlock(&parking_lock); 01707 if (pu) { 01708 peer = pu->chan; 01709 con = ast_context_find(parking_con); 01710 if (con) { 01711 snprintf(exten, sizeof(exten), "%d", pu->parkingnum); 01712 if (ast_context_remove_extension2(con, exten, 1, NULL)) 01713 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 01714 } else 01715 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 01716 01717 manager_event(EVENT_FLAG_CALL, "UnParkedCall", 01718 "Exten: %d\r\n" 01719 "Channel: %s\r\n" 01720 "From: %s\r\n" 01721 "CallerID: %s\r\n" 01722 "CallerIDName: %s\r\n" 01723 ,pu->parkingnum, pu->chan->name, chan->name 01724 ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>") 01725 ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>") 01726 ); 01727 01728 free(pu); 01729 } 01730 /* JK02: it helps to answer the channel if not already up */ 01731 if (chan->_state != AST_STATE_UP) { 01732 ast_answer(chan); 01733 } 01734 01735 if (peer) { 01736 /* Play a courtesy beep in the calling channel to prefix the bridge connecting */ 01737 if (!ast_strlen_zero(courtesytone)) { 01738 if (!ast_streamfile(chan, courtesytone, chan->language)) { 01739 if (ast_waitstream(chan, "") < 0) { 01740 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); 01741 ast_hangup(peer); 01742 return -1; 01743 } 01744 } 01745 } 01746 01747 ast_moh_stop(peer); 01748 ast_indicate(peer, AST_CONTROL_UNHOLD); 01749 res = ast_channel_make_compatible(chan, peer); 01750 if (res < 0) { 01751 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name); 01752 ast_hangup(peer); 01753 return -1; 01754 } 01755 /* This runs sorta backwards, since we give the incoming channel control, as if it 01756 were the person called. */ 01757 if (option_verbose > 2) 01758 ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park); 01759 01760 memset(&config, 0, sizeof(struct ast_bridge_config)); 01761 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT); 01762 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT); 01763 config.timelimit = 0; 01764 config.play_warning = 0; 01765 config.warning_freq = 0; 01766 config.warning_sound=NULL; 01767 res = ast_bridge_call(chan, peer, &config); 01768 01769 /* Simulate the PBX hanging up */ 01770 if (res != AST_PBX_NO_HANGUP_PEER) 01771 ast_hangup(peer); 01772 return res; 01773 } else { 01774 /* XXX Play a message XXX */ 01775 dres = ast_streamfile(chan, "pbx-invalidpark", chan->language); 01776 if (!dres) 01777 dres = ast_waitstream(chan, ""); 01778 else { 01779 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name); 01780 dres = 0; 01781 } 01782 if (option_verbose > 2) 01783 ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park); 01784 res = -1; 01785 } 01786 LOCAL_USER_REMOVE(u); 01787 return res; 01788 }
|
|
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 2128 of file res_features.c. References load_config(). 02128 { 02129 return load_config(); 02130 }
|
|
Definition at line 964 of file res_features.c. References ast_log(), ast_verbose(), builtin_features, LOG_WARNING, name, option_verbose, and VERBOSE_PREFIX_2. Referenced by load_config(). 00965 { 00966 int x; 00967 int res = -1; 00968 for (x = 0; x < FEATURES_COUNT; x++) { 00969 if (!strcasecmp(name, builtin_features[x].sname)) { 00970 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten)); 00971 if (option_verbose > 1) 00972 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); 00973 res = 0; 00974 } else if (!strcmp(value, builtin_features[x].exten)) 00975 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); 00976 } 00977 return res; 00978 }
|
|
Definition at line 1036 of file res_features.c. References AST_BRIDGE_DTMF_CHANNEL_0, AST_BRIDGE_DTMF_CHANNEL_1, ast_clear_flag, AST_FEATURE_FLAG_CALLEE, AST_FEATURE_FLAG_CALLER, AST_FEATURE_FLAG_NEEDSDTMF, AST_FLAGS_ALL, ast_set_flag, ast_strdupa, ast_test_flag, builtin_features, ast_call_feature::feature_mask, ast_bridge_config::features_callee, ast_bridge_config::features_caller, find_feature(), pbx_builtin_getvar_helper(), and strsep(). Referenced by ast_bridge_call(). 01037 { 01038 int x; 01039 01040 ast_clear_flag(config, AST_FLAGS_ALL); 01041 for (x = 0; x < FEATURES_COUNT; x++) { 01042 if (ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF)) { 01043 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask)) 01044 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 01045 01046 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask)) 01047 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 01048 } 01049 } 01050 01051 if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) { 01052 char *dynamic_features; 01053 01054 dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"); 01055 01056 if (dynamic_features) { 01057 char *tmp = ast_strdupa(dynamic_features); 01058 char *tok; 01059 struct ast_call_feature *feature; 01060 01061 if (!tmp) { 01062 return; 01063 } 01064 01065 /* while we have a feature */ 01066 while (NULL != (tok = strsep(&tmp, "#"))) { 01067 if ((feature = find_feature(tok))) { 01068 if (ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) { 01069 if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLER)) 01070 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 01071 if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLEE)) 01072 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 01073 } 01074 } 01075 } 01076 } 01077 } 01078 }
|
|
Cleanup all module structures, sockets, etc. Standard module functions ... Definition at line 2155 of file res_features.c. References ast_cli_unregister(), ast_manager_unregister(), ast_unregister_application(), parkcall, parkedcall, showfeatures, and showparked. 02156 { 02157 STANDARD_HANGUP_LOCALUSERS; 02158 02159 ast_manager_unregister("ParkedCalls"); 02160 ast_cli_unregister(&showfeatures); 02161 ast_cli_unregister(&showparked); 02162 ast_unregister_application(parkcall); 02163 return ast_unregister_application(parkedcall); 02164 }
|
|
Definition at line 957 of file res_features.c. References builtin_features. Referenced by load_config(). 00958 { 00959 int x; 00960 for (x = 0; x < FEATURES_COUNT; x++) 00961 strcpy(builtin_features[x].exten, builtin_features[x].default_exten); 00962 }
|
|
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 2171 of file res_features.c. References STANDARD_USECOUNT. 02172 { 02173 /* Never allow parking to be unloaded because it will 02174 unresolve needed symbols in the dialer */ 02175 #if 0 02176 int res; 02177 STANDARD_USECOUNT(res); 02178 return res; 02179 #else 02180 return 1; 02181 #endif 02182 }
|
|
Definition at line 106 of file res_features.c. Referenced by ast_park_call(), and load_config(). |
|
Definition at line 860 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. Referenced by builtin_automonitor(), load_config(), and park_exec(). |
|
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. Referenced by load_module(). |
|
Definition at line 128 of file res_features.c. Referenced by load_module(). |
|
Definition at line 109 of file res_features.c. Referenced by load_config(). |
|
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. Referenced by ast_bridge_call(), and builtin_automonitor(). |
|
Definition at line 124 of file res_features.c. Referenced by load_config(), load_module(), and unload_module(). |
|
Definition at line 75 of file res_features.c. Referenced by ast_park_call(), load_module(), and unload_module(). |
|
Definition at line 104 of file res_features.c. Referenced by load_config(). |
|
Definition at line 81 of file res_features.c. Referenced by ast_park_call(), do_parking_thread(), handle_showfeatures(), load_config(), load_module(), and park_exec(). |
|
Definition at line 84 of file res_features.c. Referenced by do_parking_thread(), and load_config(). |
|
Definition at line 87 of file res_features.c. Referenced by handle_showfeatures(), load_config(), and load_module(). |
|
Definition at line 102 of file res_features.c. Referenced by ast_park_call(). |
|
Definition at line 97 of file res_features.c. Referenced by ast_park_call(), handle_showfeatures(), and load_config(). |
|
Definition at line 100 of file res_features.c. Referenced by ast_park_call(), handle_showfeatures(), and load_config(). |
|
Definition at line 157 of file res_features.c. Referenced by ast_park_call(), and load_module(). |
|
Definition at line 153 of file res_features.c. Referenced by ast_park_call(), do_parking_thread(), and park_exec(). |
|
Definition at line 78 of file res_features.c. Referenced by load_config(). |
|
Definition at line 89 of file res_features.c. Referenced by load_config(). |
|
Definition at line 114 of file res_features.c. Referenced by ast_park_call(), do_parking_thread(), and load_config(). |
|
Initial value: { { "show", "features", NULL }, handle_showfeatures, "Lists configured features", showfeatures_help } Definition at line 1835 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 1831 of file res_features.c. |
|
Initial value: { { "show", "parkedcalls", NULL }, handle_parkedcalls, "Lists parked calls", showparked_help } Definition at line 1868 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 1864 of file res_features.c. |
|
Definition at line 159 of file res_features.c. |
|
Definition at line 116 of file res_features.c. Referenced by load_module(). |
|
Definition at line 126 of file res_features.c. Referenced by load_module(). |
|
Definition at line 108 of file res_features.c. Referenced by builtin_atxfer(), builtin_blindtransfer(), and load_config(). |
|
Definition at line 94 of file res_features.c. Referenced by builtin_atxfer(), builtin_blindtransfer(), and load_config(). |
|
Definition at line 93 of file res_features.c. Referenced by builtin_atxfer(), and load_config(). |