Mon May 14 04:47:40 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 1326 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, ast_option_header::flag, 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(), and ast_cdr::userfield.

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          if (f->subclass == AST_CONTROL_RINGING)
01470             ast_indicate(other, AST_CONTROL_RINGING);
01471          else if (f->subclass == -1)
01472             ast_indicate(other, -1);
01473          else if (f->subclass == AST_CONTROL_FLASH)
01474             ast_indicate(other, AST_CONTROL_FLASH);
01475          else if (f->subclass == AST_CONTROL_OPTION) {
01476             aoh = f->data;
01477             /* Forward option Requests */
01478             if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST)
01479                ast_channel_setoption(other, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
01480          }
01481       } else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
01482          /* eat it */
01483       } else if (f->frametype == AST_FRAME_DTMF) {
01484          char *featurecode;
01485          int sense;
01486 
01487          hadfeatures = hasfeatures;
01488          /* This cannot overrun because the longest feature is one shorter than our buffer */
01489          if (who == chan) {
01490             sense = FEATURE_SENSE_CHAN;
01491             featurecode = chan_featurecode;
01492          } else  {
01493             sense = FEATURE_SENSE_PEER;
01494             featurecode = peer_featurecode;
01495          }
01496          /*! append the event to featurecode. we rely on the string being zero-filled, and
01497           * not overflowing it. 
01498           * \todo XXX how do we guarantee the latter ?
01499           */
01500          featurecode[strlen(featurecode)] = f->subclass;
01501          /* Get rid of the frame before we start doing "stuff" with the channels */
01502          ast_frfree(f);
01503          f = NULL;
01504          config->feature_timer = backup_config.feature_timer;
01505          res = ast_feature_interpret(chan, peer, config, featurecode, sense);
01506          switch(res) {
01507          case FEATURE_RETURN_PASSDIGITS:
01508             ast_dtmf_stream(other, who, featurecode, 0);
01509             /* Fall through */
01510          case FEATURE_RETURN_SUCCESS:
01511             memset(featurecode, 0, sizeof(chan_featurecode));
01512             break;
01513          }
01514          if (res >= FEATURE_RETURN_PASSDIGITS) {
01515             res = 0;
01516          } else 
01517             break;
01518          hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01519          if (hadfeatures && !hasfeatures) {
01520             /* Restore backup */
01521             memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01522             memset(&backup_config, 0, sizeof(struct ast_bridge_config));
01523          } else if (hasfeatures) {
01524             if (!hadfeatures) {
01525                /* Backup configuration */
01526                memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
01527                /* Setup temporary config options */
01528                config->play_warning = 0;
01529                ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
01530                ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
01531                config->warning_freq = 0;
01532                config->warning_sound = NULL;
01533                config->end_sound = NULL;
01534                config->start_sound = NULL;
01535                config->firstpass = 0;
01536             }
01537             config->start_time = ast_tvnow();
01538             config->feature_timer = featuredigittimeout;
01539             if (option_debug)
01540                ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer);
01541          }
01542       }
01543       if (f)
01544          ast_frfree(f);
01545 
01546    }
01547 
01548    /* arrange the cdrs */
01549    bridge_cdr = ast_cdr_alloc();
01550    if (bridge_cdr) {
01551       if (chan->cdr && peer->cdr) { /* both of them? merge */
01552          ast_cdr_init(bridge_cdr,chan); /* seems more logicaller to use the  destination as a base, but, really, it's random */
01553          ast_cdr_start(bridge_cdr); /* now is the time to start */
01554 
01555          /* absorb the channel cdr */
01556          ast_cdr_merge(bridge_cdr, chan->cdr);
01557          ast_cdr_discard(chan->cdr); /* no posting these guys */
01558          
01559          /* absorb the peer cdr */
01560          ast_cdr_merge(bridge_cdr, peer->cdr);
01561          ast_cdr_discard(peer->cdr); /* no posting these guys */
01562          peer->cdr = NULL;
01563          chan->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */
01564       } else if (chan->cdr) {
01565          /* take the cdr from the channel - literally */
01566          ast_cdr_init(bridge_cdr,chan);
01567          /* absorb this data */
01568          ast_cdr_merge(bridge_cdr, chan->cdr);
01569          ast_cdr_discard(chan->cdr); /* no posting these guys */
01570          chan->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */
01571       } else if (peer->cdr) {
01572          /* take the cdr from the peer - literally */
01573          ast_cdr_init(bridge_cdr,peer);
01574          /* absorb this data */
01575          ast_cdr_merge(bridge_cdr, peer->cdr);
01576          ast_cdr_discard(peer->cdr); /* no posting these guys */
01577          peer->cdr = NULL;
01578          peer->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */
01579       } else {
01580          /* make up a new cdr */
01581          ast_cdr_init(bridge_cdr,chan); /* eh, just pick one of them */
01582          chan->cdr = bridge_cdr; /*  */
01583       }
01584       if (ast_strlen_zero(bridge_cdr->dstchannel)) {
01585          if (strcmp(bridge_cdr->channel, peer->name) != 0)
01586             ast_cdr_setdestchan(bridge_cdr, peer->name);
01587          else
01588             ast_cdr_setdestchan(bridge_cdr, chan->name);
01589       }
01590    }
01591    return res;
01592 }

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 440 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().

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

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

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 2122 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().

02123 {
02124    struct ast_channel *cur = NULL;
02125    int res = -1;
02126 
02127    while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
02128       if (!cur->pbx && 
02129          (cur != chan) &&
02130          (chan->pickupgroup & cur->callgroup) &&
02131          ((cur->_state == AST_STATE_RINGING) ||
02132           (cur->_state == AST_STATE_RING))) {
02133             break;
02134       }
02135       ast_channel_unlock(cur);
02136    }
02137    if (cur) {
02138       if (option_debug)
02139          ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
02140       res = ast_answer(chan);
02141       if (res)
02142          ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
02143       res = ast_queue_control(chan, AST_CONTROL_ANSWER);
02144       if (res)
02145          ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
02146       res = ast_channel_masquerade(cur, chan);
02147       if (res)
02148          ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);     /* Done */
02149       ast_channel_unlock(cur);
02150    } else   {
02151       if (option_debug)
02152          ast_log(LOG_DEBUG, "No call pickup possible...\n");
02153    }
02154    return res;
02155 }

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

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

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

References AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, and free.

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


Generated on Mon May 14 04:47:41 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1