Wed Aug 15 01:25:07 2007

Asterisk developer's documentation


features.h File Reference

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

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


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.

Referenced by load_config().

#define FEATURE_APP_LEN   64

Definition at line 28 of file features.h.

Referenced by load_config().

#define FEATURE_EXTEN_LEN   32

Definition at line 31 of file features.h.

Referenced by load_config().

#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.

Referenced by load_config().

#define FEATURE_SNAME_LEN   32

Definition at line 30 of file features.h.

Referenced by load_config().


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 1326 of file res_features.c.

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

01327 {
01328    /* Copy voice back and forth between the two channels.  Give the peer
01329       the ability to transfer calls with '#<extension' syntax. */
01330    struct ast_frame *f;
01331    struct ast_channel *who;
01332    char chan_featurecode[FEATURE_MAX_LEN + 1]="";
01333    char peer_featurecode[FEATURE_MAX_LEN + 1]="";
01334    int res;
01335    int diff;
01336    int hasfeatures=0;
01337    int hadfeatures=0;
01338    struct ast_option_header *aoh;
01339    struct ast_bridge_config backup_config;
01340    struct ast_cdr *bridge_cdr;
01341 
01342    memset(&backup_config, 0, sizeof(backup_config));
01343 
01344    config->start_time = ast_tvnow();
01345 
01346    if (chan && peer) {
01347       pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
01348       pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
01349    } else if (chan)
01350       pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
01351 
01352    if (monitor_ok) {
01353       const char *monitor_exec;
01354       struct ast_channel *src = NULL;
01355       if (!monitor_app) { 
01356          if (!(monitor_app = pbx_findapp("Monitor")))
01357             monitor_ok=0;
01358       }
01359       if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 
01360          src = chan;
01361       else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
01362          src = peer;
01363       if (monitor_app && src) {
01364          char *tmp = ast_strdupa(monitor_exec);
01365          pbx_exec(src, monitor_app, tmp);
01366       }
01367    }
01368    
01369    set_config_flags(chan, peer, config);
01370    config->firstpass = 1;
01371 
01372    /* Answer if need be */
01373    if (ast_answer(chan))
01374       return -1;
01375    peer->appl = "Bridged Call";
01376    peer->data = chan->name;
01377 
01378    /* copy the userfield from the B-leg to A-leg if applicable */
01379    if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
01380       char tmp[256];
01381       if (!ast_strlen_zero(chan->cdr->userfield)) {
01382          snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield);
01383          ast_cdr_appenduserfield(chan, tmp);
01384       } else
01385          ast_cdr_setuserfield(chan, peer->cdr->userfield);
01386       /* free the peer's cdr without ast_cdr_free complaining */
01387       free(peer->cdr);
01388       peer->cdr = NULL;
01389    }
01390 
01391    for (;;) {
01392       struct ast_channel *other; /* used later */
01393 
01394       res = ast_channel_bridge(chan, peer, config, &f, &who);
01395 
01396       if (config->feature_timer) {
01397          /* Update time limit for next pass */
01398          diff = ast_tvdiff_ms(ast_tvnow(), config->start_time);
01399          config->feature_timer -= diff;
01400          if (hasfeatures) {
01401             /* Running on backup config, meaning a feature might be being
01402                activated, but that's no excuse to keep things going 
01403                indefinitely! */
01404             if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
01405                if (option_debug)
01406                   ast_log(LOG_DEBUG, "Timed out, realtime this time!\n");
01407                config->feature_timer = 0;
01408                who = chan;
01409                if (f)
01410                   ast_frfree(f);
01411                f = NULL;
01412                res = 0;
01413             } else if (config->feature_timer <= 0) {
01414                /* Not *really* out of time, just out of time for
01415                   digits to come in for features. */
01416                if (option_debug)
01417                   ast_log(LOG_DEBUG, "Timed out for feature!\n");
01418                if (!ast_strlen_zero(peer_featurecode)) {
01419                   ast_dtmf_stream(chan, peer, peer_featurecode, 0);
01420                   memset(peer_featurecode, 0, sizeof(peer_featurecode));
01421                }
01422                if (!ast_strlen_zero(chan_featurecode)) {
01423                   ast_dtmf_stream(peer, chan, chan_featurecode, 0);
01424                   memset(chan_featurecode, 0, sizeof(chan_featurecode));
01425                }
01426                if (f)
01427                   ast_frfree(f);
01428                hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01429                if (!hasfeatures) {
01430                   /* Restore original (possibly time modified) bridge config */
01431                   memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01432                   memset(&backup_config, 0, sizeof(backup_config));
01433                }
01434                hadfeatures = hasfeatures;
01435                /* Continue as we were */
01436                continue;
01437             } else if (!f) {
01438                /* The bridge returned without a frame and there is a feature in progress.
01439                 * However, we don't think the feature has quite yet timed out, so just
01440                 * go back into the bridge. */
01441                continue;
01442             }
01443          } else {
01444             if (config->feature_timer <=0) {
01445                /* We ran out of time */
01446                config->feature_timer = 0;
01447                who = chan;
01448                if (f)
01449                   ast_frfree(f);
01450                f = NULL;
01451                res = 0;
01452             }
01453          }
01454       }
01455       if (res < 0) {
01456          ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
01457          return -1;
01458       }
01459       
01460       if (!f || (f->frametype == AST_FRAME_CONTROL &&
01461             (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY || 
01462                f->subclass == AST_CONTROL_CONGESTION ) ) ) {
01463          res = -1;
01464          break;
01465       }
01466       /* many things should be sent to the 'other' channel */
01467       other = (who == chan) ? peer : chan;
01468       if (f->frametype == AST_FRAME_CONTROL) {
01469          switch (f->subclass) {
01470          case AST_CONTROL_RINGING:
01471          case AST_CONTROL_FLASH:
01472          case -1:
01473             ast_indicate(other, f->subclass);
01474             break;
01475          case AST_CONTROL_HOLD:
01476          case AST_CONTROL_UNHOLD:
01477             ast_indicate_data(other, f->subclass, f->data, f->datalen);
01478             break;
01479          case AST_CONTROL_OPTION:
01480             aoh = f->data;
01481             /* Forward option Requests */
01482             if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) {
01483                ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 
01484                   f->datalen - sizeof(struct ast_option_header), 0);
01485             }
01486             break;
01487          }
01488       } else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
01489          /* eat it */
01490       } else if (f->frametype == AST_FRAME_DTMF) {
01491          char *featurecode;
01492          int sense;
01493 
01494          hadfeatures = hasfeatures;
01495          /* This cannot overrun because the longest feature is one shorter than our buffer */
01496          if (who == chan) {
01497             sense = FEATURE_SENSE_CHAN;
01498             featurecode = chan_featurecode;
01499          } else  {
01500             sense = FEATURE_SENSE_PEER;
01501             featurecode = peer_featurecode;
01502          }
01503          /*! append the event to featurecode. we rely on the string being zero-filled, and
01504           * not overflowing it. 
01505           * \todo XXX how do we guarantee the latter ?
01506           */
01507          featurecode[strlen(featurecode)] = f->subclass;
01508          /* Get rid of the frame before we start doing "stuff" with the channels */
01509          ast_frfree(f);
01510          f = NULL;
01511          config->feature_timer = backup_config.feature_timer;
01512          res = ast_feature_interpret(chan, peer, config, featurecode, sense);
01513          switch(res) {
01514          case FEATURE_RETURN_PASSDIGITS:
01515             ast_dtmf_stream(other, who, featurecode, 0);
01516             /* Fall through */
01517          case FEATURE_RETURN_SUCCESS:
01518             memset(featurecode, 0, sizeof(chan_featurecode));
01519             break;
01520          }
01521          if (res >= FEATURE_RETURN_PASSDIGITS) {
01522             res = 0;
01523          } else 
01524             break;
01525          hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01526          if (hadfeatures && !hasfeatures) {
01527             /* Restore backup */
01528             memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01529             memset(&backup_config, 0, sizeof(struct ast_bridge_config));
01530          } else if (hasfeatures) {
01531             if (!hadfeatures) {
01532                /* Backup configuration */
01533                memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
01534                /* Setup temporary config options */
01535                config->play_warning = 0;
01536                ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
01537                ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
01538                config->warning_freq = 0;
01539                config->warning_sound = NULL;
01540                config->end_sound = NULL;
01541                config->start_sound = NULL;
01542                config->firstpass = 0;
01543             }
01544             config->start_time = ast_tvnow();
01545             config->feature_timer = featuredigittimeout;
01546             if (option_debug)
01547                ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer);
01548          }
01549       }
01550       if (f)
01551          ast_frfree(f);
01552 
01553    }
01554 
01555    /* arrange the cdrs */
01556    bridge_cdr = ast_cdr_alloc();
01557    if (bridge_cdr) {
01558       if (chan->cdr && peer->cdr) { /* both of them? merge */
01559          ast_cdr_init(bridge_cdr,chan); /* seems more logicaller to use the  destination as a base, but, really, it's random */
01560          ast_cdr_start(bridge_cdr); /* now is the time to start */
01561 
01562          /* absorb the channel cdr */
01563          ast_cdr_merge(bridge_cdr, chan->cdr);
01564          if (!ast_test_flag(chan->cdr, AST_CDR_FLAG_LOCKED))
01565             ast_cdr_discard(chan->cdr); /* if locked cdrs are in chan, they are taken over in the merge */
01566          
01567          /* absorb the peer cdr */
01568          ast_cdr_merge(bridge_cdr, peer->cdr);
01569          if (ast_test_flag(peer->cdr, AST_CDR_FLAG_LOCKED))
01570             ast_cdr_discard(peer->cdr); /* if locked cdrs are in peer, they are taken over in the merge */
01571          
01572          peer->cdr = NULL;
01573          chan->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */
01574       } else if (chan->cdr) {
01575          /* take the cdr from the channel - literally */
01576          ast_cdr_init(bridge_cdr,chan);
01577          /* absorb this data */
01578          ast_cdr_merge(bridge_cdr, chan->cdr);
01579          if (!ast_test_flag(chan->cdr, AST_CDR_FLAG_LOCKED))
01580             ast_cdr_discard(chan->cdr); /* if locked cdrs are in chan, they are taken over in the merge */
01581          chan->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */
01582       } else if (peer->cdr) {
01583          /* take the cdr from the peer - literally */
01584          ast_cdr_init(bridge_cdr,peer);
01585          /* absorb this data */
01586          ast_cdr_merge(bridge_cdr, peer->cdr);
01587          if (!ast_test_flag(peer->cdr, AST_CDR_FLAG_LOCKED))
01588             ast_cdr_discard(peer->cdr); /* if locked cdrs are in chan, they are taken over in the merge */
01589          peer->cdr = NULL;
01590          peer->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */
01591       } else {
01592          /* make up a new cdr */
01593          ast_cdr_init(bridge_cdr,chan); /* eh, just pick one of them */
01594          chan->cdr = bridge_cdr; /*  */
01595       }
01596       if (ast_strlen_zero(bridge_cdr->dstchannel)) {
01597          if (strcmp(bridge_cdr->channel, peer->name) != 0)
01598             ast_cdr_setdestchan(bridge_cdr, peer->name);
01599          else
01600             ast_cdr_setdestchan(bridge_cdr, chan->name);
01601       }
01602    }
01603    return res;
01604 }

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 442 of file res_features.c.

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

00443 {
00444    struct ast_channel *chan;
00445    struct ast_frame *f;
00446 
00447    /* Make a new, fake channel that we'll use to masquerade in the real one */
00448    if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) {
00449       ast_log(LOG_WARNING, "Unable to create parked channel\n");
00450       return -1;
00451    }
00452 
00453    /* Make formats okay */
00454    chan->readformat = rchan->readformat;
00455    chan->writeformat = rchan->writeformat;
00456    ast_channel_masquerade(chan, rchan);
00457 
00458    /* Setup the extensions and such */
00459    set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority);
00460 
00461    /* Make the masq execute */
00462    f = ast_read(chan);
00463    if (f)
00464       ast_frfree(f);
00465 
00466    ast_park_call(chan, peer, timeout, extout);
00467    return 0;
00468 }

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

Park a call and read back parked location.

Parameters:
chan the channel to actually be parked
host the channel which will have the parked location read to Park the channel chan, and read back the parked location to the host. If the call is not picked up within a specified period of time, then the call will return to the last step that it was in (in terms of exten, priority and context)
timeout is a timeout in milliseconds
extout is a parameter to an int that will hold the parked location, or NULL if you want
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.

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_mutex_unlock(&parking_lock);
00329          free(pu);
00330          ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parking_con);
00331          return -1; /* We failed to park this call, plain and simple so we need to error out */
00332       }
00333       ast_copy_string(pu->parkingexten, parkingexten, sizeof(pu->parkingexten));
00334       x = atoi(parkingexten);
00335    } else {
00336       /* Select parking space within range */
00337       parking_range = parking_stop - parking_start+1;
00338       for (i = 0; i < parking_range; i++) {
00339          x = (i + parking_offset) % parking_range + parking_start;
00340          cur = parkinglot;
00341          while(cur) {
00342             if (cur->parkingnum == x) 
00343                break;
00344             cur = cur->next;
00345          }
00346          if (!cur)
00347             break;
00348       }
00349 
00350       if (!(i < parking_range)) {
00351          ast_log(LOG_WARNING, "No more parking spaces\n");
00352          free(pu);
00353          ast_mutex_unlock(&parking_lock);
00354          return -1;
00355       }
00356       /* Set pointer for next parking */
00357       if (parkfindnext) 
00358          parking_offset = x - parking_start + 1;
00359    }
00360    
00361    chan->appl = "Parked Call";
00362    chan->data = NULL; 
00363 
00364    pu->chan = chan;
00365    
00366    /* Put the parked channel on hold if we have two different channels */
00367    if (chan != peer) {
00368       ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
00369          S_OR(parkmohclass, NULL),
00370          !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
00371    }
00372    
00373    pu->start = ast_tvnow();
00374    pu->parkingnum = x;
00375    pu->parkingtime = (timeout > 0) ? timeout : parkingtime;
00376    if (extout)
00377       *extout = x;
00378 
00379    if (peer) 
00380       ast_copy_string(pu->peername, peer->name, sizeof(pu->peername));
00381 
00382    /* Remember what had been dialed, so that if the parking
00383       expires, we try to come back to the same place */
00384    ast_copy_string(pu->context, S_OR(chan->macrocontext, chan->context), sizeof(pu->context));
00385    ast_copy_string(pu->exten, S_OR(chan->macroexten, chan->exten), sizeof(pu->exten));
00386    pu->priority = chan->macropriority ? chan->macropriority : chan->priority;
00387    pu->next = parkinglot;
00388    parkinglot = pu;
00389 
00390    /* If parking a channel directly, don't quiet yet get parking running on it */
00391    if (peer == chan) 
00392       pu->notquiteyet = 1;
00393    ast_mutex_unlock(&parking_lock);
00394    /* Wake up the (presumably select()ing) thread */
00395    pthread_kill(parking_thread, SIGURG);
00396    if (option_verbose > 1) 
00397       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));
00398 
00399    if (pu->parkingnum != -1)
00400       snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", x);
00401    manager_event(EVENT_FLAG_CALL, "ParkedCall",
00402       "Exten: %s\r\n"
00403       "Channel: %s\r\n"
00404       "From: %s\r\n"
00405       "Timeout: %ld\r\n"
00406       "CallerID: %s\r\n"
00407       "CallerIDName: %s\r\n",
00408       pu->parkingexten, pu->chan->name, peer ? peer->name : "",
00409       (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL),
00410       S_OR(pu->chan->cid.cid_num, "<unknown>"),
00411       S_OR(pu->chan->cid.cid_name, "<unknown>")
00412       );
00413 
00414    if (peer && adsipark && ast_adsi_available(peer)) {
00415       adsi_announce_park(peer, pu->parkingexten);  /* Only supports parking numbers */
00416       ast_adsi_unload_session(peer);
00417    }
00418 
00419    con = ast_context_find(parking_con);
00420    if (!con) 
00421       con = ast_context_create(NULL, parking_con, registrar);
00422    if (!con)   /* Still no context? Bad */
00423       ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
00424    /* Tell the peer channel the number of the parking space */
00425    if (peer && pu->parkingnum != -1) /* Only say number if it's a number */
00426       ast_say_digits(peer, pu->parkingnum, "", peer->language);
00427    if (con) {
00428       if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, strdup(pu->parkingexten), ast_free, registrar))
00429          notify_metermaids(pu->parkingexten, parking_con);
00430    }
00431    if (pu->notquiteyet) {
00432       /* Wake up parking thread if we're really done */
00433       ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
00434          S_OR(parkmohclass, NULL),
00435          !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
00436       pu->notquiteyet = 0;
00437       pthread_kill(parking_thread, SIGURG);
00438    }
00439    return 0;
00440 }

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 155 of file res_features.c.

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

00156 {
00157    return parking_ext;
00158 }

int ast_pickup_call ( struct ast_channel chan  ) 

Pickup a call.

Definition at line 2134 of file res_features.c.

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

02135 {
02136    struct ast_channel *cur = NULL;
02137    int res = -1;
02138 
02139    while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
02140       if (!cur->pbx && 
02141          (cur != chan) &&
02142          (chan->pickupgroup & cur->callgroup) &&
02143          ((cur->_state == AST_STATE_RINGING) ||
02144           (cur->_state == AST_STATE_RING))) {
02145             break;
02146       }
02147       ast_channel_unlock(cur);
02148    }
02149    if (cur) {
02150       if (option_debug)
02151          ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
02152       res = ast_answer(chan);
02153       if (res)
02154          ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
02155       res = ast_queue_control(chan, AST_CONTROL_ANSWER);
02156       if (res)
02157          ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
02158       res = ast_channel_masquerade(cur, chan);
02159       if (res)
02160          ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);     /* Done */
02161       ast_channel_unlock(cur);
02162    } else   {
02163       if (option_debug)
02164          ast_log(LOG_DEBUG, "No call pickup possible...\n");
02165    }
02166    return res;
02167 }

char* ast_pickup_ext ( void   ) 

Determine system call pickup extension.

Definition at line 160 of file res_features.c.

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

00161 {
00162    return pickup_ext;
00163 }

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 895 of file res_features.c.

Referenced by load_config().

00896 {
00897    if (!feature) {
00898       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
00899          return;
00900    }
00901   
00902    AST_LIST_LOCK(&feature_list);
00903    AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry);
00904    AST_LIST_UNLOCK(&feature_list);
00905 
00906    if (option_verbose >= 2) 
00907       ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
00908 }

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 911 of file res_features.c.

00912 {
00913    if (!feature)
00914       return;
00915 
00916    AST_LIST_LOCK(&feature_list);
00917    AST_LIST_REMOVE(&feature_list,feature,feature_entry);
00918    AST_LIST_UNLOCK(&feature_list);
00919    free(feature);
00920 }


Generated on Wed Aug 15 01:25:07 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.3