This graph shows which files directly or indirectly include this file:

Go to the source code of this file.
Defines | |
| #define | FEATURE_APP_ARGS_LEN 256 |
| #define | FEATURE_APP_LEN 64 |
| #define | FEATURE_EXTEN_LEN 32 |
| #define | FEATURE_MAX_LEN 11 |
| #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 | |
Definition in file features.h.
|
|
Definition at line 29 of file features.h. Referenced by load_config(). |
|
|
Definition at line 28 of file features.h. Referenced by load_config(). |
|
|
Definition at line 31 of file features.h. Referenced by load_config(). |
|
|
Definition at line 27 of file features.h. Referenced by ast_bridge_call(). |
|
|
Definition at line 30 of file features.h. Referenced by load_config(). |
|
||||||||||||||||
|
Bridge a call, optionally allowing redirection.
Definition at line 1261 of file res_features.c. References ast_channel::appl, ast_answer(), ast_cdr_appenduserfield(), ast_cdr_setuserfield(), ast_channel_bridge(), ast_channel_setoption(), ast_clear_flag, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_FLASH, AST_CONTROL_HANGUP, AST_CONTROL_OPTION, AST_CONTROL_RINGING, ast_dtmf_stream(), ast_feature_interpret(), AST_FEATURE_PLAY_WARNING, AST_FRAME_CONTROL, AST_FRAME_DTMF, ast_frfree(), ast_indicate(), ast_log(), AST_OPTION_FLAG_REQUEST, ast_strlen_zero(), ast_channel::cdr, ast_channel::data, ast_frame::data, ast_option_header::data, ast_frame::datalen, ast_bridge_config::end_sound, FEATURE_MAX_LEN, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_SUCCESS, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, ast_bridge_config::feature_timer, featuredigittimeout, 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, monitor_ok, ast_channel::name, ast_option_header::option, 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 ast_bridge_call_thread(), builtin_atxfer(), dial_exec_full(), park_exec(), and try_calling(). 01262 {
01263 /* Copy voice back and forth between the two channels. Give the peer
01264 the ability to transfer calls with '#<extension' syntax. */
01265 struct ast_frame *f;
01266 struct ast_channel *who;
01267 char chan_featurecode[FEATURE_MAX_LEN + 1]="";
01268 char peer_featurecode[FEATURE_MAX_LEN + 1]="";
01269 int res;
01270 int diff;
01271 int hasfeatures=0;
01272 int hadfeatures=0;
01273 struct ast_option_header *aoh;
01274 struct timeval start = { 0 , 0 };
01275 struct ast_bridge_config backup_config;
01276 char *monitor_exec;
01277
01278 memset(&backup_config, 0, sizeof(backup_config));
01279
01280 config->start_time = ast_tvnow();
01281
01282 if (chan && peer) {
01283 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
01284 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
01285 } else if (chan)
01286 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
01287
01288 if (monitor_ok) {
01289 if (!monitor_app) {
01290 if (!(monitor_app = pbx_findapp("Monitor")))
01291 monitor_ok=0;
01292 }
01293 if (monitor_app) {
01294 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR")))
01295 pbx_exec(chan, monitor_app, monitor_exec, 1);
01296 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
01297 pbx_exec(peer, monitor_app, monitor_exec, 1);
01298 }
01299 }
01300
01301 set_config_flags(chan, peer, config);
01302 config->firstpass = 1;
01303
01304 /* Answer if need be */
01305 if (ast_answer(chan))
01306 return -1;
01307 peer->appl = "Bridged Call";
01308 peer->data = chan->name;
01309
01310 /* copy the userfield from the B-leg to A-leg if applicable */
01311 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
01312 char tmp[256];
01313 if (!ast_strlen_zero(chan->cdr->userfield)) {
01314 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield);
01315 ast_cdr_appenduserfield(chan, tmp);
01316 } else
01317 ast_cdr_setuserfield(chan, peer->cdr->userfield);
01318 /* free the peer's cdr without ast_cdr_free complaining */
01319 free(peer->cdr);
01320 peer->cdr = NULL;
01321 }
01322 for (;;) {
01323 if (config->feature_timer)
01324 start = ast_tvnow();
01325
01326 res = ast_channel_bridge(chan, peer, config, &f, &who);
01327
01328 if (config->feature_timer) {
01329 /* Update time limit for next pass */
01330 diff = ast_tvdiff_ms(ast_tvnow(), start);
01331 config->feature_timer -= diff;
01332 if (hasfeatures) {
01333 /* Running on backup config, meaning a feature might be being
01334 activated, but that's no excuse to keep things going
01335 indefinitely! */
01336 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
01337 ast_log(LOG_DEBUG, "Timed out, realtime this time!\n");
01338 config->feature_timer = 0;
01339 who = chan;
01340 if (f)
01341 ast_frfree(f);
01342 f = NULL;
01343 res = 0;
01344 } else if (config->feature_timer <= 0) {
01345 /* Not *really* out of time, just out of time for
01346 digits to come in for features. */
01347 ast_log(LOG_DEBUG, "Timed out for feature!\n");
01348 if (!ast_strlen_zero(peer_featurecode)) {
01349 ast_dtmf_stream(chan, peer, peer_featurecode, 0);
01350 memset(peer_featurecode, 0, sizeof(peer_featurecode));
01351 }
01352 if (!ast_strlen_zero(chan_featurecode)) {
01353 ast_dtmf_stream(peer, chan, chan_featurecode, 0);
01354 memset(chan_featurecode, 0, sizeof(chan_featurecode));
01355 }
01356 if (f)
01357 ast_frfree(f);
01358 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01359 if (!hasfeatures) {
01360 /* Restore original (possibly time modified) bridge config */
01361 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01362 memset(&backup_config, 0, sizeof(backup_config));
01363 }
01364 hadfeatures = hasfeatures;
01365 /* Continue as we were */
01366 continue;
01367 }
01368 } else {
01369 if (config->feature_timer <=0) {
01370 /* We ran out of time */
01371 config->feature_timer = 0;
01372 who = chan;
01373 if (f)
01374 ast_frfree(f);
01375 f = NULL;
01376 res = 0;
01377 }
01378 }
01379 }
01380 if (res < 0) {
01381 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
01382 return -1;
01383 }
01384
01385 if (!f || ((f->frametype == AST_FRAME_CONTROL) && ((f->subclass == AST_CONTROL_HANGUP) || (f->subclass == AST_CONTROL_BUSY) ||
01386 (f->subclass == AST_CONTROL_CONGESTION)))) {
01387 res = -1;
01388 break;
01389 }
01390 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_RINGING)) {
01391 if (who == chan)
01392 ast_indicate(peer, AST_CONTROL_RINGING);
01393 else
01394 ast_indicate(chan, AST_CONTROL_RINGING);
01395 }
01396 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == -1)) {
01397 if (who == chan)
01398 ast_indicate(peer, -1);
01399 else
01400 ast_indicate(chan, -1);
01401 }
01402 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_FLASH)) {
01403 if (who == chan)
01404 ast_indicate(peer, AST_CONTROL_FLASH);
01405 else
01406 ast_indicate(chan, AST_CONTROL_FLASH);
01407 }
01408 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_OPTION)) {
01409 aoh = f->data;
01410 /* Forward option Requests */
01411 if (aoh && (aoh->flag == AST_OPTION_FLAG_REQUEST)) {
01412 if (who == chan)
01413 ast_channel_setoption(peer, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
01414 else
01415 ast_channel_setoption(chan, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
01416 }
01417 }
01418 /* check for '*', if we find it it's time to disconnect */
01419 if (f && (f->frametype == AST_FRAME_DTMF)) {
01420 char *featurecode;
01421 int sense;
01422 struct ast_channel *other;
01423
01424 hadfeatures = hasfeatures;
01425 /* This cannot overrun because the longest feature is one shorter than our buffer */
01426 if (who == chan) {
01427 other = peer;
01428 sense = FEATURE_SENSE_CHAN;
01429 featurecode = chan_featurecode;
01430 } else {
01431 other = chan;
01432 sense = FEATURE_SENSE_PEER;
01433 featurecode = peer_featurecode;
01434 }
01435 featurecode[strlen(featurecode)] = f->subclass;
01436 /* Get rid of the frame before we start doing "stuff" with the channels */
01437 ast_frfree(f);
01438 f = NULL;
01439 config->feature_timer = backup_config.feature_timer;
01440 res = ast_feature_interpret(chan, peer, config, featurecode, sense);
01441 switch(res) {
01442 case FEATURE_RETURN_PASSDIGITS:
01443 ast_dtmf_stream(other, who, featurecode, 0);
01444 /* Fall through */
01445 case FEATURE_RETURN_SUCCESS:
01446 memset(featurecode, 0, sizeof(chan_featurecode));
01447 break;
01448 }
01449 if (res >= FEATURE_RETURN_PASSDIGITS) {
01450 res = 0;
01451 } else
01452 break;
01453 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01454 if (hadfeatures && !hasfeatures) {
01455 /* Restore backup */
01456 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01457 memset(&backup_config, 0, sizeof(struct ast_bridge_config));
01458 } else if (hasfeatures) {
01459 if (!hadfeatures) {
01460 /* Backup configuration */
01461 memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
01462 /* Setup temporary config options */
01463 config->play_warning = 0;
01464 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
01465 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
01466 config->warning_freq = 0;
01467 config->warning_sound = NULL;
01468 config->end_sound = NULL;
01469 config->start_sound = NULL;
01470 config->firstpass = 0;
01471 }
01472 config->feature_timer = featuredigittimeout;
01473 ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer);
01474 }
01475 }
01476 if (f)
01477 ast_frfree(f);
01478 }
01479 return res;
01480 }
|
|
||||||||||||||||||||
|
Park a call via a masqueraded channel.
Definition at line 401 of file res_features.c. References ast_channel_alloc(), ast_channel_masquerade(), ast_frfree(), ast_log(), ast_park_call(), ast_read(), ast_channel::context, ast_channel::exten, LOG_WARNING, ast_channel::name, ast_channel::priority, ast_channel::readformat, and ast_channel::writeformat. Referenced by mgcp_ss(), parkandannounce_exec(), rpt_exec(), skinny_ss(), and ss_thread(). 00402 {
00403 struct ast_channel *chan;
00404 struct ast_frame *f;
00405
00406 /* Make a new, fake channel that we'll use to masquerade in the real one */
00407 chan = ast_channel_alloc(0);
00408 if (chan) {
00409 /* Let us keep track of the channel name */
00410 snprintf(chan->name, sizeof (chan->name), "Parked/%s",rchan->name);
00411
00412 /* Make formats okay */
00413 chan->readformat = rchan->readformat;
00414 chan->writeformat = rchan->writeformat;
00415 ast_channel_masquerade(chan, rchan);
00416
00417 /* Setup the extensions and such */
00418 ast_copy_string(chan->context, rchan->context, sizeof(chan->context));
00419 ast_copy_string(chan->exten, rchan->exten, sizeof(chan->exten));
00420 chan->priority = rchan->priority;
00421
00422 /* Make the masq execute */
00423 f = ast_read(chan);
00424 if (f)
00425 ast_frfree(f);
00426 ast_park_call(chan, peer, timeout, extout);
00427 } else {
00428 ast_log(LOG_WARNING, "Unable to create parked channel\n");
00429 return -1;
00430 }
00431 return 0;
00432 }
|
|
||||||||||||||||||||
|
Park a call and read back parked location.
Definition at line 278 of file res_features.c. References adsi_announce_park(), adsi_available(), adsi_unload_session(), adsipark, ast_channel::appl, ast_add_extension2(), ast_context_create(), ast_context_find(), AST_CONTROL_HOLD, ast_indicate(), ast_log(), AST_MAX_EXTENSION, ast_moh_start(), ast_mutex_lock(), ast_mutex_unlock(), ast_say_digits(), ast_strlen_zero(), ast_verbose(), parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, parkeduser::context, ast_channel::context, ast_channel::data, EVENT_FLAG_CALL, exten, parkeduser::exten, ast_channel::exten, free, FREE, LOG_ERROR, LOG_WARNING, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::macropriority, malloc, manager_event(), ast_channel::name, parkeduser::next, parkeduser::notquiteyet, option_verbose, parkedcall, parkfindnext, parking_con, parking_offset, parking_start, parking_stop, parking_thread, parkeduser::parkingnum, parkeduser::parkingtime, parkingtime, parkeduser::peername, parkeduser::priority, ast_channel::priority, registrar, parkeduser::start, strdup, and VERBOSE_PREFIX_2. Referenced by ast_masq_park_call(), builtin_blindtransfer(), iax_park_thread(), park_call_exec(), and sip_park_thread(). 00279 {
00280 struct parkeduser *pu, *cur;
00281 int i,x,parking_range;
00282 char exten[AST_MAX_EXTENSION];
00283 struct ast_context *con;
00284
00285 pu = malloc(sizeof(struct parkeduser));
00286 if (!pu) {
00287 ast_log(LOG_WARNING, "Out of memory\n");
00288 return -1;
00289 }
00290 memset(pu, 0, sizeof(struct parkeduser));
00291 ast_mutex_lock(&parking_lock);
00292 parking_range = parking_stop - parking_start+1;
00293 for (i = 0; i < parking_range; i++) {
00294 x = (i + parking_offset) % parking_range + parking_start;
00295 cur = parkinglot;
00296 while(cur) {
00297 if (cur->parkingnum == x)
00298 break;
00299 cur = cur->next;
00300 }
00301 if (!cur)
00302 break;
00303 }
00304
00305 if (!(i < parking_range)) {
00306 ast_log(LOG_WARNING, "No more parking spaces\n");
00307 free(pu);
00308 ast_mutex_unlock(&parking_lock);
00309 return -1;
00310 }
00311 if (parkfindnext)
00312 parking_offset = x - parking_start + 1;
00313 chan->appl = "Parked Call";
00314 chan->data = NULL;
00315
00316 pu->chan = chan;
00317 /* Start music on hold */
00318 if (chan != peer) {
00319 ast_indicate(pu->chan, AST_CONTROL_HOLD);
00320 ast_moh_start(pu->chan, NULL);
00321 }
00322 pu->start = ast_tvnow();
00323 pu->parkingnum = x;
00324 if (timeout > 0)
00325 pu->parkingtime = timeout;
00326 else
00327 pu->parkingtime = parkingtime;
00328 if (extout)
00329 *extout = x;
00330 if (peer)
00331 ast_copy_string(pu->peername, peer->name, sizeof(pu->peername));
00332
00333 /* Remember what had been dialed, so that if the parking
00334 expires, we try to come back to the same place */
00335 if (!ast_strlen_zero(chan->macrocontext))
00336 ast_copy_string(pu->context, chan->macrocontext, sizeof(pu->context));
00337 else
00338 ast_copy_string(pu->context, chan->context, sizeof(pu->context));
00339 if (!ast_strlen_zero(chan->macroexten))
00340 ast_copy_string(pu->exten, chan->macroexten, sizeof(pu->exten));
00341 else
00342 ast_copy_string(pu->exten, chan->exten, sizeof(pu->exten));
00343 if (chan->macropriority)
00344 pu->priority = chan->macropriority;
00345 else
00346 pu->priority = chan->priority;
00347 pu->next = parkinglot;
00348 parkinglot = pu;
00349 /* If parking a channel directly, don't quiet yet get parking running on it */
00350 if (peer == chan)
00351 pu->notquiteyet = 1;
00352 ast_mutex_unlock(&parking_lock);
00353 /* Wake up the (presumably select()ing) thread */
00354 pthread_kill(parking_thread, SIGURG);
00355 if (option_verbose > 1)
00356 ast_verbose(VERBOSE_PREFIX_2 "Parked %s on %d. Will timeout back to extension [%s] %s, %d in %d seconds\n", pu->chan->name, pu->parkingnum, pu->context, pu->exten, pu->priority, (pu->parkingtime/1000));
00357
00358 manager_event(EVENT_FLAG_CALL, "ParkedCall",
00359 "Exten: %d\r\n"
00360 "Channel: %s\r\n"
00361 "From: %s\r\n"
00362 "Timeout: %ld\r\n"
00363 "CallerID: %s\r\n"
00364 "CallerIDName: %s\r\n"
00365 ,pu->parkingnum, pu->chan->name, peer ? peer->name : ""
00366 ,(long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL)
00367 ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
00368 ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
00369 );
00370
00371 if (peer) {
00372 if (adsipark && adsi_available(peer)) {
00373 adsi_announce_park(peer, pu->parkingnum);
00374 }
00375 if (adsipark && adsi_available(peer)) {
00376 adsi_unload_session(peer);
00377 }
00378 }
00379 con = ast_context_find(parking_con);
00380 if (!con) {
00381 con = ast_context_create(NULL, parking_con, registrar);
00382 if (!con) {
00383 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
00384 }
00385 }
00386 if (con) {
00387 snprintf(exten, sizeof(exten), "%d", x);
00388 ast_add_extension2(con, 1, exten, 1, NULL, NULL, parkedcall, strdup(exten), FREE, registrar);
00389 }
00390 if (peer)
00391 ast_say_digits(peer, pu->parkingnum, "", peer->language);
00392 if (pu->notquiteyet) {
00393 /* Wake up parking thread if we're really done */
00394 ast_moh_start(pu->chan, NULL);
00395 pu->notquiteyet = 0;
00396 pthread_kill(parking_thread, SIGURG);
00397 }
00398 return 0;
00399 }
|
|
|
Determine system parking extension Returns the call parking extension for drivers that provide special call parking help.
Definition at line 163 of file res_features.c. References parking_ext. Referenced by builtin_blindtransfer(), dp_lookup(), get_refer_info(), handle_request_refer(), load_config(), mgcp_ss(), skinny_ss(), socket_read(), and ss_thread(). 00164 {
00165 return parking_ext;
00166 }
|
|
|
Pickup a call.
Definition at line 1926 of file res_features.c. References ast_channel::_state, ast_answer(), ast_channel_masquerade(), ast_channel_walk_locked(), AST_CONTROL_ANSWER, ast_log(), ast_mutex_unlock(), ast_queue_control(), AST_STATE_RING, AST_STATE_RINGING, ast_channel::callgroup, ast_channel::lock, LOG_DEBUG, LOG_WARNING, ast_channel::name, option_debug, ast_channel::pbx, and ast_channel::pickupgroup. Referenced by cb_events(), handle_request_invite(), mgcp_ss(), monitor_handle_notowned(), skinny_ss(), and ss_thread(). 01927 {
01928 struct ast_channel *cur = NULL;
01929 int res = -1;
01930
01931 while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
01932 if (!cur->pbx &&
01933 (cur != chan) &&
01934 (chan->pickupgroup & cur->callgroup) &&
01935 ((cur->_state == AST_STATE_RINGING) ||
01936 (cur->_state == AST_STATE_RING))) {
01937 break;
01938 }
01939 ast_mutex_unlock(&cur->lock);
01940 }
01941 if (cur) {
01942 if (option_debug)
01943 ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
01944 res = ast_answer(chan);
01945 if (res)
01946 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
01947 res = ast_queue_control(chan, AST_CONTROL_ANSWER);
01948 if (res)
01949 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
01950 res = ast_channel_masquerade(cur, chan);
01951 if (res)
01952 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */
01953 ast_mutex_unlock(&cur->lock);
01954 } else {
01955 if (option_debug)
01956 ast_log(LOG_DEBUG, "No call pickup possible...\n");
01957 }
01958 return res;
01959 }
|
|
|
Determine system call pickup extension.
Definition at line 168 of file res_features.c. References pickup_ext. Referenced by cb_events(), get_destination(), handle_request_invite(), handle_showfeatures(), mgcp_ss(), monitor_handle_notowned(), skinny_ss(), and ss_thread(). 00169 {
00170 return pickup_ext;
00171 }
|
|
|
register new feature into feature_set
Definition at line 872 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(). 00873 {
00874 if (!feature) {
00875 ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
00876 return;
00877 }
00878
00879 AST_LIST_LOCK(&feature_list);
00880 AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry);
00881 AST_LIST_UNLOCK(&feature_list);
00882
00883 if (option_verbose >= 2)
00884 ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
00885 }
|
|
|
unregister feature from feature_set
Definition at line 888 of file res_features.c. References AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, and free. 00889 {
00890 if (!feature) return;
00891
00892 AST_LIST_LOCK(&feature_list);
00893 AST_LIST_REMOVE(&feature_list,feature,feature_entry);
00894 AST_LIST_UNLOCK(&feature_list);
00895 free(feature);
00896 }
|
1.4.2