Changes to the channels directory for Digium phone support.

Next step: Get this poopoo compiling!



git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/10-digiumphones@361261 65c4cc65-6c06-0410-ace0-fbb531ad65f3
10-digiumphones
Mark Michelson 14 years ago
parent 3979ff87b4
commit 1cd169d034

@ -264,6 +264,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/cel.h"
#include "asterisk/data.h"
#include "asterisk/aoc.h"
#include "asterisk/custom_control_frame.h"
#include "asterisk/message.h"
#include "sip/include/sip.h"
#include "sip/include/globals.h"
@ -1086,6 +1087,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
@ -1369,7 +1377,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_devicestate(void *data);
static int sip_poke_noanswer(const void *data);
static int sip_poke_peer(struct sip_peer *peer, int force);
@ -1500,7 +1509,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);
@ -3858,7 +3867,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>");
@ -6866,6 +6878,54 @@ static int initialize_udptl(struct sip_pvt *p)
return 0;
}
/*!
* \brief Sends AST_CUSTOM_FRAME of type sip info.
*
* \note pvt is expected to be locked before entering this function.
*/
static int sip_handle_custom_info(struct sip_pvt *pvt, struct ast_custom_payload *pl)
{
struct ast_variable *headers = NULL;
char *content_type = NULL;
char *content = NULL;
char *useragent_filter = NULL;
struct ast_variable *var;
struct sip_request req;
int res = -1;
if (ast_custom_payload_sipinfo_decode(pl, &headers, &content_type, &content, &useragent_filter)) {
goto custom_info_cleanup;
}
if (!(ast_strlen_zero(useragent_filter))) {
int match = (strstr(pvt->useragent, useragent_filter)) ? 1 : 0;
if (!match) {
goto custom_info_cleanup;
}
}
reqprep(&req, pvt, 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(pvt, &req, XMIT_RELIABLE, pvt->ocseq);
custom_info_cleanup:
ast_free(content);
ast_free(content_type);
ast_free(useragent_filter);
ast_variables_destroy(headers);
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
@ -6995,6 +7055,11 @@ static int sip_indicate(struct ast_channel *ast, int condition, const void *data
case AST_CONTROL_REDIRECTING:
update_redirecting(p, data, datalen);
break;
case AST_CONTROL_CUSTOM:
if (datalen && ast_custom_payload_type((struct ast_custom_payload *) data) == AST_CUSTOM_SIP_INFO) {
sip_handle_custom_info(p, (struct ast_custom_payload *) data);
}
break;
case AST_CONTROL_AOC:
{
struct ast_aoc_decoded *decoded = ast_aoc_decode((struct ast_aoc_encoded *) data, datalen, ast);
@ -12875,8 +12940,13 @@ static int find_calling_channel(void *obj, void *arg, void *data, int flags)
return res ? CMP_MATCH | CMP_STOP : 0;
}
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";
@ -12884,7 +12954,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;
@ -12929,9 +12999,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++;
@ -12979,12 +13056,24 @@ 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_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;
@ -13053,7 +13142,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);
@ -13097,7 +13186,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];
@ -13129,7 +13218,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");
@ -13152,19 +13241,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;
@ -14946,37 +15035,35 @@ static void cb_extensionstate_destroy(int id, void *data)
dialog_unref(p, "the extensionstate containing this dialog ptr was destroyed");
}
/*! \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);
@ -14984,6 +15071,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
*/
@ -21022,9 +21130,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;
@ -25714,8 +25828,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);
@ -25725,14 +25841,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");

@ -1481,7 +1481,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)
@ -2990,11 +2990,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;

@ -1019,6 +1019,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 */
@ -1117,6 +1119,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 */

Loading…
Cancel
Save