summaryrefslogtreecommitdiff
path: root/channels
diff options
context:
space:
mode:
authorMark Michelson <mmichelson@digium.com>2012-06-04 20:26:12 +0000
committerMark Michelson <mmichelson@digium.com>2012-06-04 20:26:12 +0000
commit14a985560ed5830aa3e1b5880890a59a5d0f0c2f (patch)
tree4d6f57c4358566c5508d79e97560640ce59df5c8 /channels
parentc1bbe79748bb1615ab116fe287b8d5d28a83b330 (diff)
Merge changes dealing with support for Digium phones.
Presence support has been added. This is accomplished by allowing for presence hints in addition to device state hints. A dialplan function called PRESENCE_STATE has been added to allow for setting and reading presence. Presence can be transmitted to Digium phones using custom XML elements in a PIDF presence document. Voicemail has new APIs that allow for moving, removing, forwarding, and playing messages. Messages have had a new unique message ID added to them so that the APIs will work reliably. The state of a voicemail mailbox can be obtained using an API that allows one to get a snapshot of the mailbox. A voicemail Dialplan App called VoiceMailPlayMsg has been added to be able to play back a specific message. Configuration hooks have been added. Configuration hooks allow for a piece of code to be executed when a specific configuration file is loaded by a specific module. This is useful for modules that are dependent on the configuration of other modules. chan_sip now has a public method that allows for a custom SIP INFO request to be sent mid-dialog. Digium phones use this in order to display progress bars when files are played. Messaging support has been expanded a bit. The main visible difference is the addition of an AMI action MessageSend. Finally, a ParkingLots manager action has been added in order to get a list of parking lots. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@368435 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'channels')
-rw-r--r--channels/chan_sip.c246
-rw-r--r--channels/chan_sip.exports.in6
-rw-r--r--channels/chan_skinny.c15
-rw-r--r--channels/sip/include/sip.h3
4 files changed, 234 insertions, 36 deletions
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 289a807cf..8456b0b99 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -230,6 +230,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
affect the speed of the program at all. They can be considered to be documentation.
*/
/* #define REF_DEBUG 1 */
+
#include "asterisk/lock.h"
#include "asterisk/config.h"
#include "asterisk/module.h"
@@ -277,7 +278,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "sip/include/dialog.h"
#include "sip/include/dialplan_functions.h"
#include "sip/include/security_events.h"
-
+#include "asterisk/sip_api.h"
/*** DOCUMENTATION
<application name="SIPDtmfMode" language="en_US">
@@ -339,6 +340,20 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<para>Always returns <literal>0</literal>.</para>
</description>
</application>
+ <application name="SIPSendCustomINFO" language="en_US">
+ <synopsis>
+ Send a custom INFO frame on specified channels.
+ </synopsis>
+ <syntax>
+ <parameter name="Data" required="true" />
+ <parameter name="UserAgent" required="false" />
+ </syntax>
+ <description>
+ <para>SIPSendCustomINFO() allows you to send a custom INFO message on all
+ active SIP channels or on channels with the specified User Agent. This
+ application is only available if TEST_FRAMEWORK is defined.</para>
+ </description>
+ </application>
<function name="SIP_HEADER" language="en_US">
<synopsis>
Gets the specified SIP header from an incoming INVITE message.
@@ -671,7 +686,8 @@ static const struct sip_reasons {
{ AST_REDIRECTING_REASON_FOLLOW_ME, "follow-me" },
{ AST_REDIRECTING_REASON_OUT_OF_ORDER, "out-of-service" },
{ AST_REDIRECTING_REASON_AWAY, "away" },
- { AST_REDIRECTING_REASON_CALL_FWD_DTE, "unknown"}
+ { AST_REDIRECTING_REASON_CALL_FWD_DTE, "unknown"},
+ { AST_REDIRECTING_REASON_SEND_TO_VM, "send_to_vm"},
};
@@ -1090,6 +1106,13 @@ static void destroy_escs(void)
}
}
+struct state_notify_data {
+ int state;
+ int presence_state;
+ const char *presence_subtype;
+ const char *presence_message;
+};
+
/*!
* \details
* Here we implement the container for dialogs which are in the
@@ -1373,7 +1396,8 @@ static int attempt_transfer(struct sip_dual *transferer, struct sip_dual *target
static int do_magic_pickup(struct ast_channel *channel, const char *extension, const char *context);
/*--- Device monitoring and Device/extension state/event handling */
-static int cb_extensionstate(const char *context, const char *exten, enum ast_extension_states state, void *data);
+static int extensionstate_update(char *context, char *exten, struct state_notify_data *data, struct sip_pvt *p);
+static int cb_extensionstate(char *context, char *exten, struct ast_state_cb_info *info, void *data);
static int sip_poke_noanswer(const void *data);
static int sip_poke_peer(struct sip_peer *peer, int force);
static void sip_poke_all_peers(void);
@@ -1505,7 +1529,7 @@ static int get_rpid(struct sip_pvt *p, struct sip_request *oreq);
static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq, char **name, char **number, int *reason);
static enum sip_get_dest_result get_destination(struct sip_pvt *p, struct sip_request *oreq, int *cc_recall_core_id);
static int get_msg_text(char *buf, int len, struct sip_request *req);
-static int transmit_state_notify(struct sip_pvt *p, int state, int full, int timeout);
+static int transmit_state_notify(struct sip_pvt *p, struct state_notify_data *data, int full, int timeout);
static void update_connectedline(struct sip_pvt *p, const void *data, size_t datalen);
static void update_redirecting(struct sip_pvt *p, const void *data, size_t datalen);
static int get_domain(const char *str, char *domain, int len);
@@ -3865,7 +3889,10 @@ static int __sip_autodestruct(const void *data)
/* If this is a subscription, tell the phone that we got a timeout */
if (p->subscribed && p->subscribed != MWI_NOTIFICATION && p->subscribed != CALL_COMPLETION) {
- transmit_state_notify(p, AST_EXTENSION_DEACTIVATED, 1, TRUE); /* Send last notification */
+ struct state_notify_data data = { 0, };
+ data.state = AST_EXTENSION_DEACTIVATED;
+
+ transmit_state_notify(p, &data, 1, TRUE); /* Send last notification */
p->subscribed = NONE;
append_history(p, "Subscribestatus", "timeout");
ast_debug(3, "Re-scheduled destruction of SIP subscription %s\n", p->callid ? p->callid : "<unknown>");
@@ -6928,6 +6955,52 @@ static int initialize_udptl(struct sip_pvt *p)
return 0;
}
+int ast_sipinfo_send(
+ struct ast_channel *chan,
+ struct ast_variable *headers,
+ const char *content_type,
+ const char *content,
+ const char *useragent_filter)
+{
+ struct sip_pvt *p;
+ struct ast_variable *var;
+ struct sip_request req;
+ int res = -1;
+
+ ast_channel_lock(chan);
+
+ if (ast_channel_tech(chan) != &sip_tech) {
+ ast_log(LOG_WARNING, "Attempted to send a custom INFO on a non-SIP channel %s\n", ast_channel_name(chan));
+ ast_channel_unlock(chan);
+ return res;
+ }
+
+ p = ast_channel_tech_pvt(chan);
+ sip_pvt_lock(p);
+
+ if (!(ast_strlen_zero(useragent_filter))) {
+ int match = (strstr(p->useragent, useragent_filter)) ? 1 : 0;
+ if (!match) {
+ goto cleanup;
+ }
+ }
+
+ reqprep(&req, p, SIP_INFO, 0, 1);
+ for (var = headers; var; var = var->next) {
+ add_header(&req, var->name, var->value);
+ }
+ if (!ast_strlen_zero(content) && !ast_strlen_zero(content_type)) {
+ add_header(&req, "Content-Type", content_type);
+ add_content(&req, content);
+ }
+
+ res = send_request(p, &req, XMIT_RELIABLE, p->ocseq);
+
+cleanup:
+ sip_pvt_unlock(p);
+ ast_channel_unlock(chan);
+ return res;
+}
/*! \brief Play indication to user
* With SIP a lot of indications is sent as messages, letting the device play
the indication - busy signal, congestion etc
@@ -13070,8 +13143,14 @@ static int find_calling_channel(void *obj, void *arg, void *data, int flags)
return res ? CMP_MATCH | CMP_STOP : 0;
}
+/* XXX Candidate for moving into its own file */
+static int allow_notify_user_presence(struct sip_pvt *p)
+{
+ return (strstr(p->useragent, "Digium")) ? 1 : 0;
+}
+
/*! \brief Builds XML portion of NOTIFY messages for presence or dialog updates */
-static void state_notify_build_xml(int state, int full, const char *exten, const char *context, struct ast_str **tmp, struct sip_pvt *p, int subscribed, const char *mfrom, const char *mto)
+static void state_notify_build_xml(struct state_notify_data *data, int full, const char *exten, const char *context, struct ast_str **tmp, struct sip_pvt *p, int subscribed, const char *mfrom, const char *mto)
{
enum state { NOTIFY_OPEN, NOTIFY_INUSE, NOTIFY_CLOSED } local_state = NOTIFY_OPEN;
const char *statestring = "terminated";
@@ -13079,7 +13158,7 @@ static void state_notify_build_xml(int state, int full, const char *exten, const
const char *pidfnote= "Ready";
char hint[AST_MAX_EXTENSION];
- switch (state) {
+ switch (data->state) {
case (AST_EXTENSION_RINGING | AST_EXTENSION_INUSE):
statestring = (sip_cfg.notifyringing) ? "early" : "confirmed";
local_state = NOTIFY_INUSE;
@@ -13124,9 +13203,16 @@ static void state_notify_build_xml(int state, int full, const char *exten, const
/* Check which device/devices we are watching and if they are registered */
if (ast_get_hint(hint, sizeof(hint), NULL, 0, NULL, context, exten)) {
- char *hint2 = hint, *individual_hint = NULL;
+ char *hint2;
+ char *individual_hint = NULL;
int hint_count = 0, unavailable_count = 0;
+ /* strip off any possible PRESENCE providers from hint */
+ if ((hint2 = strrchr(hint, ','))) {
+ *hint2 = '\0';
+ }
+ hint2 = hint;
+
while ((individual_hint = strsep(&hint2, "&"))) {
hint_count++;
@@ -13174,12 +13260,30 @@ static void state_notify_build_xml(int state, int full, const char *exten, const
ast_str_append(tmp, 0, "<status><basic>open</basic></status>\n");
else
ast_str_append(tmp, 0, "<status><basic>%s</basic></status>\n", (local_state != NOTIFY_CLOSED) ? "open" : "closed");
+
+ if (allow_notify_user_presence(p) && (data->presence_state > 0)) {
+ ast_str_append(tmp, 0, "</tuple>\n");
+ ast_str_append(tmp, 0, "<tuple id=\"digium-presence\">\n");
+ ast_str_append(tmp, 0, "<status>\n");
+ ast_str_append(tmp, 0, "<digium_presence type=\"%s\" subtype=\"%s\">%s</digium_presence>\n",
+ ast_presence_state2str(data->presence_state),
+ S_OR(data->presence_subtype, ""),
+ S_OR(data->presence_message, ""));
+ ast_str_append(tmp, 0, "</status>\n");
+ ast_test_suite_event_notify("DIGIUM_PRESENCE_SENT",
+ "PresenceState: %s\r\n"
+ "Subtype: %s\r\n"
+ "Message: %s",
+ ast_presence_state2str(data->presence_state),
+ S_OR(data->presence_subtype, ""),
+ S_OR(data->presence_message, ""));
+ }
ast_str_append(tmp, 0, "</tuple>\n</presence>\n");
break;
case DIALOG_INFO_XML: /* SNOM subscribes in this format */
ast_str_append(tmp, 0, "<?xml version=\"1.0\"?>\n");
ast_str_append(tmp, 0, "<dialog-info xmlns=\"urn:ietf:params:xml:ns:dialog-info\" version=\"%u\" state=\"%s\" entity=\"%s\">\n", p->dialogver, full ? "full" : "partial", mto);
- if ((state & AST_EXTENSION_RINGING) && sip_cfg.notifyringing) {
+ if ((data->state & AST_EXTENSION_RINGING) && sip_cfg.notifyringing) {
const char *local_display = exten;
char *local_target = ast_strdupa(mto);
const char *remote_display = exten;
@@ -13256,7 +13360,7 @@ static void state_notify_build_xml(int state, int full, const char *exten, const
ast_str_append(tmp, 0, "<dialog id=\"%s\">\n", exten);
}
ast_str_append(tmp, 0, "<state>%s</state>\n", statestring);
- if (state == AST_EXTENSION_ONHOLD) {
+ if (data->state == AST_EXTENSION_ONHOLD) {
ast_str_append(tmp, 0, "<local>\n<target uri=\"%s\">\n"
"<param pname=\"+sip.rendering\" pvalue=\"no\"/>\n"
"</target>\n</local>\n", mto);
@@ -13300,7 +13404,7 @@ static int transmit_cc_notify(struct ast_cc_agent *agent, struct sip_pvt *subscr
}
/*! \brief Used in the SUBSCRIBE notification subsystem (RFC3265) */
-static int transmit_state_notify(struct sip_pvt *p, int state, int full, int timeout)
+static int transmit_state_notify(struct sip_pvt *p, struct state_notify_data *data, int full, int timeout)
{
struct ast_str *tmp = ast_str_alloca(4000);
char from[256], to[256];
@@ -13332,7 +13436,7 @@ static int transmit_state_notify(struct sip_pvt *p, int state, int full, int tim
reqprep(&req, p, SIP_NOTIFY, 0, 1);
- switch(state) {
+ switch(data->state) {
case AST_EXTENSION_DEACTIVATED:
if (timeout)
add_header(&req, "Subscription-State", "terminated;reason=timeout");
@@ -13355,19 +13459,19 @@ static int transmit_state_notify(struct sip_pvt *p, int state, int full, int tim
case XPIDF_XML:
case CPIM_PIDF_XML:
add_header(&req, "Event", subscriptiontype->event);
- state_notify_build_xml(state, full, p->exten, p->context, &tmp, p, p->subscribed, mfrom, mto);
+ state_notify_build_xml(data, full, p->exten, p->context, &tmp, p, p->subscribed, mfrom, mto);
add_header(&req, "Content-Type", subscriptiontype->mediatype);
p->dialogver++;
break;
case PIDF_XML: /* Eyebeam supports this format */
add_header(&req, "Event", subscriptiontype->event);
- state_notify_build_xml(state, full, p->exten, p->context, &tmp, p, p->subscribed, mfrom, mto);
+ state_notify_build_xml(data, full, p->exten, p->context, &tmp, p, p->subscribed, mfrom, mto);
add_header(&req, "Content-Type", subscriptiontype->mediatype);
p->dialogver++;
break;
case DIALOG_INFO_XML: /* SNOM subscribes in this format */
add_header(&req, "Event", subscriptiontype->event);
- state_notify_build_xml(state, full, p->exten, p->context, &tmp, p, p->subscribed, mfrom, mto);
+ state_notify_build_xml(data, full, p->exten, p->context, &tmp, p, p->subscribed, mfrom, mto);
add_header(&req, "Content-Type", subscriptiontype->mediatype);
p->dialogver++;
break;
@@ -15152,34 +15256,35 @@ static void cb_extensionstate_destroy(int id, void *data)
/*! \brief Callback for the devicestate notification (SUBSCRIBE) support subsystem
\note If you add an "hint" priority to the extension in the dial plan,
you will get notifications on device state changes */
-static int cb_extensionstate(const char *context, const char *exten, enum ast_extension_states state, void *data)
+static int extensionstate_update(char *context, char *exten, struct state_notify_data *data, struct sip_pvt *p)
{
- struct sip_pvt *p = data;
-
sip_pvt_lock(p);
- switch(state) {
+ switch (data->state) {
case AST_EXTENSION_DEACTIVATED: /* Retry after a while */
case AST_EXTENSION_REMOVED: /* Extension is gone */
sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT); /* Delete subscription in 32 secs */
- ast_verb(2, "Extension state: Watcher for hint %s %s. Notify User %s\n", exten, state == AST_EXTENSION_DEACTIVATED ? "deactivated" : "removed", p->username);
+ ast_verb(2, "Extension state: Watcher for hint %s %s. Notify User %s\n", exten, data->state == AST_EXTENSION_DEACTIVATED ? "deactivated" : "removed", p->username);
p->subscribed = NONE;
- append_history(p, "Subscribestatus", "%s", state == AST_EXTENSION_REMOVED ? "HintRemoved" : "Deactivated");
+ append_history(p, "Subscribestatus", "%s", data->state == AST_EXTENSION_REMOVED ? "HintRemoved" : "Deactivated");
break;
default: /* Tell user */
- p->laststate = state;
+ p->laststate = data->state;
+ p->last_presence_state = data->presence_state;
+ ast_string_field_set(p, last_presence_subtype, S_OR(data->presence_subtype, ""));
+ ast_string_field_set(p, last_presence_message, S_OR(data->presence_message, ""));
break;
}
if (p->subscribed != NONE) { /* Only send state NOTIFY if we know the format */
if (!p->pendinginvite) {
- transmit_state_notify(p, state, 1, FALSE);
+ transmit_state_notify(p, data, 1, FALSE);
} else {
/* We already have a NOTIFY sent that is not answered. Queue the state up.
if many state changes happen meanwhile, we will only send a notification of the last one */
ast_set_flag(&p->flags[1], SIP_PAGE2_STATECHANGEQUEUE);
}
}
- ast_verb(2, "Extension Changed %s[%s] new state %s for Notify User %s %s\n", exten, context, ast_extension_state2str(state), p->username,
+ ast_verb(2, "Extension Changed %s[%s] new state %s for Notify User %s %s\n", exten, context, ast_extension_state2str(data->state), p->username,
ast_test_flag(&p->flags[1], SIP_PAGE2_STATECHANGEQUEUE) ? "(queued)" : "");
sip_pvt_unlock(p);
@@ -15187,6 +15292,27 @@ static int cb_extensionstate(const char *context, const char *exten, enum ast_ex
return 0;
}
+/*! \brief Callback for the devicestate notification (SUBSCRIBE) support subsystem
+\note If you add an "hint" priority to the extension in the dial plan,
+ you will get notifications on device state changes */
+static int cb_extensionstate(char *context, char *exten, struct ast_state_cb_info *info, void *data)
+{
+ struct sip_pvt *p = data;
+ struct state_notify_data notify_data = {
+ .state = info->exten_state,
+ .presence_state = info->presence_state,
+ .presence_subtype = info->presence_subtype,
+ .presence_message = info->presence_message,
+ };
+
+ if ((info->reason == AST_HINT_UPDATE_PRESENCE) && !(allow_notify_user_presence(p))) {
+ /* ignore a presence triggered update if we know the useragent doesn't care */
+ return 0;
+ }
+
+ return extensionstate_update(context, exten, &notify_data, p);
+}
+
/*! \brief Send a fake 401 Unauthorized response when the administrator
wants to hide the names of local devices from fishers
*/
@@ -21342,9 +21468,15 @@ static void handle_response_notify(struct sip_pvt *p, int resp, const char *rest
pvt_set_needdestroy(p, "received 200 response");
}
if (ast_test_flag(&p->flags[1], SIP_PAGE2_STATECHANGEQUEUE)) {
+ struct state_notify_data data = {
+ .state = p->laststate,
+ .presence_state = p->last_presence_state,
+ .presence_subtype = p->last_presence_subtype,
+ .presence_message = p->last_presence_message,
+ };
/* Ready to send the next state we have on queue */
ast_clear_flag(&p->flags[1], SIP_PAGE2_STATECHANGEQUEUE);
- cb_extensionstate((char *)p->context, (char *)p->exten, p->laststate, (void *) p);
+ extensionstate_update((char *)p->context, (char *)p->exten, &data, (void *) p);
}
}
break;
@@ -24331,6 +24463,8 @@ static int handle_request_refer(struct sip_pvt *p, struct sip_request *req, int
int localtransfer = 0;
int attendedtransfer = 0;
int res = 0;
+ struct ast_party_redirecting redirecting;
+ struct ast_set_party_redirecting update_redirecting;
if (req->debug) {
ast_verbose("Call %s got a SIP call transfer from %s: (REFER)!\n",
@@ -24635,6 +24769,16 @@ static int handle_request_refer(struct sip_pvt *p, struct sip_request *req, int
}
ast_set_flag(&p->flags[0], SIP_DEFER_BYE_ON_TRANSFER); /* Delay hangup */
+ /* When a call is transferred to voicemail from a Digium phone, there may be
+ * a Diversion header present in the REFER with an appropriate reason parameter
+ * set. We need to update the redirecting information appropriately.
+ */
+ ast_party_redirecting_init(&redirecting);
+ memset(&update_redirecting, 0, sizeof(update_redirecting));
+ change_redirecting_information(p, req, &redirecting, &update_redirecting, FALSE);
+ ast_channel_update_redirecting(current.chan2, &redirecting, &update_redirecting);
+ ast_party_redirecting_free(&redirecting);
+
/* Do not hold the pvt lock during the indicate and async_goto. Those functions
* lock channels which will invalidate locking order if the pvt lock is held.*/
/* For blind transfers, move the call to the new extensions. For attended transfers on multiple
@@ -25684,7 +25828,6 @@ static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req,
{
int gotdest = 0;
int res = 0;
- int firststate;
struct sip_peer *authpeer = NULL;
const char *eventheader = sip_get_header(req, "Event"); /* Get Event package name */
int resubscribe = (p->subscribed != NONE) && !req->ignore;
@@ -26037,9 +26180,10 @@ static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req,
sip_unref_peer(peer, "release a peer ref now that MWI is sent");
}
} else if (p->subscribed != CALL_COMPLETION) {
-
- if ((firststate = ast_extension_state(NULL, p->context, p->exten)) < 0) {
-
+ struct state_notify_data data = { 0, };
+ char *subtype = NULL;
+ char *message = NULL;
+ if ((data.state = ast_extension_state(NULL, p->context, p->exten)) < 0) {
ast_log(LOG_NOTICE, "Got SUBSCRIBE for extension %s@%s from %s, but there is no hint for that extension.\n", p->exten, p->context, ast_sockaddr_stringify(&p->sa));
transmit_response(p, "404 Not found", req);
pvt_set_needdestroy(p, "no extension for SUBSCRIBE");
@@ -26048,14 +26192,21 @@ static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req,
}
return 0;
}
+ if (allow_notify_user_presence(p)) {
+ data.presence_state = ast_hint_presence_state(NULL, p->context, p->exten, &subtype, &message);
+ data.presence_subtype = subtype;
+ data.presence_message = message;
+ }
ast_set_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED);
transmit_response(p, "200 OK", req);
- transmit_state_notify(p, firststate, 1, FALSE); /* Send first notification */
- append_history(p, "Subscribestatus", "%s", ast_extension_state2str(firststate));
+ transmit_state_notify(p, &data, 1, FALSE); /* Send first notification */
+ append_history(p, "Subscribestatus", "%s", ast_extension_state2str(data.state));
/* hide the 'complete' exten/context in the refer_to field for later display */
ast_string_field_build(p, subscribeuri, "%s@%s", p->exten, p->context);
/* Deleted the slow iteration of all sip dialogs to find old subscribes from this peer for exten@context */
+ ast_free(subtype);
+ ast_free(message);
}
if (!p->expiry) {
pvt_set_needdestroy(p, "forcing expiration");
@@ -30813,6 +30964,9 @@ static struct ast_rtp_glue sip_rtp_glue = {
static char *app_dtmfmode = "SIPDtmfMode";
static char *app_sipaddheader = "SIPAddHeader";
static char *app_sipremoveheader = "SIPRemoveHeader";
+#ifdef TEST_FRAMEWORK
+static char *app_sipsendcustominfo = "SIPSendCustomINFO";
+#endif
/*! \brief Set the DTMFmode for an outbound SIP call (application) */
static int sip_dtmfmode(struct ast_channel *chan, const char *data)
@@ -30941,6 +31095,28 @@ static int sip_removeheader(struct ast_channel *chan, const char *data)
return 0;
}
+#ifdef TEST_FRAMEWORK
+/*! \brief Send a custom INFO message via AST_CONTROL_CUSTOM indication */
+static int sip_sendcustominfo(struct ast_channel *chan, const char *data)
+{
+ char *info_data, *useragent;
+
+ if (ast_strlen_zero(data)) {
+ ast_log(LOG_WARNING, "You must provide data to be sent\n");
+ return 0;
+ }
+
+ useragent = ast_strdupa(data);
+ info_data = strsep(&useragent, ",");
+
+ if (ast_sipinfo_send(chan, NULL, "text/plain", info_data, useragent)) {
+ ast_log(LOG_WARNING, "Failed to create payload for custom SIP INFO\n");
+ return 0;
+ }
+ return 0;
+}
+#endif
+
/*! \brief Transfer call before connect with a 302 redirect
\note Called by the transfer() dialplan application through the sip_transfer()
pbx interface function if the call is in ringing state
@@ -31922,6 +32098,9 @@ static int load_module(void)
ast_register_application_xml(app_dtmfmode, sip_dtmfmode);
ast_register_application_xml(app_sipaddheader, sip_addheader);
ast_register_application_xml(app_sipremoveheader, sip_removeheader);
+#ifdef TEST_FRAMEWORK
+ ast_register_application_xml(app_sipsendcustominfo, sip_sendcustominfo);
+#endif
/* Register dialplan functions */
ast_custom_function_register(&sip_header_function);
@@ -32015,8 +32194,9 @@ static int unload_module(void)
ast_unregister_application(app_dtmfmode);
ast_unregister_application(app_sipaddheader);
ast_unregister_application(app_sipremoveheader);
-
#ifdef TEST_FRAMEWORK
+ ast_unregister_application(app_sipsendcustominfo);
+
AST_TEST_UNREGISTER(test_sip_peers_get);
AST_TEST_UNREGISTER(test_sip_mwi_subscribe_parse);
#endif
@@ -32166,7 +32346,7 @@ static int unload_module(void)
return 0;
}
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Session Initiation Protocol (SIP)",
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Session Initiation Protocol (SIP)",
.load = load_module,
.unload = unload_module,
.reload = reload,
diff --git a/channels/chan_sip.exports.in b/channels/chan_sip.exports.in
new file mode 100644
index 000000000..1e9972a72
--- /dev/null
+++ b/channels/chan_sip.exports.in
@@ -0,0 +1,6 @@
+{
+ global:
+ LINKER_SYMBOL_PREFIX*ast_sipinfo_send;
+ local:
+ *;
+};
diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c
index 753d7aeba..6923f8fb9 100644
--- a/channels/chan_skinny.c
+++ b/channels/chan_skinny.c
@@ -1510,7 +1510,7 @@ static struct ast_channel_tech skinny_tech = {
.bridge = ast_rtp_instance_bridge,
};
-static int skinny_extensionstate_cb(const char *context, const char *exten, enum ast_extension_states state, void *data);
+static int skinny_extensionstate_cb(char *context, char *id, struct ast_state_cb_info *info, void *data);
static int skinny_transfer(struct skinny_subchannel *sub);
static struct skinny_line *skinny_line_alloc(void)
@@ -3029,11 +3029,17 @@ static void transmit_capabilitiesreq(struct skinny_device *d)
transmit_response(d, req);
}
-static int skinny_extensionstate_cb(const char *context, const char *exten, enum ast_extension_states state, void *data)
+static int skinny_extensionstate_cb(char *context, char *exten, struct ast_state_cb_info *info, void *data)
{
struct skinny_container *container = data;
struct skinny_device *d = NULL;
char hint[AST_MAX_EXTENSION];
+ int state = info->exten_state;
+
+ /* only interested in device state here */
+ if (info->reason != AST_HINT_UPDATE_DEVICE) {
+ return 0;
+ }
if (container->type == SKINNY_SDCONTAINER) {
struct skinny_speeddial *sd = container->data;
@@ -5060,10 +5066,13 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
AST_LIST_TRAVERSE(&tmpline->sublines, tmpsubline, list) {
if (!(subline == tmpsubline)) {
if (!strcasecmp(subline->lnname, tmpsubline->lnname)) {
+ struct ast_state_cb_info info = {
+ .exten_state = tmpsubline->extenstate,
+ };
tmpsubline->callid = callnums++;
transmit_callstate(tmpsubline->line->device, tmpsubline->line->instance, tmpsubline->callid, SKINNY_OFFHOOK);
push_callinfo(tmpsubline, sub);
- skinny_extensionstate_cb(NULL, NULL, tmpsubline->extenstate, tmpsubline->container);
+ skinny_extensionstate_cb(NULL, NULL, &info, tmpsubline->container);
}
}
}
diff --git a/channels/sip/include/sip.h b/channels/sip/include/sip.h
index 958fe9af2..e8f079df6 100644
--- a/channels/sip/include/sip.h
+++ b/channels/sip/include/sip.h
@@ -1041,6 +1041,8 @@ struct sip_pvt {
AST_STRING_FIELD(parkinglot); /*!< Parkinglot */
AST_STRING_FIELD(engine); /*!< RTP engine to use */
AST_STRING_FIELD(dialstring); /*!< The dialstring used to call this SIP endpoint */
+ AST_STRING_FIELD(last_presence_subtype); /*!< The last presence subtype sent for a subscription. */
+ AST_STRING_FIELD(last_presence_message); /*!< The last presence message for a subscription */
AST_STRING_FIELD(msg_body); /*!< Text for a MESSAGE body */
);
char via[128]; /*!< Via: header */
@@ -1141,6 +1143,7 @@ struct sip_pvt {
enum subscriptiontype subscribed; /*!< SUBSCRIBE: Is this dialog a subscription? */
int stateid; /*!< SUBSCRIBE: ID for devicestate subscriptions */
int laststate; /*!< SUBSCRIBE: Last known extension state */
+ int last_presence_state; /*!< SUBSCRIBE: Last known presence state */
uint32_t dialogver; /*!< SUBSCRIBE: Version for subscription dialog-info */
struct ast_dsp *dsp; /*!< Inband DTMF or Fax CNG tone Detection dsp */