static int find_channel_by_group(void *obj, void *arg, void *data, int flags) { struct ast_channel *target = obj;/*!< Potential pickup target */ struct ast_channel *chan = data;/*!< Channel wanting to pickup call */ ast_channel_lock(target); if (chan != target && (ast_channel_pickupgroup(chan) & ast_channel_callgroup(target)) && ast_can_pickup(target)) { /* Return with the channel still locked on purpose */ return CMP_MATCH | CMP_STOP; } ast_channel_unlock(target); return 0; }
/* Attempt to pick up specified by partial channel name */ static int pickup_by_part(struct ast_channel *chan, const char *part) { struct ast_channel *target;/*!< Potential pickup target */ int res = -1; /* The found channel is already locked. */ target = ast_channel_callback(find_by_part, NULL, (char *) part, 0); if (target) { res = ast_do_pickup(chan, target); ast_channel_unlock(target); target = ast_channel_unref(target); } return res; }
/*! * \brief after bridge callback for the dial bridge * * The only purpose of this callback is to ensure that the control structure's * bridge pointer is NULLed */ static void dial_bridge_after_cb(struct ast_channel *chan, void *data) { struct stasis_app_control *control = data; struct ast_bridge_channel *bridge_channel; ast_channel_lock(chan); bridge_channel = ast_channel_get_bridge_channel(chan); ast_channel_unlock(chan); ast_debug(3, "Channel: <%s> Reason: %d\n", ast_channel_name(control->channel), ast_channel_hangupcause(chan)); stasis_app_send_command_async(control, bridge_channel_depart, bridge_channel, __ao2_cleanup); control->bridge = NULL; }
static int speex_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) { struct ast_datastore *datastore = NULL; struct speex_info *si = NULL; struct speex_direction_info *sdi = NULL; if (!chan) { ast_log(LOG_ERROR, "%s cannot be used without a channel!\n", cmd); return -1; } ast_channel_lock(chan); if (!(datastore = ast_channel_datastore_find(chan, &speex_datastore, NULL))) { ast_channel_unlock(chan); return -1; } ast_channel_unlock(chan); si = datastore->data; if (!strcasecmp(data, "tx")) sdi = si->tx; else if (!strcasecmp(data, "rx")) sdi = si->rx; else { ast_log(LOG_ERROR, "%s(%s) must either \"tx\" or \"rx\"\n", cmd, data); return -1; } if (!strcasecmp(cmd, "agc")) snprintf(buf, len, "%.01f", sdi ? sdi->agclevel : 0.0); else snprintf(buf, len, "%d", sdi ? sdi->denoise : 0); return 0; }
/*! \brief The callback from the audiohook subsystem. We basically get a frame to have fun with */ static int mute_callback(struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction) { struct ast_datastore *datastore = NULL; struct mute_information *mute = NULL; /* If the audiohook is stopping it means the channel is shutting down.... but we let the datastore destroy take care of it */ if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE) { return 0; } ast_channel_lock(chan); /* Grab datastore which contains our mute information */ if (!(datastore = ast_channel_datastore_find(chan, &mute_datastore, NULL))) { ast_channel_unlock(chan); ast_debug(2, "Can't find any datastore to use. Bad. \n"); return 0; } mute = datastore->data; /* If this is audio then allow them to increase/decrease the gains */ if (frame->frametype == AST_FRAME_VOICE) { ast_debug(2, "Audio frame - direction %s mute READ %s WRITE %s\n", direction == AST_AUDIOHOOK_DIRECTION_READ ? "read" : "write", mute->mute_read ? "on" : "off", mute->mute_write ? "on" : "off"); /* Based on direction of frame grab the gain, and confirm it is applicable */ if ((direction == AST_AUDIOHOOK_DIRECTION_READ && mute->mute_read) || (direction == AST_AUDIOHOOK_DIRECTION_WRITE && mute->mute_write)) { /* Ok, we just want to reset all audio in this frame. Keep NOTHING, thanks. */ ast_frame_clear(frame); } } ast_channel_unlock(chan); return 0; }
static struct chanspy_ds *next_channel(struct ast_channel *chan, const struct ast_channel *last, const char *spec, const char *exten, const char *context, struct chanspy_ds *chanspy_ds) { struct ast_channel *this; char channel_name[AST_CHANNEL_NAME]; static size_t PSEUDO_CHAN_LEN = 0; if (!PSEUDO_CHAN_LEN) { PSEUDO_CHAN_LEN = *dahdi_chan_name_len + strlen("/pseudo"); } redo: if (spec) this = ast_walk_channel_by_name_prefix_locked(last, spec, strlen(spec)); else if (exten) this = ast_walk_channel_by_exten_locked(last, exten, context); else this = ast_channel_walk_locked(last); if (!this) return NULL; snprintf(channel_name, AST_CHANNEL_NAME, "%s/pseudo", dahdi_chan_name); if (!strncmp(this->name, channel_name, PSEUDO_CHAN_LEN)) { last = this; ast_channel_unlock(this); goto redo; } else if (this == chan) { last = this; ast_channel_unlock(this); goto redo; } return setup_chanspy_ds(this, chanspy_ds); }
static int bridgeadd_exec(struct ast_channel *chan, const char *data) { struct ast_channel *c_ref; struct ast_bridge_features chan_features; struct ast_bridge *bridge; char *c_name; /* Answer the channel if needed */ if (ast_channel_state(chan) != AST_STATE_UP) { ast_answer(chan); } if (!(c_ref = ast_channel_get_by_name_prefix(data, strlen(data)))) { ast_log(LOG_WARNING, "Channel %s not found\n", data); return -1; } c_name = ast_strdupa(ast_channel_name(c_ref)); ast_channel_lock(c_ref); bridge = ast_channel_get_bridge(c_ref); ast_channel_unlock(c_ref); ast_channel_unref(c_ref); if (!bridge) { ast_log(LOG_WARNING, "Channel %s is not in a bridge\n", c_name); return -1; } ast_verb(3, "%s is joining %s in bridge %s\n", ast_channel_name(chan), c_name, bridge->uniqueid); if (ast_bridge_features_init(&chan_features) || ast_bridge_join(bridge, chan, NULL, &chan_features, NULL, 0)) { ast_log(LOG_WARNING, "%s failed to join %s in bridge %s\n", ast_channel_name(chan), c_name, bridge->uniqueid); ast_bridge_features_cleanup(&chan_features); ao2_cleanup(bridge); return -1; } ast_bridge_features_cleanup(&chan_features); ao2_cleanup(bridge); return 0; }
static int find_by_mark(void *obj, void *arg, void *data, int flags) { struct ast_channel *target = obj;/*!< Potential pickup target */ const char *mark = data; const char *tmp; ast_channel_lock(target); tmp = pbx_builtin_getvar_helper(target, PICKUPMARK); if (tmp && !strcasecmp(tmp, mark) && ast_can_pickup(target)) { /* Return with the channel still locked on purpose */ return CMP_MATCH | CMP_STOP; } ast_channel_unlock(target); return 0; }
static int pickup_by_group(struct ast_channel *chan) { struct ast_channel *target;/*!< Potential pickup target */ int res = -1; /* The found channel is already locked. */ target = ast_pickup_find_by_group(chan); if (target) { ast_log(LOG_NOTICE, "pickup %s attempt by %s\n", ast_channel_name(target), ast_channel_name(chan)); res = ast_do_pickup(chan, target); ast_channel_unlock(target); target = ast_channel_unref(target); } return res; }
/* Find channel for pick up specified by partial channel name */ static int find_by_part(void *obj, void *arg, void *data, int flags) { struct ast_channel *target = obj;/*!< Potential pickup target */ const char *part = data; int len = strlen(part); ast_channel_lock(target); if (len <= strlen(ast_channel_name(target)) && !strncmp(ast_channel_name(target), part, len) && ast_can_pickup(target)) { /* Return with the channel still locked on purpose */ return CMP_MATCH | CMP_STOP; } ast_channel_unlock(target); return 0; }
/*! \brief possibly uninitialize the video console. * Called at the end of a call, should reset the 'owner' field, * then possibly terminate the video thread if the gui has * not been started manually. * In practice, signal the thread and give it a bit of time to * complete, giving up if it gets stuck. Because uninit * is called from hangup with the channel locked, and the thread * uses the chan lock, we need to unlock here. This is unsafe, * and we should really use refcounts for the channels. */ void console_video_uninit(struct video_desc *env) { int i, t = 100; /* initial wait is shorter, than make it longer */ if (env->stayopen == 0) { /* in a call */ env->shutdown = 1; for (i=0; env->shutdown && i < 10; i++) { if (env->owner) ast_channel_unlock(env->owner); usleep(t); t = 1000000; if (env->owner) ast_channel_lock(env->owner); } } env->owner = NULL; /* this is unconditional */ }
static char *handle_redirect(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { const char *name, *dest; struct ast_channel *chan; int res; switch (cmd) { case CLI_INIT: e->command = "channel redirect"; e->usage = "" "Usage: channel redirect <channel> <[[context,]exten,]priority>\n" " Redirect an active channel to a specified extension.\n"; /*! \todo It would be nice to be able to redirect 2 channels at the same * time like you can with AMI redirect. However, it is not possible to acquire * two channels without the potential for a deadlock with how ast_channel structs * are managed today. Once ast_channel is a refcounted object, this command * will be able to support that. */ return NULL; case CLI_GENERATE: return ast_complete_channels(a->line, a->word, a->pos, a->n, 2); } if (a->argc != e->args + 2) { return CLI_SHOWUSAGE; } name = a->argv[2]; dest = a->argv[3]; chan = ast_get_channel_by_name_locked(name); if (!chan) { ast_cli(a->fd, "Channel '%s' not found\n", name); return CLI_FAILURE; } res = ast_async_parseable_goto(chan, dest); ast_channel_unlock(chan); if (!res) { ast_cli(a->fd, "Channel '%s' successfully redirected to %s\n", name, dest); } else { ast_cli(a->fd, "Channel '%s' failed to be redirected to %s\n", name, dest); } return res ? CLI_FAILURE : CLI_SUCCESS; }
static void limits_interval_playback(struct ast_bridge_channel *bridge_channel, struct ast_bridge_features_limits *limits, const char *file) { if (!strcasecmp(file, "timeleft")) { unsigned int remaining = ast_tvdiff_ms(limits->quitting_time, ast_tvnow()) / 1000; unsigned int min; unsigned int sec; if (remaining <= 0) { return; } if ((remaining / 60) > 1) { min = remaining / 60; sec = remaining % 60; } else { min = 0; sec = remaining; } ast_stream_and_wait(bridge_channel->chan, "vm-youhave", AST_DIGIT_NONE); if (min) { ast_say_number(bridge_channel->chan, min, AST_DIGIT_NONE, ast_channel_language(bridge_channel->chan), NULL); ast_stream_and_wait(bridge_channel->chan, "queue-minutes", AST_DIGIT_NONE); } if (sec) { ast_say_number(bridge_channel->chan, sec, AST_DIGIT_NONE, ast_channel_language(bridge_channel->chan), NULL); ast_stream_and_wait(bridge_channel->chan, "queue-seconds", AST_DIGIT_NONE); } } else { ast_stream_and_wait(bridge_channel->chan, file, AST_DIGIT_NONE); } /* * It may be necessary to resume music on hold after we finish * playing the announcment. */ if (ast_test_flag(ast_channel_flags(bridge_channel->chan), AST_FLAG_MOH)) { const char *latest_musicclass; ast_channel_lock(bridge_channel->chan); latest_musicclass = ast_strdupa(ast_channel_latest_musicclass(bridge_channel->chan)); ast_channel_unlock(bridge_channel->chan); ast_moh_start(bridge_channel->chan, latest_musicclass, NULL); } }
/*! \brief Attempt to pick up named channel, does not use context */ static int pickup_by_channel(struct ast_channel *chan, char *pickup) { int res = -1; struct ast_channel *target;/*!< Potential pickup target */ target = my_ast_get_channel_by_name_locked(pickup); if (target) { /* Just check that we are not picking up the SAME as target. (i.e. ourself) */ if (chan != target) { res = ast_do_pickup(chan, target); } ast_channel_unlock(target); target = ast_channel_unref(target); } return res; }
static void manager_park_bridged(struct mansession *s, const struct message *m, struct ast_channel *chan, struct ast_channel *parker_chan, const char *parkinglot, int timeout_override) { struct ast_bridge_channel *bridge_channel; char *app_data; if (timeout_override != -1) { if (ast_asprintf(&app_data, "%s,t(%d)", parkinglot, timeout_override) == -1) { astman_send_error(s, m, "Park action failed\n"); return; } } else { if (ast_asprintf(&app_data, "%s", parkinglot) == -1) { astman_send_error(s, m, "Park action failed\n"); return; } } ast_channel_lock(parker_chan); bridge_channel = ast_channel_get_bridge_channel(parker_chan); ast_channel_unlock(parker_chan); if (!bridge_channel) { ast_free(app_data); astman_send_error(s, m, "Park action failed\n"); return; } /* Subscribe to park messages for the channel being parked */ if (create_parked_subscription(parker_chan, ast_channel_uniqueid(chan), 1)) { ast_free(app_data); astman_send_error(s, m, "Park action failed\n"); ao2_cleanup(bridge_channel); return; } ast_bridge_channel_write_park(bridge_channel, ast_channel_uniqueid(chan), ast_channel_uniqueid(parker_chan), app_data); ast_free(app_data); astman_send_ack(s, m, "Park successful\n"); ao2_cleanup(bridge_channel); }
static int start_spying(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook) { int res = 0; ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan_name, ast_channel_name(autochan->chan)); ast_set_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC | AST_AUDIOHOOK_SMALL_QUEUE); res = ast_audiohook_attach(autochan->chan, audiohook); if (!res) { ast_channel_lock(autochan->chan); if (ast_channel_is_bridged(autochan->chan)) { ast_softhangup_nolock(autochan->chan, AST_SOFTHANGUP_UNBRIDGE); } ast_channel_unlock(autochan->chan); } return res; }
int ast_pbx_hangup_handler_pop(struct ast_channel *chan) { struct ast_hangup_handler_list *handlers; struct ast_hangup_handler *h_handler; ast_channel_lock(chan); handlers = ast_channel_hangup_handlers(chan); h_handler = AST_LIST_REMOVE_HEAD(handlers, node); if (h_handler) { publish_hangup_handler_message("pop", chan, h_handler->args); } ast_channel_unlock(chan); if (h_handler) { ast_free(h_handler); return 1; } return 0; }
/*! * \internal * \brief Session supplement callback for outgoing INVITE requests * * On all INVITEs (initial and reinvite) we may add other identity headers * such as P-Asserted-Identity and Remote-Party-ID based on configuration * and privacy settings * * \param session The session on which the INVITE will be sent * \param tdata The outbound INVITE request */ static void caller_id_outgoing_request(struct ast_sip_session *session, pjsip_tx_data *tdata) { struct ast_party_id effective_id; struct ast_party_id connected_id; if (!session->channel) { return; } ast_party_id_init(&connected_id); ast_channel_lock(session->channel); effective_id = ast_channel_connected_effective_id(session->channel); ast_party_id_copy(&connected_id, &effective_id); ast_channel_unlock(session->channel); add_id_headers(session, tdata, &connected_id); ast_party_id_free(&connected_id); }
static int manager_bridge_kick(struct mansession *s, const struct message *m) { const char *bridge_uniqueid = astman_get_header(m, "BridgeUniqueid"); const char *channel_name = astman_get_header(m, "Channel"); RAII_VAR(struct ast_bridge *, bridge, NULL, ao2_cleanup); RAII_VAR(struct ast_channel *, channel, NULL, ao2_cleanup); if (ast_strlen_zero(channel_name)) { astman_send_error(s, m, "Channel must be provided"); return 0; } channel = ast_channel_get_by_name(channel_name); if (!channel) { astman_send_error(s, m, "Channel does not exist"); return 0; } if (ast_strlen_zero(bridge_uniqueid)) { /* get the bridge from the channel */ ast_channel_lock(channel); bridge = ast_channel_get_bridge(channel); ast_channel_unlock(channel); if (!bridge) { astman_send_error(s, m, "Channel is not in a bridge"); return 0; } } else { bridge = ast_bridge_find_by_id(bridge_uniqueid); if (!bridge) { astman_send_error(s, m, "Bridge not found"); return 0; } } if (ast_bridge_kick(bridge, channel)) { astman_send_error(s, m, "Channel kick from bridge failed"); return 0; } astman_send_ack(s, m, "Channel has been kicked"); return 0; }
/*! * \internal * \brief Destroy the speech datastore on the given channel. * * \param chan Channel to destroy speech datastore. * * \retval 0 on success. * \retval -1 not found. */ static int speech_datastore_destroy(struct ast_channel *chan) { struct ast_datastore *datastore; int res; ast_channel_lock(chan); datastore = ast_channel_datastore_find(chan, &speech_datastore, NULL); if (datastore) { ast_channel_datastore_remove(chan, datastore); } ast_channel_unlock(chan); if (datastore) { ast_datastore_free(datastore); res = 0; } else { res = -1; } return res; }
/*! \note Returns the channel in the chanspy_ds locked as well as the chanspy_ds locked */ static struct chanspy_ds *setup_chanspy_ds(struct ast_channel *chan, struct chanspy_ds *chanspy_ds) { struct ast_datastore *datastore = NULL; ast_mutex_lock(&chanspy_ds->lock); if (!(datastore = ast_channel_datastore_alloc(&chanspy_ds_info, chanspy_ds->unique_id))) { ast_mutex_unlock(&chanspy_ds->lock); chanspy_ds = chanspy_ds_free(chanspy_ds); ast_channel_unlock(chan); return NULL; } chanspy_ds->chan = chan; datastore->data = chanspy_ds; ast_channel_datastore_add(chan, datastore); return chanspy_ds; }
/*! * \internal * \brief Session supplement for outgoing INVITE response * * This will add P-Asserted-Identity and Remote-Party-ID headers if necessary * * \param session The session on which the INVITE response is to be sent * \param tdata The outbound INVITE response */ static void caller_id_outgoing_response(struct ast_sip_session *session, pjsip_tx_data *tdata) { struct ast_party_id effective_id; struct ast_party_id connected_id; if (!session->channel) { return; } /* Must do a deep copy unless we hold the channel lock the entire time. */ ast_party_id_init(&connected_id); ast_channel_lock(session->channel); effective_id = ast_channel_connected_effective_id(session->channel); ast_party_id_copy(&connected_id, &effective_id); ast_channel_unlock(session->channel); add_id_headers(session, tdata, &connected_id); ast_party_id_free(&connected_id); }
/*! \brief Helper function used to find the speech structure attached to a channel */ static struct ast_speech *find_speech(struct ast_channel *chan) { struct ast_speech *speech = NULL; struct ast_datastore *datastore = NULL; if (!chan) { return NULL; } ast_channel_lock(chan); datastore = ast_channel_datastore_find(chan, &speech_datastore, NULL); ast_channel_unlock(chan); if (datastore == NULL) { return NULL; } speech = datastore->data; return speech; }
static u_char *ast_var_channel_bridge(struct variable *vp, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { static unsigned long long_ret; struct ast_channel *chan = NULL; long_ret = 0; if (header_generic(vp, name, length, exact, var_len, write_method)) return NULL; while ((chan = ast_channel_walk_locked(chan))) { if (ast_bridged_channel(chan)) long_ret++; ast_channel_unlock(chan); } *var_len = sizeof(long_ret); return (vp->magic == ASTCHANBRIDGECOUNT) ? (u_char *) &long_ret : NULL; }
/*! \brief Helper function to not deadlock when queueing the hangup frame */ static void bridge_queue_hangup(struct bridge_pvt *p, struct ast_channel *us) { struct ast_channel *other = (p->input == us ? p->output : p->input); while (other && ast_channel_trylock(other)) { ast_mutex_unlock(&p->lock); do { CHANNEL_DEADLOCK_AVOIDANCE(us); } while (ast_mutex_trylock(&p->lock)); other = (p->input == us ? p->output : p->input); } /* We basically queue the frame up on the other channel if present */ if (other) { ast_queue_hangup(other); ast_channel_unlock(other); } return; }
static int find_by_uniqueid(void *obj, void *arg, void *data, int flags) { struct ast_channel *target = obj;/*!< Potential pickup target */ struct pickup_by_name_args *args = data; if (args->chan == target) { /* The channel attempting to pickup a call cannot pickup itself. */ return 0; } ast_channel_lock(target); if (!strcasecmp(ast_channel_uniqueid(target), args->name) && ast_can_pickup(target)) { /* Return with the channel still locked on purpose */ return CMP_MATCH | CMP_STOP; } ast_channel_unlock(target); return 0; }
int ast_local_setup_bridge(struct ast_channel *ast, struct ast_bridge *bridge, struct ast_channel *swap, struct ast_bridge_features *features) { struct local_pvt *p; struct local_pvt *found; int res = -1; /* Sanity checks. */ if (!ast || !bridge) { ast_bridge_features_destroy(features); return -1; } ast_channel_lock(ast); p = ast_channel_tech_pvt(ast); ast_channel_unlock(ast); found = p ? ao2_find(locals, p, 0) : NULL; if (found) { ao2_lock(found); if (found->type == LOCAL_CALL_ACTION_DIALPLAN && found->base.owner && found->base.chan && !ast_test_flag(&found->base, AST_UNREAL_CARETAKER_THREAD)) { ao2_ref(bridge, +1); if (swap) { ast_channel_ref(swap); } found->type = LOCAL_CALL_ACTION_BRIDGE; found->action.bridge.join = bridge; found->action.bridge.swap = swap; found->action.bridge.features = features; res = 0; } else { ast_bridge_features_destroy(features); } ao2_unlock(found); ao2_ref(found, -1); } return res; }
static struct ast_parked_call_payload *parked_call_payload_from_parked_user(struct parked_user *pu, enum ast_parked_call_event_type event_type) { RAII_VAR(struct ast_channel_snapshot *, parkee_snapshot, NULL, ao2_cleanup); long int timeout; long int duration; struct timeval now = ast_tvnow(); const char *lot_name = pu->lot->name; ast_channel_lock(pu->chan); parkee_snapshot = ast_channel_snapshot_create(pu->chan); ast_channel_unlock(pu->chan); if (!parkee_snapshot) { return NULL; } timeout = pu->start.tv_sec + (long) pu->time_limit - now.tv_sec; duration = now.tv_sec - pu->start.tv_sec; return ast_parked_call_payload_create(event_type, parkee_snapshot, pu->parker_dial_string, pu->retriever, lot_name, pu->parking_space, timeout, duration); }
/*! * \brief queue a frame onto either the p->owner or p->chan * * \note the ast_unreal_pvt MUST have it's ref count bumped before entering this function and * decremented after this function is called. This is a side effect of the deadlock * avoidance that is necessary to lock 2 channels and a tech_pvt. Without a ref counted * ast_unreal_pvt, it is impossible to guarantee it will not be destroyed by another thread * during deadlock avoidance. */ static int unreal_queue_frame(struct ast_unreal_pvt *p, int isoutbound, struct ast_frame *f, struct ast_channel *us, int us_locked) { struct ast_channel *other; /* Recalculate outbound channel */ other = isoutbound ? p->owner : p->chan; if (!other) { return 0; } /* do not queue media frames if a generator is on both unreal channels */ if (us && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) && ast_channel_generator(us) && ast_channel_generator(other)) { return 0; } /* grab a ref on the channel before unlocking the pvt, * other can not go away from us now regardless of locking */ ast_channel_ref(other); if (us && us_locked) { ast_channel_unlock(us); } ao2_unlock(p); if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_RINGING) { ast_setstate(other, AST_STATE_RINGING); } ast_queue_frame(other, f); other = ast_channel_unref(other); if (us && us_locked) { ast_channel_lock(us); } ao2_lock(p); return 0; }
/*! * \internal * \brief Session supplement callback for outgoing INVITE requests * * For an initial INVITE request, we may change the From header to appropriately * reflect the identity information. On all INVITEs (initial and reinvite) we may * add other identity headers such as P-Asserted-Identity and Remote-Party-ID based * on configuration and privacy settings * * \param session The session on which the INVITE will be sent * \param tdata The outbound INVITE request */ static void caller_id_outgoing_request(struct ast_sip_session *session, pjsip_tx_data *tdata) { struct ast_party_id effective_id; struct ast_party_id connected_id; if (!session->channel) { return; } /* Must do a deep copy unless we hold the channel lock the entire time. */ ast_party_id_init(&connected_id); ast_channel_lock(session->channel); effective_id = ast_channel_connected_effective_id(session->channel); ast_party_id_copy(&connected_id, &effective_id); ast_channel_unlock(session->channel); if (session->inv_session->state < PJSIP_INV_STATE_CONFIRMED) { /* Only change the From header on the initial outbound INVITE. Switching it * mid-call might confuse some UAs. */ pjsip_fromto_hdr *from; pjsip_dialog *dlg; from = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_FROM, tdata->msg->hdr.next); dlg = session->inv_session->dlg; if (ast_strlen_zero(session->endpoint->fromuser) && (session->endpoint->id.trust_outbound || (ast_party_id_presentation(&connected_id) & AST_PRES_RESTRICTION) == AST_PRES_ALLOWED)) { modify_id_header(tdata->pool, from, &connected_id); modify_id_header(dlg->pool, dlg->local.info, &connected_id); } ast_sip_add_usereqphone(session->endpoint, tdata->pool, from->uri); ast_sip_add_usereqphone(session->endpoint, dlg->pool, dlg->local.info->uri); } add_id_headers(session, tdata, &connected_id); ast_party_id_free(&connected_id); }