Fri Aug 24 02:25:47 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 1330 of file res_features.c.

References ast_channel::appl, ast_answer(), ast_cdr_alloc(), ast_cdr_appenduserfield(), ast_cdr_discard(), AST_CDR_FLAG_LOCKED, 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_HOLD, AST_CONTROL_OPTION, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, 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_indicate_data(), ast_log(), AST_OPTION_FLAG_REQUEST, ast_strdupa, ast_strlen_zero(), ast_test_flag, 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().

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

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.

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

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_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(), 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 2138 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().

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

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

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

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

References AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, and free.

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


Generated on Fri Aug 24 02:25:47 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1