Mon Nov 24 15:34:37 2008

Asterisk developer's documentation


features.h File Reference

Call Parking and Pickup API Includes code and algorithms from the Zapata library. More...

Go to the source code of this file.

Data Structures

struct  ast_call_feature
 main call feature structure More...

Defines

#define FEATURE_APP_ARGS_LEN   256
#define FEATURE_APP_LEN   64
#define FEATURE_EXTEN_LEN   32
#define FEATURE_MAX_LEN   11
#define FEATURE_MOH_LEN   80
#define FEATURE_SNAME_LEN   32

Functions

int ast_bridge_call (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
 Bridge a call, optionally allowing redirection.
int ast_masq_park_call (struct ast_channel *rchan, struct ast_channel *host, int timeout, int *extout)
 Park a call via a masqueraded channel.
int ast_park_call (struct ast_channel *chan, struct ast_channel *host, 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


Detailed Description

Call Parking and Pickup API Includes code and algorithms from the Zapata library.

Definition in file features.h.


Define Documentation

#define FEATURE_APP_ARGS_LEN   256

Definition at line 29 of file features.h.

#define FEATURE_APP_LEN   64

Definition at line 28 of file features.h.

#define FEATURE_EXTEN_LEN   32

Definition at line 31 of file features.h.

#define FEATURE_MAX_LEN   11

Definition at line 27 of file features.h.

Referenced by ast_bridge_call().

#define FEATURE_MOH_LEN   80

Definition at line 32 of file features.h.

#define FEATURE_SNAME_LEN   32

Definition at line 30 of file features.h.


Function Documentation

int ast_bridge_call ( struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config 
)

Bridge a call, optionally allowing redirection.

append the event to featurecode. we rely on the string being zero-filled, and not overflowing it.

Todo:
XXX how do we guarantee the latter ?

Definition at line 1446 of file res_features.c.

References ast_cdr::accountcode, ast_cdr::amaflags, ast_cdr::answer, ast_answer(), ast_cdr_alloc(), ast_cdr_answer(), AST_CDR_ANSWERED, ast_cdr_detach(), ast_cdr_dup(), ast_cdr_end(), AST_CDR_FLAG_BRIDGED, AST_CDR_FLAG_MAIN, AST_CDR_FLAG_POST_DISABLED, ast_cdr_isset_unanswered(), AST_CDR_NULL, ast_cdr_setcid(), ast_cdr_specialized_reset(), ast_cdr_start(), ast_cdr_update(), ast_channel_bridge(), ast_channel_lock, ast_channel_setoption(), ast_channel_unlock, ast_check_hangup(), ast_clear_flag, AST_CONTROL_ATXFERCMD, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_FLASH, AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_OPTION, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, ast_default_amaflags, ast_dtmf_stream(), ast_feature_interpret(), AST_FEATURE_PLAY_WARNING, AST_FLAG_ZOMBIE, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_DTMF_BEGIN, ast_frfree, ast_indicate(), ast_indicate_data(), ast_log(), AST_MAX_EXTENSION, AST_OPTION_FLAG_REQUEST, ast_set_flag, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_channel::cdr, ast_cdr::channel, cmd_atxfer(), config, ast_option_header::data, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_cdr::end, f, FEATURE_MAX_LEN, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_SUCCESS, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, ast_option_header::flag, ast_cdr::lastapp, ast_cdr::lastdata, LOG_DEBUG, LOG_WARNING, monitor_app, ast_cdr::next, ast_option_header::option, option_debug, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), set_config_flags(), ast_cdr::start, ast_cdr::uniqueid, and ast_cdr::userfield.

Referenced by app_exec(), ast_bridge_call_thread(), do_atxfer(), park_exec(), and try_calling().

01447 {
01448    /* Copy voice back and forth between the two channels.  Give the peer
01449       the ability to transfer calls with '#<extension' syntax. */
01450    struct ast_frame *f;
01451    struct ast_channel *who;
01452    char chan_featurecode[FEATURE_MAX_LEN + 1]="";
01453    char peer_featurecode[FEATURE_MAX_LEN + 1]="";
01454    char orig_channame[AST_MAX_EXTENSION];
01455    char orig_peername[AST_MAX_EXTENSION];
01456 
01457    int res;
01458    int diff;
01459    int hasfeatures=0;
01460    int hadfeatures=0;
01461    struct ast_option_header *aoh;
01462    struct ast_bridge_config backup_config;
01463    struct ast_cdr *bridge_cdr = NULL;
01464    struct ast_cdr *orig_peer_cdr = NULL;
01465 
01466    memset(&backup_config, 0, sizeof(backup_config));
01467 
01468    config->start_time = ast_tvnow();
01469 
01470    if (chan && peer) {
01471       pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
01472       pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
01473    } else if (chan)
01474       pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
01475 
01476    if (monitor_ok) {
01477       const char *monitor_exec;
01478       struct ast_channel *src = NULL;
01479       if (!monitor_app) { 
01480          if (!(monitor_app = pbx_findapp("Monitor")))
01481             monitor_ok=0;
01482       }
01483       if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 
01484          src = chan;
01485       else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
01486          src = peer;
01487       if (monitor_app && src) {
01488          char *tmp = ast_strdupa(monitor_exec);
01489          pbx_exec(src, monitor_app, tmp);
01490       }
01491    }
01492    
01493    set_config_flags(chan, peer, config);
01494    config->firstpass = 1;
01495 
01496    /* Answer if need be */
01497    if (ast_answer(chan))
01498       return -1;
01499 
01500    ast_copy_string(orig_channame,chan->name,sizeof(orig_channame));
01501    ast_copy_string(orig_peername,peer->name,sizeof(orig_peername));
01502    orig_peer_cdr = peer->cdr;
01503    
01504    if (!chan->cdr || (chan->cdr && !ast_test_flag(chan->cdr, AST_CDR_FLAG_POST_DISABLED))) {
01505          
01506       if (chan->cdr) {
01507          ast_set_flag(chan->cdr, AST_CDR_FLAG_MAIN);
01508          ast_cdr_update(chan);
01509          bridge_cdr = ast_cdr_dup(chan->cdr);
01510          ast_copy_string(bridge_cdr->lastapp, chan->appl, sizeof(bridge_cdr->lastapp));
01511          ast_copy_string(bridge_cdr->lastdata, chan->data, sizeof(bridge_cdr->lastdata));
01512       } else {
01513          /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */
01514          bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */
01515          ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel));
01516          ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel));
01517          ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid));
01518          ast_copy_string(bridge_cdr->lastapp, chan->appl, sizeof(bridge_cdr->lastapp));
01519          ast_copy_string(bridge_cdr->lastdata, chan->data, sizeof(bridge_cdr->lastdata));
01520          ast_cdr_setcid(bridge_cdr, chan);
01521          bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ?  AST_CDR_ANSWERED : AST_CDR_NULL;
01522          bridge_cdr->amaflags = chan->amaflags ? chan->amaflags :  ast_default_amaflags;
01523          ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode));
01524          /* Destination information */
01525          ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst));
01526          ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext));
01527          if (peer->cdr) {
01528             bridge_cdr->start = peer->cdr->start;
01529             ast_copy_string(bridge_cdr->userfield, peer->cdr->userfield, sizeof(bridge_cdr->userfield));
01530          } else {
01531             ast_cdr_start(bridge_cdr);
01532          }
01533       }
01534       /* peer->cdr->answer will be set when a macro runs on the peer;
01535          in that case, the bridge answer will be delayed while the
01536          macro plays on the peer channel. The peer answered the call
01537          before the macro started playing. To the phone system,
01538          this is billable time for the call, even tho the caller
01539          hears nothing but ringing while the macro does its thing. */
01540       if (peer->cdr && !ast_tvzero(peer->cdr->answer)) {
01541          bridge_cdr->answer = peer->cdr->answer;
01542          chan->cdr->answer = peer->cdr->answer;
01543       } else {
01544          ast_cdr_answer(bridge_cdr);
01545          ast_cdr_answer(chan->cdr); /* for the sake of cli status checks */
01546       }
01547       ast_set_flag(chan->cdr, AST_CDR_FLAG_BRIDGED);
01548       if (peer->cdr) {
01549          ast_set_flag(peer->cdr, AST_CDR_FLAG_BRIDGED);
01550       }
01551    }
01552    
01553    for (;;) {
01554       struct ast_channel *other; /* used later */
01555       
01556       res = ast_channel_bridge(chan, peer, config, &f, &who);
01557       
01558       if (config->feature_timer) {
01559          /* Update time limit for next pass */
01560          diff = ast_tvdiff_ms(ast_tvnow(), config->start_time);
01561          config->feature_timer -= diff;
01562          if (hasfeatures) {
01563             /* Running on backup config, meaning a feature might be being
01564                activated, but that's no excuse to keep things going 
01565                indefinitely! */
01566             if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
01567                if (option_debug)
01568                   ast_log(LOG_DEBUG, "Timed out, realtime this time!\n");
01569                config->feature_timer = 0;
01570                who = chan;
01571                if (f)
01572                   ast_frfree(f);
01573                f = NULL;
01574                res = 0;
01575             } else if (config->feature_timer <= 0) {
01576                /* Not *really* out of time, just out of time for
01577                   digits to come in for features. */
01578                if (option_debug)
01579                   ast_log(LOG_DEBUG, "Timed out for feature!\n");
01580                if (!ast_strlen_zero(peer_featurecode)) {
01581                   ast_dtmf_stream(chan, peer, peer_featurecode, 0);
01582                   memset(peer_featurecode, 0, sizeof(peer_featurecode));
01583                }
01584                if (!ast_strlen_zero(chan_featurecode)) {
01585                   ast_dtmf_stream(peer, chan, chan_featurecode, 0);
01586                   memset(chan_featurecode, 0, sizeof(chan_featurecode));
01587                }
01588                if (f)
01589                   ast_frfree(f);
01590                hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01591                if (!hasfeatures) {
01592                   /* Restore original (possibly time modified) bridge config */
01593                   memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01594                   memset(&backup_config, 0, sizeof(backup_config));
01595                }
01596                hadfeatures = hasfeatures;
01597                /* Continue as we were */
01598                continue;
01599             } else if (!f) {
01600                /* The bridge returned without a frame and there is a feature in progress.
01601                 * However, we don't think the feature has quite yet timed out, so just
01602                 * go back into the bridge. */
01603                continue;
01604             }
01605          } else {
01606             if (config->feature_timer <=0) {
01607                /* We ran out of time */
01608                config->feature_timer = 0;
01609                who = chan;
01610                if (f)
01611                   ast_frfree(f);
01612                f = NULL;
01613                res = 0;
01614             }
01615          }
01616       }
01617       if (res < 0) {
01618          if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer))
01619             ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
01620          goto before_you_go;
01621       }
01622       
01623       if (!f || (f->frametype == AST_FRAME_CONTROL &&
01624             (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY || 
01625                f->subclass == AST_CONTROL_CONGESTION ) ) ) {
01626          res = -1;
01627          break;
01628       }
01629       /* many things should be sent to the 'other' channel */
01630       other = (who == chan) ? peer : chan;
01631       if (f->frametype == AST_FRAME_CONTROL) {
01632          switch (f->subclass) {
01633          case AST_CONTROL_RINGING:
01634          case AST_CONTROL_FLASH:
01635          case -1:
01636             ast_indicate(other, f->subclass);
01637             break;
01638          case AST_CONTROL_HOLD:
01639          case AST_CONTROL_UNHOLD:
01640             ast_indicate_data(other, f->subclass, f->data, f->datalen);
01641             break;
01642          case AST_CONTROL_OPTION:
01643             aoh = f->data;
01644             /* Forward option Requests */
01645             if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) {
01646                ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 
01647                   f->datalen - sizeof(struct ast_option_header), 0);
01648             }
01649             break;
01650          case AST_CONTROL_ATXFERCMD:
01651             cmd_atxfer(chan, peer, config, who, f->data);
01652             break;
01653          }
01654       } else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
01655          /* eat it */
01656       } else if (f->frametype == AST_FRAME_DTMF) {
01657          char *featurecode;
01658          int sense;
01659 
01660          hadfeatures = hasfeatures;
01661          /* This cannot overrun because the longest feature is one shorter than our buffer */
01662          if (who == chan) {
01663             sense = FEATURE_SENSE_CHAN;
01664             featurecode = chan_featurecode;
01665          } else  {
01666             sense = FEATURE_SENSE_PEER;
01667             featurecode = peer_featurecode;
01668          }
01669          /*! append the event to featurecode. we rely on the string being zero-filled, and
01670           * not overflowing it. 
01671           * \todo XXX how do we guarantee the latter ?
01672           */
01673          featurecode[strlen(featurecode)] = f->subclass;
01674          /* Get rid of the frame before we start doing "stuff" with the channels */
01675          ast_frfree(f);
01676          f = NULL;
01677          config->feature_timer = backup_config.feature_timer;
01678          res = ast_feature_interpret(chan, peer, config, featurecode, sense);
01679          switch(res) {
01680          case FEATURE_RETURN_PASSDIGITS:
01681             ast_dtmf_stream(other, who, featurecode, 0);
01682             /* Fall through */
01683          case FEATURE_RETURN_SUCCESS:
01684             memset(featurecode, 0, sizeof(chan_featurecode));
01685             break;
01686          }
01687          if (res >= FEATURE_RETURN_PASSDIGITS) {
01688             res = 0;
01689          } else 
01690             break;
01691          hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01692          if (hadfeatures && !hasfeatures) {
01693             /* Restore backup */
01694             memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01695             memset(&backup_config, 0, sizeof(struct ast_bridge_config));
01696          } else if (hasfeatures) {
01697             if (!hadfeatures) {
01698                /* Backup configuration */
01699                memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
01700                /* Setup temporary config options */
01701                config->play_warning = 0;
01702                ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
01703                ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
01704                config->warning_freq = 0;
01705                config->warning_sound = NULL;
01706                config->end_sound = NULL;
01707                config->start_sound = NULL;
01708                config->firstpass = 0;
01709             }
01710             config->start_time = ast_tvnow();
01711             config->feature_timer = featuredigittimeout;
01712             if (option_debug)
01713                ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer);
01714          }
01715       }
01716       if (f)
01717          ast_frfree(f);
01718 
01719    }
01720    before_you_go:
01721    /* obey the NoCDR() wishes. */
01722    if (!chan->cdr || (chan->cdr && !ast_test_flag(chan->cdr, AST_CDR_FLAG_POST_DISABLED))) {
01723       
01724       ast_cdr_end(bridge_cdr);
01725       
01726       ast_cdr_detach(bridge_cdr);
01727       
01728       /* just in case, these channels get bridged again before hangup */
01729       if (chan->cdr) {
01730          ast_cdr_specialized_reset(chan->cdr,0);
01731       }
01732       if (peer->cdr) {
01733          struct ast_cdr *cur;
01734 
01735          ast_channel_lock(peer);
01736          for (cur = peer->cdr; cur; cur = cur->next) {
01737             if (cur == orig_peer_cdr) {
01738                break;
01739             }
01740          }
01741 
01742          if (!cur) {
01743             /* orig_peer_cdr is gone, probably because of a masquerade
01744              * during the bridge. */
01745             ast_channel_unlock(peer);
01746             return res;
01747          }
01748 
01749          /* before resetting the peer cdr, throw a copy of it to the
01750             backend, just in case the cdr.conf file is calling for
01751             unanswered CDR's. */
01752          
01753          /* When peer->cdr isn't the same addr as orig_peer_cdr,
01754             this can only happen if there was a transfer, methinks;
01755             at any rate, only pay attention to the original*/
01756          if (ast_cdr_isset_unanswered()) {
01757             struct ast_cdr *dupd = ast_cdr_dup(orig_peer_cdr);
01758             if (dupd) {
01759                if (ast_tvzero(dupd->end) && ast_cdr_isset_unanswered())
01760                   ast_cdr_end(dupd);
01761                ast_cdr_detach(dupd);
01762             }
01763          }
01764          ast_cdr_specialized_reset(orig_peer_cdr,0);
01765          ast_channel_unlock(peer);
01766       }
01767    }
01768    return res;
01769 }

int ast_masq_park_call ( struct ast_channel rchan,
struct ast_channel host,
int  timeout,
int *  extout 
)

Park a call via a masqueraded channel.

Parameters:
rchan the real channel to be parked
host the channel to have the parking read to Masquerade the channel rchan into a new, empty channel which is then parked with ast_park_call
timeout is a timeout in milliseconds
extout is a parameter to an int that will hold the parked location, or NULL if you want

Definition at line 481 of file res_features.c.

References ast_channel::amaflags, ast_channel_alloc(), ast_channel_masquerade(), ast_frfree, ast_hangup(), ast_log(), ast_read(), AST_STATE_DOWN, ast_strdupa, ast_channel::context, ast_channel::exten, f, LOG_WARNING, park_call_full(), ast_channel::priority, ast_channel::readformat, set_c_e_p(), and ast_channel::writeformat.

Referenced by manager_park(), mgcp_ss(), parkandannounce_exec(), and ss_thread().

00482 {
00483    struct ast_channel *chan;
00484    struct ast_frame *f;
00485    char *orig_chan_name = NULL;
00486    int park_status;
00487 
00488    /* Make a new, fake channel that we'll use to masquerade in the real one */
00489    if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) {
00490       ast_log(LOG_WARNING, "Unable to create parked channel\n");
00491       return -1;
00492    }
00493 
00494    /* Make formats okay */
00495    chan->readformat = rchan->readformat;
00496    chan->writeformat = rchan->writeformat;
00497    ast_channel_masquerade(chan, rchan);
00498 
00499    /* Setup the extensions and such */
00500    set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority);
00501 
00502    /* Make the masq execute */
00503    f = ast_read(chan);
00504    if (f)
00505       ast_frfree(f);
00506 
00507    orig_chan_name = ast_strdupa(chan->name);
00508 
00509    park_status = park_call_full(chan, peer, timeout, extout, orig_chan_name);
00510    if (park_status == 1) {
00511       /* would be nice to play: "invalid parking extension" */
00512       ast_hangup(chan);
00513       return -1;
00514    }
00515 
00516    return 0;
00517 }

int ast_park_call ( struct ast_channel chan,
struct ast_channel peer,
int  timeout,
int *  extout 
)

Park a call and read back parked location.

Note:
We put the user in the parking list, then wake up the parking thread to be sure it looks after these channels too

Definition at line 476 of file res_features.c.

References park_call_full().

Referenced by builtin_blindtransfer(), builtin_parkcall(), iax_park_thread(), and sip_park_thread().

00477 {
00478    return park_call_full(chan, peer, timeout, extout, NULL);
00479 }

char* ast_parking_ext ( void   ) 

Determine system parking extension Returns the call parking extension for drivers that provide special call parking help.

Definition at line 160 of file res_features.c.

Referenced by builtin_blindtransfer(), dp_lookup(), handle_request_refer(), mgcp_ss(), socket_process(), and ss_thread().

00161 {
00162    return parking_ext;
00163 }

int ast_pickup_call ( struct ast_channel chan  ) 

Pickup a call.

Definition at line 2333 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().

02334 {
02335    struct ast_channel *cur = NULL;
02336    int res = -1;
02337 
02338    while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
02339       if (!cur->pbx && 
02340          (cur != chan) &&
02341          (chan->pickupgroup & cur->callgroup) &&
02342          ((cur->_state == AST_STATE_RINGING) ||
02343           (cur->_state == AST_STATE_RING))) {
02344             break;
02345       }
02346       ast_channel_unlock(cur);
02347    }
02348    if (cur) {
02349       if (option_debug)
02350          ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
02351       res = ast_answer(chan);
02352       if (res)
02353          ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
02354       res = ast_queue_control(chan, AST_CONTROL_ANSWER);
02355       if (res)
02356          ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
02357       res = ast_channel_masquerade(cur, chan);
02358       if (res)
02359          ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);     /* Done */
02360       ast_channel_unlock(cur);
02361    } else   {
02362       if (option_debug)
02363          ast_log(LOG_DEBUG, "No call pickup possible...\n");
02364    }
02365    return res;
02366 }

char* ast_pickup_ext ( void   ) 

Determine system call pickup extension.

Definition at line 165 of file res_features.c.

Referenced by cb_events(), get_destination(), handle_request_invite(), handle_showfeatures(), mgcp_ss(), and ss_thread().

00166 {
00167    return pickup_ext;
00168 }

void ast_register_feature ( struct ast_call_feature feature  ) 

register new feature into feature_set

Parameters:
feature an ast_call_feature object which contains a keysequence and a callback function which is called when this keysequence is pressed during a call.

Definition at line 1023 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.

01024 {
01025    if (!feature) {
01026       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
01027          return;
01028    }
01029   
01030    AST_LIST_LOCK(&feature_list);
01031    AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry);
01032    AST_LIST_UNLOCK(&feature_list);
01033 
01034    if (option_verbose >= 2) 
01035       ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
01036 }

void ast_unregister_feature ( struct ast_call_feature feature  ) 

unregister feature from feature_set

Parameters:
feature the ast_call_feature object which was registered before

Definition at line 1039 of file res_features.c.

References AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, and free.

01040 {
01041    if (!feature)
01042       return;
01043 
01044    AST_LIST_LOCK(&feature_list);
01045    AST_LIST_REMOVE(&feature_list,feature,feature_entry);
01046    AST_LIST_UNLOCK(&feature_list);
01047    free(feature);
01048 }


Generated on Mon Nov 24 15:34:37 2008 for Asterisk - the Open Source PBX by  doxygen 1.4.7