mirror of
				https://github.com/asterisk/asterisk.git
				synced 2025-10-31 02:37:10 +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.
(cherry picked from commit 57f77e8218)
			
			
This commit is contained in:
		
				
					committed by
					
						 Asterisk Development Team
						Asterisk Development Team
					
				
			
			
				
	
			
			
			
						parent
						
							de8890e0e4
						
					
				
				
					commit
					fd4ebb4482
				
			| @@ -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