#include <pthread.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <netinet/in.h>
#include "asterisk.h"
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/options.h"
#include "asterisk/causes.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/app.h"
#include "asterisk/say.h"
#include "asterisk/features.h"
#include "asterisk/musiconhold.h"
#include "asterisk/config.h"
#include "asterisk/cli.h"
#include "asterisk/manager.h"
#include "asterisk/utils.h"
#include "asterisk/adsi.h"
#include "asterisk/monitor.h"

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