Sat Apr 12 07:12:46 2008

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_autoanswer_login (struct ast_channel *chan, void *data)
int ast_bridge_call (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
 Bridge a call, optionally allowing redirection.
struct ast_channelast_get_holded_call (char *uniqueid)
int ast_hold_call (struct ast_channel *chan, struct ast_channel *host)
int ast_masq_autoanswer_login (struct ast_channel *rchan, void *data)
int ast_masq_hold_call (struct ast_channel *rchan, struct ast_channel *host)
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
int ast_retrieve_call (struct ast_channel *chan, char *uniqueid)
int ast_retrieve_call_to_death (char *uniqueid)
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_autoanswer_login ( struct ast_channel chan,
void *  data 
)

Definition at line 2576 of file res_features.c.

References ast_channel::_state, ast_channel::appl, ast_add_extension2(), ast_answer(), ast_context_create(), ast_context_find(), ast_hangup(), ast_log(), AST_MAX_EXTENSION, ast_moh_start(), ast_mutex_lock(), ast_mutex_unlock(), AST_STATE_UP, ast_strdupa, ast_verbose(), aauser::chan, aauser::context, ast_channel::data, EVENT_FLAG_CALL, aauser::exten, exten, free, LOG_ERROR, LOG_NOTICE, LOG_WARNING, malloc, manager_event(), aauser::next, option_verbose, s, aauser::start, strdup, strsep(), and VERBOSE_PREFIX_2.

Referenced by ast_masq_autoanswer_login(), and autoanswer_exec().

02577 {
02578    /* We put the user in the parking list, then wake up the parking thread to be sure it looks
02579       after these channels too */
02580    struct ast_context *con;
02581    char exten[AST_MAX_EXTENSION];
02582    struct aauser *pu,*pl = NULL;
02583    char *s, *stringp, *aacontext, *aaexten = NULL;
02584 
02585    s = ast_strdupa((void *) data);
02586    stringp=s;
02587    aacontext = strsep(&stringp, "|");
02588    aaexten = strsep(&stringp, "|");
02589    if (!aaexten) {
02590        aaexten = aacontext;
02591        aacontext = NULL;
02592    }
02593    if (!aaexten) {
02594       ast_log(LOG_WARNING, "AutoanswerLogin requires at least an extension!\n");
02595       return -1;
02596    } else {
02597       if (!aacontext) {
02598          aacontext = "default";
02599       }
02600    }
02601 
02602    ast_mutex_lock(&autoanswer_lock);
02603    pu = aalot;
02604    while(pu) {
02605       if ((!strncasecmp(pu->exten, aaexten, sizeof(pu->exten)-1)) && (!strncasecmp(pu->context, aacontext, sizeof(pu->context)-1))){
02606          if (pl)
02607             pl->next = pu->next;
02608          else
02609             aalot = pu->next;
02610          break;
02611       }
02612       pl = pu;
02613       pu = pu->next;
02614    }
02615    ast_mutex_unlock(&autoanswer_lock);
02616    if (pu) {
02617        ast_log(LOG_NOTICE, "Logout old Channel %s for %s@%s.\n",pu->chan->name, pu->exten, pu->context);
02618        manager_event(EVENT_FLAG_CALL, "AutoanswerLogout",
02619                                "Channel: %s\r\n"
02620                                "Uniqueid: %s\r\n"
02621                                "Context: %s\r\n"
02622                                "Exten: %s\r\n"
02623                            ,pu->chan->name, pu->chan->uniqueid, pu->context, pu->exten);
02624        ast_hangup(pu->chan);
02625        free(pu);
02626    }
02627    pu = malloc(sizeof(struct aauser));
02628    if (pu) {
02629       memset(pu, 0, sizeof(pu));
02630       ast_mutex_lock(&autoanswer_lock);
02631       chan->appl = "Autoanswer";
02632       chan->data = NULL; 
02633 
02634       pu->chan = chan;
02635       if (chan->_state != AST_STATE_UP) {
02636           ast_answer(chan);
02637       }
02638 
02639       /* Start music on hold */
02640       ast_moh_start(pu->chan, NULL, NULL);
02641       gettimeofday(&pu->start, NULL);
02642       strncpy(pu->exten, aaexten, sizeof(pu->exten)-1);
02643       strncpy(pu->context, aacontext, sizeof(pu->exten)-1);
02644       pu->next = aalot;
02645       aalot = pu;
02646       con = ast_context_find(aacontext);
02647       if (!con) {
02648          con = ast_context_create(NULL,aacontext, registrar);
02649          if (!con) {
02650             ast_log(LOG_ERROR, "Context '%s' does not exist and unable to create\n", aacontext);
02651          }
02652       }
02653       if (con) {
02654          snprintf(exten, sizeof(exten), "%s", aaexten);
02655          ast_add_extension2(con, 1, exten, 1, NULL, NULL, autoanswer, strdup((char *)data), free, registrar);
02656       }
02657 
02658       ast_mutex_unlock(&autoanswer_lock);
02659       /* Wake up the (presumably select()ing) thread */
02660       pthread_kill(autoanswer_thread, SIGURG);
02661       if (option_verbose > 1) 
02662          ast_verbose(VERBOSE_PREFIX_2 "Autoanswer login from %s for %s@%s.\n", pu->chan->name, pu->exten, pu->context);
02663          manager_event(EVENT_FLAG_CALL, "AutoanswerLogin",
02664                                 "Channel: %s\r\n"
02665                                 "Uniqueid: %s\r\n"
02666                "Context: %s\r\n"
02667                         "Exten: %s\r\n"
02668                         ,pu->chan->name, pu->chan->uniqueid, pu->context, pu->exten);
02669 
02670          return 0;
02671    } else {
02672       ast_log(LOG_WARNING, "Out of memory\n");
02673       return -1;
02674    }
02675    return 0;
02676 }

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 1405 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_check_hangup(), 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_FLAG_ZOMBIE, 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, ast_option_header::data, ast_frame::data, ast_channel::data, ast_frame::datalen, ast_cdr::dstchannel, ast_bridge_config::end_sound, f, FEATURE_MAX_LEN, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_SUCCESS, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, ast_bridge_config::feature_timer, ast_bridge_config::features_callee, ast_bridge_config::features_caller, ast_bridge_config::firstpass, ast_option_header::flag, ast_frame::frametype, free, LOG_DEBUG, LOG_WARNING, ast_option_header::option, option_debug, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), ast_bridge_config::play_warning, set_config_flags(), ast_bridge_config::start_sound, ast_bridge_config::start_time, ast_frame::subclass, ast_cdr::userfield, ast_bridge_config::warning_freq, and ast_bridge_config::warning_sound.

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

01406 {
01407    /* Copy voice back and forth between the two channels.  Give the peer
01408       the ability to transfer calls with '#<extension' syntax. */
01409    struct ast_frame *f;
01410    struct ast_channel *who;
01411    char chan_featurecode[FEATURE_MAX_LEN + 1]="";
01412    char peer_featurecode[FEATURE_MAX_LEN + 1]="";
01413    int res;
01414    int diff;
01415    int hasfeatures=0;
01416    int hadfeatures=0;
01417    struct ast_option_header *aoh;
01418    struct ast_bridge_config backup_config;
01419    struct ast_cdr *bridge_cdr;
01420 
01421    memset(&backup_config, 0, sizeof(backup_config));
01422 
01423    config->start_time = ast_tvnow();
01424 
01425    if (chan && peer) {
01426       pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
01427       pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
01428    } else if (chan)
01429       pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
01430 
01431    if (monitor_ok) {
01432       const char *monitor_exec;
01433       struct ast_channel *src = NULL;
01434       if (!monitor_app) { 
01435          if (!(monitor_app = pbx_findapp("Monitor")))
01436             monitor_ok=0;
01437       }
01438       if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 
01439          src = chan;
01440       else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
01441          src = peer;
01442       if (monitor_app && src) {
01443          char *tmp = ast_strdupa(monitor_exec);
01444          pbx_exec(src, monitor_app, tmp);
01445       }
01446    }
01447    
01448    set_config_flags(chan, peer, config);
01449    config->firstpass = 1;
01450 
01451    /* Answer if need be */
01452    if (ast_answer(chan))
01453       return -1;
01454    peer->appl = "Bridged Call";
01455    peer->data = chan->name;
01456 
01457    /* copy the userfield from the B-leg to A-leg if applicable */
01458    if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
01459       char tmp[256];
01460       if (!ast_strlen_zero(chan->cdr->userfield)) {
01461          snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield);
01462          ast_cdr_appenduserfield(chan, tmp);
01463       } else
01464          ast_cdr_setuserfield(chan, peer->cdr->userfield);
01465       /* free the peer's cdr without ast_cdr_free complaining */
01466       free(peer->cdr);
01467       peer->cdr = NULL;
01468    }
01469 
01470    for (;;) {
01471       struct ast_channel *other; /* used later */
01472 
01473       res = ast_channel_bridge(chan, peer, config, &f, &who);
01474 
01475       if (config->feature_timer) {
01476          /* Update time limit for next pass */
01477          diff = ast_tvdiff_ms(ast_tvnow(), config->start_time);
01478          config->feature_timer -= diff;
01479          if (hasfeatures) {
01480             /* Running on backup config, meaning a feature might be being
01481                activated, but that's no excuse to keep things going 
01482                indefinitely! */
01483             if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
01484                if (option_debug)
01485                   ast_log(LOG_DEBUG, "Timed out, realtime this time!\n");
01486                config->feature_timer = 0;
01487                who = chan;
01488                if (f)
01489                   ast_frfree(f);
01490                f = NULL;
01491                res = 0;
01492             } else if (config->feature_timer <= 0) {
01493                /* Not *really* out of time, just out of time for
01494                   digits to come in for features. */
01495                if (option_debug)
01496                   ast_log(LOG_DEBUG, "Timed out for feature!\n");
01497                if (!ast_strlen_zero(peer_featurecode)) {
01498                   ast_dtmf_stream(chan, peer, peer_featurecode, 0);
01499                   memset(peer_featurecode, 0, sizeof(peer_featurecode));
01500                }
01501                if (!ast_strlen_zero(chan_featurecode)) {
01502                   ast_dtmf_stream(peer, chan, chan_featurecode, 0);
01503                   memset(chan_featurecode, 0, sizeof(chan_featurecode));
01504                }
01505                if (f)
01506                   ast_frfree(f);
01507                hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01508                if (!hasfeatures) {
01509                   /* Restore original (possibly time modified) bridge config */
01510                   memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01511                   memset(&backup_config, 0, sizeof(backup_config));
01512                }
01513                hadfeatures = hasfeatures;
01514                /* Continue as we were */
01515                continue;
01516             } else if (!f) {
01517                /* The bridge returned without a frame and there is a feature in progress.
01518                 * However, we don't think the feature has quite yet timed out, so just
01519                 * go back into the bridge. */
01520                continue;
01521             }
01522          } else {
01523             if (config->feature_timer <=0) {
01524                /* We ran out of time */
01525                config->feature_timer = 0;
01526                who = chan;
01527                if (f)
01528                   ast_frfree(f);
01529                f = NULL;
01530                res = 0;
01531             }
01532          }
01533       }
01534       if (res < 0) {
01535          if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer))
01536             ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
01537          return -1;
01538       }
01539       
01540       if (!f || (f->frametype == AST_FRAME_CONTROL &&
01541             (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY || 
01542                f->subclass == AST_CONTROL_CONGESTION ) ) ) {
01543          res = -1;
01544          break;
01545       }
01546       /* many things should be sent to the 'other' channel */
01547       other = (who == chan) ? peer : chan;
01548       if (f->frametype == AST_FRAME_CONTROL) {
01549          switch (f->subclass) {
01550          case AST_CONTROL_RINGING:
01551          case AST_CONTROL_FLASH:
01552          case -1:
01553             ast_indicate(other, f->subclass);
01554             break;
01555          case AST_CONTROL_HOLD:
01556          case AST_CONTROL_UNHOLD:
01557             ast_indicate_data(other, f->subclass, f->data, f->datalen);
01558             break;
01559          case AST_CONTROL_OPTION:
01560             aoh = f->data;
01561             /* Forward option Requests */
01562             if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) {
01563                ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 
01564                   f->datalen - sizeof(struct ast_option_header), 0);
01565             }
01566             break;
01567          }
01568       } else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
01569          /* eat it */
01570       } else if (f->frametype == AST_FRAME_DTMF) {
01571          char *featurecode;
01572          int sense;
01573 
01574          hadfeatures = hasfeatures;
01575          /* This cannot overrun because the longest feature is one shorter than our buffer */
01576          if (who == chan) {
01577             sense = FEATURE_SENSE_CHAN;
01578             featurecode = chan_featurecode;
01579          } else  {
01580             sense = FEATURE_SENSE_PEER;
01581             featurecode = peer_featurecode;
01582          }
01583          /*! append the event to featurecode. we rely on the string being zero-filled, and
01584           * not overflowing it. 
01585           * \todo XXX how do we guarantee the latter ?
01586           */
01587          featurecode[strlen(featurecode)] = f->subclass;
01588          /* Get rid of the frame before we start doing "stuff" with the channels */
01589          ast_frfree(f);
01590          f = NULL;
01591          config->feature_timer = backup_config.feature_timer;
01592          res = ast_feature_interpret(chan, peer, config, featurecode, sense);
01593          switch(res) {
01594          case FEATURE_RETURN_PASSDIGITS:
01595             ast_dtmf_stream(other, who, featurecode, 0);
01596             /* Fall through */
01597          case FEATURE_RETURN_SUCCESS:
01598             memset(featurecode, 0, sizeof(chan_featurecode));
01599             break;
01600          }
01601          if (res >= FEATURE_RETURN_PASSDIGITS) {
01602             res = 0;
01603          } else 
01604             break;
01605          hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01606          if (hadfeatures && !hasfeatures) {
01607             /* Restore backup */
01608             memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01609             memset(&backup_config, 0, sizeof(struct ast_bridge_config));
01610          } else if (hasfeatures) {
01611             if (!hadfeatures) {
01612                /* Backup configuration */
01613                memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
01614                /* Setup temporary config options */
01615                config->play_warning = 0;
01616                ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
01617                ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
01618                config->warning_freq = 0;
01619                config->warning_sound = NULL;
01620                config->end_sound = NULL;
01621                config->start_sound = NULL;
01622                config->firstpass = 0;
01623             }
01624             config->start_time = ast_tvnow();
01625             config->feature_timer = featuredigittimeout;
01626             if (option_debug)
01627                ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer);
01628          }
01629       }
01630       if (f)
01631          ast_frfree(f);
01632 
01633    }
01634 
01635    /* arrange the cdrs */
01636    bridge_cdr = ast_cdr_alloc();
01637    if (bridge_cdr) {
01638       if (chan->cdr && peer->cdr) { /* both of them? merge */
01639          ast_cdr_init(bridge_cdr,chan); /* seems more logicaller to use the  destination as a base, but, really, it's random */
01640          ast_cdr_start(bridge_cdr); /* now is the time to start */
01641 
01642          /* absorb the channel cdr */
01643          ast_cdr_merge(bridge_cdr, chan->cdr);
01644          if (!ast_test_flag(chan->cdr, AST_CDR_FLAG_LOCKED))
01645             ast_cdr_discard(chan->cdr); /* if locked cdrs are in chan, they are taken over in the merge */
01646          
01647          /* absorb the peer cdr */
01648          ast_cdr_merge(bridge_cdr, peer->cdr);
01649          if (!ast_test_flag(peer->cdr, AST_CDR_FLAG_LOCKED))
01650             ast_cdr_discard(peer->cdr); /* if locked cdrs are in peer, they are taken over in the merge */
01651          
01652          peer->cdr = NULL;
01653          chan->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */
01654       } else if (chan->cdr) {
01655          /* take the cdr from the channel - literally */
01656          ast_cdr_init(bridge_cdr,chan);
01657          /* absorb this data */
01658          ast_cdr_merge(bridge_cdr, chan->cdr);
01659          if (!ast_test_flag(chan->cdr, AST_CDR_FLAG_LOCKED))
01660             ast_cdr_discard(chan->cdr); /* if locked cdrs are in chan, they are taken over in the merge */
01661          chan->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */
01662       } else if (peer->cdr) {
01663          /* take the cdr from the peer - literally */
01664          ast_cdr_init(bridge_cdr,peer);
01665          /* absorb this data */
01666          ast_cdr_merge(bridge_cdr, peer->cdr);
01667          if (!ast_test_flag(peer->cdr, AST_CDR_FLAG_LOCKED))
01668             ast_cdr_discard(peer->cdr); /* if locked cdrs are in chan, they are taken over in the merge */
01669          peer->cdr = NULL;
01670          peer->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */
01671       } else {
01672          /* make up a new cdr */
01673          ast_cdr_init(bridge_cdr,chan); /* eh, just pick one of them */
01674          chan->cdr = bridge_cdr; /*  */
01675       }
01676       if (ast_strlen_zero(bridge_cdr->dstchannel)) {
01677          if (strcmp(bridge_cdr->channel, peer->name) != 0)
01678             ast_cdr_setdestchan(bridge_cdr, peer->name);
01679          else
01680             ast_cdr_setdestchan(bridge_cdr, chan->name);
01681       }
01682    }
01683    return res;
01684 }

struct ast_channel* ast_get_holded_call ( char *  uniqueid  )  [read]

Definition at line 2180 of file res_features.c.

References ast_get_channel_by_uniqueid_locked(), ast_log(), ast_moh_stop(), ast_mutex_lock(), ast_mutex_unlock(), ast_verbose(), free, LOG_WARNING, holdeduser::next, option_verbose, holdeduser::uniqueid, and VERBOSE_PREFIX_3.

Referenced by ast_retrieve_call(), and ast_retrieve_call_to_death().

02181 {
02182    int res=-1;
02183    struct ast_channel *peer=NULL;
02184    struct holdeduser *pu, *pl=NULL;
02185 
02186    ast_mutex_lock(&holding_lock);
02187    pu = holdlist;
02188    while(pu) {
02189       if (!strncmp(uniqueid,pu->uniqueid,sizeof(pu->uniqueid))) {
02190          if (pl)
02191             pl->next = pu->next;
02192          else
02193             holdlist = pu->next; 
02194          break;
02195       }
02196       pl = pu;
02197       pu = pu->next;
02198    }
02199    ast_mutex_unlock(&holding_lock);
02200    if (pu) {
02201       peer = ast_get_channel_by_uniqueid_locked(pu->uniqueid);
02202       free(pu);
02203       if (peer) {
02204           res=0;
02205           if (option_verbose > 2) 
02206          ast_verbose(VERBOSE_PREFIX_3 "Channel %s removed from hold.\n", peer->name);
02207           ast_moh_stop(peer);
02208           return peer;
02209       } else {
02210           if (option_verbose > 2) 
02211          ast_verbose(VERBOSE_PREFIX_3 "Could not find channel with uniqueid %s.\n", uniqueid);
02212           return NULL;
02213       }
02214    } else {
02215       ast_log(LOG_WARNING, "Could not find held channel with uniqueid %s to retrieve.\n", uniqueid);
02216    }
02217    return NULL;
02218 }

int ast_hold_call ( struct ast_channel chan,
struct ast_channel host 
)

Definition at line 2038 of file res_features.c.

References ast_channel::appl, ast_log(), ast_moh_start(), ast_mutex_lock(), ast_mutex_unlock(), holdeduser::chan, ast_channel::data, EVENT_FLAG_CALL, LOG_WARNING, malloc, manager_event(), holdeduser::next, holdeduser::start, holdeduser::uniqueid, and holdeduser::uniqueidpeer.

Referenced by ast_masq_hold_call().

02039 {
02040    /* We put the user in the parking list, then wake up the parking thread to be sure it looks
02041       after these channels too */
02042    struct holdeduser *pu;
02043    pu = malloc(sizeof(struct holdeduser));
02044    if (pu) {
02045       memset(pu, 0, sizeof(pu));
02046       ast_mutex_lock(&holding_lock);
02047       chan->appl = "Holded Call";
02048       chan->data = NULL; 
02049 
02050       pu->chan = chan;
02051       strncpy(pu->uniqueid, chan->uniqueid, sizeof(pu->uniqueid));
02052       strncpy(pu->uniqueidpeer, peer->uniqueid, sizeof(pu->uniqueidpeer));
02053       /* Start music on hold */
02054       ast_moh_start(pu->chan, NULL, NULL);
02055       gettimeofday(&pu->start, NULL);
02056       pu->next = holdlist;
02057       holdlist = pu;
02058       ast_mutex_unlock(&holding_lock);
02059       /* Wake up the (presumably select()ing) thread */
02060       pthread_kill(holding_thread, SIGURG);
02061 
02062       manager_event(EVENT_FLAG_CALL, "HoldedCall",
02063                          "Channel1: %s\r\n"
02064                          "Channel2: %s\r\n"
02065                       "Uniqueid1: %s\r\n"
02066                       "Uniqueid2: %s\r\n"
02067                              ,pu->chan->name, peer->name, pu->chan->uniqueid, peer->uniqueid);
02068 
02069    } else {
02070       ast_log(LOG_WARNING, "Out of memory\n");
02071       return -1;
02072    }
02073    return 0;
02074 }

int ast_masq_autoanswer_login ( struct ast_channel rchan,
void *  data 
)

Definition at line 2530 of file res_features.c.

References ast_autoanswer_login(), ast_channel_alloc(), ast_channel_masquerade(), ast_frfree, ast_log(), ast_read(), AST_STATE_DOWN, ast_string_field_build, ast_channel::context, ast_channel::exten, f, LOG_WARNING, name, ast_channel::priority, ast_channel::readformat, and ast_channel::writeformat.

Referenced by autoanswer_login_exec().

02531 {
02532    struct ast_channel *chan;
02533    struct ast_frame *f;
02534    /* Make a new, fake channel that we'll use to masquerade in the real one */
02535    chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Autoanswer/%s", rchan->name);
02536    if (chan) {
02537       /* Let us keep track of the channel name */
02538       ast_string_field_build(chan, name, "Autoanswer/%s",rchan->name);
02539       /* Make formats okay */
02540       chan->readformat = rchan->readformat;
02541       chan->writeformat = rchan->writeformat;
02542       ast_channel_masquerade(chan, rchan);
02543       /* Setup the extensions and such */
02544       strncpy(chan->context, rchan->context, sizeof(chan->context) - 1);
02545       strncpy(chan->exten, rchan->exten, sizeof(chan->exten) - 1);
02546       chan->priority = rchan->priority;
02547       /* might be dirty but we want trackable channels */
02548       ast_string_field_build(chan, uniqueid, "%s",rchan->uniqueid);
02549       /* Make the masq execute */
02550       f = ast_read(chan);
02551       if (f)
02552          ast_frfree(f);
02553       ast_autoanswer_login(chan, data);
02554    } else {
02555       ast_log(LOG_WARNING, "Unable to create aa channel\n");
02556       return -1;
02557    }
02558    return 0;
02559 }

int ast_masq_hold_call ( struct ast_channel rchan,
struct ast_channel host 
)

Definition at line 2076 of file res_features.c.

References ast_channel_alloc(), ast_channel_masquerade(), ast_frfree, ast_hold_call(), ast_log(), ast_read(), AST_STATE_DOWN, ast_string_field_build, ast_channel::context, ast_channel::exten, f, LOG_WARNING, name, ast_channel::priority, ast_channel::readformat, and ast_channel::writeformat.

02077 {
02078    struct ast_channel *chan;
02079    struct ast_frame *f;
02080    /* Make a new, fake channel that we'll use to masquerade in the real one */
02081    chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Onhold/%s",rchan->name);
02082    if (chan) {
02083       /* Let us keep track of the channel name */
02084       ast_string_field_build(chan, name, "Onhold/%s",rchan->name);
02085       /* Make formats okay */
02086       chan->readformat = rchan->readformat;
02087       chan->writeformat = rchan->writeformat;
02088       ast_channel_masquerade(chan, rchan);
02089       /* Setup the extensions and such */
02090       strncpy(chan->context, rchan->context, sizeof(chan->context) - 1);
02091       strncpy(chan->exten, rchan->exten, sizeof(chan->exten) - 1);
02092       chan->priority = rchan->priority;
02093       /* this might be dirty, but we need to preserve the uniqueid */
02094       ast_string_field_build(chan, uniqueid, "%s",rchan->uniqueid);
02095       /* Make the masq execute */
02096       f = ast_read(chan);
02097       if (f)
02098          ast_frfree(f);
02099       ast_hold_call(chan, peer);
02100       return -1;
02101    } else {
02102       ast_log(LOG_WARNING, "Unable to create holded channel\n");
02103       return -1;
02104    }
02105    return 0;
02106 }

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

00513 {
00514    struct ast_channel *chan;
00515    struct ast_frame *f;
00516 
00517    /* Make a new, fake channel that we'll use to masquerade in the real one */
00518    if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) {
00519       ast_log(LOG_WARNING, "Unable to create parked channel\n");
00520       return -1;
00521    }
00522 
00523    /* Make formats okay */
00524    chan->readformat = rchan->readformat;
00525    chan->writeformat = rchan->writeformat;
00526    ast_channel_masquerade(chan, rchan);
00527 
00528    /* Setup the extensions and such */
00529    set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority);
00530 
00531    /* Make the masq execute */
00532    f = ast_read(chan);
00533    if (f)
00534       ast_frfree(f);
00535 
00536    ast_park_call(chan, peer, timeout, extout);
00537    return 0;
00538 }

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

References park_call_full().

Referenced by ast_masq_park_call(), builtin_blindtransfer(), builtin_parkcall(), iax_park_thread(), and sip_park_thread().

00508 {
00509    return park_call_full(chan, peer, timeout, extout, NULL);
00510 }

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

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

00215 {
00216    return parking_ext;
00217 }

int ast_pickup_call ( struct ast_channel chan  ) 

Pickup a call.

Definition at line 2918 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().

02919 {
02920    struct ast_channel *cur = NULL;
02921    int res = -1;
02922 
02923    while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
02924       if (!cur->pbx && 
02925          (cur != chan) &&
02926          (chan->pickupgroup & cur->callgroup) &&
02927          ((cur->_state == AST_STATE_RINGING) ||
02928           (cur->_state == AST_STATE_RING))) {
02929             break;
02930       }
02931       ast_channel_unlock(cur);
02932    }
02933    if (cur) {
02934       if (option_debug)
02935          ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
02936       res = ast_answer(chan);
02937       if (res)
02938          ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
02939       res = ast_queue_control(chan, AST_CONTROL_ANSWER);
02940       if (res)
02941          ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
02942       res = ast_channel_masquerade(cur, chan);
02943       if (res)
02944          ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);     /* Done */
02945       ast_channel_unlock(cur);
02946    } else   {
02947       if (option_debug)
02948          ast_log(LOG_DEBUG, "No call pickup possible...\n");
02949    }
02950    return res;
02951 }

char* ast_pickup_ext ( void   ) 

Determine system call pickup extension.

Definition at line 219 of file res_features.c.

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

00220 {
00221    return pickup_ext;
00222 }

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

Referenced by load_config().

00976 {
00977    if (!feature) {
00978       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
00979          return;
00980    }
00981   
00982    AST_LIST_LOCK(&feature_list);
00983    AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry);
00984    AST_LIST_UNLOCK(&feature_list);
00985 
00986    if (option_verbose >= 2) 
00987       ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
00988 }

int ast_retrieve_call ( struct ast_channel chan,
char *  uniqueid 
)

Definition at line 2108 of file res_features.c.

References ast_channel::_state, ast_answer(), ast_bridge_call(), ast_channel_make_compatible(), AST_FEATURE_REDIRECT, ast_get_holded_call(), ast_hangup(), ast_log(), ast_moh_stop(), ast_mutex_unlock(), AST_PBX_NO_HANGUP_PEER, ast_set_flag, AST_STATE_UP, ast_streamfile(), ast_verbose(), ast_waitstream(), ast_bridge_config::features_callee, ast_bridge_config::features_caller, LOG_WARNING, option_verbose, ast_bridge_config::play_warning, ast_bridge_config::timelimit, VERBOSE_PREFIX_3, ast_bridge_config::warning_freq, and ast_bridge_config::warning_sound.

Referenced by retrieve_call_exec().

02109 {
02110    int res=-1, dres=-1;
02111    struct ast_channel *peer=NULL;
02112    struct ast_bridge_config config;
02113 
02114    peer = ast_get_holded_call(uniqueid);
02115 
02116    /* JK02: it helps to answer the channel if not already up */
02117    if (chan->_state != AST_STATE_UP) {
02118       ast_answer(chan);
02119    }
02120 
02121    if (peer) {
02122       ast_mutex_unlock(&peer->lock);
02123       ast_moh_stop(peer);
02124       res = ast_channel_make_compatible(chan, peer);
02125       if (res < 0) {
02126          ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
02127          ast_hangup(peer);
02128          return -1;
02129       }
02130       /* This runs sorta backwards, since we give the incoming channel control, as if it
02131          were the person called. */
02132       if (option_verbose > 2) 
02133          ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to holded call %s\n", chan->name, peer->name);
02134 
02135       memset(&config,0,sizeof(struct ast_bridge_config));
02136       ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
02137       ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
02138       config.timelimit = 0;
02139       config.play_warning = 0;
02140       config.warning_freq = 0;
02141       config.warning_sound=NULL;
02142       res = ast_bridge_call(chan,peer,&config);
02143 
02144       /* Simulate the PBX hanging up */
02145       if (res != AST_PBX_NO_HANGUP_PEER)
02146          ast_hangup(peer);
02147       return res;
02148    } else {
02149       /* XXX Play a message XXX */
02150      dres = ast_streamfile(chan, "pbx-invalidpark", chan->language);
02151      if (!dres)
02152        dres = ast_waitstream(chan, "");
02153      else {
02154        ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
02155        dres = 0;
02156      }
02157    }
02158    return res;
02159 }

int ast_retrieve_call_to_death ( char *  uniqueid  ) 

Definition at line 2161 of file res_features.c.

References ast_get_holded_call(), ast_hangup(), ast_log(), ast_mutex_unlock(), ast_verbose(), ast_channel::lock, LOG_WARNING, option_verbose, and VERBOSE_PREFIX_3.

02162 {
02163    int res=-1;
02164    struct ast_channel *peer=NULL;
02165 
02166    peer = ast_get_holded_call(uniqueid);
02167 
02168    if (peer) {
02169       res=0;
02170       if (option_verbose > 2) 
02171          ast_verbose(VERBOSE_PREFIX_3 "Channel %s removed from hold.\n", peer->name);
02172       ast_mutex_unlock(&peer->lock);
02173       ast_hangup(peer);
02174    } else {
02175       ast_log(LOG_WARNING, "Could not find channel with uniqueid %s to retrieve.\n", uniqueid);
02176    }
02177    return res;
02178 }

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

References AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, and free.

00992 {
00993    if (!feature)
00994       return;
00995 
00996    AST_LIST_LOCK(&feature_list);
00997    AST_LIST_REMOVE(&feature_list,feature,feature_entry);
00998    AST_LIST_UNLOCK(&feature_list);
00999    free(feature);
01000 }


Generated on Sat Apr 12 07:12:46 2008 for Asterisk - the Open Source PBX by  doxygen 1.5.5