mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-03 11:25:35 +00:00
core/ari/pjsip: Add refer mechanism
This change adds support for refers that are not session based. It includes a refer implementation for the PJSIP technology which results in out-of-dialog REFERs being sent to a PJSIP endpoint. These can be triggered using the new ARI endpoint `/endpoints/refer`. Resolves: #71 UserNote: There is a new ARI endpoint `/endpoints/refer` for referring an endpoint to some URI or endpoint.
This commit is contained in:
@@ -195,571 +195,6 @@ static enum pjsip_status_code check_content_type_in_dialog(const pjsip_rx_data *
|
||||
return res;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Find a contact and insert a "user@" into its URI.
|
||||
*
|
||||
* \param to Original destination (for error messages only)
|
||||
* \param endpoint_name Endpoint name (for error messages only)
|
||||
* \param aors Command separated list of AORs
|
||||
* \param user The user to insert in the contact URI
|
||||
* \param uri Pointer to buffer in which to return the URI
|
||||
*
|
||||
* \return 0 Success
|
||||
* \return -1 Fail
|
||||
*
|
||||
* \note If the contact URI found for the endpoint already has a user in
|
||||
* its URI, it will be replaced.
|
||||
*/
|
||||
static int insert_user_in_contact_uri(const char *to, const char *endpoint_name, const char *aors,
|
||||
const char *user, char **uri)
|
||||
{
|
||||
char *scheme = NULL;
|
||||
char *contact_uri = NULL;
|
||||
char *after_scheme = NULL;
|
||||
char *host;
|
||||
struct ast_sip_contact *contact = NULL;
|
||||
|
||||
|
||||
contact = ast_sip_location_retrieve_contact_from_aor_list(aors);
|
||||
if (!contact) {
|
||||
/*
|
||||
* We're getting the contact using the same method as
|
||||
* ast_sip_create_request() so if there's no contact
|
||||
* we can never send this message.
|
||||
*/
|
||||
ast_log(LOG_WARNING, "Dest: '%s' MSG SEND FAIL: Couldn't find contact for endpoint '%s'\n",
|
||||
to, endpoint_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
contact_uri = ast_strdupa(contact->uri);
|
||||
ao2_cleanup(contact);
|
||||
|
||||
ast_debug(3, "Dest: '%s' User: '%s' Endpoint: '%s' ContactURI: '%s'\n", to, user, endpoint_name, contact_uri);
|
||||
|
||||
/*
|
||||
* Contact URIs must have a scheme so we must insert the user between it and the host.
|
||||
*/
|
||||
scheme = contact_uri;
|
||||
after_scheme = strchr(contact_uri, ':');
|
||||
if (!after_scheme) {
|
||||
/* A contact URI without a scheme? Something's wrong. Bail */
|
||||
ast_log(LOG_WARNING, "Dest: '%s' MSG SEND FAIL: There was no scheme in the contact URI '%s'\n",
|
||||
to, contact_uri);
|
||||
return -1;
|
||||
}
|
||||
/*
|
||||
* Terminate the scheme.
|
||||
*/
|
||||
*after_scheme = '\0';
|
||||
after_scheme++;
|
||||
|
||||
/*
|
||||
* If the contact_uri already has a user, the host starts after the '@', otherwise
|
||||
* the host is at after_scheme.
|
||||
*
|
||||
* We're going to ignore the existing user.
|
||||
*/
|
||||
host = strchr(after_scheme, '@');
|
||||
if (host) {
|
||||
host++;
|
||||
} else {
|
||||
host = after_scheme;
|
||||
}
|
||||
|
||||
*uri = ast_malloc(strlen(scheme) + strlen(user) + strlen(host) + 3 /* One for the ':', '@' and terminating NULL */);
|
||||
sprintf(*uri, "%s:%s@%s", scheme, user, host); /* Safe */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Get endpoint and URI when the destination is only a single token
|
||||
*
|
||||
* "to" could be one of the following:
|
||||
* \verbatim
|
||||
endpoint_name
|
||||
hostname
|
||||
* \endverbatim
|
||||
*
|
||||
* \param to Destination specified in MessageSend
|
||||
* \param destination
|
||||
* \param uri Pointer to URI variable. Must be freed by caller
|
||||
* \return endpoint
|
||||
*/
|
||||
static struct ast_sip_endpoint *handle_single_token(const char *to, char *destination, char **uri) {
|
||||
char *endpoint_name = NULL;
|
||||
struct ast_sip_endpoint *endpoint = NULL;
|
||||
struct ast_sip_contact *contact = NULL;
|
||||
|
||||
/*
|
||||
* If "to" is just one token, it could be an endpoint name
|
||||
* or a hostname without a scheme.
|
||||
*/
|
||||
|
||||
endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", destination);
|
||||
if (!endpoint) {
|
||||
/*
|
||||
* We can only assume it's a hostname.
|
||||
*/
|
||||
char *temp_uri = ast_malloc(strlen(destination) + strlen("sip:") + 1);
|
||||
sprintf(temp_uri, "sip:%s", destination);
|
||||
*uri = temp_uri;
|
||||
endpoint = ast_sip_default_outbound_endpoint();
|
||||
ast_debug(3, "Dest: '%s' Didn't find endpoint so adding scheme and using URI '%s' with default endpoint\n",
|
||||
to, *uri);
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
/*
|
||||
* It's an endpoint
|
||||
*/
|
||||
|
||||
endpoint_name = destination;
|
||||
contact = ast_sip_location_retrieve_contact_from_aor_list(endpoint->aors);
|
||||
if (!contact) {
|
||||
/*
|
||||
* We're getting the contact using the same method as
|
||||
* ast_sip_create_request() so if there's no contact
|
||||
* we can never send this message.
|
||||
*/
|
||||
ast_log(LOG_WARNING, "Dest: '%s' MSG SEND FAIL: Found endpoint '%s' but didn't find an aor/contact for it\n",
|
||||
to, endpoint_name);
|
||||
ao2_cleanup(endpoint);
|
||||
*uri = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*uri = ast_strdup(contact->uri);
|
||||
ast_debug(3, "Dest: '%s' Found endpoint '%s' and found contact with URI '%s'\n",
|
||||
to, endpoint_name, *uri);
|
||||
ao2_cleanup(contact);
|
||||
return endpoint;
|
||||
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Get endpoint and URI when the destination contained a '/'
|
||||
*
|
||||
* "to" could be one of the following:
|
||||
* \verbatim
|
||||
endpoint/aor
|
||||
endpoint/<sip[s]:host>
|
||||
endpoint/<sip[s]:user@host>
|
||||
endpoint/"Bob" <sip[s]:host>
|
||||
endpoint/"Bob" <sip[s]:user@host>
|
||||
endpoint/sip[s]:host
|
||||
endpoint/sip[s]:user@host
|
||||
endpoint/host
|
||||
endpoint/user@host
|
||||
* \endverbatim
|
||||
*
|
||||
* \param to Destination specified in MessageSend
|
||||
* \param uri Pointer to URI variable. Must be freed by caller
|
||||
* \param destination, slash, atsign, scheme
|
||||
* \return endpoint
|
||||
*/
|
||||
static struct ast_sip_endpoint *handle_slash(const char *to, char *destination, char **uri,
|
||||
char *slash, char *atsign, char *scheme)
|
||||
{
|
||||
char *endpoint_name = NULL;
|
||||
struct ast_sip_endpoint *endpoint = NULL;
|
||||
struct ast_sip_contact *contact = NULL;
|
||||
char *user = NULL;
|
||||
char *afterslash = slash + 1;
|
||||
struct ast_sip_aor *aor;
|
||||
|
||||
if (ast_begins_with(destination, "PJSIP/")) {
|
||||
ast_debug(3, "Dest: '%s' Dialplan format'\n", to);
|
||||
/*
|
||||
* This has to be the form PJSIP/user@endpoint
|
||||
*/
|
||||
if (!atsign || strchr(afterslash, '/')) {
|
||||
/*
|
||||
* If there's no "user@" or there's a slash somewhere after
|
||||
* "PJSIP/" then we go no further.
|
||||
*/
|
||||
*uri = NULL;
|
||||
ast_log(LOG_WARNING,
|
||||
"Dest: '%s' MSG SEND FAIL: Destinations beginning with 'PJSIP/' must be in the form of 'PJSIP/user@endpoint'\n",
|
||||
to);
|
||||
return NULL;
|
||||
}
|
||||
*atsign = '\0';
|
||||
user = afterslash;
|
||||
endpoint_name = atsign + 1;
|
||||
ast_debug(3, "Dest: '%s' User: '%s' Endpoint: '%s'\n", to, user, endpoint_name);
|
||||
} else {
|
||||
/*
|
||||
* Either...
|
||||
* endpoint/aor
|
||||
* endpoint/uri
|
||||
*/
|
||||
*slash = '\0';
|
||||
endpoint_name = destination;
|
||||
ast_debug(3, "Dest: '%s' Endpoint: '%s'\n", to, endpoint_name);
|
||||
}
|
||||
|
||||
endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", endpoint_name);
|
||||
if (!endpoint) {
|
||||
*uri = NULL;
|
||||
ast_log(LOG_WARNING, "Dest: '%s' MSG SEND FAIL: Didn't find endpoint with name '%s'\n",
|
||||
to, endpoint_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (scheme) {
|
||||
/*
|
||||
* If we found a scheme, then everything after the slash MUST be a URI.
|
||||
* We don't need to do any further modification.
|
||||
*/
|
||||
*uri = ast_strdup(afterslash);
|
||||
ast_debug(3, "Dest: '%s' Found endpoint '%s' and found URI '%s' after '/'\n",
|
||||
to, endpoint_name, *uri);
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
if (user) {
|
||||
/*
|
||||
* This has to be the form PJSIP/user@endpoint
|
||||
*/
|
||||
int rc;
|
||||
|
||||
/*
|
||||
* Set the return URI to be the endpoint's contact URI with the user
|
||||
* portion set to the user that was specified before the endpoint name.
|
||||
*/
|
||||
rc = insert_user_in_contact_uri(to, endpoint_name, endpoint->aors, user, uri);
|
||||
if (rc != 0) {
|
||||
/*
|
||||
* insert_user_in_contact_uri prints the warning message.
|
||||
*/
|
||||
ao2_cleanup(endpoint);
|
||||
endpoint = NULL;
|
||||
*uri = NULL;
|
||||
}
|
||||
ast_debug(3, "Dest: '%s' User: '%s' Endpoint: '%s' URI: '%s'\n", to, user,
|
||||
endpoint_name, *uri);
|
||||
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
/*
|
||||
* We're now left with two possibilities...
|
||||
* endpoint/aor
|
||||
* endpoint/uri-without-scheme
|
||||
*/
|
||||
aor = ast_sip_location_retrieve_aor(afterslash);
|
||||
if (!aor) {
|
||||
/*
|
||||
* It's probably a URI without a scheme but we don't have a way to tell
|
||||
* for sure. We're going to assume it is and prepend it with a scheme.
|
||||
*/
|
||||
*uri = ast_malloc(strlen(afterslash) + strlen("sip:") + 1);
|
||||
sprintf(*uri, "sip:%s", afterslash);
|
||||
ast_debug(3, "Dest: '%s' Found endpoint '%s' but didn't find aor after '/' so using URI '%s'\n",
|
||||
to, endpoint_name, *uri);
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
/*
|
||||
* Only one possibility left... There was an aor name after the slash.
|
||||
*/
|
||||
ast_debug(3, "Dest: '%s' Found endpoint '%s' and found aor '%s' after '/'\n",
|
||||
to, endpoint_name, ast_sorcery_object_get_id(aor));
|
||||
|
||||
contact = ast_sip_location_retrieve_first_aor_contact(aor);
|
||||
if (!contact) {
|
||||
/*
|
||||
* An aor without a contact is useless and since
|
||||
* ast_sip_create_message() won't be able to find one
|
||||
* either, we just need to bail.
|
||||
*/
|
||||
ast_log(LOG_WARNING, "Dest: '%s' MSG SEND FAIL: Found endpoint '%s' but didn't find contact for aor '%s'\n",
|
||||
to, endpoint_name, ast_sorcery_object_get_id(aor));
|
||||
ao2_cleanup(aor);
|
||||
ao2_cleanup(endpoint);
|
||||
*uri = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*uri = ast_strdup(contact->uri);
|
||||
ast_debug(3, "Dest: '%s' Found endpoint '%s' and found contact with URI '%s' for aor '%s'\n",
|
||||
to, endpoint_name, *uri, ast_sorcery_object_get_id(aor));
|
||||
ao2_cleanup(contact);
|
||||
ao2_cleanup(aor);
|
||||
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Get endpoint and URI when the destination contained a '\@' but no '/' or scheme
|
||||
*
|
||||
* "to" could be one of the following:
|
||||
* \verbatim
|
||||
<sip[s]:user@host>
|
||||
"Bob" <sip[s]:user@host>
|
||||
sip[s]:user@host
|
||||
user@host
|
||||
* \endverbatim
|
||||
*
|
||||
* \param to Destination specified in MessageSend
|
||||
* \param uri Pointer to URI variable. Must be freed by caller
|
||||
* \param destination, slash, atsign, scheme
|
||||
* \return endpoint
|
||||
*/
|
||||
static struct ast_sip_endpoint *handle_atsign(const char *to, char *destination, char **uri,
|
||||
char *slash, char *atsign, char *scheme)
|
||||
{
|
||||
char *endpoint_name = NULL;
|
||||
struct ast_sip_endpoint *endpoint = NULL;
|
||||
struct ast_sip_contact *contact = NULL;
|
||||
char *afterat = atsign + 1;
|
||||
|
||||
*atsign = '\0';
|
||||
endpoint_name = destination;
|
||||
|
||||
/* Apparently there may be ';<user_options>' after the endpoint name ??? */
|
||||
AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(endpoint_name);
|
||||
endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", endpoint_name);
|
||||
if (!endpoint) {
|
||||
/*
|
||||
* It's probably a uri with a user but without a scheme but we don't have a way to tell.
|
||||
* We're going to assume it is and prepend it with a scheme.
|
||||
*/
|
||||
*uri = ast_malloc(strlen(to) + strlen("sip:") + 1);
|
||||
sprintf(*uri, "sip:%s", to);
|
||||
endpoint = ast_sip_default_outbound_endpoint();
|
||||
ast_debug(3, "Dest: '%s' Didn't find endpoint before the '@' so using URI '%s' with default endpoint\n",
|
||||
to, *uri);
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
/*
|
||||
* OK, it's an endpoint and a domain (which we ignore)
|
||||
*/
|
||||
contact = ast_sip_location_retrieve_contact_from_aor_list(endpoint->aors);
|
||||
if (!contact) {
|
||||
/*
|
||||
* We're getting the contact using the same method as
|
||||
* ast_sip_create_request() so if there's no contact
|
||||
* we can never send this message.
|
||||
*/
|
||||
ao2_cleanup(endpoint);
|
||||
endpoint = NULL;
|
||||
*uri = NULL;
|
||||
ast_log(LOG_WARNING, "Dest: '%s' MSG SEND FAIL: Found endpoint '%s' but didn't find contact\n",
|
||||
to, endpoint_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*uri = ast_strdup(contact->uri);
|
||||
ao2_cleanup(contact);
|
||||
ast_debug(3, "Dest: '%s' Found endpoint '%s' and found contact with URI '%s' (discarding domain %s)\n",
|
||||
to, endpoint_name, *uri, afterat);
|
||||
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Retrieves an endpoint and URI from the "to" string.
|
||||
*
|
||||
* This URI is used as the Request URI.
|
||||
*
|
||||
* Expects the given 'to' to be in one of the following formats:
|
||||
* Why we allow so many is a mystery.
|
||||
*
|
||||
* Basic:
|
||||
*
|
||||
* endpoint : We'll get URI from the default aor/contact
|
||||
* endpoint/aor : We'll get the URI from the specific aor/contact
|
||||
* endpoint@domain : We toss the domain part and just use the endpoint
|
||||
*
|
||||
* These all use the endpoint and specified URI:
|
||||
* \verbatim
|
||||
endpoint/<sip[s]:host>
|
||||
endpoint/<sip[s]:user@host>
|
||||
endpoint/"Bob" <sip[s]:host>
|
||||
endpoint/"Bob" <sip[s]:user@host>
|
||||
endpoint/sip[s]:host
|
||||
endpoint/sip[s]:user@host
|
||||
endpoint/host
|
||||
endpoint/user@host
|
||||
\endverbatim
|
||||
*
|
||||
* These all use the default endpoint and specified URI:
|
||||
* \verbatim
|
||||
<sip[s]:host>
|
||||
<sip[s]:user@host>
|
||||
"Bob" <sip[s]:host>
|
||||
"Bob" <sip[s]:user@host>
|
||||
sip[s]:host
|
||||
sip[s]:user@host
|
||||
\endverbatim
|
||||
*
|
||||
* These use the default endpoint and specified host:
|
||||
* \verbatim
|
||||
host
|
||||
user@host
|
||||
\endverbatim
|
||||
*
|
||||
* This form is similar to a dialstring:
|
||||
* \verbatim
|
||||
PJSIP/user@endpoint
|
||||
\endverbatim
|
||||
*
|
||||
* In this case, the user will be added to the endpoint contact's URI.
|
||||
* If the contact URI already has a user, it will be replaced.
|
||||
*
|
||||
* The ones that have the sip[s] scheme are the easiest to parse.
|
||||
* The rest all have some issue.
|
||||
*
|
||||
* endpoint vs host : We have to test for endpoint first
|
||||
* endpoint/aor vs endpoint/host : We have to test for aor first
|
||||
* What if there's an aor with the same
|
||||
* name as the host?
|
||||
* endpoint@domain vs user@host : We have to test for endpoint first.
|
||||
* What if there's an endpoint with the
|
||||
* same name as the user?
|
||||
*
|
||||
* \param to 'To' field with possible endpoint
|
||||
* \param uri Pointer to a char* which will be set to the URI.
|
||||
* Must be ast_free'd by the caller.
|
||||
*
|
||||
* \note The logic below could probably be condensed but then it wouldn't be
|
||||
* as clear.
|
||||
*/
|
||||
static struct ast_sip_endpoint *get_outbound_endpoint(const char *to, char **uri)
|
||||
{
|
||||
char *destination;
|
||||
char *slash = NULL;
|
||||
char *atsign = NULL;
|
||||
char *scheme = NULL;
|
||||
struct ast_sip_endpoint *endpoint = NULL;
|
||||
|
||||
destination = ast_strdupa(to);
|
||||
slash = strchr(destination, '/');
|
||||
atsign = strchr(destination, '@');
|
||||
scheme = S_OR(strstr(destination, "sip:"), strstr(destination, "sips:"));
|
||||
|
||||
if (!slash && !atsign && !scheme) {
|
||||
/*
|
||||
* If there's only a single token, it can be either...
|
||||
* endpoint
|
||||
* host
|
||||
*/
|
||||
return handle_single_token(to, destination, uri);
|
||||
}
|
||||
|
||||
if (slash) {
|
||||
/*
|
||||
* If there's a '/', then the form must be one of the following...
|
||||
* PJSIP/user@endpoint
|
||||
* endpoint/aor
|
||||
* endpoint/uri
|
||||
*/
|
||||
return handle_slash(to, destination, uri, slash, atsign, scheme);
|
||||
}
|
||||
|
||||
if (!endpoint && atsign && !scheme) {
|
||||
/*
|
||||
* If there's an '@' but no scheme then it's either following an endpoint name
|
||||
* and being followed by a domain name (which we discard).
|
||||
* OR is's a user@host uri without a scheme. It's probably the latter but because
|
||||
* endpoint@domain looks just like user@host, we'll test for endpoint first.
|
||||
*/
|
||||
return handle_atsign(to, destination, uri, slash, atsign, scheme);
|
||||
}
|
||||
|
||||
/*
|
||||
* If all else fails, we assume it's a URI or just a hostname.
|
||||
*/
|
||||
if (scheme) {
|
||||
*uri = ast_strdup(destination);
|
||||
ast_debug(3, "Dest: '%s' Didn't find an endpoint but did find a scheme so using URI '%s' with default endpoint\n",
|
||||
to, *uri);
|
||||
} else {
|
||||
*uri = ast_malloc(strlen(destination) + strlen("sip:") + 1);
|
||||
sprintf(*uri, "sip:%s", destination);
|
||||
ast_debug(3, "Dest: '%s' Didn't find an endpoint and didn't find scheme so adding scheme and using URI '%s' with default endpoint\n",
|
||||
to, *uri);
|
||||
}
|
||||
endpoint = ast_sip_default_outbound_endpoint();
|
||||
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Replace the To URI in the tdata with the supplied one
|
||||
*
|
||||
* \param tdata the outbound message data structure
|
||||
* \param to URI to replace the To URI with
|
||||
*
|
||||
* \return 0: success, -1: failure
|
||||
*/
|
||||
static int update_to_uri(pjsip_tx_data *tdata, char *to)
|
||||
{
|
||||
pjsip_name_addr *parsed_name_addr;
|
||||
pjsip_sip_uri *sip_uri;
|
||||
pjsip_name_addr *tdata_name_addr;
|
||||
pjsip_sip_uri *tdata_sip_uri;
|
||||
char *buf = NULL;
|
||||
#define DEBUG_BUF_SIZE 256
|
||||
|
||||
parsed_name_addr = (pjsip_name_addr *) pjsip_parse_uri(tdata->pool, to, strlen(to),
|
||||
PJSIP_PARSE_URI_AS_NAMEADDR);
|
||||
|
||||
if (!parsed_name_addr || (!PJSIP_URI_SCHEME_IS_SIP(parsed_name_addr->uri)
|
||||
&& !PJSIP_URI_SCHEME_IS_SIPS(parsed_name_addr->uri))) {
|
||||
ast_log(LOG_WARNING, "To address '%s' is not a valid SIP/SIPS URI\n", to);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sip_uri = pjsip_uri_get_uri(parsed_name_addr->uri);
|
||||
if (DEBUG_ATLEAST(3)) {
|
||||
buf = ast_alloca(DEBUG_BUF_SIZE);
|
||||
pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, sip_uri, buf, DEBUG_BUF_SIZE);
|
||||
ast_debug(3, "Parsed To: %.*s %s\n", (int)parsed_name_addr->display.slen,
|
||||
parsed_name_addr->display.ptr, buf);
|
||||
}
|
||||
|
||||
tdata_name_addr = (pjsip_name_addr *) PJSIP_MSG_TO_HDR(tdata->msg)->uri;
|
||||
if (!tdata_name_addr || (!PJSIP_URI_SCHEME_IS_SIP(tdata_name_addr->uri)
|
||||
&& !PJSIP_URI_SCHEME_IS_SIPS(tdata_name_addr->uri))) {
|
||||
/* Highly unlikely but we have to check */
|
||||
ast_log(LOG_WARNING, "tdata To address '%s' is not a valid SIP/SIPS URI\n", to);
|
||||
return -1;
|
||||
}
|
||||
|
||||
tdata_sip_uri = pjsip_uri_get_uri(tdata_name_addr->uri);
|
||||
if (DEBUG_ATLEAST(3)) {
|
||||
buf[0] = '\0';
|
||||
pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, tdata_sip_uri, buf, DEBUG_BUF_SIZE);
|
||||
ast_debug(3, "Original tdata To: %.*s %s\n", (int)tdata_name_addr->display.slen,
|
||||
tdata_name_addr->display.ptr, buf);
|
||||
}
|
||||
|
||||
/* Replace the uri */
|
||||
pjsip_sip_uri_assign(tdata->pool, tdata_sip_uri, sip_uri);
|
||||
/* The display name isn't part of the URI so we need to replace it separately */
|
||||
pj_strdup(tdata->pool, &tdata_name_addr->display, &parsed_name_addr->display);
|
||||
|
||||
if (DEBUG_ATLEAST(3)) {
|
||||
buf[0] = '\0';
|
||||
pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, tdata_sip_uri, buf, 256);
|
||||
ast_debug(3, "New tdata To: %.*s %s\n", (int)tdata_name_addr->display.slen,
|
||||
tdata_name_addr->display.ptr, buf);
|
||||
}
|
||||
|
||||
return 0;
|
||||
#undef DEBUG_BUF_SIZE
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Update the display name in the To uri in the tdata with the one from the supplied uri
|
||||
@@ -790,77 +225,6 @@ static int update_to_display_name(pjsip_tx_data *tdata, char *to)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Overwrite fields in the outbound 'From' header
|
||||
*
|
||||
* The outbound 'From' header is created/added in ast_sip_create_request with
|
||||
* default data. If available that data may be info specified in the 'from_user'
|
||||
* and 'from_domain' options found on the endpoint. That information will be
|
||||
* overwritten with data in the given 'from' parameter.
|
||||
*
|
||||
* \param tdata the outbound message data structure
|
||||
* \param from info to copy into the header
|
||||
*
|
||||
* \return 0: success, -1: failure
|
||||
*/
|
||||
static int update_from(pjsip_tx_data *tdata, char *from)
|
||||
{
|
||||
pjsip_name_addr *name_addr;
|
||||
pjsip_sip_uri *uri;
|
||||
pjsip_name_addr *parsed_name_addr;
|
||||
|
||||
if (ast_strlen_zero(from)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
name_addr = (pjsip_name_addr *) PJSIP_MSG_FROM_HDR(tdata->msg)->uri;
|
||||
uri = pjsip_uri_get_uri(name_addr);
|
||||
|
||||
parsed_name_addr = (pjsip_name_addr *) pjsip_parse_uri(tdata->pool, from,
|
||||
strlen(from), PJSIP_PARSE_URI_AS_NAMEADDR);
|
||||
if (parsed_name_addr) {
|
||||
pjsip_sip_uri *parsed_uri;
|
||||
|
||||
if (!PJSIP_URI_SCHEME_IS_SIP(parsed_name_addr->uri)
|
||||
&& !PJSIP_URI_SCHEME_IS_SIPS(parsed_name_addr->uri)) {
|
||||
ast_log(LOG_WARNING, "From address '%s' is not a valid SIP/SIPS URI\n", from);
|
||||
return -1;
|
||||
}
|
||||
|
||||
parsed_uri = pjsip_uri_get_uri(parsed_name_addr->uri);
|
||||
|
||||
if (pj_strlen(&parsed_name_addr->display)) {
|
||||
pj_strdup(tdata->pool, &name_addr->display, &parsed_name_addr->display);
|
||||
}
|
||||
|
||||
/* Unlike the To header, we only want to replace the user, host and port */
|
||||
pj_strdup(tdata->pool, &uri->user, &parsed_uri->user);
|
||||
pj_strdup(tdata->pool, &uri->host, &parsed_uri->host);
|
||||
uri->port = parsed_uri->port;
|
||||
|
||||
return 0;
|
||||
} else {
|
||||
/* assume it is 'user[@domain]' format */
|
||||
char *domain = strchr(from, '@');
|
||||
|
||||
if (domain) {
|
||||
pj_str_t pj_from;
|
||||
|
||||
pj_strset3(&pj_from, from, domain);
|
||||
pj_strdup(tdata->pool, &uri->user, &pj_from);
|
||||
|
||||
pj_strdup2(tdata->pool, &uri->host, domain + 1);
|
||||
} else {
|
||||
pj_strdup2(tdata->pool, &uri->user, from);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Checks if the given msg var name should be blocked.
|
||||
@@ -1252,7 +616,7 @@ static int msg_send(void *data)
|
||||
ast_debug(3, "mdata From: %s msg From: %s mdata Destination: %s msg To: %s\n",
|
||||
mdata->from, ast_msg_get_from(mdata->msg), mdata->destination, ast_msg_get_to(mdata->msg));
|
||||
|
||||
endpoint = get_outbound_endpoint(mdata->destination, &uri);
|
||||
endpoint = ast_sip_get_endpoint(mdata->destination, 1, &uri);
|
||||
if (!endpoint) {
|
||||
ast_log(LOG_ERROR,
|
||||
"PJSIP MESSAGE - Could not find endpoint '%s' and no default outbound endpoint configured\n",
|
||||
@@ -1290,7 +654,7 @@ static int msg_send(void *data)
|
||||
if (ast_begins_with(msg_to, "pjsip:")) {
|
||||
msg_to += 6;
|
||||
}
|
||||
update_to_uri(tdata, msg_to);
|
||||
ast_sip_update_to_uri(tdata, msg_to);
|
||||
} else {
|
||||
/*
|
||||
* If there was no To in the message, it's still possible
|
||||
@@ -1301,9 +665,9 @@ static int msg_send(void *data)
|
||||
}
|
||||
|
||||
if (!ast_strlen_zero(mdata->from)) {
|
||||
update_from(tdata, mdata->from);
|
||||
ast_sip_update_from(tdata, mdata->from);
|
||||
} else if (!ast_strlen_zero(ast_msg_get_from(mdata->msg))) {
|
||||
update_from(tdata, (char *)ast_msg_get_from(mdata->msg));
|
||||
ast_sip_update_from(tdata, (char *)ast_msg_get_from(mdata->msg));
|
||||
}
|
||||
|
||||
#ifdef TEST_FRAMEWORK
|
||||
|
Reference in New Issue
Block a user