![]() |
Home page |
Mailing list |
Docs
Asterisk developer's documentation :: Codename Pineapple
res_features.c File Reference
Definition in file res_features.c.
#include "asterisk.h"
#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/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/devicestate.h"
#include "asterisk/monitor.h"
Include dependency graph for res_features.c:

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_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000 |
| #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])) |
Enumerations | |
| enum | { AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0), AST_FEATURE_FLAG_ONPEER = (1 << 1), AST_FEATURE_FLAG_ONSELF = (1 << 2), AST_FEATURE_FLAG_BYCALLEE = (1 << 3), AST_FEATURE_FLAG_BYCALLER = (1 << 4), AST_FEATURE_FLAG_BYBOTH = (3 << 3) } |
Functions | |
| static int | adsi_announce_park (struct ast_channel *chan, char *parkingexten) |
| 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_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS,"Call Features Resource",.load=load_module,.unload=unload_module,.reload=reload,) | |
| 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) |
| Remove all features in the list. | |
| 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 int | builtin_parkcall (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) |
| support routing for one touch call parking | |
| static int | check_compat (struct ast_channel *c, struct ast_channel *newchan) |
| static void | check_goto_on_transfer (struct ast_channel *chan) |
| static void * | do_parking_thread (void *ignore) |
| Take care of parked calls and unpark them if needed. | |
| static int | feature_exec_app (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) |
| exec an app by feature | |
| static struct ast_call_feature * | find_feature (char *name) |
| find a feature by name | |
| static int | finishup (struct ast_channel *chan) |
| static int | handle_parkedcalls (int fd, int argc, char *argv[]) |
| static int | handle_showfeatures (int fd, int argc, char *argv[]) |
| static int | load_config (void) |
| static int | load_module (void) |
| static int | manager_park (struct mansession *s, const struct message *m) |
| static int | manager_parking_status (struct mansession *s, const struct message *m) |
| Dump lot status. | |
| static int | metermaidstate (const char *data) |
| metermaids callback from devicestate.c | |
| static void | notify_metermaids (char *exten, char *context) |
| Notify metermaids that we've changed an extension. | |
| static void | park_add_hints (char *context, int start, int stop) |
| Add parking hints for all defined parking lots. | |
| static int | park_call_exec (struct ast_channel *chan, void *data) |
| Park a call. | |
| static int | park_exec (struct ast_channel *chan, void *data) |
| Pickup parked call. | |
| static void | post_manager_event (const char *s, char *parkingexten, struct ast_channel *chan) |
| static const char * | real_ctx (struct ast_channel *transferer, struct ast_channel *transferee) |
| Find the context for the transfer. | |
| static int | reload (void) |
| static int | remap_feature (const char *name, const char *value) |
| static void | set_c_e_p (struct ast_channel *chan, const char *context, const char *ext, int pri) |
| store context, priority and extension | |
| static void | set_config_flags (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config) |
| static void | set_peers (struct ast_channel **caller, struct ast_channel **callee, struct ast_channel *peer, struct ast_channel *chan, int sense) |
| set caller and callee according to the direction | |
| static int | unload_module (void) |
| static void | unmap_features (void) |
Variables | |
| static int | adsipark |
| static int | atxfernoanswertimeout |
| ast_call_feature | builtin_features [] |
| static struct ast_cli_entry | cli_features [] |
| static int | comebacktoorigin = 1 |
| static char | courtesytone [256] |
| static char * | descrip |
| static char * | descrip2 |
| static int | featuredigittimeout |
| static char | mandescr_park [] |
| static struct ast_app * | monitor_app = NULL |
| static int | monitor_ok = 1 |
| static int | parkaddhints = 0 |
| static char * | parkcall = "Park" |
| static char * | parkedcall = "ParkedCall" |
| static int | parkedcalltransfers = 0 |
| static int | parkedplay = 0 |
| 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 | parkmohclass [MAX_MUSICCLASS] |
| static char | pickup_ext [AST_MAX_EXTENSION] |
| static char * | registrar = "res_features" |
| static char | showfeatures_help [] |
| static char | showparked_help [] |
| static char * | synopsis = "Answer a parked call" |
| static char * | synopsis2 = "Park yourself" |
| static int | transferdigittimeout |
| static char | xferfailsound [256] |
| static char | xfersound [256] |
|
|
Definition at line 67 of file res_features.c. |
|
|
Definition at line 64 of file res_features.c. Referenced by load_config(). |
|
|
Definition at line 65 of file res_features.c. Referenced by load_config(). |
|
|
Definition at line 62 of file res_features.c. |
|
|
Definition at line 63 of file res_features.c. Referenced by load_config(). |
|
|
Definition at line 468 of file res_features.c. Referenced by builtin_disconnect(). |
|
|
Definition at line 471 of file res_features.c. Referenced by feature_exec_app(). |
|
|
Definition at line 472 of file res_features.c. Referenced by ast_bridge_call(), ast_feature_interpret(), and feature_exec_app(). |
|
|
Definition at line 470 of file res_features.c. Referenced by feature_exec_app(). |
|
|
Definition at line 473 of file res_features.c. |
|
|
Definition at line 474 of file res_features.c. Referenced by ast_bridge_call(), builtin_atxfer(), builtin_automonitor(), builtin_blindtransfer(), and feature_exec_app(). |
|
|
Definition at line 469 of file res_features.c. Referenced by feature_exec_app(). |
|
|
Definition at line 476 of file res_features.c. Referenced by ast_bridge_call(), ast_feature_interpret(), builtin_parkcall(), and feature_exec_app(). |
|
|
Definition at line 477 of file res_features.c. Referenced by ast_bridge_call(), and set_peers(). |
|
|
Definition at line 868 of file res_features.c. Referenced by ast_feature_interpret(), ast_feature_request_and_dial(), remap_feature(), set_config_flags(), and unmap_features(). |
|
|
Definition at line 69 of file res_features.c. 00069 { 00070 AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0), 00071 AST_FEATURE_FLAG_ONPEER = (1 << 1), 00072 AST_FEATURE_FLAG_ONSELF = (1 << 2), 00073 AST_FEATURE_FLAG_BYCALLEE = (1 << 3), 00074 AST_FEATURE_FLAG_BYCALLER = (1 << 4), 00075 AST_FEATURE_FLAG_BYBOTH = (3 << 3), 00076 };
|
|
||||||||||||
|
Definition at line 260 of file res_features.c. References ADSI_JUST_CENT, ast_adsi_load_session(), and ast_adsi_print(). 00261 { 00262 int res; 00263 int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT}; 00264 char tmp[256]; 00265 char *message[5] = {NULL, NULL, NULL, NULL, NULL}; 00266 00267 snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten); 00268 message[0] = tmp; 00269 res = ast_adsi_load_session(chan, NULL, 0, 1); 00270 if (res == -1) 00271 return res; 00272 return ast_adsi_print(chan, message, justify, 1); 00273 }
|
|
||||||||||||||||
|
Bridge a call, optionally allowing redirection. append the event to featurecode. we rely on the string being zero-filled, and not overflowing it.
Definition at line 1289 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_FRAME_DTMF_BEGIN, ast_frfree(), ast_indicate(), ast_log(), AST_OPTION_FLAG_REQUEST, ast_strdupa, ast_strlen_zero(), ast_channel::cdr, config, ast_option_header::data, ast_frame::data, ast_channel::data, ast_frame::datalen, FEATURE_MAX_LEN, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_SUCCESS, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, ast_option_header::flag, ast_frame::frametype, free, LOG_DEBUG, LOG_WARNING, monitor_app, ast_option_header::option, option_debug, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), set_config_flags(), ast_frame::subclass, and ast_cdr::userfield. Referenced by ast_bridge_call_thread(), builtin_atxfer(), and park_exec(). 01290 { 01291 /* Copy voice back and forth between the two channels. Give the peer 01292 the ability to transfer calls with '#<extension' syntax. */ 01293 struct ast_frame *f; 01294 struct ast_channel *who; 01295 char chan_featurecode[FEATURE_MAX_LEN + 1]=""; 01296 char peer_featurecode[FEATURE_MAX_LEN + 1]=""; 01297 int res; 01298 int diff; 01299 int hasfeatures=0; 01300 int hadfeatures=0; 01301 struct ast_option_header *aoh; 01302 struct ast_bridge_config backup_config; 01303 01304 memset(&backup_config, 0, sizeof(backup_config)); 01305 01306 config->start_time = ast_tvnow(); 01307 01308 if (chan && peer) { 01309 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name); 01310 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name); 01311 } else if (chan) 01312 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL); 01313 01314 if (monitor_ok) { 01315 const char *monitor_exec; 01316 struct ast_channel *src = NULL; 01317 if (!monitor_app) { 01318 if (!(monitor_app = pbx_findapp("Monitor"))) 01319 monitor_ok=0; 01320 } 01321 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 01322 src = chan; 01323 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR"))) 01324 src = peer; 01325 if (monitor_app && src) { 01326 char *tmp = ast_strdupa(monitor_exec); 01327 pbx_exec(src, monitor_app, tmp); 01328 } 01329 } 01330 01331 set_config_flags(chan, peer, config); 01332 config->firstpass = 1; 01333 01334 /* Answer if need be */ 01335 if (ast_answer(chan)) 01336 return -1; 01337 peer->appl = "Bridged Call"; 01338 peer->data = chan->name; 01339 01340 /* copy the userfield from the B-leg to A-leg if applicable */ 01341 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) { 01342 char tmp[256]; 01343 if (!ast_strlen_zero(chan->cdr->userfield)) { 01344 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield); 01345 ast_cdr_appenduserfield(chan, tmp); 01346 } else 01347 ast_cdr_setuserfield(chan, peer->cdr->userfield); 01348 /* free the peer's cdr without ast_cdr_free complaining */ 01349 free(peer->cdr); 01350 peer->cdr = NULL; 01351 } 01352 for (;;) { 01353 struct ast_channel *other; /* used later */ 01354 01355 res = ast_channel_bridge(chan, peer, config, &f, &who); 01356 01357 if (config->feature_timer) { 01358 /* Update time limit for next pass */ 01359 diff = ast_tvdiff_ms(ast_tvnow(), config->start_time); 01360 config->feature_timer -= diff; 01361 if (hasfeatures) { 01362 /* Running on backup config, meaning a feature might be being 01363 activated, but that's no excuse to keep things going 01364 indefinitely! */ 01365 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) { 01366 if (option_debug) 01367 ast_log(LOG_DEBUG, "Timed out, realtime this time!\n"); 01368 config->feature_timer = 0; 01369 who = chan; 01370 if (f) 01371 ast_frfree(f); 01372 f = NULL; 01373 res = 0; 01374 } else if (config->feature_timer <= 0) { 01375 /* Not *really* out of time, just out of time for 01376 digits to come in for features. */ 01377 if (option_debug) 01378 ast_log(LOG_DEBUG, "Timed out for feature!\n"); 01379 if (!ast_strlen_zero(peer_featurecode)) { 01380 ast_dtmf_stream(chan, peer, peer_featurecode, 0); 01381 memset(peer_featurecode, 0, sizeof(peer_featurecode)); 01382 } 01383 if (!ast_strlen_zero(chan_featurecode)) { 01384 ast_dtmf_stream(peer, chan, chan_featurecode, 0); 01385 memset(chan_featurecode, 0, sizeof(chan_featurecode)); 01386 } 01387 if (f) 01388 ast_frfree(f); 01389 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 01390 if (!hasfeatures) { 01391 /* Restore original (possibly time modified) bridge config */ 01392 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 01393 memset(&backup_config, 0, sizeof(backup_config)); 01394 } 01395 hadfeatures = hasfeatures; 01396 /* Continue as we were */ 01397 continue; 01398 } else if (!f) { 01399 /* The bridge returned without a frame and there is a feature in progress. 01400 * However, we don't think the feature has quite yet timed out, so just 01401 * go back into the bridge. */ 01402 continue; 01403 } 01404 } else { 01405 if (config->feature_timer <=0) { 01406 /* We ran out of time */ 01407 config->feature_timer = 0; 01408 who = chan; 01409 if (f) 01410 ast_frfree(f); 01411 f = NULL; 01412 res = 0; 01413 } 01414 } 01415 } 01416 if (res < 0) { 01417 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name); 01418 return -1; 01419 } 01420 01421 if (!f || (f->frametype == AST_FRAME_CONTROL && 01422 (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY || 01423 f->subclass == AST_CONTROL_CONGESTION ) ) ) { 01424 res = -1; 01425 break; 01426 } 01427 /* many things should be sent to the 'other' channel */ 01428 other = (who == chan) ? peer : chan; 01429 if (f->frametype == AST_FRAME_CONTROL) { 01430 if (f->subclass == AST_CONTROL_RINGING) 01431 ast_indicate(other, AST_CONTROL_RINGING); 01432 else if (f->subclass == -1) 01433 ast_indicate(other, -1); 01434 else if (f->subclass == AST_CONTROL_FLASH) 01435 ast_indicate(other, AST_CONTROL_FLASH); 01436 else if (f->subclass == AST_CONTROL_OPTION) { 01437 aoh = f->data; 01438 /* Forward option Requests */ 01439 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) 01440 ast_channel_setoption(other, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0); 01441 } 01442 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) { 01443 /* eat it */ 01444 } else if (f->frametype == AST_FRAME_DTMF) { 01445 char *featurecode; 01446 int sense; 01447 01448 hadfeatures = hasfeatures; 01449 /* This cannot overrun because the longest feature is one shorter than our buffer */ 01450 if (who == chan) { 01451 sense = FEATURE_SENSE_CHAN; 01452 featurecode = chan_featurecode; 01453 } else { 01454 sense = FEATURE_SENSE_PEER; 01455 featurecode = peer_featurecode; 01456 } 01457 /*! append the event to featurecode. we rely on the string being zero-filled, and 01458 * not overflowing it. 01459 * \todo XXX how do we guarantee the latter ? 01460 */ 01461 featurecode[strlen(featurecode)] = f->subclass; 01462 /* Get rid of the frame before we start doing "stuff" with the channels */ 01463 ast_frfree(f); 01464 f = NULL; 01465 config->feature_timer = backup_config.feature_timer; 01466 res = ast_feature_interpret(chan, peer, config, featurecode, sense); 01467 switch(res) { 01468 case FEATURE_RETURN_PASSDIGITS: 01469 ast_dtmf_stream(other, who, featurecode, 0); 01470 /* Fall through */ 01471 case FEATURE_RETURN_SUCCESS: 01472 memset(featurecode, 0, sizeof(chan_featurecode)); 01473 break; 01474 } 01475 if (res >= FEATURE_RETURN_PASSDIGITS) { 01476 res = 0; 01477 } else 01478 break; 01479 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 01480 if (hadfeatures && !hasfeatures) { 01481 /* Restore backup */ 01482 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 01483 memset(&backup_config, 0, sizeof(struct ast_bridge_config)); 01484 } else if (hasfeatures) { 01485 if (!hadfeatures) { 01486 /* Backup configuration */ 01487 memcpy(&backup_config, config, sizeof(struct ast_bridge_config)); 01488 /* Setup temporary config options */ 01489 config->play_warning = 0; 01490 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); 01491 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); 01492 config->warning_freq = 0; 01493 config->warning_sound = NULL; 01494 config->end_sound = NULL; 01495 config->start_sound = NULL; 01496 config->firstpass = 0; 01497 } 01498 config->start_time = ast_tvnow(); 01499 config->feature_timer = featuredigittimeout; 01500 if (option_debug) 01501 ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer); 01502 } 01503 } 01504 if (f) 01505 ast_frfree(f); 01506 } 01507 return res; 01508 }
|
|
|
Definition at line 221 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, and ast_bridge_thread_obj::peer. Referenced by ast_bridge_call_thread_launch(). 00222 { 00223 struct ast_bridge_thread_obj *tobj = data; 00224 00225 tobj->chan->appl = "Transferred Call"; 00226 tobj->chan->data = tobj->peer->name; 00227 tobj->peer->appl = "Transferred Call"; 00228 tobj->peer->data = tobj->chan->name; 00229 if (tobj->chan->cdr) { 00230 ast_cdr_reset(tobj->chan->cdr, NULL); 00231 ast_cdr_setdestchan(tobj->chan->cdr, tobj->peer->name); 00232 } 00233 if (tobj->peer->cdr) { 00234 ast_cdr_reset(tobj->peer->cdr, NULL); 00235 ast_cdr_setdestchan(tobj->peer->cdr, tobj->chan->name); 00236 } 00237 00238 ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig); 00239 ast_hangup(tobj->chan); 00240 ast_hangup(tobj->peer); 00241 bzero(tobj, sizeof(*tobj)); /*! \todo XXX for safety */ 00242 free(tobj); 00243 return NULL; 00244 }
|
|
|
Definition at line 246 of file res_features.c. References ast_bridge_call_thread(), ast_pthread_create, and thread. Referenced by builtin_atxfer(). 00247 { 00248 pthread_t thread; 00249 pthread_attr_t attr; 00250 struct sched_param sched; 00251 00252 pthread_attr_init(&attr); 00253 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 00254 ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data); 00255 pthread_attr_destroy(&attr); 00256 memset(&sched, 0, sizeof(sched)); 00257 pthread_setschedparam(thread, SCHED_RR, &sched); 00258 }
|
|
||||||||||||||||||||||||
|
Definition at line 1028 of file res_features.c. References ast_copy_flags, AST_FLAGS_ALL, ast_log(), ast_strlen_zero(), ast_test_flag, builtin_features, config, exten, ast_call_feature::feature_mask, FEATURE_RETURN_PASSDIGITS, FEATURE_SENSE_CHAN, FEATURES_COUNT, ast_channel::flags, LOG_DEBUG, ast_call_feature::operation, option_debug, and pbx_builtin_getvar_helper(). Referenced by ast_bridge_call(). 01029 { 01030 int x; 01031 struct ast_flags features; 01032 int res = FEATURE_RETURN_PASSDIGITS; 01033 struct ast_call_feature *feature; 01034 const char *dynamic_features=pbx_builtin_getvar_helper(chan,"DYNAMIC_FEATURES"); 01035 01036 if (sense == FEATURE_SENSE_CHAN) 01037 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL); 01038 else 01039 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL); 01040 if (option_debug > 2) 01041 ast_log(LOG_DEBUG, "Feature interpret: chan=%s, peer=%s, sense=%d, features=%d\n", chan->name, peer->name, sense, features.flags); 01042 01043 for (x=0; x < FEATURES_COUNT; x++) { 01044 if ((ast_test_flag(&features, builtin_features[x].feature_mask)) && 01045 !ast_strlen_zero(builtin_features[x].exten)) { 01046 /* Feature is up for consideration */ 01047 if (!strcmp(builtin_features[x].exten, code)) { 01048 res = builtin_features[x].operation(chan, peer, config, code, sense); 01049 break; 01050 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) { 01051 if (res == FEATURE_RETURN_PASSDIGITS) 01052 res = FEATURE_RETURN_STOREDIGITS; 01053 } 01054 } 01055 } 01056 01057 01058 if (!ast_strlen_zero(dynamic_features)) { 01059 char *tmp = ast_strdupa(dynamic_features); 01060 char *tok; 01061 01062 while ((tok = strsep(&tmp, "#")) != NULL) { 01063 feature = find_feature(tok); 01064 01065 if (feature) { 01066 /* Feature is up for consideration */ 01067 if (!strcmp(feature->exten, code)) { 01068 if (option_verbose > 2) 01069 ast_verbose(VERBOSE_PREFIX_3 " Feature Found: %s exten: %s\n",feature->sname, tok); 01070 res = feature->operation(chan, peer, config, code, sense); 01071 break; 01072 } else if (!strncmp(feature->exten, code, strlen(code))) { 01073 res = FEATURE_RETURN_STOREDIGITS; 01074 } 01075 } 01076 } 01077 } 01078 01079 return res; 01080 }
|
|
||||||||||||||||||||||||||||||||||||
|
Definition at line 1119 of file res_features.c. References ast_channel::_softhangup, ast_call(), ast_channel_inherit_variables(), ast_check_hangup(), AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_HANGUP, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_TEXT, ast_frfree(), ast_indicate(), ast_log(), ast_read(), ast_request(), ast_set_callerid(), AST_STATE_UP, ast_verbose(), ast_waitfor_n(), builtin_features, ast_call_feature::exten, FEATURES_COUNT, ast_frame::frametype, len, LOG_NOTICE, option_verbose, pbx_builtin_setvar_helper(), ast_frame::subclass, and VERBOSE_PREFIX_3. Referenced by builtin_atxfer(). 01120 { 01121 int state = 0; 01122 int cause = 0; 01123 int to; 01124 struct ast_channel *chan; 01125 struct ast_channel *monitor_chans[2]; 01126 struct ast_channel *active_channel; 01127 int res = 0, ready = 0; 01128 01129 if ((chan = ast_request(type, format, data, &cause))) { 01130 ast_set_callerid(chan, cid_num, cid_name, cid_num); 01131 ast_channel_inherit_variables(caller, chan); 01132 pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name); 01133 if (!ast_call(chan, data, timeout)) { 01134 struct timeval started; 01135 int x, len = 0; 01136 char *disconnect_code = NULL, *dialed_code = NULL; 01137 01138 ast_indicate(caller, AST_CONTROL_RINGING); 01139 /* support dialing of the featuremap disconnect code while performing an attended tranfer */ 01140 for (x=0; x < FEATURES_COUNT; x++) { 01141 if (strcasecmp(builtin_features[x].sname, "disconnect")) 01142 continue; 01143 01144 disconnect_code = builtin_features[x].exten; 01145 len = strlen(disconnect_code) + 1; 01146 dialed_code = alloca(len); 01147 memset(dialed_code, 0, len); 01148 break; 01149 } 01150 x = 0; 01151 started = ast_tvnow(); 01152 to = timeout; 01153 while (!ast_check_hangup(caller) && timeout && (chan->_state != AST_STATE_UP)) { 01154 struct ast_frame *f = NULL; 01155 01156 monitor_chans[0] = caller; 01157 monitor_chans[1] = chan; 01158 active_channel = ast_waitfor_n(monitor_chans, 2, &to); 01159 01160 /* see if the timeout has been violated */ 01161 if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) { 01162 state = AST_CONTROL_UNHOLD; 01163 ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n"); 01164 break; /*doh! timeout*/ 01165 } 01166 01167 if (!active_channel) 01168 continue; 01169 01170 if (chan && (chan == active_channel)){ 01171 f = ast_read(chan); 01172 if (f == NULL) { /*doh! where'd he go?*/ 01173 state = AST_CONTROL_HANGUP; 01174 res = 0; 01175 break; 01176 } 01177 01178 if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) { 01179 if (f->subclass == AST_CONTROL_RINGING) { 01180 state = f->subclass; 01181 if (option_verbose > 2) 01182 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", chan->name); 01183 ast_indicate(caller, AST_CONTROL_RINGING); 01184 } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) { 01185 state = f->subclass; 01186 if (option_verbose > 2) 01187 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", chan->name); 01188 ast_indicate(caller, AST_CONTROL_BUSY); 01189 ast_frfree(f); 01190 f = NULL; 01191 break; 01192 } else if (f->subclass == AST_CONTROL_ANSWER) { 01193 /* This is what we are hoping for */ 01194 state = f->subclass; 01195 ast_frfree(f); 01196 f = NULL; 01197 ready=1; 01198 break; 01199 } else { 01200 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass); 01201 } 01202 /* else who cares */ 01203 } 01204 01205 } else if (caller && (active_channel == caller)) { 01206 f = ast_read(caller); 01207 if (f == NULL) { /*doh! where'd he go?*/ 01208 if (caller->_softhangup && !chan->_softhangup) { 01209 /* make this a blind transfer */ 01210 ready = 1; 01211 break; 01212 } 01213 state = AST_CONTROL_HANGUP; 01214 res = 0; 01215 break; 01216 } 01217 01218 if (f->frametype == AST_FRAME_DTMF) { 01219 dialed_code[x++] = f->subclass; 01220 dialed_code[x] = '\0'; 01221 if (strlen(dialed_code) == len) { 01222 x = 0; 01223 } else if (x && strncmp(dialed_code, disconnect_code, x)) { 01224 x = 0; 01225 dialed_code[x] = '\0'; 01226 } 01227 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) { 01228 /* Caller Canceled the call */ 01229 state = AST_CONTROL_UNHOLD; 01230 ast_frfree(f); 01231 f = NULL; 01232 break; 01233 } 01234 } 01235 } 01236 if (f) 01237 ast_frfree(f); 01238 } /* end while */ 01239 } else 01240 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data); 01241 } else { 01242 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data); 01243 switch(cause) { 01244 case AST_CAUSE_BUSY: 01245 state = AST_CONTROL_BUSY; 01246 break; 01247 case AST_CAUSE_CONGESTION: 01248 state = AST_CONTROL_CONGESTION; 01249 break; 01250 } 01251 } 01252 01253 ast_indicate(caller, -1); 01254 if (chan && ready) { 01255 if (chan->_state == AST_STATE_UP) 01256 state = AST_CONTROL_ANSWER; 01257 res = 0; 01258 } else if(chan) { 01259 res = -1; 01260 ast_hangup(chan); 01261 chan = NULL; 01262 } else { 01263 res = -1; 01264 } 01265 01266 if (outstate) 01267 *outstate = state; 01268 01269 if (chan && res <= 0) { 01270 if (chan->cdr || (chan->cdr = ast_cdr_alloc())) { 01271 char tmp[256]; 01272 ast_cdr_init(chan->cdr, chan); 01273 snprintf(tmp, 256, "%s/%s", type, (char *)data); 01274 ast_cdr_setapp(chan->cdr,"Dial",tmp); 01275 ast_cdr_update(chan); 01276 ast_cdr_start(chan->cdr); 01277 ast_cdr_end(chan->cdr); 01278 /* If the cause wasn't handled properly */ 01279 if (ast_cdr_disposition(chan->cdr,chan->hangupcause)) 01280 ast_cdr_failed(chan->cdr); 01281 } else { 01282 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n"); 01283 } 01284 } 01285 01286 return chan; 01287 }
|
|
||||||||||||
|
|
|
||||||||||||||||||||
|
Park a call via a masqueraded channel.
Definition at line 439 of file res_features.c. References ast_channel_alloc(), ast_channel_masquerade(), ast_frfree(), ast_log(), ast_park_call(), ast_read(), AST_STATE_DOWN, ast_channel::context, ast_channel::exten, LOG_WARNING, ast_channel::priority, ast_channel::readformat, set_c_e_p(), and ast_channel::writeformat. Referenced by manager_park(), mgcp_ss(), and ss_thread(). 00440 { 00441 struct ast_channel *chan; 00442 struct ast_frame *f; 00443 00444 /* Make a new, fake channel that we'll use to masquerade in the real one */ 00445 if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "Parked/%s",rchan->name))) { 00446 ast_log(LOG_WARNING, "Unable to create parked channel\n"); 00447 return -1; 00448 } 00449 00450 /* Make formats okay */ 00451 chan->readformat = rchan->readformat; 00452 chan->writeformat = rchan->writeformat; 00453 ast_channel_masquerade(chan, rchan); 00454 00455 /* Setup the extensions and such */ 00456 set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority); 00457 00458 /* Make the masq execute */ 00459 f = ast_read(chan); 00460 if (f) 00461 ast_frfree(f); 00462 00463 ast_park_call(chan, peer, timeout, extout); 00464 return 0; 00465 }
|
|
||||||||||||||||||||||||||||
|
|
|
|
protects all static variables above |
|
||||||||||||||||||||
|
Park a call and read back parked location.
Definition at line 311 of file res_features.c. References ast_calloc, ast_exists_extension(), ast_log(), ast_mutex_lock(), ast_strlen_zero(), LOG_WARNING, parkeduser::next, parkinglot, parkeduser::parkingnum, and pbx_builtin_getvar_helper(). Referenced by ast_masq_park_call(), builtin_blindtransfer(), builtin_parkcall(), iax_park_thread(), park_call_exec(), and sip_park_thread(). 00312 { 00313 struct parkeduser *pu, *cur; 00314 int i, x = -1, parking_range; 00315 struct ast_context *con; 00316 const char *parkingexten; 00317 00318 /* Allocate memory for parking data */ 00319 if (!(pu = ast_calloc(1, sizeof(*pu)))) 00320 return -1; 00321 00322 /* Lock parking lot */ 00323 ast_mutex_lock(&parking_lock); 00324 /* Check for channel variable PARKINGEXTEN */ 00325 parkingexten = pbx_builtin_getvar_helper(chan, "PARKINGEXTEN"); 00326 if (!ast_strlen_zero(parkingexten)) { 00327 if (ast_exists_extension(NULL, parking_con, parkingexten, 1, NULL)) { 00328 ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parking_con); 00329 return 0; /* Continue execution if possible */ 00330 } 00331 ast_copy_string(pu->parkingexten, parkingexten, sizeof(pu->parkingexten)); 00332 } else { 00333 /* Select parking space within range */ 00334 parking_range = parking_stop - parking_start+1; 00335 for (i = 0; i < parking_range; i++) { 00336 x = (i + parking_offset) % parking_range + parking_start; 00337 cur = parkinglot; 00338 while(cur) { 00339 if (cur->parkingnum == x) 00340 break; 00341 cur = cur->next; 00342 } 00343 if (!cur) 00344 break; 00345 } 00346 00347 if (!(i < parking_range)) { 00348 ast_log(LOG_WARNING, "No more parking spaces\n"); 00349 free(pu); 00350 ast_mutex_unlock(&parking_lock); 00351 return -1; 00352 } 00353 /* Set pointer for next parking */ 00354 if (parkfindnext) 00355 parking_offset = x - parking_start + 1; 00356 } 00357 00358 chan->appl = "Parked Call"; 00359 chan->data = NULL; 00360 00361 pu->chan = chan; 00362 00363 /* Put the parked channel on hold if we have two different channels */ 00364 if (chan != peer) { 00365 ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 00366 S_OR(parkmohclass, NULL), 00367 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0); 00368 } 00369 00370 pu->start = ast_tvnow(); 00371 pu->parkingnum = x; 00372 pu->parkingtime = (timeout > 0) ? timeout : parkingtime; 00373 if (extout) 00374 *extout = x; 00375 00376 if (peer) 00377 ast_copy_string(pu->peername, peer->name, sizeof(pu->peername)); 00378 00379 /* Remember what had been dialed, so that if the parking 00380 expires, we try to come back to the same place */ 00381 ast_copy_string(pu->context, S_OR(chan->macrocontext, chan->context), sizeof(pu->context)); 00382 ast_copy_string(pu->exten, S_OR(chan->macroexten, chan->exten), sizeof(pu->exten)); 00383 pu->priority = chan->macropriority ? chan->macropriority : chan->priority; 00384 pu->next = parkinglot; 00385 parkinglot = pu; 00386 00387 /* If parking a channel directly, don't quiet yet get parking running on it */ 00388 if (peer == chan) 00389 pu->notquiteyet = 1; 00390 ast_mutex_unlock(&parking_lock); 00391 /* Wake up the (presumably select()ing) thread */ 00392 pthread_kill(parking_thread, SIGURG); 00393 if (option_verbose > 1) 00394 ast_verbose(VERBOSE_PREFIX_2 "Parked %s on %d@%s. Will timeout back to extension [%s] %s, %d in %d seconds\n", pu->chan->name, pu->parkingnum, parking_con, pu->context, pu->exten, pu->priority, (pu->parkingtime/1000)); 00395 00396 if (pu->parkingnum != -1) 00397 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", x); 00398 manager_event(EVENT_FLAG_CALL, "ParkedCall", 00399 "Exten: %s\r\n" 00400 "Channel: %s\r\n" 00401 "From: %s\r\n" 00402 "Timeout: %ld\r\n" 00403 "CallerIDNum: %s\r\n" 00404 "CallerIDName: %s\r\n", 00405 pu->parkingexten, pu->chan->name, peer ? peer->name : "", 00406 (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL), 00407 S_OR(pu->chan->cid.cid_num, "<unknown>"), 00408 S_OR(pu->chan->cid.cid_name, "<unknown>") 00409 ); 00410 00411 if (peer && adsipark && ast_adsi_available(peer)) { 00412 adsi_announce_park(peer, pu->parkingexten); /* Only supports parking numbers */ 00413 ast_adsi_unload_session(peer); 00414 } 00415 00416 con = ast_context_find(parking_con); 00417 if (!con) 00418 con = ast_context_create(NULL, parking_con, registrar); 00419 if (!con) /* Still no context? Bad */ 00420 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con); 00421 else { /* Add extension to context */ 00422 if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, strdup(pu->parkingexten), ast_free, registrar)) 00423 notify_metermaids(pu->parkingexten, parking_con); 00424 } 00425 /* Tell the peer channel the number of the parking space */ 00426 if (peer && pu->parkingnum != -1) /* Only say number if it's a number */ 00427 ast_say_digits(peer, pu->parkingnum, "", peer->language); 00428 if (pu->notquiteyet) { 00429 /* Wake up parking thread if we're really done */ 00430 ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 00431 S_OR(parkmohclass, NULL), 00432 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0); 00433 pu->notquiteyet = 0; 00434 pthread_kill(parking_thread, SIGURG); 00435 } 00436 return 0; 00437 }
|
|
|
Determine system parking extension Returns the call parking extension for drivers that provide special call parking help.
Definition at line 157 of file res_features.c. Referenced by builtin_blindtransfer(), dp_lookup(), handle_request_refer(), mgcp_ss(), socket_process(), and ss_thread(). 00158 { 00159 return parking_ext; 00160 }
|
|
|
Pickup a call.
Definition at line 2045 of file res_features.c. References ast_channel::_state, ast_answer(), ast_channel_masquerade(), ast_channel_unlock, ast_channel_walk_locked(), AST_CONTROL_ANSWER, ast_log(), ast_queue_control(), AST_STATE_RING, AST_STATE_RINGING, ast_channel::callgroup, LOG_DEBUG, LOG_WARNING, option_debug, ast_channel::pbx, and ast_channel::pickupgroup. Referenced by cb_events(), handle_request_invite(), mgcp_ss(), and ss_thread(). 02046 { 02047 struct ast_channel *cur = NULL; 02048 int res = -1; 02049 02050 while ( (cur = ast_channel_walk_locked(cur)) != NULL) { 02051 if (!cur->pbx && 02052 (cur != chan) && 02053 (chan->pickupgroup & cur->callgroup) && 02054 ((cur->_state == AST_STATE_RINGING) || 02055 (cur->_state == AST_STATE_RING))) { 02056 break; 02057 } 02058 ast_channel_unlock(cur); 02059 } 02060 if (cur) { 02061 if (option_debug) 02062 ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name); 02063 res = ast_answer(chan); 02064 if (res) 02065 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name); 02066 res = ast_queue_control(chan, AST_CONTROL_ANSWER); 02067 if (res) 02068 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name); 02069 res = ast_channel_masquerade(cur, chan); 02070 if (res) 02071 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */ 02072 ast_channel_unlock(cur); 02073 } else { 02074 if (option_debug) 02075 ast_log(LOG_DEBUG, "No call pickup possible...\n"); 02076 } 02077 return res; 02078 }
|
|
|
Determine system call pickup extension.
Definition at line 162 of file res_features.c. Referenced by cb_events(), get_destination(), handle_request_invite(), handle_showfeatures(), mgcp_ss(), and ss_thread(). 00163 { 00164 return pickup_ext; 00165 }
|
|
|
register new feature into feature_set
Definition at line 883 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. 00884 { 00885 if (!feature) { 00886 ast_log(LOG_NOTICE,"You didn't pass a feature!\n"); 00887 return; 00888 } 00889 00890 AST_LIST_LOCK(&feature_list); 00891 AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry); 00892 AST_LIST_UNLOCK(&feature_list); 00893 00894 if (option_verbose >= 2) 00895 ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname); 00896 }
|
|
|
unregister feature from feature_set
Definition at line 899 of file res_features.c. References AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, and free. 00900 { 00901 if (!feature) 00902 return; 00903 00904 AST_LIST_LOCK(&feature_list); 00905 AST_LIST_REMOVE(&feature_list,feature,feature_entry); 00906 AST_LIST_UNLOCK(&feature_list); 00907 free(feature); 00908 }
|
|
|
Remove all features in the list.
Definition at line 911 of file res_features.c. References AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, and free. 00912 { 00913 struct ast_call_feature *feature; 00914 00915 AST_LIST_LOCK(&feature_list); 00916 while ((feature = AST_LIST_REMOVE_HEAD(&feature_list,feature_entry))) 00917 free(feature); 00918 AST_LIST_UNLOCK(&feature_list); 00919 }
|
|
||||||||||||||||||||||||
|
Definition at line 731 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_calloc, ast_channel_alloc(), 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_read(), ast_set_flag, AST_STATE_DOWN, AST_STATE_UP, ast_stream_and_wait(), ast_waitfordigit(), ast_bridge_thread_obj::bconfig, ast_bridge_thread_obj::chan, check_compat(), ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, config, ast_channel::context, ast_channel::exten, FEATURE_RETURN_SUCCESS, ast_bridge_config::features_callee, ast_bridge_config::features_caller, finishup(), LOG_DEBUG, LOG_WARNING, ast_channel::nativeformats, option_debug, ast_bridge_thread_obj::peer, ast_channel::priority, ast_channel::readformat, real_ctx(), set_peers(), and ast_channel::writeformat. 00732 { 00733 struct ast_channel *transferer; 00734 struct ast_channel *transferee; 00735 const char *transferer_real_context; 00736 char xferto[256] = ""; 00737 int res; 00738 int outstate=0; 00739 struct ast_channel *newchan; 00740 struct ast_channel *xferchan; 00741 struct ast_bridge_thread_obj *tobj; 00742 struct ast_bridge_config bconfig; 00743 struct ast_frame *f; 00744 int l; 00745 00746 if (option_debug) 00747 ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense); 00748 set_peers(&transferer, &transferee, peer, chan, sense); 00749 transferer_real_context = real_ctx(transferer, transferee); 00750 /* Start autoservice on chan while we talk to the originator */ 00751 ast_autoservice_start(transferee); 00752 ast_indicate(transferee, AST_CONTROL_HOLD); 00753 00754 /* Transfer */ 00755 res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY); 00756 if (res < 0) { 00757 finishup(transferee); 00758 return res; 00759 } 00760 if (res > 0) /* If they've typed a digit already, handle it */ 00761 xferto[0] = (char) res; 00762 00763 /* this is specific of atxfer */ 00764 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout); 00765 if (res < 0) { /* hangup, would be 0 for invalid and 1 for valid */ 00766 finishup(transferee); 00767 return res; 00768 } 00769 if (res == 0) { 00770 ast_log(LOG_WARNING, "Did not read data.\n"); 00771 finishup(transferee); 00772 if (ast_stream_and_wait(transferer, "beeperr", "")) 00773 return -1; 00774 return FEATURE_RETURN_SUCCESS; 00775 } 00776 00777 /* valid extension, res == 1 */ 00778 if (!ast_exists_extension(transferer, transferer_real_context, xferto, 1, transferer->cid.cid_num)) { 00779 ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context); 00780 finishup(transferee); 00781 if (ast_stream_and_wait(transferer, "beeperr", "")) 00782 return -1; 00783 return FEATURE_RETURN_SUCCESS; 00784 } 00785 00786 l = strlen(xferto); 00787 snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context); /* append context */ 00788 newchan = ast_feature_request_and_dial(transferer, "Local", ast_best_codec(transferer->nativeformats), 00789 xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name); 00790 ast_indicate(transferer, -1); 00791 if (!newchan) { 00792 finishup(transferee); 00793 /* any reason besides user requested cancel and busy triggers the failed sound */ 00794 if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY && 00795 ast_stream_and_wait(transferer, xferfailsound, "")) 00796 return -1; 00797 return FEATURE_RETURN_SUCCESS; 00798 } 00799 00800 if (check_compat(transferer, newchan)) 00801 return -1; 00802 memset(&bconfig,0,sizeof(struct ast_bridge_config)); 00803 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT); 00804 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT); 00805 res = ast_bridge_call(transferer, newchan, &bconfig); 00806 if (newchan->_softhangup || newchan->_state != AST_STATE_UP || !transferer->_softhangup) { 00807 ast_hangup(newchan); 00808 if (ast_stream_and_wait(transferer, xfersound, "")) 00809 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 00810 finishup(transferee); 00811 transferer->_softhangup = 0; 00812 return FEATURE_RETURN_SUCCESS; 00813 } 00814 00815 if (check_compat(transferee, newchan)) 00816 return -1; 00817 00818 ast_indicate(transferee, AST_CONTROL_UNHOLD); 00819 00820 if ((ast_autoservice_stop(transferee) < 0) 00821 || (ast_waitfordigit(transferee, 100) < 0) 00822 || (ast_waitfordigit(newchan, 100) < 0) 00823 || ast_check_hangup(transferee) 00824 || ast_check_hangup(newchan)) { 00825 ast_hangup(newchan); 00826 return -1; 00827 } 00828 00829 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "Transfered/%s", transferee->name); 00830 if (!xferchan) { 00831 ast_hangup(newchan); 00832 return -1; 00833 } 00834 /* Make formats okay */ 00835 xferchan->readformat = transferee->readformat; 00836 xferchan->writeformat = transferee->writeformat; 00837 ast_channel_masquerade(xferchan, transferee); 00838 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority); 00839 xferchan->_state = AST_STATE_UP; 00840 ast_clear_flag(xferchan, AST_FLAGS_ALL); 00841 xferchan->_softhangup = 0; 00842 00843 if ((f = ast_read(xferchan))) 00844 ast_frfree(f); 00845 00846 newchan->_state = AST_STATE_UP; 00847 ast_clear_flag(newchan, AST_FLAGS_ALL); 00848 newchan->_softhangup = 0; 00849 00850 tobj = ast_calloc(1, sizeof(struct ast_bridge_thread_obj)); 00851 if (!tobj) { 00852 ast_hangup(xferchan); 00853 ast_hangup(newchan); 00854 return -1; 00855 } 00856 tobj->chan = xferchan; 00857 tobj->peer = newchan; 00858 tobj->bconfig = *config; 00859 00860 if (ast_stream_and_wait(newchan, xfersound, "")) 00861 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 00862 ast_bridge_call_thread_launch(tobj); 00863 return -1; /* XXX meaning the channel is bridged ? */ 00864 }
|
|
||||||||||||||||||||||||
|
Definition at line 528 of file res_features.c. References ast_autoservice_start(), ast_autoservice_stop(), ast_log(), ast_monitor_stop(), ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_verbose(), ast_channel::cid, ast_callerid::cid_num, FEATURE_RETURN_SUCCESS, len, LOG_ERROR, LOG_WARNING, ast_channel::monitor, monitor_app, option_verbose, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), S_OR, set_peers(), and VERBOSE_PREFIX_3. 00529 { 00530 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL; 00531 int x = 0; 00532 size_t len; 00533 struct ast_channel *caller_chan, *callee_chan; 00534 00535 if (!monitor_ok) { 00536 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); 00537 return -1; 00538 } 00539 00540 if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) { 00541 monitor_ok = 0; 00542 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); 00543 return -1; 00544 } 00545 00546 set_peers(&caller_chan, &callee_chan, peer, chan, sense); 00547 00548 if (!ast_strlen_zero(courtesytone)) { 00549 if (ast_autoservice_start(callee_chan)) 00550 return -1; 00551 if (ast_stream_and_wait(caller_chan, courtesytone, "")) { 00552 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); 00553 ast_autoservice_stop(callee_chan); 00554 return -1; 00555 } 00556 if (ast_autoservice_stop(callee_chan)) 00557 return -1; 00558 } 00559 00560 if (callee_chan->monitor) { 00561 if (option_verbose > 3) 00562 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to stop recording call.\n", code); 00563 ast_monitor_stop(callee_chan, 1); 00564 return FEATURE_RETURN_SUCCESS; 00565 } 00566 00567 if (caller_chan && callee_chan) { 00568 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT"); 00569 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR"); 00570 00571 if (!touch_format) 00572 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT"); 00573 00574 if (!touch_monitor) 00575 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR"); 00576 00577 if (touch_monitor) { 00578 len = strlen(touch_monitor) + 50; 00579 args = alloca(len); 00580 touch_filename = alloca(len); 00581 snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor); 00582 snprintf(args, len, "%s|%s|m", (touch_format) ? touch_format : "wav", touch_filename); 00583 } else { 00584 caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name)); 00585 callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name)); 00586 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50; 00587 args = alloca(len); 00588 touch_filename = alloca(len); 00589 snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id); 00590 snprintf(args, len, "%s|%s|m", S_OR(touch_format, "wav"), touch_filename); 00591 } 00592 00593 for( x = 0; x < strlen(args); x++) { 00594 if (args[x] == '/') 00595 args[x] = '-'; 00596 } 00597 00598 if (option_verbose > 3) 00599 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call. filename: %s\n", code, args); 00600 00601 pbx_exec(callee_chan, monitor_app, args); 00602 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); 00603 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); 00604 00605 return FEATURE_RETURN_SUCCESS; 00606 } 00607 00608 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n"); 00609 return -1; 00610 }
|
|
||||||||||||||||||||||||
|
Definition at line 639 of file res_features.c. References ast_app_dtget(), ast_async_goto(), ast_autoservice_start(), AST_CONTROL_HOLD, AST_DIGIT_ANY, ast_exists_extension(), ast_indicate(), ast_log(), ast_park_call(), ast_parking_ext(), AST_PBX_KEEPALIVE, AST_PBX_NO_HANGUP_PEER, ast_stopstream(), ast_stream_and_wait(), ast_verbose(), check_goto_on_transfer(), ast_channel::cid, ast_callerid::cid_num, FEATURE_RETURN_SUCCESS, finishup(), LOG_WARNING, option_verbose, ast_channel::pbx, pbx_builtin_setvar_helper(), real_ctx(), set_c_e_p(), set_peers(), VERBOSE_PREFIX_2, and VERBOSE_PREFIX_3. 00640 { 00641 struct ast_channel *transferer; 00642 struct ast_channel *transferee; 00643 const char *transferer_real_context; 00644 char xferto[256]; 00645 int res; 00646 00647 set_peers(&transferer, &transferee, peer, chan, sense); 00648 transferer_real_context = real_ctx(transferer, transferee); 00649 /* Start autoservice on chan while we talk to the originator */ 00650 ast_autoservice_start(transferee); 00651 ast_indicate(transferee, AST_CONTROL_HOLD); 00652 00653 memset(xferto, 0, sizeof(xferto)); 00654 00655 /* Transfer */ 00656 res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY); 00657 if (res < 0) { 00658 finishup(transferee); 00659 return -1; /* error ? */ 00660 } 00661 if (res > 0) /* If they've typed a digit already, handle it */ 00662 xferto[0] = (char) res; 00663 00664 ast_stopstream(transferer); 00665 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout); 00666 if (res < 0) { /* hangup, would be 0 for invalid and 1 for valid */ 00667 finishup(transferee); 00668 return res; 00669 } 00670 if (!strcmp(xferto, ast_parking_ext())) { 00671 res = finishup(transferee); 00672 if (res) 00673 res = -1; 00674 else if (!ast_park_call(transferee, transferer, 0, NULL)) { /* success */ 00675 /* We return non-zero, but tell the PBX not to hang the channel when 00676 the thread dies -- We have to be careful now though. We are responsible for 00677 hanging up the channel, else it will never be hung up! */ 00678 00679 return (transferer == peer) ? AST_PBX_KEEPALIVE : AST_PBX_NO_HANGUP_PEER; 00680 } else { 00681 ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name); 00682 } 00683 /*! \todo XXX Maybe we should have another message here instead of invalid extension XXX */ 00684 } else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) { 00685 pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", chan->name); 00686 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", peer->name); 00687 res=finishup(transferee); 00688 if (!transferee->pbx) { 00689 /* Doh! Use our handy async_goto functions */ 00690 if (option_verbose > 2) 00691 ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n" 00692 ,transferee->name, xferto, transferer_real_context); 00693 if (ast_async_goto(transferee, transferer_real_context, xferto, 1)) 00694 ast_log(LOG_WARNING, "Async goto failed :-(\n"); 00695 res = -1; 00696 } else { 00697 /* Set the channel's new extension, since it exists, using transferer context */ 00698 set_c_e_p(transferee, transferer_real_context, xferto, 0); 00699 } 00700 check_goto_on_transfer(transferer); 00701 return res; 00702 } else { 00703 if (option_verbose > 2) 00704 ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context); 00705 } 00706 if (ast_stream_and_wait(transferer, xferfailsound, AST_DIGIT_ANY) < 0 ) { 00707 finishup(transferee); 00708 return -1; 00709 } 00710 ast_stopstream(transferer); 00711 res = finishup(transferee); 00712 if (res) { 00713 if (option_verbose > 1) 00714 ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name); 00715 return res; 00716 } 00717 return FEATURE_RETURN_SUCCESS; 00718 }
|
|
||||||||||||||||||||||||
|
Definition at line 612 of file res_features.c. References ast_verbose(), FEATURE_RETURN_HANGUP, option_verbose, and VERBOSE_PREFIX_3. 00613 { 00614 if (option_verbose > 3) 00615 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code); 00616 return FEATURE_RETURN_HANGUP; 00617 }
|
|
||||||||||||||||||||||||
|
support routing for one touch call parking
Definition at line 495 of file res_features.c. References ast_channel::_state, ast_answer(), ast_module_user_add, ast_module_user_remove, ast_park_call(), AST_PBX_KEEPALIVE, AST_PBX_NO_HANGUP_PEER, ast_safe_sleep(), AST_STATE_UP, ast_module_user::chan, ast_channel::exten, FEATURE_SENSE_CHAN, ast_channel::priority, and set_peers(). 00496 { 00497 struct ast_channel *parker; 00498 struct ast_channel *parkee; 00499 int res = 0; 00500 struct ast_module_user *u; 00501 00502 u = ast_module_user_add(chan); 00503 00504 set_peers(&parker, &parkee, peer, chan, sense); 00505 /* Setup the exten/priority to be s/1 since we don't know 00506 where this call should return */ 00507 strcpy(chan->exten, "s"); 00508 chan->priority = 1; 00509 if (chan->_state != AST_STATE_UP) 00510 res = ast_answer(chan); 00511 if (!res) 00512 res = ast_safe_sleep(chan, 1000); 00513 if (!res) 00514 res = ast_park_call(parkee, parker, 0, NULL); 00515 00516 ast_module_user_remove(u); 00517 00518 if (!res) { 00519 if (sense == FEATURE_SENSE_CHAN) 00520 res = AST_PBX_NO_HANGUP_PEER; 00521 else 00522 res = AST_PBX_KEEPALIVE; 00523 } 00524 return res; 00525 00526 }
|
|
||||||||||||
|
Definition at line 720 of file res_features.c. References ast_channel_make_compatible(), ast_hangup(), ast_log(), and LOG_WARNING. Referenced by builtin_atxfer(). 00721 { 00722 if (ast_channel_make_compatible(c, newchan) < 0) { 00723 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", 00724 c->name, newchan->name); 00725 ast_hangup(newchan); 00726 return -1; 00727 } 00728 return 0; 00729 }
|
|
|
Definition at line 182 of file res_features.c. References ast_channel_alloc(), AST_STATE_DOWN, ast_strdupa, ast_strlen_zero(), and pbx_builtin_getvar_helper(). Referenced by builtin_blindtransfer(). 00183 { 00184 struct ast_channel *xferchan; 00185 const char *val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR"); 00186 char *x, *goto_on_transfer; 00187 struct ast_frame *f; 00188 00189 if (ast_strlen_zero(val)) 00190 return; 00191 00192 goto_on_transfer = ast_strdupa(val); 00193 00194 if (!(xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, chan->name))) 00195 return; 00196 00197 for (x = goto_on_transfer; x && *x; x++) { 00198 if (*x == '^') 00199 *x = '|'; 00200 } 00201 /* Make formats okay */ 00202 xferchan->readformat = chan->readformat; 00203 xferchan->writeformat = chan->writeformat; 00204 ast_channel_masquerade(xferchan, chan); 00205 ast_parseable_goto(xferchan, goto_on_transfer); 00206 xferchan->_state = AST_STATE_UP; 00207 ast_clear_flag(xferchan, AST_FLAGS_ALL); 00208 xferchan->_softhangup = 0; 00209 if ((f = ast_read(xferchan))) { 00210 ast_frfree(f); 00211 f = NULL; 00212 ast_pbx_start(xferchan); 00213 } else { 00214 ast_hangup(xferchan); 00215 } 00216 }
|
|
|
Take care of parked calls and unpark them if needed.
Definition at line 1525 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_HOLD, AST_CONTROL_UNHOLD, AST_FLAG_EXCEPTION, AST_FRAME_CONTROL, ast_free, ast_frfree(), ast_hangup(), ast_indicate(), ast_indicate_data(), ast_log(), AST_MAX_EXTENSION, AST_MAX_FDS, ast_mutex_lock(), ast_pbx_start(), ast_read(), ast_set_flag, ast_strdupa, ast_strlen_zero(), ast_verbose(), parkeduser::chan, ast_channel::context, parkeduser::context, ast_channel::exten, parkeduser::exten, ast_channel::fds, free, LOG_DEBUG, LOG_ERROR, LOG_WARNING, parkeduser::moh_trys, parkeduser::next, notify_metermaids(), parkeduser::notquiteyet, option_debug, option_verbose, parkeduser::parkingexten, parkinglot, parkeduser::parkingnum, parkeduser::parkingtime, pbx_builtin_setvar_helper(), parkeduser::peername, post_manager_event(), ast_channel::priority, parkeduser::priority, S_OR, set_c_e_p(), parkeduser::start, strdup, and VERBOSE_PREFIX_2. Referenced by load_module(). 01526 { 01527 char parkingslot[AST_MAX_EXTENSION]; 01528 fd_set rfds, efds; /* results from previous select, to be preserved across loops. */ 01529 01530 FD_ZERO(&rfds); 01531 FD_ZERO(&efds); 01532 01533 for (;;) { 01534 struct parkeduser *pu, *pl, *pt = NULL; 01535 int ms = -1; /* select timeout, uninitialized */ 01536 int max = -1; /* max fd, none there yet */ 01537 fd_set nrfds, nefds; /* args for the next select */ 01538 FD_ZERO(&nrfds); 01539 FD_ZERO(&nefds); 01540 01541 ast_mutex_lock(&parking_lock); 01542 pl = NULL; 01543 pu = parkinglot; 01544 /* navigate the list with prev-cur pointers to support removals */ 01545 while (pu) { 01546 struct ast_channel *chan = pu->chan; /* shorthand */ 01547 int tms; /* timeout for this item */ 01548 int x; /* fd index in channel */ 01549 struct ast_context *con; 01550 01551 if (pu->notquiteyet) { /* Pretend this one isn't here yet */ 01552 pl = pu; 01553 pu = pu->next; 01554 continue; 01555 } 01556 tms = ast_tvdiff_ms(ast_tvnow(), pu->start); 01557 if (tms > pu->parkingtime) { 01558 ast_indicate(chan, AST_CONTROL_UNHOLD); 01559 /* Get chan, exten from derived kludge */ 01560 if (pu->peername[0]) { 01561 char *peername = ast_strdupa(pu->peername); 01562 char *cp = strrchr(peername, '-'); 01563 if (cp) 01564 *cp = 0; 01565 con = ast_context_find(parking_con_dial); 01566 if (!con) { 01567 con = ast_context_create(NULL, parking_con_dial, registrar); 01568 if (!con) 01569 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial); 01570 } 01571 if (con) { 01572 char returnexten[AST_MAX_EXTENSION]; 01573 snprintf(returnexten, sizeof(returnexten), "%s||t", peername); 01574 ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), ast_free, registrar); 01575 } 01576 if (comebacktoorigin) { 01577 set_c_e_p(chan, parking_con_dial, peername, 1); 01578 } else { 01579 ast_log(LOG_WARNING, "now going to parkedcallstimeout,s,1 | ps is %d\n",pu->parkingnum); 01580 snprintf(parkingslot, sizeof(parkingslot), "%d", pu->parkingnum); 01581 pbx_builtin_setvar_helper(pu->chan, "PARKINGSLOT", parkingslot); 01582 set_c_e_p(chan, "parkedcallstimeout", peername, 1); 01583 } 01584 } else { 01585 /* They've been waiting too long, send them back to where they came. Theoretically they 01586 should have their original extensions and such, but we copy to be on the safe side */ 01587 set_c_e_p(chan, pu->context, pu->exten, pu->priority); 01588 } 01589 01590 post_manager_event("ParkedCallTimeOut", pu->parkingexten, chan); 01591 01592 if (option_verbose > 1) 01593 ast_verbose(VERBOSE_PREFIX_2 "Timeout for %s parked on %d. Returning to %s,%s,%d\n", chan->name, pu->parkingnum, chan->context, chan->exten, chan->priority); 01594 /* Start up the PBX, or hang them up */ 01595 if (ast_pbx_start(chan)) { 01596 ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", chan->name); 01597 ast_hangup(chan); 01598 } 01599 /* And take them out of the parking lot */ 01600 if (pl) 01601 pl->next = pu->next; 01602 else 01603 parkinglot = pu->next; 01604 pt = pu; 01605 pu = pu->next; 01606 con = ast_context_find(parking_con); 01607 if (con) { 01608 if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL)) 01609 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 01610 else 01611 notify_metermaids(pt->parkingexten, parking_con); 01612 } else 01613 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 01614 free(pt); 01615 } else { /* still within parking time, process descriptors */ 01616 for (x = 0; x < AST_MAX_FDS; x++) { 01617 struct ast_frame *f; 01618 01619 if (chan->fds[x] == -1 || (!FD_ISSET(chan->fds[x], &rfds) && !FD_ISSET(chan->fds[x], &efds))) 01620 continue; /* nothing on this descriptor */ 01621 01622 if (FD_ISSET(chan->fds[x], &efds)) 01623 ast_set_flag(chan, AST_FLAG_EXCEPTION); 01624 else 01625 ast_clear_flag(chan, AST_FLAG_EXCEPTION); 01626 chan->fdno = x; 01627 01628 /* See if they need servicing */ 01629 f = ast_read(chan); 01630 if (!f || (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_HANGUP)) { 01631 if (f) 01632 ast_frfree(f); 01633 post_manager_event("ParkedCallGiveUp", pu->parkingexten, chan); 01634 01635 /* There's a problem, hang them up*/ 01636 if (option_verbose > 1) 01637 ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", chan->name); 01638 ast_hangup(chan); 01639 /* And take them out of the parking lot */ 01640 if (pl) 01641 pl->next = pu->next; 01642 else 01643 parkinglot = pu->next; 01644 pt = pu; 01645 pu = pu->next; 01646 con = ast_context_find(parking_con); 01647 if (con) { 01648 if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL)) 01649 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 01650 else 01651 notify_metermaids(pt->parkingexten, parking_con); 01652 } else 01653 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 01654 free(pt); 01655 break; 01656 } else { 01657 /*! \todo XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */ 01658 ast_frfree(f); 01659 if (pu->moh_trys < 3 && !chan->generatordata) { 01660 if (option_debug) 01661 ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source. Restarting.\n"); 01662 ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 01663 S_OR(parkmohclass, NULL), 01664 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0); 01665 pu->moh_trys++; 01666 } 01667 goto std; /*! \todo XXX Ick: jumping into an else statement??? XXX */ 01668 } 01669 01670 } /* end for */ 01671 if (x >= AST_MAX_FDS) { 01672 std: for (x=0; x<AST_MAX_FDS; x++) { /* mark fds for next round */ 01673 if (chan->fds[x] > -1) { 01674 FD_SET(chan->fds[x], &nrfds); 01675 FD_SET(chan->fds[x], &nefds); 01676 if (chan->fds[x] > max) 01677 max = chan->fds[x]; 01678 } 01679 } 01680 /* Keep track of our shortest wait */ 01681 if (tms < ms || ms < 0) 01682 ms = tms; 01683 pl = pu; 01684 pu = pu->next; 01685 } 01686 } 01687 } /* end while */ 01688 ast_mutex_unlock(&parking_lock); 01689 rfds = nrfds; 01690 efds = nefds; 01691 { 01692 struct timeval tv = ast_samp2tv(ms, 1000); 01693 /* Wait for something to happen */ 01694 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL); 01695 } 01696 pthread_testcancel(); 01697 } 01698 return NULL; /* Never reached */ 01699 }
|
|
||||||||||||||||||||||||
|
exec an app by feature
Definition at line 937 of file res_features.c. References ast_call_feature::app, app, ast_call_feature::app_args, ast_autoservice_start(), ast_autoservice_stop(), AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_FLAG_ONSELF, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_moh_start(), ast_moh_stop(), AST_PBX_KEEPALIVE, AST_PBX_NO_HANGUP_PEER, ast_strlen_zero(), ast_test_flag, ast_call_feature::exten, FEATURE_RETURN_NO_HANGUP_PEER, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_PBX_KEEPALIVE, FEATURE_RETURN_SUCCESS, FEATURE_RETURN_SUCCESSBREAK, FEATURE_SENSE_CHAN, LOG_NOTICE, LOG_WARNING, ast_call_feature::moh_class, pbx_exec(), and pbx_findapp(). 00938 { 00939 struct ast_app *app; 00940 struct ast_call_feature *feature; 00941 struct ast_channel *work, *idle; 00942 int res; 00943 00944 AST_LIST_LOCK(&feature_list); 00945 AST_LIST_TRAVERSE(&feature_list, feature, feature_entry) { 00946 if (!strcasecmp(feature->exten, code)) 00947 break; 00948 } 00949 AST_LIST_UNLOCK(&feature_list); 00950 00951 if (!feature) { /* shouldn't ever happen! */ 00952 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n"); 00953 return -1; 00954 } 00955 00956 if (sense == FEATURE_SENSE_CHAN) { 00957 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) 00958 return FEATURE_RETURN_PASSDIGITS; 00959 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) { 00960 work = chan; 00961 idle = peer; 00962 } else { 00963 work = peer; 00964 idle = chan; 00965 } 00966 } else { 00967 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) 00968 return FEATURE_RETURN_PASSDIGITS; 00969 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) { 00970 work = peer; 00971 idle = chan; 00972 } else { 00973 work = chan; 00974 idle = peer; 00975 } 00976 } 00977 00978 if (!(app = pbx_findapp(feature->app))) { 00979 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app); 00980 return -2; 00981 } 00982 00983 ast_autoservice_start(idle); 00984 00985 if (!ast_strlen_zero(feature->moh_class)) 00986 ast_moh_start(idle, feature->moh_class, NULL); 00987 00988 res = pbx_exec(work, app, feature->app_args); 00989 00990 if (!ast_strlen_zero(feature->moh_class)) 00991 ast_moh_stop(idle); 00992 00993 ast_autoservice_stop(idle); 00994 00995 if (res == AST_PBX_KEEPALIVE) 00996 return FEATURE_RETURN_PBX_KEEPALIVE; 00997 else if (res == AST_PBX_NO_HANGUP_PEER) 00998 return FEATURE_RETURN_NO_HANGUP_PEER; 00999 else if (res) 01000 return FEATURE_RETURN_SUCCESSBREAK; 01001 01002 return FEATURE_RETURN_SUCCESS; /*! \todo XXX should probably return res */ 01003 }
|
|
|
find a feature by name
Definition at line 922 of file res_features.c. References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, and ast_call_feature::sname. 00923 { 00924 struct ast_call_feature *tmp; 00925 00926 AST_LIST_LOCK(&feature_list); 00927 AST_LIST_TRAVERSE(&feature_list, tmp, feature_entry) { 00928 if (!strcasecmp(tmp->sname, name)) 00929 break; 00930 } 00931 AST_LIST_UNLOCK(&feature_list); 00932 00933 return tmp; 00934 }
|
|
|
Definition at line 619 of file res_features.c. References ast_autoservice_stop(), AST_CONTROL_UNHOLD, and ast_indicate(). Referenced by builtin_atxfer(), and builtin_blindtransfer(). 00620 { 00621 ast_indicate(chan, AST_CONTROL_UNHOLD); 00622 00623 return ast_autoservice_stop(chan); 00624 }
|
|
||||||||||||||||
|
Definition at line 1904 of file res_features.c. References ast_cli(), ast_mutex_lock(), parkeduser::chan, parkeduser::context, parkeduser::exten, parkeduser::next, parkeduser::parkingexten, parkinglot, parkeduser::parkingtime, parkeduser::priority, and parkeduser::start. 01905 { 01906 struct parkeduser *cur; 01907 int numparked = 0; 01908 01909 ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel" 01910 , "Context", "Extension", "Pri", "Timeout"); 01911 01912 ast_mutex_lock(&parking_lock); 01913 01914 for (cur = parkinglot; cur; cur = cur->next) { 01915 ast_cli(fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n" 01916 ,cur->parkingexten, cur->chan->name, cur->context, cur->exten 01917 ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL)); 01918 01919 numparked++; 01920 } 01921 ast_mutex_unlock(&parking_lock); 01922 ast_cli(fd, "%d parked call%s.\n", numparked, ESS(numparked)); 01923 01924 01925 return RESULT_SUCCESS; 01926 }
|
|
||||||||||||||||
|
Definition at line 1859 of file res_features.c. References ast_cli(), ast_pickup_ext(), builtin_features, ast_call_feature::default_exten, exten, ast_call_feature::fname, and format. 01860 { 01861 int i; 01862 int fcount; 01863 struct ast_call_feature *feature; 01864 char format[] = "%-25s %-7s %-7s\n"; 01865 01866 ast_cli(fd, format, "Builtin Feature", "Default", "Current"); 01867 ast_cli(fd, format, "---------------", "-------", "-------"); 01868 01869 ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */ 01870 01871 fcount = sizeof(builtin_features) / sizeof(builtin_features[0]); 01872 01873 for (i = 0; i < fcount; i++) 01874 { 01875 ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten); 01876 } 01877 ast_cli(fd, "\n"); 01878 ast_cli(fd, format, "Dynamic Feature", "Default", "Current"); 01879 ast_cli(fd, format, "---------------", "-------", "-------"); 01880 if (AST_LIST_EMPTY(&feature_list)) { 01881 ast_cli(fd, "(none)\n"); 01882 } 01883 else { 01884 AST_LIST_LOCK(&feature_list); 01885 AST_LIST_TRAVERSE(&feature_list, feature, feature_entry) { 01886 ast_cli(fd, format, feature->sname, "no def", feature->exten); 01887 } 01888 AST_LIST_UNLOCK(&feature_list); 01889 } 01890 ast_cli(fd, "\nCall parking\n"); 01891 ast_cli(fd, "------------\n"); 01892 ast_cli(fd,"%-20s: %s\n", "Parking extension", parking_ext); 01893 ast_cli(fd,"%-20s: %s\n", "Parking context", parking_con); 01894 ast_cli(fd,"%-20s: %d-%d\n", "Parked call extensions", parking_start, parking_stop); 01895 ast_cli(fd,"\n"); 01896 01897 return RESULT_SUCCESS; 01898 }
|
|
|
Definition at line 2095 of file res_features.c. References ast_config_load(), ast_log(), AST_MAX_EXTENSION, AST_MODULE_LOAD_DECLINE, ast_strlen_zero(), ast_variable_browse(), DEFAULT_FEATURE_DIGIT_TIMEOUT, DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER, DEFAULT_TRANSFER_DIGIT_TIMEOUT, LOG_WARNING, and var. Referenced by load_module(), and reload(). 02096 { 02097 int start = 0, end = 0; 02098 int res; 02099 struct ast_context *con = NULL; 02100 struct ast_config *cfg = NULL; 02101 struct ast_variable *var = NULL; 02102 char old_parking_ext[AST_MAX_EXTENSION]; 02103 char old_parking_con[AST_MAX_EXTENSION] = ""; 02104 02105 if (!ast_strlen_zero(parking_con)) { 02106 strcpy(old_parking_ext, parking_ext); 02107 strcpy(old_parking_con, parking_con); 02108 } 02109 02110 /* Reset to defaults */ 02111 strcpy(parking_con, "parkedcalls"); 02112 strcpy(parking_con_dial, "park-dial"); 02113 strcpy(parking_ext, "700"); 02114 strcpy(pickup_ext, "*8"); 02115 strcpy(parkmohclass, "default"); 02116 courtesytone[0] = '\0'; 02117 strcpy(xfersound, "beep"); 02118 strcpy(xferfailsound, "pbx-invalid"); 02119 parking_start = 701; 02120 parking_stop = 750; 02121 parkfindnext = 0; 02122 adsipark = 0; 02123 comebacktoorigin = 1; 02124 parkaddhints = 0; 02125 parkedcalltransfers = 0; 02126 02127 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 02128 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 02129 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; 02130 02131 cfg = ast_config_load("features.conf"); 02132 if (!cfg) { 02133 ast_log(LOG_WARNING,"Could not load features.conf\n"); 02134 return AST_MODULE_LOAD_DECLINE; 02135 } 02136 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) { 02137 if (!strcasecmp(var->name, "parkext")) { 02138 ast_copy_string(parking_ext, var->value, sizeof(parking_ext)); 02139 } else if (!strcasecmp(var->name, "context")) { 02140 ast_copy_string(parking_con, var->value, sizeof(parking_con)); 02141 } else if (!strcasecmp(var->name, "parkingtime")) { 02142 if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) { 02143 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value); 02144 parkingtime = DEFAULT_PARK_TIME; 02145 } else 02146 parkingtime = parkingtime * 1000; 02147 } else if (!strcasecmp(var->name, "parkpos")) { 02148 if (sscanf(var->value, "%d-%d", &start, &end) != 2) { 02149 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); 02150 } else { 02151 parking_start = start; 02152 parking_stop = end; 02153 } 02154 } else if (!strcasecmp(var->name, "findslot")) { 02155 parkfindnext = (!strcasecmp(var->value, "next")); 02156 } else if (!strcasecmp(var->name, "parkinghints")) { 02157 parkaddhints = ast_true(var->value); 02158 } else if (!strcasecmp(var->name, "parkedcalltransfers")) { 02159 parkedcalltransfers = ast_true(var->value); 02160 } else if (!strcasecmp(var->name, "adsipark")) { 02161 adsipark = ast_true(var->value); 02162 } else if (!strcasecmp(var->name, "transferdigittimeout")) { 02163 if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) { 02164 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value); 02165 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 02166 } else 02167 transferdigittimeout = transferdigittimeout * 1000; 02168 } else if (!strcasecmp(var->name, "featuredigittimeout")) { 02169 if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) { 02170 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value); 02171 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 02172 } 02173 } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) { 02174 if ((sscanf(var->value, "%d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) { 02175 ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value); 02176 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; 02177 } else 02178 atxfernoanswertimeout = atxfernoanswertimeout * 1000; 02179 } else if (!strcasecmp(var->name, "courtesytone")) { 02180 ast_copy_string(courtesytone, var->value, sizeof(courtesytone)); 02181 } else if (!strcasecmp(var->name, "parkedplay")) { 02182 if (!strcasecmp(var->value, "both")) 02183 parkedplay = 2; 02184 else if (!strcasecmp(var->value, "parked")) 02185 parkedplay = 1; 02186 else 02187 parkedplay = 0; 02188 } else if (!strcasecmp(var->name, "xfersound")) { 02189 ast_copy_string(xfersound, var->value, sizeof(xfersound)); 02190 } else if (!strcasecmp(var->name, "xferfailsound")) { 02191 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound)); 02192 } else if (!strcasecmp(var->name, "pickupexten")) { 02193 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext)); 02194 } else if (!strcasecmp(var->name, "comebacktoorigin")) { 02195 comebacktoorigin = ast_true(var->value); 02196 } else if (!strcasecmp(var->name, "parkedmusicclass")) { 02197 ast_copy_string(parkmohclass, var->value, sizeof(parkmohclass)); 02198 } 02199 } 02200 02201 unmap_features(); 02202 for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) { 02203 if (remap_feature(var->name, var->value)) 02204 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name); 02205 } 02206 02207 /* Map a key combination to an application*/ 02208 ast_unregister_features(); 02209 for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) { 02210 char *tmp_val = ast_strdupa(var->value); 02211 char *exten, *activateon, *activatedby, *app, *app_args, *moh_class; 02212 struct ast_call_feature *feature; 02213 02214 /* strsep() sets the argument to NULL if match not found, and it 02215 * is safe to use it with a NULL argument, so we don't check 02216 * between calls. 02217 */ 02218 exten = strsep(&tmp_val,","); 02219 activatedby = strsep(&tmp_val,","); 02220 app = strsep(&tmp_val,","); 02221 app_args = strsep(&tmp_val,","); 02222 moh_class = strsep(&tmp_val,","); 02223 02224 activateon = strsep(&activatedby, "/"); 02225 02226 /*! \todo XXX var_name or app_args ? */ 02227 if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) { 02228 ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n", 02229 app, exten, activateon, var->name); 02230 continue; 02231 } 02232 02233 if ((feature = find_feature(var->name))) { 02234 ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name); 02235 continue; 02236 } 02237 02238 if (!(feature = ast_calloc(1, sizeof(*feature)))) 02239 continue; 02240 02241 ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN); 02242 ast_copy_string(feature->app, app, FEATURE_APP_LEN); 02243 ast_copy_string(feature->exten, exten, FEATURE_EXTEN_LEN); 02244 02245 if (app_args) 02246 ast_copy_string(feature->app_args, app_args, FEATURE_APP_ARGS_LEN); 02247 02248 if (moh_class) 02249 ast_copy_string(feature->moh_class, moh_class, FEATURE_MOH_LEN); 02250 02251 ast_copy_string(feature->exten, exten, sizeof(feature->exten)); 02252 feature->operation = feature_exec_app; 02253 ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF); 02254 02255 /* Allow caller and calle to be specified for backwards compatability */ 02256 if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller")) 02257 ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF); 02258 else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee")) 02259 ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER); 02260 else { 02261 ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s'," 02262 " must be 'self', or 'peer'\n", var->name); 02263 continue; 02264 } 02265 02266 if (ast_strlen_zero(activatedby)) 02267 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); 02268 else if (!strcasecmp(activatedby, "caller")) 02269 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER); 02270 else if (!strcasecmp(activatedby, "callee")) 02271 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE); 02272 else if (!strcasecmp(activatedby, "both")) 02273 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); 02274 else { 02275 ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s'," 02276 " must be 'caller', or 'callee', or 'both'\n", var->name); 02277 continue; 02278 } 02279 02280 ast_register_feature(feature); 02281 02282 if (option_verbose >= 1) 02283 ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, app, app_args, exten); 02284 } 02285 ast_config_destroy(cfg); 02286 02287 /* Remove the old parking extension */ 02288 if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) { 02289 if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar)) 02290 notify_metermaids(old_parking_ext, old_parking_con); 02291 if (option_debug) 02292 ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con); 02293 } 02294 02295 if (!(con = ast_context_find(parking_con)) && !(con = ast_context_create(NULL, parking_con, registrar))) { 02296 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con); 02297 return -1; 02298 } 02299 res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar); 02300 if (parkaddhints) 02301 park_add_hints(parking_con, parking_start, parking_stop); 02302 if (!res) 02303 notify_metermaids(ast_parking_ext(), parking_con); 02304 return res; 02305 02306 }
|
|
|
||||||||||||
|
Definition at line 1990 of file res_features.c. References ast_channel_unlock, ast_get_channel_by_name_locked(), ast_masq_park_call(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), and s. Referenced by load_module(). 01991 { 01992 const char *channel = astman_get_header(m, "Channel"); 01993 const char *channel2 = astman_get_header(m, "Channel2"); 01994 const char *timeout = astman_get_header(m, "Timeout"); 01995 char buf[BUFSIZ]; 01996 int to = 0; 01997 int res = 0; 01998 int parkExt = 0; 01999 struct ast_channel *ch1, *ch2; 02000 02001 if (ast_strlen_zero(channel)) { 02002 astman_send_error(s, m, "Channel not specified"); 02003 return 0; 02004 } 02005 02006 if (ast_strlen_zero(channel2)) { 02007 astman_send_error(s, m, "Channel2 not specified"); 02008 return 0; 02009 } 02010 02011 ch1 = ast_get_channel_by_name_locked(channel); 02012 if (!ch1) { 02013 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel); 02014 astman_send_error(s, m, buf); 02015 return 0; 02016 } 02017 02018 ch2 = ast_get_channel_by_name_locked(channel2); 02019 if (!ch2) { 02020 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2); 02021 astman_send_error(s, m, buf); 02022 ast_channel_unlock(ch1); 02023 return 0; 02024 } 02025 02026 if (!ast_strlen_zero(timeout)) { 02027 sscanf(timeout, "%d", &to); 02028 } 02029 02030 res = ast_masq_park_call(ch1, ch2, to, &parkExt); 02031 if (!res) { 02032 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT); 02033 astman_send_ack(s, m, "Park successful"); 02034 } else { 02035 astman_send_error(s, m, "Park failure"); 02036 } 02037 02038 ast_channel_unlock(ch1); 02039 ast_channel_unlock(ch2); 02040 02041 return 0; 02042 }
|
|
||||||||||||
|
Dump lot status.
Definition at line 1943 of file res_features.c. References ast_mutex_lock(), ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_ack(), parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, parkeduser::next, parkinglot, parkeduser::parkingnum, parkeduser::parkingtime, parkeduser::peername, s, S_OR, and parkeduser::start. Referenced by load_module(). 01944 { 01945 struct parkeduser *cur; 01946 const char *id = astman_get_header(m,"ActionID"); 01947 char idText[256] = ""; 01948 01949 if (!ast_strlen_zero(id)) 01950 snprintf(idText, 256, "ActionID: %s\r\n", id); 01951 01952 astman_send_ack(s, m, "Parked calls will follow"); 01953 01954 ast_mutex_lock(&parking_lock); 01955 01956 for (cur=parkinglot; cur; cur = cur->next) { 01957 astman_append(s, "Event: ParkedCall\r\n" 01958 "Exten: %d\r\n" 01959 "Channel: %s\r\n" 01960 "From: %s\r\n" 01961 "Timeout: %ld\r\n" 01962 "CallerIDNum: %s\r\n" 01963 "CallerIDName: %s\r\n" 01964 "%s" 01965 "\r\n", 01966 cur->parkingnum, cur->chan->name, cur->peername, 01967 (long)cur->start.tv_sec + (long)(cur->parkingtime/1000) - (long)time(NULL), 01968 S_OR(cur->chan->cid.cid_num, ""), /* XXX in other places it is <unknown> */ 01969 S_OR(cur->chan->cid.cid_name, ""), 01970 idText); 01971 } 01972 01973 astman_append(s, 01974 "Event: ParkedCallsComplete\r\n" 01975 "%s" 01976 "\r\n",idText); 01977 01978 ast_mutex_unlock(&parking_lock); 01979 01980 return RESULT_SUCCESS; 01981 }
|
|
|
metermaids callback from devicestate.c
Definition at line 287 of file res_features.c. References AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, ast_exists_extension(), ast_log(), ast_strdupa, context, exten, LOG_DEBUG, option_debug, and strsep(). Referenced by load_module(). 00288 { 00289 int res = AST_DEVICE_INVALID; 00290 char *context = ast_strdupa(data); 00291 char *exten; 00292 00293 exten = strsep(&context, "@"); 00294 if (!context) 00295 return res; 00296 00297 if (option_debug > 3) 00298 ast_log(LOG_DEBUG, "Checking state of exten %s in context %s\n", exten, context); 00299 00300 res = ast_exists_extension(NULL, context, exten, 1, NULL); 00301 00302 if (!res) 00303 return AST_DEVICE_NOT_INUSE; 00304 else 00305 return AST_DEVICE_INUSE; 00306 }
|
|
||||||||||||
|
Notify metermaids that we've changed an extension.
Definition at line 276 of file res_features.c. References ast_device_state_changed(), ast_log(), LOG_DEBUG, and option_debug. Referenced by do_parking_thread(), and park_exec(). 00277 { 00278 if (option_debug > 3) 00279 ast_log(LOG_DEBUG, "Notification of state change to metermaids %s@%s\n", exten, context); 00280 00281 /* Send notification to devicestate subsystem */ 00282 ast_device_state_changed("park:%s@%s", exten, context); 00283 return; 00284 }
|
|
||||||||||||||||
|
Add parking hints for all defined parking lots.
Definition at line 2081 of file res_features.c. References ast_add_extension(), AST_MAX_EXTENSION, exten, and PRIORITY_HINT. 02082 { 02083 int numext; 02084 char device[AST_MAX_EXTENSION]; 02085 char exten[10]; 02086 02087 for (numext = start; numext <= stop; numext++) { 02088 snprintf(exten, sizeof(exten), "%d", numext); 02089 snprintf(device, sizeof(device), "park:%s@%s", exten, context); 02090 ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar); 02091 } 02092 }
|
|
||||||||||||
|
Park a call.
Definition at line 1702 of file res_features.c. References ast_channel::_state, ast_answer(), ast_module_user_add, ast_module_user_remove, ast_park_call(), AST_PBX_KEEPALIVE, ast_safe_sleep(), AST_STATE_UP, ast_module_user::chan, ast_channel::exten, and ast_channel::priority. Referenced by load_module(). 01703 { 01704 /* Data is unused at the moment but could contain a parking 01705 lot context eventually */ 01706 int res = 0; 01707 struct ast_module_user *u; 01708 01709 u = ast_module_user_add(chan); 01710 01711 /* Setup the exten/priority to be s/1 since we don't know 01712 where this call should return */ 01713 strcpy(chan->exten, "s"); 01714 chan->priority = 1; 01715 /* Answer if call is not up */ 01716 if (chan->_state != AST_STATE_UP) 01717 res = ast_answer(chan); 01718 /* Sleep to allow VoIP streams to settle down */ 01719 if (!res) 01720 res = ast_safe_sleep(chan, 1000); 01721 /* Park the call */ 01722 if (!res) 01723 res = ast_park_call(chan, chan, 0, NULL); 01724 01725 ast_module_user_remove(u); 01726 01727 return !res ? AST_PBX_KEEPALIVE : res; 01728 }
|
|
||||||||||||
|
Pickup parked call.
Definition at line 1731 of file res_features.c. References ast_channel::_state, ast_answer(), ast_bridge_call(), ast_cdr_setdestchan(), ast_channel_make_compatible(), ast_context_find(), ast_context_remove_extension2(), AST_CONTROL_UNHOLD, AST_FEATURE_REDIRECT, ast_hangup(), ast_indicate(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_mutex_lock(), ast_mutex_unlock(), AST_PBX_NO_HANGUP_PEER, ast_set_flag, AST_STATE_UP, ast_stream_and_wait(), ast_streamfile(), ast_strlen_zero(), ast_verbose(), ast_waitstream(), parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, config, error(), EVENT_FLAG_CALL, free, LOG_WARNING, manager_event, parkeduser::next, notify_metermaids(), option_verbose, parkeduser::parkingexten, parkinglot, parkeduser::parkingnum, pbx_builtin_setvar_helper(), S_OR, and VERBOSE_PREFIX_3. Referenced by load_module(). 01732 { 01733 int res = 0; 01734 struct ast_module_user *u; 01735 struct ast_channel *peer=NULL; 01736 struct parkeduser *pu, *pl=NULL; 01737 struct ast_context *con; 01738 int park; 01739 struct ast_bridge_config config; 01740 01741 if (!data) { 01742 ast_log(LOG_WARNING, "Parkedcall requires an argument (extension number)\n"); 01743 return -1; 01744 } 01745 01746 u = ast_module_user_add(chan); 01747 01748 park = atoi((char *)data); 01749 ast_mutex_lock(&parking_lock); 01750 pu = parkinglot; 01751 while(pu) { 01752 if (pu->parkingnum == park) { 01753 if (pl) 01754 pl->next = pu->next; 01755 else 01756 parkinglot = pu->next; 01757 break; 01758 } 01759 pl = pu; 01760 pu = pu->next; 01761 } 01762 ast_mutex_unlock(&parking_lock); 01763 if (pu) { 01764 peer = pu->chan; 01765 con = ast_context_find(parking_con); 01766 if (con) { 01767 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL)) 01768 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 01769 else 01770 notify_metermaids(pu->parkingexten, parking_con); 01771 } else 01772 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 01773 01774 manager_event(EVENT_FLAG_CALL, "UnParkedCall", 01775 "Exten: %s\r\n" 01776 "Channel: %s\r\n" 01777 "From: %s\r\n" 01778 "CallerIDNum: %s\r\n" 01779 "CallerIDName: %s\r\n", 01780 pu->parkingexten, pu->chan->name, chan->name, 01781 S_OR(pu->chan->cid.cid_num, "<unknown>"), 01782 S_OR(pu->chan->cid.cid_name, "<unknown>") 01783 ); 01784 01785 free(pu); 01786 } 01787 /* JK02: it helps to answer the channel if not already up */ 01788 if (chan->_state != AST_STATE_UP) 01789 ast_answer(chan); 01790 01791 if (peer) { 01792 /* Play a courtesy to the source(s) configured to prefix the bridge connecting */ 01793 01794 if (!ast_strlen_zero(courtesytone)) { 01795 int error = 0; 01796 ast_indicate(peer, AST_CONTROL_UNHOLD); 01797 if (parkedplay == 0) { 01798 error = ast_stream_and_wait(chan, courtesytone, ""); 01799 } else if (parkedplay == 1) { 01800 error = ast_stream_and_wait(peer, courtesytone, ""); 01801 } else if (parkedplay == 2) { 01802 if (!ast_streamfile(chan, courtesytone, chan->language) && 01803 !ast_streamfile(peer, courtesytone, chan->language)) { 01804 /*! \todo XXX we would like to wait on both! */ 01805 res = ast_waitstream(chan, ""); 01806 if (res >= 0) 01807 res = ast_waitstream(peer, ""); 01808 if (res < 0) 01809 error = 1; 01810 } 01811 } 01812 if (error) { 01813 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); 01814 ast_hangup(peer); 01815 return -1; 01816 } 01817 } else 01818 ast_indicate(peer, AST_CONTROL_UNHOLD); 01819 01820 res = ast_channel_make_compatible(chan, peer); 01821 if (res < 0) { 01822 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name); 01823 ast_hangup(peer); 01824 return -1; 01825 } 01826 /* This runs sorta backwards, since we give the incoming channel control, as if it 01827 were the person called. */ 01828 if (option_verbose > 2) 01829 ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park); 01830 01831 memset(&config, 0, sizeof(struct ast_bridge_config)); 01832 if (parkedcalltransfers) { 01833 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT); 01834 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT); 01835 } 01836 res = ast_bridge_call(chan, peer, &config); 01837 01838 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name); 01839 ast_cdr_setdestchan(chan->cdr, peer->name); 01840 01841 /* Simulate the PBX hanging up */ 01842 if (res != AST_PBX_NO_HANGUP_PEER) 01843 ast_hangup(peer); 01844 return res; 01845 } else { 01846 /*! \todo XXX Play a message XXX */ 01847 if (ast_stream_and_wait(chan, "pbx-invalidpark", "")) 01848 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name); 01849 if (option_verbose > 2) 01850 ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park); 01851 res = -1; 01852 } 01853 01854 ast_module_user_remove(u); 01855 01856 return res; 01857 }
|
|
||||||||||||||||
|
Definition at line 1510 of file res_features.c. References ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, EVENT_FLAG_CALL, manager_event, and S_OR. Referenced by do_parking_thread(). 01511 { 01512 manager_event(EVENT_FLAG_CALL, s, 01513 "Exten: %s\r\n" 01514 "Channel: %s\r\n" 01515 "CallerIDNum: %s\r\n" 01516 "CallerIDName: %s\r\n\r\n", 01517 parkingexten, 01518 chan->name, 01519 S_OR(chan->cid.cid_num, "<unknown>"), 01520 S_OR(chan->cid.cid_name, "<unknown>") 01521 ); 01522 }
|
|
||||||||||||
|
Find the context for the transfer.
Definition at line 627 of file res_features.c. References ast_strlen_zero(), ast_channel::context, ast_channel::macrocontext, pbx_builtin_getvar_helper(), and s. Referenced by builtin_atxfer(), and builtin_blindtransfer(). 00628 { 00629 const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"); 00630 if (ast_strlen_zero(s)) 00631 s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT"); 00632 if (ast_strlen_zero(s)) /* Use the non-macro context to transfer the call XXX ? */ 00633 s = transferer->macrocontext; 00634 if (ast_strlen_zero(s)) 00635 s = transferer->context; 00636 return s; 00637 }
|
|
|
Definition at line 2308 of file res_features.c. References load_config(). 02309 { 02310 return load_config(); 02311 }
|
|
||||||||||||
|
Definition at line 1012 of file res_features.c. References ast_verbose(), builtin_features, exten, FEATURES_COUNT, option_verbose, and VERBOSE_PREFIX_2. 01013 { 01014 int x; 01015 int res = -1; 01016 for (x = 0; x < FEATURES_COUNT; x++) { 01017 if (!strcasecmp(name, builtin_features[x].sname)) { 01018 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten)); 01019 if (option_verbose > 1) 01020 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); 01021 res = 0; 01022 } else if (!strcmp(value, builtin_features[x].exten)) 01023 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); 01024 } 01025 return res; 01026 }
|
|
||||||||||||||||||||
|
store context, priority and extension
Definition at line 175 of file res_features.c. References ast_channel::context, ast_channel::exten, and ast_channel::priority. Referenced by ast_masq_park_call(), builtin_blindtransfer(), and do_parking_thread(). 00176 { 00177 ast_copy_string(chan->context, context, sizeof(chan->context)); 00178 ast_copy_string(chan->exten, ext, sizeof(chan->exten)); 00179 chan->priority = pri; 00180 }
|
|
||||||||||||||||
|
||||||||||||||||||||||||
|
set caller and callee according to the direction
Definition at line 482 of file res_features.c. References FEATURE_SENSE_PEER. Referenced by builtin_atxfer(), builtin_automonitor(), builtin_blindtransfer(), and builtin_parkcall(). 00484 { 00485 if (sense == FEATURE_SENSE_PEER) { 00486 *caller = peer; 00487 *callee = chan; 00488 } else { 00489 *callee = peer; 00490 *caller = chan; 00491 } 00492 }
|
|
|
Definition at line 2339 of file res_features.c. References ast_cli_unregister_multiple(), ast_devstate_prov_del(), ast_manager_unregister(), ast_module_user_hangup_all, ast_unregister_application(), and cli_features. 02340 { 02341 ast_module_user_hangup_all(); 02342 02343 ast_manager_unregister("ParkedCalls"); 02344 ast_manager_unregister("Park"); 02345 ast_cli_unregister_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry)); 02346 ast_unregister_application(parkcall); 02347 ast_devstate_prov_del("Park"); 02348 return ast_unregister_application(parkedcall); 02349 }
|
|
|
Definition at line 1005 of file res_features.c. References builtin_features, exten, and FEATURES_COUNT. 01006 { 01007 int x; 01008 for (x = 0; x < FEATURES_COUNT; x++) 01009 strcpy(builtin_features[x].exten, builtin_features[x].default_exten); 01010 }
|
|
|
Definition at line 99 of file res_features.c. |
|
|
Definition at line 105 of file res_features.c. |
|
|
Definition at line 870 of file res_features.c. Referenced by ast_feature_interpret(), ast_feature_request_and_dial(), handle_showfeatures(), remap_feature(), set_config_flags(), and unmap_features(). |
|
|
Definition at line 1932 of file res_features.c. |
|
|
Definition at line 103 of file res_features.c. |
|
|
Courtesy tone Definition at line 91 of file res_features.c. |
|
|
Initial value: "ParkedCall(exten):" "Used to connect to a parked call. This application is always\n" "registered internally and does not need to be explicitly added\n" "into the dialplan, although you should include the 'parkedcalls'\n" "context.\n" Definition at line 112 of file res_features.c. |
|
|
Definition at line 122 of file res_features.c. |
|
|
Definition at line 102 of file res_features.c. |
|
|
Definition at line 1983 of file res_features.c. Referenced by load_module(). |
|
|
Definition at line 133 of file res_features.c. Referenced by ast_bridge_call(), and builtin_automonitor(). |
|
|
Definition at line 134 of file res_features.c. |
|
|
Add parking hints automatically Definition at line 80 of file res_features.c. |
|
|
Definition at line 118 of file res_features.c. |
|
|
Definition at line 78 of file res_features.c. |
|
|
Enable DTMF based transfers on bridge when picking up parked calls Definition at line 81 of file res_features.c. |
|
|
Who to play the courtesy tone to Definition at line 92 of file res_features.c. |
|
|
Definition at line 97 of file res_features.c. |
|
|
Context for which parking is made accessible Definition at line 83 of file res_features.c. |
|
|
Context for dialback for parking (KLUDGE) Definition at line 84 of file res_features.c. |
|
|
Extension you type to park the call Definition at line 85 of file res_features.c. |
|
|
Definition at line 96 of file res_features.c. |
|
|
First available extension for parking Definition at line 88 of file res_features.c. |
|
|
Last available extension for parking Definition at line 89 of file res_features.c. |
|
|
Definition at line 155 of file res_features.c. |
|
|
Definition at line 151 of file res_features.c. Referenced by ast_park_call(), do_parking_thread(), handle_parkedcalls(), manager_parking_status(), and park_exec(). |
|
|
No more than 45 seconds parked before you do something with them Definition at line 82 of file res_features.c. |
|
|
Music class used for parking Definition at line 87 of file res_features.c. |
|
|
Call pickup extension Definition at line 86 of file res_features.c. |
|
|
Registrar for operations Definition at line 107 of file res_features.c. |
|
|
Initial value: "Usage: feature list\n" " Lists currently configured features.\n" Definition at line 1900 of file res_features.c. |
|
|
Initial value: "Usage: show parkedcalls\n" " Lists currently parked calls.\n" Definition at line 1928 of file res_features.c. |
|
|
Definition at line 110 of file res_features.c. |
|
|
Definition at line 120 of file res_features.c. |
|
|
Definition at line 101 of file res_features.c. |
|
|
Call transfer failure sound Definition at line 94 of file |