chan_pjsip: Add PJSIPHangup dialplan app and manager action

See UserNote below.

Exposed the existing Hangup AMI action in manager.c so we can use
all of it's channel search and AMI protocol handling without
duplicating that code in dialplan_functions.c.

Added a lookup function to res_pjsip.c that takes in the
string represenation of the pjsip_status_code enum and returns
the actual status code.  I.E.  ast_sip_str2rc("DECLINE") returns
603.  This allows the caller to specify PJSIPHangup(decline) in
the dialplan, just like Hangup(call_rejected).

Also extracted the XML documentation to its own file since it was
almost as large as the code itself.

UserNote: A new dialplan app PJSIPHangup and AMI action allows you
to hang up an unanswered incoming PJSIP call with a specific SIP
response code in the 400 -> 699 range.

(cherry picked from commit 8e012faf9e)
This commit is contained in:
George Joseph 2023-10-31 15:08:14 -06:00 committed by Asterisk Development Team
parent eb173479df
commit e5f3c646e5
8 changed files with 955 additions and 491 deletions

View File

@ -3292,6 +3292,8 @@ static struct ast_custom_function session_refresh_function = {
.write = pjsip_acf_session_refresh_write,
};
static char *app_pjsip_hangup = "PJSIPHangup";
/*!
* \brief Load the module
*
@ -3349,6 +3351,13 @@ static int load_module(void)
goto end;
}
if (ast_register_application_xml(app_pjsip_hangup, pjsip_app_hangup)) {
ast_log(LOG_WARNING, "Unable to register PJSIPHangup dialplan application\n");
goto end;
}
ast_manager_register_xml(app_pjsip_hangup, EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, pjsip_action_hangup);
ast_sip_register_service(&refer_callback_module);
ast_sip_session_register_supplement(&chan_pjsip_supplement);
@ -3394,6 +3403,9 @@ end:
ast_custom_function_unregister(&chan_pjsip_dial_contacts_function);
ast_custom_function_unregister(&chan_pjsip_parse_uri_function);
ast_custom_function_unregister(&session_refresh_function);
ast_unregister_application(app_pjsip_hangup);
ast_manager_unregister(app_pjsip_hangup);
ast_channel_unregister(&chan_pjsip_tech);
ast_rtp_glue_unregister(&chan_pjsip_rtp_glue);
@ -3422,6 +3434,8 @@ static int unload_module(void)
ast_custom_function_unregister(&chan_pjsip_dial_contacts_function);
ast_custom_function_unregister(&chan_pjsip_parse_uri_function);
ast_custom_function_unregister(&session_refresh_function);
ast_unregister_application(app_pjsip_hangup);
ast_manager_unregister(app_pjsip_hangup);
ast_channel_unregister(&chan_pjsip_tech);
ao2_ref(chan_pjsip_tech.capabilities, -1);

View File

@ -29,492 +29,6 @@
<support_level>core</support_level>
***/
/*** DOCUMENTATION
<function name="PJSIP_DIAL_CONTACTS" language="en_US">
<synopsis>
Return a dial string for dialing all contacts on an AOR.
</synopsis>
<syntax>
<parameter name="endpoint" required="true">
<para>Name of the endpoint</para>
</parameter>
<parameter name="aor" required="false">
<para>Name of an AOR to use, if not specified the configured AORs on the endpoint are used</para>
</parameter>
<parameter name="request_user" required="false">
<para>Optional request user to use in the request URI</para>
</parameter>
</syntax>
<description>
<para>Returns a properly formatted dial string for dialing all contacts on an AOR.</para>
</description>
</function>
<function name="PJSIP_MEDIA_OFFER" language="en_US">
<synopsis>
Media and codec offerings to be set on an outbound SIP channel prior to dialing.
</synopsis>
<syntax>
<parameter name="media" required="true">
<para>types of media offered</para>
</parameter>
</syntax>
<description>
<para>When read, returns the codecs offered based upon the media choice.</para>
<para>When written, sets the codecs to offer when an outbound dial attempt is made,
or when a session refresh is sent using <replaceable>PJSIP_SEND_SESSION_REFRESH</replaceable>.
</para>
</description>
<see-also>
<ref type="function">PJSIP_SEND_SESSION_REFRESH</ref>
</see-also>
</function>
<function name="PJSIP_DTMF_MODE" language="en_US">
<synopsis>
Get or change the DTMF mode for a SIP call.
</synopsis>
<syntax>
</syntax>
<description>
<para>When read, returns the current DTMF mode</para>
<para>When written, sets the current DTMF mode</para>
<para>This function uses the same DTMF mode naming as the dtmf_mode configuration option</para>
</description>
</function>
<function name="PJSIP_MOH_PASSTHROUGH" language="en_US">
<synopsis>
Get or change the on-hold behavior for a SIP call.
</synopsis>
<syntax>
</syntax>
<description>
<para>When read, returns the current moh passthrough mode</para>
<para>When written, sets the current moh passthrough mode</para>
<para>If <replaceable>yes</replaceable>, on-hold re-INVITEs are sent. If <replaceable>no</replaceable>, music on hold is generated.</para>
<para>This function can be used to override the moh_passthrough configuration option</para>
</description>
</function>
<function name="PJSIP_SEND_SESSION_REFRESH" language="en_US">
<synopsis>
W/O: Initiate a session refresh via an UPDATE or re-INVITE on an established media session
</synopsis>
<syntax>
<parameter name="update_type" required="false">
<para>The type of update to send. Default is <literal>invite</literal>.</para>
<enumlist>
<enum name="invite">
<para>Send the session refresh as a re-INVITE.</para>
</enum>
<enum name="update">
<para>Send the session refresh as an UPDATE.</para>
</enum>
</enumlist>
</parameter>
</syntax>
<description>
<para>This function will cause the PJSIP stack to immediately refresh
the media session for the channel. This will be done using either a
re-INVITE (default) or an UPDATE request.
</para>
<para>This is most useful when combined with the <replaceable>PJSIP_MEDIA_OFFER</replaceable>
dialplan function, as it allows the formats in use on a channel to be
re-negotiated after call setup.</para>
<warning>
<para>The formats the endpoint supports are <emphasis>not</emphasis>
checked or enforced by this function. Using this function to offer
formats not supported by the endpoint <emphasis>may</emphasis> result
in a loss of media.</para>
</warning>
<example title="Re-negotiate format to g722">
; Within some existing extension on an answered channel
same => n,Set(PJSIP_MEDIA_OFFER(audio)=!all,g722)
same => n,Set(PJSIP_SEND_SESSION_REFRESH()=invite)
</example>
</description>
<see-also>
<ref type="function">PJSIP_MEDIA_OFFER</ref>
</see-also>
</function>
<function name="PJSIP_PARSE_URI" language="en_US">
<synopsis>
Parse an uri and return a type part of the URI.
</synopsis>
<syntax>
<parameter name="uri" required="true">
<para>URI to parse</para>
</parameter>
<parameter name="type" required="true">
<para>The <literal>type</literal> parameter specifies which URI part to read</para>
<enumlist>
<enum name="display">
<para>Display name.</para>
</enum>
<enum name="scheme">
<para>URI scheme.</para>
</enum>
<enum name="user">
<para>User part.</para>
</enum>
<enum name="passwd">
<para>Password part.</para>
</enum>
<enum name="host">
<para>Host part.</para>
</enum>
<enum name="port">
<para>Port number, or zero.</para>
</enum>
<enum name="user_param">
<para>User parameter.</para>
</enum>
<enum name="method_param">
<para>Method parameter.</para>
</enum>
<enum name="transport_param">
<para>Transport parameter.</para>
</enum>
<enum name="ttl_param">
<para>TTL param, or -1.</para>
</enum>
<enum name="lr_param">
<para>Loose routing param, or zero.</para>
</enum>
<enum name="maddr_param">
<para>Maddr param.</para>
</enum>
</enumlist>
</parameter>
</syntax>
<description>
<para>Parse an URI and return a specified part of the URI.</para>
</description>
</function>
<info name="CHANNEL" language="en_US" tech="PJSIP">
<enumlist>
<enum name="rtp">
<para>R/O Retrieve media related information.</para>
<parameter name="type" required="true">
<para>When <replaceable>rtp</replaceable> is specified, the
<literal>type</literal> parameter must be provided. It specifies
which RTP parameter to read.</para>
<enumlist>
<enum name="src">
<para>Retrieve the local address for RTP.</para>
</enum>
<enum name="dest">
<para>Retrieve the remote address for RTP.</para>
</enum>
<enum name="direct">
<para>If direct media is enabled, this address is the remote address
used for RTP.</para>
</enum>
<enum name="secure">
<para>Whether or not the media stream is encrypted.</para>
<enumlist>
<enum name="0">
<para>The media stream is not encrypted.</para>
</enum>
<enum name="1">
<para>The media stream is encrypted.</para>
</enum>
</enumlist>
</enum>
<enum name="hold">
<para>Whether or not the media stream is currently restricted
due to a call hold.</para>
<enumlist>
<enum name="0">
<para>The media stream is not held.</para>
</enum>
<enum name="1">
<para>The media stream is held.</para>
</enum>
</enumlist>
</enum>
</enumlist>
</parameter>
<parameter name="media_type" required="false">
<para>When <replaceable>rtp</replaceable> is specified, the
<literal>media_type</literal> parameter may be provided. It specifies
which media stream the chosen RTP parameter should be retrieved
from.</para>
<enumlist>
<enum name="audio">
<para>Retrieve information from the audio media stream.</para>
<note><para>If not specified, <literal>audio</literal> is used
by default.</para></note>
</enum>
<enum name="video">
<para>Retrieve information from the video media stream.</para>
</enum>
</enumlist>
</parameter>
</enum>
<enum name="rtcp">
<para>R/O Retrieve RTCP statistics.</para>
<parameter name="statistic" required="true">
<para>When <replaceable>rtcp</replaceable> is specified, the
<literal>statistic</literal> parameter must be provided. It specifies
which RTCP statistic parameter to read.</para>
<enumlist>
<enum name="all">
<para>Retrieve a summary of all RTCP statistics.</para>
<para>The following data items are returned in a semi-colon
delineated list:</para>
<enumlist>
<enum name="ssrc">
<para>Our Synchronization Source identifier</para>
</enum>
<enum name="themssrc">
<para>Their Synchronization Source identifier</para>
</enum>
<enum name="lp">
<para>Our lost packet count</para>
</enum>
<enum name="rxjitter">
<para>Received packet jitter</para>
</enum>
<enum name="rxcount">
<para>Received packet count</para>
</enum>
<enum name="txjitter">
<para>Transmitted packet jitter</para>
</enum>
<enum name="txcount">
<para>Transmitted packet count</para>
</enum>
<enum name="rlp">
<para>Remote lost packet count</para>
</enum>
<enum name="rtt">
<para>Round trip time</para>
</enum>
</enumlist>
</enum>
<enum name="all_jitter">
<para>Retrieve a summary of all RTCP Jitter statistics.</para>
<para>The following data items are returned in a semi-colon
delineated list:</para>
<enumlist>
<enum name="minrxjitter">
<para>Our minimum jitter</para>
</enum>
<enum name="maxrxjitter">
<para>Our max jitter</para>
</enum>
<enum name="avgrxjitter">
<para>Our average jitter</para>
</enum>
<enum name="stdevrxjitter">
<para>Our jitter standard deviation</para>
</enum>
<enum name="reported_minjitter">
<para>Their minimum jitter</para>
</enum>
<enum name="reported_maxjitter">
<para>Their max jitter</para>
</enum>
<enum name="reported_avgjitter">
<para>Their average jitter</para>
</enum>
<enum name="reported_stdevjitter">
<para>Their jitter standard deviation</para>
</enum>
</enumlist>
</enum>
<enum name="all_loss">
<para>Retrieve a summary of all RTCP packet loss statistics.</para>
<para>The following data items are returned in a semi-colon
delineated list:</para>
<enumlist>
<enum name="minrxlost">
<para>Our minimum lost packets</para>
</enum>
<enum name="maxrxlost">
<para>Our max lost packets</para>
</enum>
<enum name="avgrxlost">
<para>Our average lost packets</para>
</enum>
<enum name="stdevrxlost">
<para>Our lost packets standard deviation</para>
</enum>
<enum name="reported_minlost">
<para>Their minimum lost packets</para>
</enum>
<enum name="reported_maxlost">
<para>Their max lost packets</para>
</enum>
<enum name="reported_avglost">
<para>Their average lost packets</para>
</enum>
<enum name="reported_stdevlost">
<para>Their lost packets standard deviation</para>
</enum>
</enumlist>
</enum>
<enum name="all_rtt">
<para>Retrieve a summary of all RTCP round trip time information.</para>
<para>The following data items are returned in a semi-colon
delineated list:</para>
<enumlist>
<enum name="minrtt">
<para>Minimum round trip time</para>
</enum>
<enum name="maxrtt">
<para>Maximum round trip time</para>
</enum>
<enum name="avgrtt">
<para>Average round trip time</para>
</enum>
<enum name="stdevrtt">
<para>Standard deviation round trip time</para>
</enum>
</enumlist>
</enum>
<enum name="txcount"><para>Transmitted packet count</para></enum>
<enum name="rxcount"><para>Received packet count</para></enum>
<enum name="txjitter"><para>Transmitted packet jitter</para></enum>
<enum name="rxjitter"><para>Received packet jitter</para></enum>
<enum name="remote_maxjitter"><para>Their max jitter</para></enum>
<enum name="remote_minjitter"><para>Their minimum jitter</para></enum>
<enum name="remote_normdevjitter"><para>Their average jitter</para></enum>
<enum name="remote_stdevjitter"><para>Their jitter standard deviation</para></enum>
<enum name="local_maxjitter"><para>Our max jitter</para></enum>
<enum name="local_minjitter"><para>Our minimum jitter</para></enum>
<enum name="local_normdevjitter"><para>Our average jitter</para></enum>
<enum name="local_stdevjitter"><para>Our jitter standard deviation</para></enum>
<enum name="txploss"><para>Transmitted packet loss</para></enum>
<enum name="rxploss"><para>Received packet loss</para></enum>
<enum name="remote_maxrxploss"><para>Their max lost packets</para></enum>
<enum name="remote_minrxploss"><para>Their minimum lost packets</para></enum>
<enum name="remote_normdevrxploss"><para>Their average lost packets</para></enum>
<enum name="remote_stdevrxploss"><para>Their lost packets standard deviation</para></enum>
<enum name="local_maxrxploss"><para>Our max lost packets</para></enum>
<enum name="local_minrxploss"><para>Our minimum lost packets</para></enum>
<enum name="local_normdevrxploss"><para>Our average lost packets</para></enum>
<enum name="local_stdevrxploss"><para>Our lost packets standard deviation</para></enum>
<enum name="rtt"><para>Round trip time</para></enum>
<enum name="maxrtt"><para>Maximum round trip time</para></enum>
<enum name="minrtt"><para>Minimum round trip time</para></enum>
<enum name="normdevrtt"><para>Average round trip time</para></enum>
<enum name="stdevrtt"><para>Standard deviation round trip time</para></enum>
<enum name="local_ssrc"><para>Our Synchronization Source identifier</para></enum>
<enum name="remote_ssrc"><para>Their Synchronization Source identifier</para></enum>
</enumlist>
</parameter>
<parameter name="media_type" required="false">
<para>When <replaceable>rtcp</replaceable> is specified, the
<literal>media_type</literal> parameter may be provided. It specifies
which media stream the chosen RTCP parameter should be retrieved
from.</para>
<enumlist>
<enum name="audio">
<para>Retrieve information from the audio media stream.</para>
<note><para>If not specified, <literal>audio</literal> is used
by default.</para></note>
</enum>
<enum name="video">
<para>Retrieve information from the video media stream.</para>
</enum>
</enumlist>
</parameter>
</enum>
<enum name="endpoint">
<para>R/O The name of the endpoint associated with this channel.
Use the <replaceable>PJSIP_ENDPOINT</replaceable> function to obtain
further endpoint related information.</para>
</enum>
<enum name="contact">
<para>R/O The name of the contact associated with this channel.
Use the <replaceable>PJSIP_CONTACT</replaceable> function to obtain
further contact related information. Note this may not be present and if so
is only available on outgoing legs.</para>
</enum>
<enum name="aor">
<para>R/O The name of the AOR associated with this channel.
Use the <replaceable>PJSIP_AOR</replaceable> function to obtain
further AOR related information. Note this may not be present and if so
is only available on outgoing legs.</para>
</enum>
<enum name="pjsip">
<para>R/O Obtain information about the current PJSIP channel and its
session.</para>
<parameter name="type" required="true">
<para>When <replaceable>pjsip</replaceable> is specified, the
<literal>type</literal> parameter must be provided. It specifies
which signalling parameter to read.</para>
<enumlist>
<enum name="call-id">
<para>The SIP call-id.</para>
</enum>
<enum name="secure">
<para>Whether or not the signalling uses a secure transport.</para>
<enumlist>
<enum name="0"><para>The signalling uses a non-secure transport.</para></enum>
<enum name="1"><para>The signalling uses a secure transport.</para></enum>
</enumlist>
</enum>
<enum name="target_uri">
<para>The contact URI where requests are sent.</para>
</enum>
<enum name="local_uri">
<para>The local URI.</para>
</enum>
<enum name="local_tag">
<para>Tag in From header</para>
</enum>
<enum name="remote_uri">
<para>The remote URI.</para>
</enum>
<enum name="remote_tag">
<para>Tag in To header</para>
</enum>
<enum name="request_uri">
<para>The request URI of the incoming <literal>INVITE</literal>
associated with the creation of this channel.</para>
</enum>
<enum name="t38state">
<para>The current state of any T.38 fax on this channel.</para>
<enumlist>
<enum name="DISABLED"><para>T.38 faxing is disabled on this channel.</para></enum>
<enum name="LOCAL_REINVITE"><para>Asterisk has sent a <literal>re-INVITE</literal> to the remote end to initiate a T.38 fax.</para></enum>
<enum name="REMOTE_REINVITE"><para>The remote end has sent a <literal>re-INVITE</literal> to Asterisk to initiate a T.38 fax.</para></enum>
<enum name="ENABLED"><para>A T.38 fax session has been enabled.</para></enum>
<enum name="REJECTED"><para>A T.38 fax session was attempted but was rejected.</para></enum>
</enumlist>
</enum>
<enum name="local_addr">
<para>On inbound calls, the full IP address and port number that
the <literal>INVITE</literal> request was received on. On outbound
calls, the full IP address and port number that the <literal>INVITE</literal>
request was transmitted from.</para>
</enum>
<enum name="remote_addr">
<para>On inbound calls, the full IP address and port number that
the <literal>INVITE</literal> request was received from. On outbound
calls, the full IP address and port number that the <literal>INVITE</literal>
request was transmitted to.</para>
</enum>
</enumlist>
</parameter>
</enum>
</enumlist>
</info>
<info name="CHANNEL_EXAMPLES" language="en_US" tech="PJSIP">
<example title="PJSIP specific CHANNEL examples">
; Log the current Call-ID
same => n,Log(NOTICE, ${CHANNEL(pjsip,call-id)})
; Log the destination address of the audio stream
same => n,Log(NOTICE, ${CHANNEL(rtp,dest)})
; Store the round-trip time associated with a
; video stream in the CDR field video-rtt
same => n,Set(CDR(video-rtt)=${CHANNEL(rtcp,rtt,video)})
</example>
</info>
***/
#include "asterisk.h"
#include <pjsip.h>
@ -525,6 +39,7 @@
#include "asterisk/module.h"
#include "asterisk/acl.h"
#include "asterisk/app.h"
#include "asterisk/conversions.h"
#include "asterisk/channel.h"
#include "asterisk/stream.h"
#include "asterisk/format.h"
@ -1701,3 +1216,121 @@ int pjsip_acf_session_refresh_write(struct ast_channel *chan, const char *cmd, c
return ast_sip_push_task_wait_serializer(channel->session->serializer, refresh_write_cb, &rdata);
}
struct hangup_data {
struct ast_sip_session *session;
int response_code;
};
/*!
* \brief Serializer task to hangup channel
*/
static int pjsip_hangup(void *obj)
{
struct hangup_data *hdata = obj;
pjsip_tx_data *packet = NULL;
if ((hdata->session->inv_session->state != PJSIP_INV_STATE_DISCONNECTED) &&
(pjsip_inv_answer(hdata->session->inv_session, hdata->response_code, NULL, NULL, &packet) == PJ_SUCCESS)) {
ast_sip_session_send_response(hdata->session, packet);
}
return 0;
}
/*!
* \brief Callback that validates the response code
*/
static int response_code_validator(const char *channel_name,
const char *response) {
int response_code;
int rc = ast_str_to_int(response, &response_code);
if (rc != 0) {
response_code = ast_sip_str2rc(response);
if (response_code < 0) {
ast_log(LOG_WARNING, "%s: Unrecognized response code parameter '%s'."
" Defaulting to 603 DECLINE\n",
channel_name, response);
return PJSIP_SC_DECLINE;
}
}
if (response_code < 400 || response_code > 699) {
ast_log(LOG_WARNING, "%s: Response code %d is out of range 400 -> 699."
" Defaulting to 603 DECLINE\n",
channel_name, response_code);
return PJSIP_SC_DECLINE;
}
return response_code;
}
/*!
* \brief Called by pjsip_app_hangup and pjsip_action_hangup
* to actually perform the hangup
*/
static void pjsip_app_hangup_handler(struct ast_channel *chan, int response_code)
{
struct ast_sip_channel_pvt *channel;
struct hangup_data hdata = { NULL, -1 };
const char *tag = ast_channel_name(chan);
hdata.response_code = response_code;
ast_channel_lock(chan);
if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {
ast_log(LOG_WARNING, "%s: Not a PJSIP channel\n", tag);
ast_channel_unlock(chan);
return;
}
channel = ast_channel_tech_pvt(chan);
hdata.session = channel->session;
if (hdata.session->inv_session->role != PJSIP_ROLE_UAS || (
hdata.session->inv_session->state != PJSIP_INV_STATE_INCOMING &&
hdata.session->inv_session->state != PJSIP_INV_STATE_EARLY)) {
ast_log(LOG_WARNING, "%s: Not an incoming channel or invalid state '%s'\n",
tag, pjsip_inv_state_name(hdata.session->inv_session->state));
ast_channel_unlock(chan);
return;
}
ast_channel_unlock(chan);
if (ast_sip_push_task_wait_serializer(channel->session->serializer,
pjsip_hangup, &hdata) != 0) {
ast_log(LOG_WARNING, "%s: failed to push hangup task to serializer\n", tag);
}
return;
}
/*!
* \brief PJSIPHangup Dialplan App
*/
int pjsip_app_hangup(struct ast_channel *chan, const char *data)
{
int response_code;
const char *tag = ast_channel_name(chan);
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "%s: Missing response code parameter\n", tag);
return -1;
}
response_code = response_code_validator(tag, data);
pjsip_app_hangup_handler(chan, response_code);
return -1;
}
/*!
* \brief PJSIPHangup Manager Action
*/
int pjsip_action_hangup(struct mansession *s, const struct message *m)
{
return ast_manager_hangup_helper(s, m,
pjsip_app_hangup_handler, response_code_validator);
}

View File

@ -0,0 +1,643 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE docs SYSTEM "appdocsxml.dtd">
<docs>
<application name="PJSIPHangup" language="en_US">
<synopsis>
Hangup an incoming PJSIP channel with a SIP response code
</synopsis>
<syntax>
<parameter name="Cause" required="true">
<para>May be one of...</para>
<enumlist>
<enum name="Response code"><para>A numeric response code in the range 400 ->699</para></enum>
<enum name="Response code name"><para>A response code name from
<literal>third-party/pjproject/source/pjsip/include/pjsip/sip_msg.h</literal>
such as <literal>USE_IDENTITY_HEADER</literal> or
<literal>PJSIP_SC_USE_IDENTITY_HEADER</literal></para></enum>
</enumlist>
</parameter>
</syntax>
<description>
<para>
Hangs up an incoming PJSIP channel and returns the
specified SIP response code in the final response to the caller.
</para>
<para>
</para>
<warning><para>
This function must be called BEFORE anything that
might cause any other final (non 1XX) response to be sent.
For example calling <literal>Answer()</literal> or
<literal>Playback</literal> without the
<literal>noanswer</literal> option will cause the call
to be answered and a final 200 response to be sent.
</para></warning>
<para>
</para>
<para>As with the <literal>Hangup</literal> application,
the dialplan will terminate after calling this function.</para>
<para>
</para>
<para>The cause code set on the channel will be translated to
a standard ISDN cause code using the table defined in
ast_sip_hangup_sip2cause() in res_pjsip.c</para>
<para>
</para>
<example title="Terminate call with 437 response code">
same = n,PJSIPHangup(437)
</example>
<example title="Terminate call with 437 response code using the response code name">
same = n,PJSIPHangup(UNSUPPORTED_CERTIFICATE)
</example>
<example title="Terminate call with 437 response code based on condition">
same = n,ExecIf($[${SOMEVALUE} = ${SOME_BAD_VALUE}]?PJSIPHangup(437))
</example>
</description>
</application>
<manager name="PJSIPHangup" language="en_US">
<synopsis>
Hangup an incoming PJSIP channel with a SIP response code
</synopsis>
<syntax>
<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
<xi:include xpointer="xpointer(/docs/manager[@name='Hangup']/syntax/parameter[@name='Channel'])" />
<xi:include xpointer="xpointer(/docs/application[@name='PJSIPHangup']/syntax/parameter[@name='Cause'])" />
</syntax>
<description>
<para>
Hangs up an incoming PJSIP channel and returns the
specified SIP response code in the final response to the caller.
</para>
<para>
</para>
<warning><para>
This function must be called BEFORE anything that
might cause any other final (non 1XX) response to be sent.
For example calling <literal>Answer()</literal> or
<literal>Playback</literal> without the
<literal>noanswer</literal> option will cause the call
to be answered and a final 200 response to be sent.
</para></warning>
<para>
</para>
<para>The cause code set on the channel will be translated to
a standard ISDN cause code using the table defined in
ast_sip_hangup_sip2cause() in res_pjsip.c</para>
<para>
</para>
<example title="Terminate call with 437 response code">
Action: PJSIPHangup
ActionID: 12345678
Channel: PJSIP/alice-00000002
Cause: 437
</example>
<example title="Terminate call with 437 response code using the response code name">
Action: PJSIPHangup
ActionID: 12345678
Channel: PJSIP/alice-00000002
Cause: UNSUPPORTED_CERTIFICATE
</example>
</description>
</manager>
<function name="PJSIP_DIAL_CONTACTS" language="en_US">
<synopsis>
Return a dial string for dialing all contacts on an AOR.
</synopsis>
<syntax>
<parameter name="endpoint" required="true">
<para>Name of the endpoint</para>
</parameter>
<parameter name="aor" required="false">
<para>Name of an AOR to use, if not specified the configured AORs on the endpoint are used</para>
</parameter>
<parameter name="request_user" required="false">
<para>Optional request user to use in the request URI</para>
</parameter>
</syntax>
<description>
<para>Returns a properly formatted dial string for dialing all contacts on an AOR.</para>
</description>
</function>
<function name="PJSIP_MEDIA_OFFER" language="en_US">
<synopsis>
Media and codec offerings to be set on an outbound SIP channel prior to dialing.
</synopsis>
<syntax>
<parameter name="media" required="true">
<para>types of media offered</para>
</parameter>
</syntax>
<description>
<para>When read, returns the codecs offered based upon the media choice.</para>
<para>When written, sets the codecs to offer when an outbound dial attempt is made,
or when a session refresh is sent using <replaceable>PJSIP_SEND_SESSION_REFRESH</replaceable>.
</para>
</description>
<see-also>
<ref type="function">PJSIP_SEND_SESSION_REFRESH</ref>
</see-also>
</function>
<function name="PJSIP_DTMF_MODE" language="en_US">
<synopsis>
Get or change the DTMF mode for a SIP call.
</synopsis>
<syntax>
</syntax>
<description>
<para>When read, returns the current DTMF mode</para>
<para>When written, sets the current DTMF mode</para>
<para>This function uses the same DTMF mode naming as the dtmf_mode configuration option</para>
</description>
</function>
<function name="PJSIP_MOH_PASSTHROUGH" language="en_US">
<synopsis>
Get or change the on-hold behavior for a SIP call.
</synopsis>
<syntax>
</syntax>
<description>
<para>When read, returns the current moh passthrough mode</para>
<para>When written, sets the current moh passthrough mode</para>
<para>If <replaceable>yes</replaceable>, on-hold re-INVITEs are sent. If <replaceable>no</replaceable>, music on hold is generated.</para>
<para>This function can be used to override the moh_passthrough configuration option</para>
</description>
</function>
<function name="PJSIP_SEND_SESSION_REFRESH" language="en_US">
<synopsis>
W/O: Initiate a session refresh via an UPDATE or re-INVITE on an established media session
</synopsis>
<syntax>
<parameter name="update_type" required="false">
<para>The type of update to send. Default is <literal>invite</literal>.</para>
<enumlist>
<enum name="invite">
<para>Send the session refresh as a re-INVITE.</para>
</enum>
<enum name="update">
<para>Send the session refresh as an UPDATE.</para>
</enum>
</enumlist>
</parameter>
</syntax>
<description>
<para>This function will cause the PJSIP stack to immediately refresh
the media session for the channel. This will be done using either a
re-INVITE (default) or an UPDATE request.
</para>
<para>This is most useful when combined with the <replaceable>PJSIP_MEDIA_OFFER</replaceable>
dialplan function, as it allows the formats in use on a channel to be
re-negotiated after call setup.</para>
<warning>
<para>The formats the endpoint supports are <emphasis>not</emphasis>
checked or enforced by this function. Using this function to offer
formats not supported by the endpoint <emphasis>may</emphasis> result
in a loss of media.</para>
</warning>
<example title="Re-negotiate format to g722">
; Within some existing extension on an answered channel
same => n,Set(PJSIP_MEDIA_OFFER(audio)=!all,g722)
same => n,Set(PJSIP_SEND_SESSION_REFRESH()=invite)
</example>
</description>
<see-also>
<ref type="function">PJSIP_MEDIA_OFFER</ref>
</see-also>
</function>
<function name="PJSIP_PARSE_URI" language="en_US">
<synopsis>
Parse an uri and return a type part of the URI.
</synopsis>
<syntax>
<parameter name="uri" required="true">
<para>URI to parse</para>
</parameter>
<parameter name="type" required="true">
<para>The <literal>type</literal> parameter specifies which URI part to read</para>
<enumlist>
<enum name="display">
<para>Display name.</para>
</enum>
<enum name="scheme">
<para>URI scheme.</para>
</enum>
<enum name="user">
<para>User part.</para>
</enum>
<enum name="passwd">
<para>Password part.</para>
</enum>
<enum name="host">
<para>Host part.</para>
</enum>
<enum name="port">
<para>Port number, or zero.</para>
</enum>
<enum name="user_param">
<para>User parameter.</para>
</enum>
<enum name="method_param">
<para>Method parameter.</para>
</enum>
<enum name="transport_param">
<para>Transport parameter.</para>
</enum>
<enum name="ttl_param">
<para>TTL param, or -1.</para>
</enum>
<enum name="lr_param">
<para>Loose routing param, or zero.</para>
</enum>
<enum name="maddr_param">
<para>Maddr param.</para>
</enum>
</enumlist>
</parameter>
</syntax>
<description>
<para>Parse an URI and return a specified part of the URI.</para>
</description>
</function>
<info name="CHANNEL" language="en_US" tech="PJSIP">
<enumlist>
<enum name="rtp">
<para>R/O Retrieve media related information.</para>
<parameter name="type" required="true">
<para>When <replaceable>rtp</replaceable> is specified, the
<literal>type</literal> parameter must be provided. It specifies
which RTP parameter to read.</para>
<enumlist>
<enum name="src">
<para>Retrieve the local address for RTP.</para>
</enum>
<enum name="dest">
<para>Retrieve the remote address for RTP.</para>
</enum>
<enum name="direct">
<para>If direct media is enabled, this address is the remote address
used for RTP.</para>
</enum>
<enum name="secure">
<para>Whether or not the media stream is encrypted.</para>
<enumlist>
<enum name="0">
<para>The media stream is not encrypted.</para>
</enum>
<enum name="1">
<para>The media stream is encrypted.</para>
</enum>
</enumlist>
</enum>
<enum name="hold">
<para>Whether or not the media stream is currently restricted
due to a call hold.</para>
<enumlist>
<enum name="0">
<para>The media stream is not held.</para>
</enum>
<enum name="1">
<para>The media stream is held.</para>
</enum>
</enumlist>
</enum>
</enumlist>
</parameter>
<parameter name="media_type" required="false">
<para>When <replaceable>rtp</replaceable> is specified, the
<literal>media_type</literal> parameter may be provided. It specifies
which media stream the chosen RTP parameter should be retrieved
from.</para>
<enumlist>
<enum name="audio">
<para>Retrieve information from the audio media stream.</para>
<note><para>If not specified, <literal>audio</literal> is used
by default.</para></note>
</enum>
<enum name="video">
<para>Retrieve information from the video media stream.</para>
</enum>
</enumlist>
</parameter>
</enum>
<enum name="rtcp">
<para>R/O Retrieve RTCP statistics.</para>
<parameter name="statistic" required="true">
<para>When <replaceable>rtcp</replaceable> is specified, the
<literal>statistic</literal> parameter must be provided. It specifies
which RTCP statistic parameter to read.</para>
<enumlist>
<enum name="all">
<para>Retrieve a summary of all RTCP statistics.</para>
<para>The following data items are returned in a semi-colon
delineated list:</para>
<enumlist>
<enum name="ssrc">
<para>Our Synchronization Source identifier</para>
</enum>
<enum name="themssrc">
<para>Their Synchronization Source identifier</para>
</enum>
<enum name="lp">
<para>Our lost packet count</para>
</enum>
<enum name="rxjitter">
<para>Received packet jitter</para>
</enum>
<enum name="rxcount">
<para>Received packet count</para>
</enum>
<enum name="txjitter">
<para>Transmitted packet jitter</para>
</enum>
<enum name="txcount">
<para>Transmitted packet count</para>
</enum>
<enum name="rlp">
<para>Remote lost packet count</para>
</enum>
<enum name="rtt">
<para>Round trip time</para>
</enum>
<enum name="txmes">
<para>Transmitted Media Experience Score</para>
</enum>
<enum name="rxmes">
<para>Received Media Experience Score</para>
</enum>
</enumlist>
</enum>
<enum name="all_jitter">
<para>Retrieve a summary of all RTCP Jitter statistics.</para>
<para>The following data items are returned in a semi-colon
delineated list:</para>
<enumlist>
<enum name="minrxjitter">
<para>Our minimum jitter</para>
</enum>
<enum name="maxrxjitter">
<para>Our max jitter</para>
</enum>
<enum name="avgrxjitter">
<para>Our average jitter</para>
</enum>
<enum name="stdevrxjitter">
<para>Our jitter standard deviation</para>
</enum>
<enum name="reported_minjitter">
<para>Their minimum jitter</para>
</enum>
<enum name="reported_maxjitter">
<para>Their max jitter</para>
</enum>
<enum name="reported_avgjitter">
<para>Their average jitter</para>
</enum>
<enum name="reported_stdevjitter">
<para>Their jitter standard deviation</para>
</enum>
</enumlist>
</enum>
<enum name="all_loss">
<para>Retrieve a summary of all RTCP packet loss statistics.</para>
<para>The following data items are returned in a semi-colon
delineated list:</para>
<enumlist>
<enum name="minrxlost">
<para>Our minimum lost packets</para>
</enum>
<enum name="maxrxlost">
<para>Our max lost packets</para>
</enum>
<enum name="avgrxlost">
<para>Our average lost packets</para>
</enum>
<enum name="stdevrxlost">
<para>Our lost packets standard deviation</para>
</enum>
<enum name="reported_minlost">
<para>Their minimum lost packets</para>
</enum>
<enum name="reported_maxlost">
<para>Their max lost packets</para>
</enum>
<enum name="reported_avglost">
<para>Their average lost packets</para>
</enum>
<enum name="reported_stdevlost">
<para>Their lost packets standard deviation</para>
</enum>
</enumlist>
</enum>
<enum name="all_rtt">
<para>Retrieve a summary of all RTCP round trip time information.</para>
<para>The following data items are returned in a semi-colon
delineated list:</para>
<enumlist>
<enum name="minrtt">
<para>Minimum round trip time</para>
</enum>
<enum name="maxrtt">
<para>Maximum round trip time</para>
</enum>
<enum name="avgrtt">
<para>Average round trip time</para>
</enum>
<enum name="stdevrtt">
<para>Standard deviation round trip time</para>
</enum>
</enumlist>
</enum>
<enum name="all_mes">
<para>Retrieve a summary of all RTCP Media Experience Score information.</para>
<para>The following data items are returned in a semi-colon
delineated list:</para>
<enumlist>
<enum name="minmes">
<para>Minimum MES based on us analysing received packets.</para>
</enum>
<enum name="maxmes">
<para>Maximum MES based on us analysing received packets.</para>
</enum>
<enum name="avgmes">
<para>Average MES based on us analysing received packets.</para>
</enum>
<enum name="stdevmes">
<para>Standard deviation MES based on us analysing received packets.</para>
</enum>
<enum name="reported_minmes">
<para>Minimum MES based on data we get in Sender and Receiver Reports sent by the remote end</para>
</enum>
<enum name="reported_maxmes">
<para>Maximum MES based on data we get in Sender and Receiver Reports sent by the remote end</para>
</enum>
<enum name="reported_avgmes">
<para>Average MES based on data we get in Sender and Receiver Reports sent by the remote end</para>
</enum>
<enum name="reported_stdevmes">
<para>Standard deviation MES based on data we get in Sender and Receiver Reports sent by the remote end</para>
</enum>
</enumlist>
</enum>
<enum name="txcount"><para>Transmitted packet count</para></enum>
<enum name="rxcount"><para>Received packet count</para></enum>
<enum name="txjitter"><para>Transmitted packet jitter</para></enum>
<enum name="rxjitter"><para>Received packet jitter</para></enum>
<enum name="remote_maxjitter"><para>Their max jitter</para></enum>
<enum name="remote_minjitter"><para>Their minimum jitter</para></enum>
<enum name="remote_normdevjitter"><para>Their average jitter</para></enum>
<enum name="remote_stdevjitter"><para>Their jitter standard deviation</para></enum>
<enum name="local_maxjitter"><para>Our max jitter</para></enum>
<enum name="local_minjitter"><para>Our minimum jitter</para></enum>
<enum name="local_normdevjitter"><para>Our average jitter</para></enum>
<enum name="local_stdevjitter"><para>Our jitter standard deviation</para></enum>
<enum name="txploss"><para>Transmitted packet loss</para></enum>
<enum name="rxploss"><para>Received packet loss</para></enum>
<enum name="remote_maxrxploss"><para>Their max lost packets</para></enum>
<enum name="remote_minrxploss"><para>Their minimum lost packets</para></enum>
<enum name="remote_normdevrxploss"><para>Their average lost packets</para></enum>
<enum name="remote_stdevrxploss"><para>Their lost packets standard deviation</para></enum>
<enum name="local_maxrxploss"><para>Our max lost packets</para></enum>
<enum name="local_minrxploss"><para>Our minimum lost packets</para></enum>
<enum name="local_normdevrxploss"><para>Our average lost packets</para></enum>
<enum name="local_stdevrxploss"><para>Our lost packets standard deviation</para></enum>
<enum name="rtt"><para>Round trip time</para></enum>
<enum name="maxrtt"><para>Maximum round trip time</para></enum>
<enum name="minrtt"><para>Minimum round trip time</para></enum>
<enum name="normdevrtt"><para>Average round trip time</para></enum>
<enum name="stdevrtt"><para>Standard deviation round trip time</para></enum>
<enum name="local_ssrc"><para>Our Synchronization Source identifier</para></enum>
<enum name="remote_ssrc"><para>Their Synchronization Source identifier</para></enum>
<enum name="txmes"><para>
Current MES based on us analyzing rtt, jitter and loss
in the actual received RTP stream received from the remote end.
I.E. This is the MES for the incoming audio stream.
</para></enum>
<enum name="rxmes"><para>
Current MES based on rtt and the jitter and loss values in
RTCP sender and receiver reports we receive from the
remote end. I.E. This is the MES for the outgoing audio stream.
</para></enum>
<enum name="remote_maxmes"><para>Max MES based on data we get in Sender and Receiver Reports sent by the remote end</para></enum>
<enum name="remote_minmes"><para>Min MES based on data we get in Sender and Receiver Reports sent by the remote end</para></enum>
<enum name="remote_normdevmes"><para>Average MES based on data we get in Sender and Receiver Reports sent by the remote end</para></enum>
<enum name="remote_stdevmes"><para>Standard deviation MES based on data we get in Sender and Receiver Reports sent by the remote end</para></enum>
<enum name="local_maxmes"><para>Max MES based on us analyzing the received RTP stream</para></enum>
<enum name="local_minmes"><para>Min MES based on us analyzing the received RTP stream</para></enum>
<enum name="local_normdevmes"><para>Average MES based on us analyzing the received RTP stream</para></enum>
<enum name="local_stdevmes"><para>Standard deviation MES based on us analyzing the received RTP stream</para></enum>
</enumlist>
</parameter>
<parameter name="media_type" required="false">
<para>When <replaceable>rtcp</replaceable> is specified, the
<literal>media_type</literal> parameter may be provided. It specifies
which media stream the chosen RTCP parameter should be retrieved
from.</para>
<enumlist>
<enum name="audio">
<para>Retrieve information from the audio media stream.</para>
<note><para>If not specified, <literal>audio</literal> is used
by default.</para></note>
</enum>
<enum name="video">
<para>Retrieve information from the video media stream.</para>
</enum>
</enumlist>
</parameter>
</enum>
<enum name="endpoint">
<para>R/O The name of the endpoint associated with this channel.
Use the <replaceable>PJSIP_ENDPOINT</replaceable> function to obtain
further endpoint related information.</para>
</enum>
<enum name="contact">
<para>R/O The name of the contact associated with this channel.
Use the <replaceable>PJSIP_CONTACT</replaceable> function to obtain
further contact related information. Note this may not be present and if so
is only available on outgoing legs.</para>
</enum>
<enum name="aor">
<para>R/O The name of the AOR associated with this channel.
Use the <replaceable>PJSIP_AOR</replaceable> function to obtain
further AOR related information. Note this may not be present and if so
is only available on outgoing legs.</para>
</enum>
<enum name="pjsip">
<para>R/O Obtain information about the current PJSIP channel and its
session.</para>
<parameter name="type" required="true">
<para>When <replaceable>pjsip</replaceable> is specified, the
<literal>type</literal> parameter must be provided. It specifies
which signalling parameter to read.</para>
<enumlist>
<enum name="call-id">
<para>The SIP call-id.</para>
</enum>
<enum name="secure">
<para>Whether or not the signalling uses a secure transport.</para>
<enumlist>
<enum name="0"><para>The signalling uses a non-secure transport.</para></enum>
<enum name="1"><para>The signalling uses a secure transport.</para></enum>
</enumlist>
</enum>
<enum name="target_uri">
<para>The contact URI where requests are sent.</para>
</enum>
<enum name="local_uri">
<para>The local URI.</para>
</enum>
<enum name="local_tag">
<para>Tag in From header</para>
</enum>
<enum name="remote_uri">
<para>The remote URI.</para>
</enum>
<enum name="remote_tag">
<para>Tag in To header</para>
</enum>
<enum name="request_uri">
<para>The request URI of the incoming <literal>INVITE</literal>
associated with the creation of this channel.</para>
</enum>
<enum name="t38state">
<para>The current state of any T.38 fax on this channel.</para>
<enumlist>
<enum name="DISABLED"><para>T.38 faxing is disabled on this channel.</para></enum>
<enum name="LOCAL_REINVITE"><para>Asterisk has sent a <literal>re-INVITE</literal> to the remote end to initiate a T.38 fax.</para></enum>
<enum name="REMOTE_REINVITE"><para>The remote end has sent a <literal>re-INVITE</literal> to Asterisk to initiate a T.38 fax.</para></enum>
<enum name="ENABLED"><para>A T.38 fax session has been enabled.</para></enum>
<enum name="REJECTED"><para>A T.38 fax session was attempted but was rejected.</para></enum>
</enumlist>
</enum>
<enum name="local_addr">
<para>On inbound calls, the full IP address and port number that
the <literal>INVITE</literal> request was received on. On outbound
calls, the full IP address and port number that the <literal>INVITE</literal>
request was transmitted from.</para>
</enum>
<enum name="remote_addr">
<para>On inbound calls, the full IP address and port number that
the <literal>INVITE</literal> request was received from. On outbound
calls, the full IP address and port number that the <literal>INVITE</literal>
request was transmitted to.</para>
</enum>
</enumlist>
</parameter>
</enum>
</enumlist>
</info>
<info name="CHANNEL_EXAMPLES" language="en_US" tech="PJSIP">
<example title="PJSIP specific CHANNEL examples">
; Log the current Call-ID
same => n,Log(NOTICE, ${CHANNEL(pjsip,call-id)})
; Log the destination address of the audio stream
same => n,Log(NOTICE, ${CHANNEL(rtp,dest)})
; Store the round-trip time associated with a
; video stream in the CDR field video-rtt
same => n,Set(CDR(video-rtt)=${CHANNEL(rtcp,rtt,video)})
</example>
</info>
</docs>

View File

@ -148,4 +148,24 @@ int pjsip_acf_dial_contacts_read(struct ast_channel *chan, const char *cmd, char
*/
int pjsip_acf_parse_uri_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len);
#endif /* _PJSIP_DIALPLAN_FUNCTIONS */
/*!
* \brief Hang up an incoming PJSIP channel with a SIP response code
* \param chan The channel the function is called on
* \param data SIP response code or name
*
* \retval 0 on success
* \retval -1 on failure
*/
int pjsip_app_hangup(struct ast_channel *chan, const char *data);
/*!
* \brief Manager action to hang up an incoming PJSIP channel with a SIP response code
* \param s session
* \param m message
*
* \retval 0 on success
* \retval -1 on failure
*/
int pjsip_action_hangup(struct mansession *s, const struct message *m);
#endif /* _PJSIP_DIALPLAN_FUNCTIONS */

View File

@ -627,4 +627,45 @@ void ast_manager_publish_event(const char *type, int class_type, struct ast_json
*/
struct stasis_message_router *ast_manager_get_message_router(void);
/*!
* \brief Callback used by ast_manager_hangup_helper
* that will actually hangup a channel
*
* \param chan The channel to hang up
* \param causecode Cause code to set on the channel
*/
typedef void (*manager_hangup_handler_t)(struct ast_channel *chan, int causecode);
/*!
* \brief Callback used by ast_manager_hangup_helper
* that will validate the cause code.
* \param channel_name Mostly for displaying log messages
* \param cause Cause code string
*
* \returns integer cause code
*/
typedef int (*manager_hangup_cause_validator_t)(const char *channel_name,
const char *cause);
/*!
* \brief A manager helper function that hangs up a channel using a supplied
* channel type specific hangup function and cause code validator
*
* This function handles the lookup of channel(s) and the AMI interaction
* but uses the supplied callbacks to actually perform the hangup. It can be
* used to implement a custom AMI 'Hangup' action without having to duplicate
* all the code in the standard Hangup action.
*
* \param s Session
* \param m Message
* \param handler Function that actually performs the hangup
* \param cause_validator Function that validates the cause code
*
* \retval 0 on success.
* \retval non-zero on error.
*/
int ast_manager_hangup_helper(struct mansession *s, const struct message *m,
manager_hangup_handler_t handler, manager_hangup_cause_validator_t cause_validator);
#endif /* _ASTERISK_MANAGER_H */

View File

@ -3753,4 +3753,17 @@ void ast_sip_transport_state_register(struct ast_sip_tpmgr_state_callback *eleme
*/
void ast_sip_transport_state_unregister(struct ast_sip_tpmgr_state_callback *element);
/*!
* \brief Convert name to SIP response code
*
* \param name SIP response code name matching one of the
* enum names defined in "enum pjsip_status_code"
* defined in sip_msg.h. May be specified with or
* without the PJSIP_SC_ prefix.
*
* \retval SIP response code
* \retval -1 if matching code not found
*/
int ast_sip_str2rc(const char *name);
#endif /* _RES_PJSIP_H */

View File

@ -4563,7 +4563,9 @@ static int action_challenge(struct mansession *s, const struct message *m)
return 0;
}
static int action_hangup(struct mansession *s, const struct message *m)
int ast_manager_hangup_helper(struct mansession *s,
const struct message *m, manager_hangup_handler_t hangup_handler,
manager_hangup_cause_validator_t cause_validator)
{
struct ast_channel *c = NULL;
int causecode = 0; /* all values <= 0 mean 'do not set hangupcause in channel' */
@ -4587,7 +4589,9 @@ static int action_hangup(struct mansession *s, const struct message *m)
idText[0] = '\0';
}
if (!ast_strlen_zero(cause)) {
if (cause_validator) {
causecode = cause_validator(name_or_regex, cause);
} else if (!ast_strlen_zero(cause)) {
char *endptr;
causecode = strtol(cause, &endptr, 10);
if (causecode < 0 || causecode > 127 || *endptr != '\0') {
@ -4614,7 +4618,7 @@ static int action_hangup(struct mansession *s, const struct message *m)
ast_sockaddr_stringify_addr(&s->session->addr),
ast_channel_name(c));
ast_channel_softhangup_withcause_locked(c, causecode);
hangup_handler(c, causecode);
c = ast_channel_unref(c);
astman_send_ack(s, m, "Channel Hungup");
@ -4660,7 +4664,7 @@ static int action_hangup(struct mansession *s, const struct message *m)
ast_sockaddr_stringify_addr(&s->session->addr),
ast_channel_name(c));
ast_channel_softhangup_withcause_locked(c, causecode);
hangup_handler(c, causecode);
channels_matched++;
astman_append(s,
@ -4680,6 +4684,12 @@ static int action_hangup(struct mansession *s, const struct message *m)
return 0;
}
static int action_hangup(struct mansession *s, const struct message *m)
{
return ast_manager_hangup_helper(s, m,
ast_channel_softhangup_withcause_locked, NULL);
}
static int action_setvar(struct mansession *s, const struct message *m)
{
struct ast_channel *c = NULL;

View File

@ -2504,6 +2504,96 @@ struct ast_threadpool *ast_sip_threadpool(void)
return sip_threadpool;
}
struct response_code_map {
int code;
const char *long_name;
const char *short_name;
};
/*
* This map was generated from sip_msg.h with
*
* sed -n -r -e 's/^\s+(PJSIP_SC_([^ =]+))\s*=\s*[0-9]+,/{ \1, "\1", "\2" },/gp' \
* third-party/pjproject/source/pjsip/include/pjsip/sip_msg.h
*
*/
static const struct response_code_map rc_map[] = {
{ PJSIP_SC_NULL, "PJSIP_SC_NULL", "NULL" },
{ PJSIP_SC_TRYING, "PJSIP_SC_TRYING", "TRYING" },
{ PJSIP_SC_RINGING, "PJSIP_SC_RINGING", "RINGING" },
{ PJSIP_SC_CALL_BEING_FORWARDED, "PJSIP_SC_CALL_BEING_FORWARDED", "CALL_BEING_FORWARDED" },
{ PJSIP_SC_QUEUED, "PJSIP_SC_QUEUED", "QUEUED" },
{ PJSIP_SC_PROGRESS, "PJSIP_SC_PROGRESS", "PROGRESS" },
{ PJSIP_SC_OK, "PJSIP_SC_OK", "OK" },
{ PJSIP_SC_ACCEPTED, "PJSIP_SC_ACCEPTED", "ACCEPTED" },
{ PJSIP_SC_MULTIPLE_CHOICES, "PJSIP_SC_MULTIPLE_CHOICES", "MULTIPLE_CHOICES" },
{ PJSIP_SC_MOVED_PERMANENTLY, "PJSIP_SC_MOVED_PERMANENTLY", "MOVED_PERMANENTLY" },
{ PJSIP_SC_MOVED_TEMPORARILY, "PJSIP_SC_MOVED_TEMPORARILY", "MOVED_TEMPORARILY" },
{ PJSIP_SC_USE_PROXY, "PJSIP_SC_USE_PROXY", "USE_PROXY" },
{ PJSIP_SC_ALTERNATIVE_SERVICE, "PJSIP_SC_ALTERNATIVE_SERVICE", "ALTERNATIVE_SERVICE" },
{ PJSIP_SC_BAD_REQUEST, "PJSIP_SC_BAD_REQUEST", "BAD_REQUEST" },
{ PJSIP_SC_UNAUTHORIZED, "PJSIP_SC_UNAUTHORIZED", "UNAUTHORIZED" },
{ PJSIP_SC_PAYMENT_REQUIRED, "PJSIP_SC_PAYMENT_REQUIRED", "PAYMENT_REQUIRED" },
{ PJSIP_SC_FORBIDDEN, "PJSIP_SC_FORBIDDEN", "FORBIDDEN" },
{ PJSIP_SC_NOT_FOUND, "PJSIP_SC_NOT_FOUND", "NOT_FOUND" },
{ PJSIP_SC_METHOD_NOT_ALLOWED, "PJSIP_SC_METHOD_NOT_ALLOWED", "METHOD_NOT_ALLOWED" },
{ PJSIP_SC_NOT_ACCEPTABLE, "PJSIP_SC_NOT_ACCEPTABLE", "NOT_ACCEPTABLE" },
{ PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED, "PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED", "PROXY_AUTHENTICATION_REQUIRED" },
{ PJSIP_SC_REQUEST_TIMEOUT, "PJSIP_SC_REQUEST_TIMEOUT", "REQUEST_TIMEOUT" },
{ PJSIP_SC_GONE, "PJSIP_SC_GONE", "GONE" },
{ PJSIP_SC_REQUEST_ENTITY_TOO_LARGE, "PJSIP_SC_REQUEST_ENTITY_TOO_LARGE", "REQUEST_ENTITY_TOO_LARGE" },
{ PJSIP_SC_REQUEST_URI_TOO_LONG, "PJSIP_SC_REQUEST_URI_TOO_LONG", "REQUEST_URI_TOO_LONG" },
{ PJSIP_SC_UNSUPPORTED_MEDIA_TYPE, "PJSIP_SC_UNSUPPORTED_MEDIA_TYPE", "UNSUPPORTED_MEDIA_TYPE" },
{ PJSIP_SC_UNSUPPORTED_URI_SCHEME, "PJSIP_SC_UNSUPPORTED_URI_SCHEME", "UNSUPPORTED_URI_SCHEME" },
{ PJSIP_SC_BAD_EXTENSION, "PJSIP_SC_BAD_EXTENSION", "BAD_EXTENSION" },
{ PJSIP_SC_EXTENSION_REQUIRED, "PJSIP_SC_EXTENSION_REQUIRED", "EXTENSION_REQUIRED" },
{ PJSIP_SC_SESSION_TIMER_TOO_SMALL, "PJSIP_SC_SESSION_TIMER_TOO_SMALL", "SESSION_TIMER_TOO_SMALL" },
{ PJSIP_SC_INTERVAL_TOO_BRIEF, "PJSIP_SC_INTERVAL_TOO_BRIEF", "INTERVAL_TOO_BRIEF" },
{ PJSIP_SC_TEMPORARILY_UNAVAILABLE, "PJSIP_SC_TEMPORARILY_UNAVAILABLE", "TEMPORARILY_UNAVAILABLE" },
{ PJSIP_SC_CALL_TSX_DOES_NOT_EXIST, "PJSIP_SC_CALL_TSX_DOES_NOT_EXIST", "CALL_TSX_DOES_NOT_EXIST" },
{ PJSIP_SC_LOOP_DETECTED, "PJSIP_SC_LOOP_DETECTED", "LOOP_DETECTED" },
{ PJSIP_SC_TOO_MANY_HOPS, "PJSIP_SC_TOO_MANY_HOPS", "TOO_MANY_HOPS" },
{ PJSIP_SC_ADDRESS_INCOMPLETE, "PJSIP_SC_ADDRESS_INCOMPLETE", "ADDRESS_INCOMPLETE" },
{ PJSIP_SC_BUSY_HERE, "PJSIP_SC_BUSY_HERE", "BUSY_HERE" },
{ PJSIP_SC_REQUEST_TERMINATED, "PJSIP_SC_REQUEST_TERMINATED", "REQUEST_TERMINATED" },
{ PJSIP_SC_NOT_ACCEPTABLE_HERE, "PJSIP_SC_NOT_ACCEPTABLE_HERE", "NOT_ACCEPTABLE_HERE" },
{ PJSIP_SC_BAD_EVENT, "PJSIP_SC_BAD_EVENT", "BAD_EVENT" },
{ PJSIP_SC_REQUEST_UPDATED, "PJSIP_SC_REQUEST_UPDATED", "REQUEST_UPDATED" },
{ PJSIP_SC_REQUEST_PENDING, "PJSIP_SC_REQUEST_PENDING", "REQUEST_PENDING" },
{ PJSIP_SC_UNDECIPHERABLE, "PJSIP_SC_UNDECIPHERABLE", "UNDECIPHERABLE" },
{ PJSIP_SC_INTERNAL_SERVER_ERROR, "PJSIP_SC_INTERNAL_SERVER_ERROR", "INTERNAL_SERVER_ERROR" },
{ PJSIP_SC_NOT_IMPLEMENTED, "PJSIP_SC_NOT_IMPLEMENTED", "NOT_IMPLEMENTED" },
{ PJSIP_SC_BAD_GATEWAY, "PJSIP_SC_BAD_GATEWAY", "BAD_GATEWAY" },
{ PJSIP_SC_SERVICE_UNAVAILABLE, "PJSIP_SC_SERVICE_UNAVAILABLE", "SERVICE_UNAVAILABLE" },
{ PJSIP_SC_SERVER_TIMEOUT, "PJSIP_SC_SERVER_TIMEOUT", "SERVER_TIMEOUT" },
{ PJSIP_SC_VERSION_NOT_SUPPORTED, "PJSIP_SC_VERSION_NOT_SUPPORTED", "VERSION_NOT_SUPPORTED" },
{ PJSIP_SC_MESSAGE_TOO_LARGE, "PJSIP_SC_MESSAGE_TOO_LARGE", "MESSAGE_TOO_LARGE" },
{ PJSIP_SC_PRECONDITION_FAILURE, "PJSIP_SC_PRECONDITION_FAILURE", "PRECONDITION_FAILURE" },
{ PJSIP_SC_BUSY_EVERYWHERE, "PJSIP_SC_BUSY_EVERYWHERE", "BUSY_EVERYWHERE" },
{ PJSIP_SC_DECLINE, "PJSIP_SC_DECLINE", "DECLINE" },
{ PJSIP_SC_DOES_NOT_EXIST_ANYWHERE, "PJSIP_SC_DOES_NOT_EXIST_ANYWHERE", "DOES_NOT_EXIST_ANYWHERE" },
{ PJSIP_SC_NOT_ACCEPTABLE_ANYWHERE, "PJSIP_SC_NOT_ACCEPTABLE_ANYWHERE", "NOT_ACCEPTABLE_ANYWHERE" },
};
int ast_sip_str2rc(const char *name)
{
int i;
if (ast_strlen_zero(name)) {
return -1;
}
for (i = 0; i < ARRAY_LEN(rc_map); i++) {
if (strcasecmp(rc_map[i].short_name, name) == 0 ||
strcasecmp(rc_map[i].long_name, name) == 0) {
return rc_map[i].code;
}
}
return -1;
}
#ifdef TEST_FRAMEWORK
AST_TEST_DEFINE(xml_sanitization_end_null)
{