Thu Oct 8 21:57:48 2009

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

02759 {
02760    /* We put the user in the parking list, then wake up the parking thread to be sure it looks
02761       after these channels too */
02762    struct ast_context *con;
02763    char exten[AST_MAX_EXTENSION];
02764    struct aauser *pu,*pl = NULL;
02765    char *s, *stringp, *aacontext, *aaexten = NULL;
02766 
02767    s = ast_strdupa((void *) data);
02768    stringp=s;
02769    aacontext = strsep(&stringp, "|");
02770    aaexten = strsep(&stringp, "|");
02771    if (!aaexten) {
02772        aaexten = aacontext;
02773        aacontext = NULL;
02774    }
02775    if (!aaexten) {
02776       ast_log(LOG_WARNING, "AutoanswerLogin requires at least an extension!\n");
02777       return -1;
02778    } else {
02779       if (!aacontext) {
02780          aacontext = "default";
02781       }
02782    }
02783 
02784    ast_mutex_lock(&autoanswer_lock);
02785    pu = aalot;
02786    while(pu) {
02787       if ((!strncasecmp(pu->exten, aaexten, sizeof(pu->exten)-1)) && (!strncasecmp(pu->context, aacontext, sizeof(pu->context)-1))){
02788          if (pl)
02789             pl->next = pu->next;
02790          else
02791             aalot = pu->next;
02792          break;
02793       }
02794       pl = pu;
02795       pu = pu->next;
02796    }
02797    ast_mutex_unlock(&autoanswer_lock);
02798    if (pu) {
02799        ast_log(LOG_NOTICE, "Logout old Channel %s for %s@%s.\n",pu->chan->name, pu->exten, pu->context);
02800        manager_event(EVENT_FLAG_CALL, "AutoanswerLogout",
02801                                "Channel: %s\r\n"
02802                                "Uniqueid: %s\r\n"
02803                                "Context: %s\r\n"
02804                                "Exten: %s\r\n"
02805                            ,pu->chan->name, pu->chan->uniqueid, pu->context, pu->exten);
02806        ast_hangup(pu->chan);
02807        free(pu);
02808    }
02809    pu = malloc(sizeof(struct aauser));
02810    if (pu) {
02811       memset(pu, 0, sizeof(pu));
02812       ast_mutex_lock(&autoanswer_lock);
02813       chan->appl = "Autoanswer";
02814       chan->data = NULL;
02815 
02816       pu->chan = chan;
02817       if (chan->_state != AST_STATE_UP) {
02818           ast_answer(chan);
02819       }
02820 
02821       /* Start music on hold */
02822       ast_moh_start(pu->chan, NULL, NULL);
02823       gettimeofday(&pu->start, NULL);
02824       strncpy(pu->exten, aaexten, sizeof(pu->exten)-1);
02825       strncpy(pu->context, aacontext, sizeof(pu->exten)-1);
02826       pu->next = aalot;
02827       aalot = pu;
02828       con = ast_context_find(aacontext);
02829       if (!con) {
02830          con = ast_context_create(NULL,aacontext, registrar);
02831          if (!con) {
02832             ast_log(LOG_ERROR, "Context '%s' does not exist and unable to create\n", aacontext);
02833          }
02834       }
02835       if (con) {
02836          snprintf(exten, sizeof(exten), "%s", aaexten);
02837          ast_add_extension2(con, 1, exten, 1, NULL, NULL, autoanswer, strdup((char *)data), free, registrar);
02838       }
02839 
02840       ast_mutex_unlock(&autoanswer_lock);
02841       /* Wake up the (presumably select()ing) thread */
02842       pthread_kill(autoanswer_thread, SIGURG);
02843       if (option_verbose > 1)
02844          ast_verbose(VERBOSE_PREFIX_2 "Autoanswer login from %s for %s@%s.\n", pu->chan->name, pu->exten, pu->context);
02845          manager_event(EVENT_FLAG_CALL, "AutoanswerLogin",
02846                                 "Channel: %s\r\n"
02847                                 "Uniqueid: %s\r\n"
02848                "Context: %s\r\n"
02849                         "Exten: %s\r\n"
02850                         ,pu->chan->name, pu->chan->uniqueid, pu->context, pu->exten);
02851 
02852          return 0;
02853    } else {
02854       ast_log(LOG_WARNING, "Out of memory\n");
02855       return -1;
02856    }
02857    return 0;
02858 }

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 1437 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_lock, ast_channel_setoption(), ast_channel_unlock, 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(), bridge_exec(), builtin_atxfer(), park_exec(), and try_calling().

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

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

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

02244 {
02245    int res=-1;
02246    struct ast_channel *peer=NULL;
02247    struct holdeduser *pu, *pl=NULL;
02248 
02249    ast_mutex_lock(&holding_lock);
02250    pu = holdlist;
02251    while(pu) {
02252       if (!strncmp(uniqueid,pu->uniqueid,sizeof(pu->uniqueid))) {
02253          if (pl)
02254             pl->next = pu->next;
02255          else
02256             holdlist = pu->next;
02257          break;
02258       }
02259       pl = pu;
02260       pu = pu->next;
02261    }
02262    ast_mutex_unlock(&holding_lock);
02263    if (pu) {
02264       peer = ast_get_channel_by_uniqueid_locked(pu->uniqueid);
02265       free(pu);
02266       if (peer) {
02267           res=0;
02268           if (option_verbose > 2)
02269          ast_verbose(VERBOSE_PREFIX_3 "Channel %s removed from hold.\n", peer->name);
02270           ast_moh_stop(peer);
02271           return peer;
02272       } else {
02273           if (option_verbose > 2)
02274          ast_verbose(VERBOSE_PREFIX_3 "Could not find channel with uniqueid %s.\n", uniqueid);
02275           return NULL;
02276       }
02277    } else {
02278       ast_log(LOG_WARNING, "Could not find held channel with uniqueid %s to retrieve.\n", uniqueid);
02279    }
02280    return NULL;
02281 }

int ast_hold_call ( struct ast_channel chan,
struct ast_channel host 
)

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

02102 {
02103    /* We put the user in the parking list, then wake up the parking thread to be sure it looks
02104       after these channels too */
02105    struct holdeduser *pu;
02106    pu = malloc(sizeof(struct holdeduser));
02107    if (pu) {
02108       memset(pu, 0, sizeof(pu));
02109       ast_mutex_lock(&holding_lock);
02110       chan->appl = "Holded Call";
02111       chan->data = NULL;
02112 
02113       pu->chan = chan;
02114       strncpy(pu->uniqueid, chan->uniqueid, sizeof(pu->uniqueid));
02115       strncpy(pu->uniqueidpeer, peer->uniqueid, sizeof(pu->uniqueidpeer));
02116       /* Start music on hold */
02117       ast_moh_start(pu->chan, NULL, NULL);
02118       gettimeofday(&pu->start, NULL);
02119       pu->next = holdlist;
02120       holdlist = pu;
02121       ast_mutex_unlock(&holding_lock);
02122       /* Wake up the (presumably select()ing) thread */
02123       pthread_kill(holding_thread, SIGURG);
02124 
02125       manager_event(EVENT_FLAG_CALL, "HoldedCall",
02126                          "Channel1: %s\r\n"
02127                          "Channel2: %s\r\n"
02128                       "Uniqueid1: %s\r\n"
02129                       "Uniqueid2: %s\r\n"
02130                              ,pu->chan->name, peer->name, pu->chan->uniqueid, peer->uniqueid);
02131 
02132    } else {
02133       ast_log(LOG_WARNING, "Out of memory\n");
02134       return -1;
02135    }
02136    return 0;
02137 }

int ast_masq_autoanswer_login ( struct ast_channel rchan,
void *  data 
)

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

02713 {
02714    struct ast_channel *chan;
02715    struct ast_frame *f;
02716    /* Make a new, fake channel that we'll use to masquerade in the real one */
02717    chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Autoanswer/%s", rchan->name);
02718    if (chan) {
02719       /* Let us keep track of the channel name */
02720       ast_string_field_build(chan, name, "Autoanswer/%s",rchan->name);
02721       /* Make formats okay */
02722       chan->readformat = rchan->readformat;
02723       chan->writeformat = rchan->writeformat;
02724       ast_channel_masquerade(chan, rchan);
02725       /* Setup the extensions and such */
02726       strncpy(chan->context, rchan->context, sizeof(chan->context) - 1);
02727       strncpy(chan->exten, rchan->exten, sizeof(chan->exten) - 1);
02728       chan->priority = rchan->priority;
02729       /* might be dirty but we want trackable channels */
02730       ast_string_field_build(chan, uniqueid, "%s",rchan->uniqueid);
02731       /* Make the masq execute */
02732       f = ast_read(chan);
02733       if (f)
02734          ast_frfree(f);
02735       ast_autoanswer_login(chan, data);
02736    } else {
02737       ast_log(LOG_WARNING, "Unable to create aa channel\n");
02738       return -1;
02739    }
02740    return 0;
02741 }

int ast_masq_hold_call ( struct ast_channel rchan,
struct ast_channel host 
)

Definition at line 2139 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.

02140 {
02141    struct ast_channel *chan;
02142    struct ast_frame *f;
02143    /* Make a new, fake channel that we'll use to masquerade in the real one */
02144    chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Onhold/%s",rchan->name);
02145    if (chan) {
02146       /* Let us keep track of the channel name */
02147       ast_string_field_build(chan, name, "Onhold/%s",rchan->name);
02148       /* Make formats okay */
02149       chan->readformat = rchan->readformat;
02150       chan->writeformat = rchan->writeformat;
02151       ast_channel_masquerade(chan, rchan);
02152       /* Setup the extensions and such */
02153       strncpy(chan->context, rchan->context, sizeof(chan->context) - 1);
02154       strncpy(chan->exten, rchan->exten, sizeof(chan->exten) - 1);
02155       chan->priority = rchan->priority;
02156       /* this might be dirty, but we need to preserve the uniqueid */
02157       ast_string_field_build(chan, uniqueid, "%s",rchan->uniqueid);
02158       /* Make the masq execute */
02159       f = ast_read(chan);
02160       if (f)
02161          ast_frfree(f);
02162       ast_hold_call(chan, peer);
02163       return -1;
02164    } else {
02165       ast_log(LOG_WARNING, "Unable to create holded channel\n");
02166       return -1;
02167    }
02168    return 0;
02169 }

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

References ast_channel::amaflags, ast_channel_alloc(), ast_channel_masquerade(), ast_frfree, ast_log(), ast_read(), AST_STATE_DOWN, ast_strdupa, ast_channel::context, ast_channel::exten, f, LOG_WARNING, park_call_full(), 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().

00539 {
00540    struct ast_channel *chan;
00541    struct ast_frame *f;
00542    char *orig_chan_name = NULL;
00543 
00544    /* Make a new, fake channel that we'll use to masquerade in the real one */
00545    if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) {
00546       ast_log(LOG_WARNING, "Unable to create parked channel\n");
00547       return -1;
00548    }
00549 
00550    /* Make formats okay */
00551    chan->readformat = rchan->readformat;
00552    chan->writeformat = rchan->writeformat;
00553    ast_channel_masquerade(chan, rchan);
00554 
00555    /* Setup the extensions and such */
00556    set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority);
00557 
00558    /* Make the masq execute */
00559    f = ast_read(chan);
00560    if (f)
00561       ast_frfree(f);
00562 
00563    orig_chan_name = ast_strdupa(chan->name);
00564 
00565    park_call_full(chan, peer, timeout, extout, orig_chan_name);
00566 
00567    return 0;
00568 }

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

References park_call_full().

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

00534 {
00535    return park_call_full(chan, peer, timeout, extout, NULL);
00536 }

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

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

00219 {
00220    return parking_ext;
00221 }

int ast_pickup_call ( struct ast_channel chan  ) 

Pickup a call.

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

03101 {
03102    struct ast_channel *cur = NULL;
03103    int res = -1;
03104 
03105    while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
03106       if (!cur->pbx && 
03107          (cur != chan) &&
03108          (chan->pickupgroup & cur->callgroup) &&
03109          ((cur->_state == AST_STATE_RINGING) ||
03110           (cur->_state == AST_STATE_RING))) {
03111             break;
03112       }
03113       ast_channel_unlock(cur);
03114    }
03115    if (cur) {
03116       if (option_debug)
03117          ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
03118       res = ast_answer(chan);
03119       if (res)
03120          ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
03121       res = ast_queue_control(chan, AST_CONTROL_ANSWER);
03122       if (res)
03123          ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
03124       res = ast_channel_masquerade(cur, chan);
03125       if (res)
03126          ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);     /* Done */
03127       ast_channel_unlock(cur);
03128    } else   {
03129       if (option_debug)
03130          ast_log(LOG_DEBUG, "No call pickup possible...\n");
03131    }
03132    return res;
03133 }

char* ast_pickup_ext ( void   ) 

Determine system call pickup extension.

Definition at line 223 of file res_features.c.

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

00224 {
00225    return pickup_ext;
00226 }

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

01007 {
01008    if (!feature) {
01009       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
01010          return;
01011    }
01012   
01013    AST_LIST_LOCK(&feature_list);
01014    AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry);
01015    AST_LIST_UNLOCK(&feature_list);
01016 
01017    if (option_verbose >= 2) 
01018       ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
01019 }

int ast_retrieve_call ( struct ast_channel chan,
char *  uniqueid 
)

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

02172 {
02173    int res=-1, dres=-1;
02174    struct ast_channel *peer=NULL;
02175    struct ast_bridge_config config;
02176 
02177    peer = ast_get_holded_call(uniqueid);
02178 
02179    /* JK02: it helps to answer the channel if not already up */
02180    if (chan->_state != AST_STATE_UP) {
02181       ast_answer(chan);
02182    }
02183 
02184    if (peer) {
02185       ast_mutex_unlock(&peer->lock);
02186       ast_moh_stop(peer);
02187       res = ast_channel_make_compatible(chan, peer);
02188       if (res < 0) {
02189          ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
02190          ast_hangup(peer);
02191          return -1;
02192       }
02193       /* This runs sorta backwards, since we give the incoming channel control, as if it
02194          were the person called. */
02195       if (option_verbose > 2)
02196          ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to holded call %s\n", chan->name, peer->name);
02197 
02198       memset(&config,0,sizeof(struct ast_bridge_config));
02199       ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
02200       ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
02201       config.timelimit = 0;
02202       config.play_warning = 0;
02203       config.warning_freq = 0;
02204       config.warning_sound=NULL;
02205       res = ast_bridge_call(chan,peer,&config);
02206 
02207       /* Simulate the PBX hanging up */
02208       if (res != AST_PBX_NO_HANGUP_PEER)
02209          ast_hangup(peer);
02210       return res;
02211    } else {
02212       /* XXX Play a message XXX */
02213      dres = ast_streamfile(chan, "pbx-invalidpark", chan->language);
02214      if (!dres)
02215        dres = ast_waitstream(chan, "");
02216      else {
02217        ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
02218        dres = 0;
02219      }
02220    }
02221    return res;
02222 }

int ast_retrieve_call_to_death ( char *  uniqueid  ) 

Definition at line 2224 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.

02225 {
02226    int res=-1;
02227    struct ast_channel *peer=NULL;
02228 
02229    peer = ast_get_holded_call(uniqueid);
02230 
02231    if (peer) {
02232       res=0;
02233       if (option_verbose > 2)
02234          ast_verbose(VERBOSE_PREFIX_3 "Channel %s removed from hold.\n", peer->name);
02235       ast_mutex_unlock(&peer->lock);
02236       ast_hangup(peer);
02237    } else {
02238       ast_log(LOG_WARNING, "Could not find channel with uniqueid %s to retrieve.\n", uniqueid);
02239    }
02240    return res;
02241 }

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

References AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, and free.

01023 {
01024    if (!feature)
01025       return;
01026 
01027    AST_LIST_LOCK(&feature_list);
01028    AST_LIST_REMOVE(&feature_list,feature,feature_entry);
01029    AST_LIST_UNLOCK(&feature_list);
01030    free(feature);
01031 }


Generated on Thu Oct 8 21:57:48 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.8