Mon Apr 30 07:42:18 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.

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

References ast_channel::appl, ast_answer(), ast_cdr_alloc(), ast_cdr_appenduserfield(), ast_cdr_discard(), ast_cdr_init(), ast_cdr_merge(), ast_cdr_setdestchan(), ast_cdr_setuserfield(), ast_cdr_start(), 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, ast_cdr::channel, config, ast_channel::data, ast_option_header::data, ast_cdr::dstchannel, f, FEATURE_MAX_LEN, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_SUCCESS, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, featuredigittimeout, ast_option_header::flag, free, LOG_DEBUG, LOG_WARNING, monitor_app, monitor_ok, ast_option_header::option, option_debug, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), set_config_flags(), and ast_cdr::userfield.

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

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

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::amaflags, ast_channel_alloc(), ast_channel_masquerade(), ast_frfree(), ast_log(), ast_park_call(), ast_read(), AST_STATE_DOWN, ast_channel::context, ast_channel::exten, f, LOG_WARNING, ast_channel::priority, ast_channel::readformat, set_c_e_p(), and ast_channel::writeformat.

Referenced by manager_park(), mgcp_ss(), parkandannounce_exec(), rpt_exec(), 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, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "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 adsi_announce_park(), ast_channel::appl, ast_add_extension2(), ast_adsi_available(), ast_adsi_unload_session(), ast_calloc, ast_context_create(), ast_context_find(), AST_CONTROL_HOLD, ast_exists_extension(), ast_free, ast_indicate_data(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_say_digits(), ast_strlen_zero(), ast_verbose(), ast_channel::context, ast_channel::data, EVENT_FLAG_CALL, ast_channel::exten, free, LOG_ERROR, LOG_WARNING, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::macropriority, manager_event(), parkeduser::next, notify_metermaids(), parkeduser::notquiteyet, option_verbose, parkinglot, parkeduser::parkingnum, pbx_builtin_getvar_helper(), ast_channel::priority, S_OR, strdup, and VERBOSE_PREFIX_2.

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       "CallerID: %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 155 of file res_features.c.

Referenced by builtin_blindtransfer(), dp_lookup(), handle_request_refer(), 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 2108 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().

02109 {
02110    struct ast_channel *cur = NULL;
02111    int res = -1;
02112 
02113    while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
02114       if (!cur->pbx && 
02115          (cur != chan) &&
02116          (chan->pickupgroup & cur->callgroup) &&
02117          ((cur->_state == AST_STATE_RINGING) ||
02118           (cur->_state == AST_STATE_RING))) {
02119             break;
02120       }
02121       ast_channel_unlock(cur);
02122    }
02123    if (cur) {
02124       if (option_debug)
02125          ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
02126       res = ast_answer(chan);
02127       if (res)
02128          ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
02129       res = ast_queue_control(chan, AST_CONTROL_ANSWER);
02130       if (res)
02131          ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
02132       res = ast_channel_masquerade(cur, chan);
02133       if (res)
02134          ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);     /* Done */
02135       ast_channel_unlock(cur);
02136    } else   {
02137       if (option_debug)
02138          ast_log(LOG_DEBUG, "No call pickup possible...\n");
02139    }
02140    return res;
02141 }

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

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

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

References AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, and free.

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


Generated on Mon Apr 30 07:42:18 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1