Codename Pineapple

Home page | Mailing list | Docs

Last updated: Sat Feb 3 05:01:31 2007

Asterisk developer's documentation :: Codename Pineapple


features.h File Reference


Detailed Description

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

Definition in file features.h.

This graph shows which files directly or indirectly include this file:

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


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 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_channel::data, ast_frame::data, ast_option_header::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 }

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 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 }

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 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 }

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 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 }

int ast_pickup_call struct ast_channel chan  ) 
 

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 }

char* ast_pickup_ext void   ) 
 

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 }

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 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 }

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 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 }


Asterisk is a trademark for Digium, inc.. | Edvina.net | Asterisk.org | This documentation was generated with Doxygen