Fixes for sending SIP MESSAGE outside of calls.

* Fix authenticate MESSAGE losing custom headers added by the MESSAGE_DATA
function in the authorization attempt.

* Pass up better From header contents for SIP to use.  Now is in the
"display-name" <URI> format expected by MessageSend.  (Note that this is a
behavior change that could concievably affect some people.)

* Block user from adding standard headers that are added automatically.
(To, From,...)

* Allow the user to override the Content-Type header contents sent by
MessageSend.

* Decrement Max-Forwards header if the user transferred it from an
incoming message.

* Expand SIP short header names so the dialplan and other code only has to
deal with the full names.

* Documents what SIP expects in the MessageSend(from) parameter.

(closes issue ASTERISK-18992)
Reported by: Yuri

(closes issue ASTERISK-18917)
Reported by: Shaun Clark

Review: https://reviewboard.asterisk.org/r/1683/
........

Merged revisions 352520 from http://svn.asterisk.org/svn/asterisk/branches/10


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@352538 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Richard Mudgett
2012-01-25 17:23:25 +00:00
parent 4bf5e3716e
commit cbe57b11cb
4 changed files with 308 additions and 95 deletions

View File

@@ -147,6 +147,12 @@ RTP changes
mode has successfully exited. These changes are based on how pjmedia handles mode has successfully exited. These changes are based on how pjmedia handles
media sources and source changes. media sources and source changes.
Text Messaging
--------------
* MESSAGE(from) for incoming SIP messages now returns "display-name" <uri>
instead of simply the uri. This is the format that MessageSend() can use
in the from parameter for outgoing SIP messages.
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
--- Functionality changes from Asterisk 1.8 to Asterisk 10 ------------------- --- Functionality changes from Asterisk 1.8 to Asterisk 10 -------------------
------------------------------------------------------------------------------ ------------------------------------------------------------------------------

View File

@@ -1275,8 +1275,7 @@ static int transmit_reinvite_with_sdp(struct sip_pvt *p, int t38version, int old
static int transmit_info_with_aoc(struct sip_pvt *p, struct ast_aoc_decoded *decoded); static int transmit_info_with_aoc(struct sip_pvt *p, struct ast_aoc_decoded *decoded);
static int transmit_info_with_digit(struct sip_pvt *p, const char digit, unsigned int duration); static int transmit_info_with_digit(struct sip_pvt *p, const char digit, unsigned int duration);
static int transmit_info_with_vidupdate(struct sip_pvt *p); static int transmit_info_with_vidupdate(struct sip_pvt *p);
static int transmit_message_with_text(struct sip_pvt *p, const char *text, int init, int auth); static int transmit_message(struct sip_pvt *p, int init, int auth);
static int transmit_message_with_msg(struct sip_pvt *p, const struct ast_msg *msg);
static int transmit_refer(struct sip_pvt *p, const char *dest); static int transmit_refer(struct sip_pvt *p, const char *dest);
static int transmit_notify_with_mwi(struct sip_pvt *p, int newmsgs, int oldmsgs, const char *vmexten); static int transmit_notify_with_mwi(struct sip_pvt *p, int newmsgs, int oldmsgs, const char *vmexten);
static int transmit_notify_with_sipfrag(struct sip_pvt *p, int cseq, char *message, int terminate); static int transmit_notify_with_sipfrag(struct sip_pvt *p, int cseq, char *message, int terminate);
@@ -1536,7 +1535,8 @@ static int add_header(struct sip_request *req, const char *var, const char *valu
static int add_header_max_forwards(struct sip_pvt *dialog, struct sip_request *req); static int add_header_max_forwards(struct sip_pvt *dialog, struct sip_request *req);
static int add_content(struct sip_request *req, const char *line); static int add_content(struct sip_request *req, const char *line);
static int finalize_content(struct sip_request *req); static int finalize_content(struct sip_request *req);
static int add_text(struct sip_request *req, const char *text); static void destroy_msg_headers(struct sip_pvt *pvt);
static int add_text(struct sip_request *req, struct sip_pvt *p);
static int add_digit(struct sip_request *req, char digit, unsigned int duration, int mode); static int add_digit(struct sip_request *req, char digit, unsigned int duration, int mode);
static int add_rpid(struct sip_request *req, struct sip_pvt *p); static int add_rpid(struct sip_request *req, struct sip_pvt *p);
static int add_vidupdate(struct sip_request *req); static int add_vidupdate(struct sip_request *req);
@@ -4512,7 +4512,12 @@ static int sip_sendtext(struct ast_channel *ast, const char *text)
ast_verbose("Sending text %s on %s\n", text, ast_channel_name(ast)); ast_verbose("Sending text %s on %s\n", text, ast_channel_name(ast));
} }
transmit_message_with_text(dialog, text, 0, 0); /* Setup to send text message */
sip_pvt_lock(dialog);
destroy_msg_headers(dialog);
ast_string_field_set(dialog, msg_body, text);
transmit_message(dialog, 0, 0);
sip_pvt_unlock(dialog);
return 0; return 0;
} }
@@ -5605,7 +5610,7 @@ static int sip_call(struct ast_channel *ast, char *dest, int timeout)
/* We're replacing a call. */ /* We're replacing a call. */
p->options->replaces = ast_var_value(current); p->options->replaces = ast_var_value(current);
} else if (!strcasecmp(ast_var_name(current), "SIP_MAX_FORWARDS")) { } else if (!strcasecmp(ast_var_name(current), "SIP_MAX_FORWARDS")) {
if (sscanf(ast_var_value(current), "%d", &(p->maxforwards)) != 1) { if (sscanf(ast_var_value(current), "%30d", &(p->maxforwards)) != 1) {
ast_log(LOG_WARNING, "The SIP_MAX_FORWARDS channel variable is not a valid integer."); ast_log(LOG_WARNING, "The SIP_MAX_FORWARDS channel variable is not a valid integer.");
} }
} }
@@ -5863,6 +5868,8 @@ void __sip_destroy(struct sip_pvt *p, int lockowner, int lockdialoglist)
p->chanvars = NULL; p->chanvars = NULL;
} }
destroy_msg_headers(p);
if (p->srtp) { if (p->srtp) {
sip_srtp_destroy(p->srtp); sip_srtp_destroy(p->srtp);
p->srtp = NULL; p->srtp = NULL;
@@ -7340,14 +7347,12 @@ static char *get_body(struct sip_request *req, char *name, char delimiter)
return ""; return "";
} }
/*! \brief Find compressed SIP alias */ /*! \brief Structure for conversion between compressed SIP and "normal" SIP headers */
static const char *find_alias(const char *name, const char *_default) struct cfalias {
{ const char *fullname;
/*! \brief Structure for conversion between compressed SIP and "normal" SIP */ const char *shortname;
static const struct cfalias { };
char * const fullname; static const struct cfalias aliases[] = {
char * const shortname;
} aliases[] = {
{ "Content-Type", "c" }, { "Content-Type", "c" },
{ "Content-Encoding", "e" }, { "Content-Encoding", "e" },
{ "From", "f" }, { "From", "f" },
@@ -7369,6 +7374,10 @@ static const char *find_alias(const char *name, const char *_default)
{ "Identity", "y" }, { "Identity", "y" },
{ "Identity-Info", "n" }, { "Identity-Info", "n" },
}; };
/*! \brief Find compressed SIP alias */
static const char *find_alias(const char *name, const char *_default)
{
int x; int x;
for (x = 0; x < ARRAY_LEN(aliases); x++) { for (x = 0; x < ARRAY_LEN(aliases); x++) {
@@ -7379,6 +7388,22 @@ static const char *find_alias(const char *name, const char *_default)
return _default; return _default;
} }
/*! \brief Find full SIP alias */
static const char *find_full_alias(const char *name, const char *_default)
{
int x;
if (strlen(name) == 1) {
/* We have a short header name to convert. */
for (x = 0; x < ARRAY_LEN(aliases); ++x) {
if (!strcasecmp(aliases[x].shortname, name))
return aliases[x].fullname;
}
}
return _default;
}
static const char *__get_header(const struct sip_request *req, const char *name, int *start) static const char *__get_header(const struct sip_request *req, const char *name, int *start)
{ {
int pass; int pass;
@@ -10981,12 +11006,80 @@ static int transmit_provisional_response(struct sip_pvt *p, const char *msg, con
return res; return res;
} }
/*! \brief Add text body to SIP message */ /*!
static int add_text(struct sip_request *req, const char *text) * \internal
* \brief Destroy all additional MESSAGE headers.
*
* \param pvt SIP private dialog struct.
*
* \return Nothing
*/
static void destroy_msg_headers(struct sip_pvt *pvt)
{ {
struct sip_msg_hdr *doomed;
while ((doomed = AST_LIST_REMOVE_HEAD(&pvt->msg_headers, next))) {
ast_free(doomed);
}
}
/*!
* \internal
* \brief Add a MESSAGE header to the dialog.
*
* \param pvt SIP private dialog struct.
* \param hdr_name Name of header for MESSAGE.
* \param hdr_value Value of header for MESSAGE.
*
* \return Nothing
*/
static void add_msg_header(struct sip_pvt *pvt, const char *hdr_name, const char *hdr_value)
{
size_t hdr_len_name;
size_t hdr_len_value;
struct sip_msg_hdr *node;
char *pos;
hdr_len_name = strlen(hdr_name) + 1;
hdr_len_value = strlen(hdr_value) + 1;
node = ast_calloc(1, sizeof(*node) + hdr_len_name + hdr_len_value);
if (!node) {
return;
}
pos = node->stuff;
node->name = pos;
strcpy(pos, hdr_name);
pos += hdr_len_name;
node->value = pos;
strcpy(pos, hdr_value);
AST_LIST_INSERT_TAIL(&pvt->msg_headers, node, next);
}
/*! \brief Add text body to SIP message */
static int add_text(struct sip_request *req, struct sip_pvt *p)
{
const char *content_type = NULL;
struct sip_msg_hdr *node;
/* Add any additional MESSAGE headers. */
AST_LIST_TRAVERSE(&p->msg_headers, node, next) {
if (!strcasecmp(node->name, "Content-Type")) {
/* Save content type */
content_type = node->value;
} else {
add_header(req, node->name, node->value);
}
}
if (ast_strlen_zero(content_type)) {
/* "Content-Type" not set - use default value */
content_type = "text/plain;charset=UTF-8";
}
add_header(req, "Content-Type", content_type);
/* XXX Convert \n's to \r\n's XXX */ /* XXX Convert \n's to \r\n's XXX */
add_header(req, "Content-Type", "text/plain;charset=UTF-8"); add_content(req, p->msg_body);
add_content(req, text);
return 0; return 0;
} }
@@ -13615,38 +13708,16 @@ static int transmit_register(struct sip_registry *r, int sipmethod, const char *
return res; return res;
} }
/*! \brief Transmit text with SIP MESSAGE method based on an ast_msg */ /*!
static int transmit_message_with_msg(struct sip_pvt *p, const struct ast_msg *msg) * \brief Transmit with SIP MESSAGE method
{ * \note The p->msg_headers and p->msg_body are already setup.
struct sip_request req; */
struct ast_msg_var_iterator *i; static int transmit_message(struct sip_pvt *p, int init, int auth)
const char *var, *val;
build_via(p);
initreqprep(&req, p, SIP_MESSAGE, NULL);
ast_string_field_set(p, msg_body, ast_msg_get_body(msg));
initialize_initreq(p, &req);
i = ast_msg_var_iterator_init(msg);
while (ast_msg_var_iterator_next(msg, i, &var, &val)) {
add_header(&req, var, val);
ast_msg_var_unref_current(i);
}
ast_msg_var_iterator_destroy(i);
add_text(&req, ast_msg_get_body(msg));
return send_request(p, &req, XMIT_RELIABLE, p->ocseq);
}
/*! \brief Transmit text with SIP MESSAGE method */
static int transmit_message_with_text(struct sip_pvt *p, const char *text, int init, int auth)
{ {
struct sip_request req; struct sip_request req;
if (init) { if (init) {
initreqprep(&req, p, SIP_MESSAGE, NULL); initreqprep(&req, p, SIP_MESSAGE, NULL);
ast_string_field_set(p, msg_body, text);
initialize_initreq(p, &req); initialize_initreq(p, &req);
} else { } else {
reqprep(&req, p, SIP_MESSAGE, 0, 1); reqprep(&req, p, SIP_MESSAGE, 0, 1);
@@ -13654,7 +13725,7 @@ static int transmit_message_with_text(struct sip_pvt *p, const char *text, int i
if (auth) { if (auth) {
return transmit_request_with_auth(p, SIP_MESSAGE, p->ocseq, XMIT_RELIABLE, 0); return transmit_request_with_auth(p, SIP_MESSAGE, p->ocseq, XMIT_RELIABLE, 0);
} else { } else {
add_text(&req, text); add_text(&req, p);
return send_request(p, &req, XMIT_RELIABLE, p->ocseq); return send_request(p, &req, XMIT_RELIABLE, p->ocseq);
} }
} }
@@ -13874,23 +13945,31 @@ static int transmit_request_with_auth(struct sip_pvt *p, int sipmethod, int seqn
ast_log(LOG_WARNING, "No authentication available for call %s\n", p->callid); ast_log(LOG_WARNING, "No authentication available for call %s\n", p->callid);
} }
} }
/* If we are hanging up and know a cause for that, send it in clear text to make
debugging easier. */ switch (sipmethod) {
if (sipmethod == SIP_BYE) { case SIP_BYE:
{
char buf[20]; char buf[20];
/*
* We are hanging up. If we know a cause for that, send it in
* clear text to make debugging easier.
*/
if (ast_test_flag(&p->flags[1], SIP_PAGE2_Q850_REASON) && p->hangupcause) { if (ast_test_flag(&p->flags[1], SIP_PAGE2_Q850_REASON) && p->hangupcause) {
sprintf(buf, "Q.850;cause=%i", p->hangupcause & 0x7f); snprintf(buf, sizeof(buf), "Q.850;cause=%d", p->hangupcause & 0x7f);
add_header(&resp, "Reason", buf); add_header(&resp, "Reason", buf);
} }
add_header(&resp, "X-Asterisk-HangupCause", ast_cause2str(p->hangupcause)); add_header(&resp, "X-Asterisk-HangupCause", ast_cause2str(p->hangupcause));
snprintf(buf, sizeof(buf), "%d", p->hangupcause); snprintf(buf, sizeof(buf), "%d", p->hangupcause);
add_header(&resp, "X-Asterisk-HangupCauseCode", buf); add_header(&resp, "X-Asterisk-HangupCauseCode", buf);
break;
} }
case SIP_MESSAGE:
if (sipmethod == SIP_MESSAGE) { add_text(&resp, p);
add_text(&resp, p->msg_body); break;
default:
break;
} }
return send_request(p, &resp, reliable, seqno ? seqno : p->ocseq); return send_request(p, &resp, reliable, seqno ? seqno : p->ocseq);
@@ -16514,23 +16593,34 @@ static int get_msg_text2(struct ast_str **buf, struct sip_request *req)
return res < 0 ? -1 : 0; return res < 0 ? -1 : 0;
} }
static void set_message_vars_from_req(struct ast_msg *msg, struct sip_request *req) static int set_message_vars_from_req(struct ast_msg *msg, struct sip_request *req)
{ {
size_t x; size_t x;
char name_buf[1024] = ""; char name_buf[1024];
char val_buf[1024] = ""; char val_buf[1024];
const char *name;
char *c; char *c;
int res = 0;
for (x = 0; x < req->headers; x++) { for (x = 0; x < req->headers; x++) {
const char *header = REQ_OFFSET_TO_STR(req, header[x]); const char *header = REQ_OFFSET_TO_STR(req, header[x]);
if ((c = strchr(header, ':'))) { if ((c = strchr(header, ':'))) {
ast_copy_string(name_buf, header, MIN((c - header + 1), sizeof(name_buf))); ast_copy_string(name_buf, header, MIN((c - header + 1), sizeof(name_buf)));
ast_copy_string(val_buf, ast_skip_blanks(c + 1), sizeof(val_buf)); ast_copy_string(val_buf, ast_skip_blanks(c + 1), sizeof(val_buf));
ast_trim_blanks(name_buf); ast_trim_blanks(name_buf);
ast_msg_set_var(msg, name_buf, val_buf);
/* Convert header name to full name alias. */
name = find_full_alias(name_buf, name_buf);
res = ast_msg_set_var(msg, name, val_buf);
if (res) {
break;
} }
} }
} }
return res;
}
AST_THREADSTORAGE(sip_msg_buf); AST_THREADSTORAGE(sip_msg_buf);
@@ -16546,12 +16636,15 @@ static void receive_message(struct sip_pvt *p, struct sip_request *req, struct a
const char *content_type = sip_get_header(req, "Content-Type"); const char *content_type = sip_get_header(req, "Content-Type");
struct ast_msg *msg; struct ast_msg *msg;
int res; int res;
char *from, *to; char *from;
char *to;
char from_name[50];
if (strncmp(content_type, "text/plain", strlen("text/plain"))) { /* No text/plain attachment */ if (strncmp(content_type, "text/plain", strlen("text/plain"))) { /* No text/plain attachment */
transmit_response(p, "415 Unsupported Media Type", req); /* Good enough, or? */ transmit_response(p, "415 Unsupported Media Type", req); /* Good enough, or? */
if (!p->owner) if (!p->owner) {
sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT); sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
}
return; return;
} }
@@ -16585,8 +16678,9 @@ static void receive_message(struct sip_pvt *p, struct sip_request *req, struct a
ast_str_truncate(buf, len); ast_str_truncate(buf, len);
if (p->owner) { if (p->owner) {
if (sip_debug_test_pvt(p)) if (sip_debug_test_pvt(p)) {
ast_verbose("SIP Text message received: '%s'\n", ast_str_buffer(buf)); ast_verbose("SIP Text message received: '%s'\n", ast_str_buffer(buf));
}
memset(&f, 0, sizeof(f)); memset(&f, 0, sizeof(f));
f.frametype = AST_FRAME_TEXT; f.frametype = AST_FRAME_TEXT;
f.subclass.integer = 0; f.subclass.integer = 0;
@@ -16598,6 +16692,13 @@ static void receive_message(struct sip_pvt *p, struct sip_request *req, struct a
return; return;
} }
/*
* At this point MESSAGE is outside of a call.
*
* NOTE: p->owner is NULL so no additional check is needed after
* this point.
*/
if (!sip_cfg.accept_outofcall_message) { if (!sip_cfg.accept_outofcall_message) {
/* Message outside of a call, we do not support that */ /* Message outside of a call, we do not support that */
ast_debug(1, "MESSAGE outside of a call administratively disabled.\n"); ast_debug(1, "MESSAGE outside of a call administratively disabled.\n");
@@ -16620,7 +16721,7 @@ static void receive_message(struct sip_pvt *p, struct sip_request *req, struct a
if (res < 0) { /* Something failed in authentication */ if (res < 0) { /* Something failed in authentication */
if (res == AUTH_FAKE_AUTH) { if (res == AUTH_FAKE_AUTH) {
ast_log(LOG_NOTICE, "Sending fake auth rejection for device %s\n", sip_get_header(req, "From")); ast_log(LOG_NOTICE, "Sending fake auth rejection for device %s\n", sip_get_header(req, "From"));
transmit_fake_auth_response(p, SIP_OPTIONS, req, XMIT_UNRELIABLE); transmit_fake_auth_response(p, SIP_MESSAGE, req, XMIT_UNRELIABLE);
} else { } else {
ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", sip_get_header(req, "From")); ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", sip_get_header(req, "From"));
transmit_response(p, "403 Forbidden", req); transmit_response(p, "403 Forbidden", req);
@@ -16665,9 +16766,7 @@ static void receive_message(struct sip_pvt *p, struct sip_request *req, struct a
if (!(msg = ast_msg_alloc())) { if (!(msg = ast_msg_alloc())) {
transmit_response(p, "500 Internal Server Error", req); transmit_response(p, "500 Internal Server Error", req);
if (!p->owner) {
sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT); sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
}
return; return;
} }
@@ -16675,7 +16774,16 @@ static void receive_message(struct sip_pvt *p, struct sip_request *req, struct a
from = ast_strdupa(sip_get_header(req, "From")); from = ast_strdupa(sip_get_header(req, "From"));
res = ast_msg_set_to(msg, "%s", to); res = ast_msg_set_to(msg, "%s", to);
res |= ast_msg_set_from(msg, "%s", get_in_brackets(from));
/* Build "display" <uri> for from string. */
from = (char *) get_calleridname(from, from_name, sizeof(from_name));
from = get_in_brackets(from);
if (from_name[0]) {
res |= ast_msg_set_from(msg, "\"%s\" <%s>", from_name, from);
} else {
res |= ast_msg_set_from(msg, "<%s>", from);
}
res |= ast_msg_set_body(msg, "%s", ast_str_buffer(buf)); res |= ast_msg_set_body(msg, "%s", ast_str_buffer(buf));
res |= ast_msg_set_context(msg, "%s", p->context); res |= ast_msg_set_context(msg, "%s", p->context);
@@ -16684,15 +16792,16 @@ static void receive_message(struct sip_pvt *p, struct sip_request *req, struct a
} }
res |= ast_msg_set_exten(msg, "%s", p->exten); res |= ast_msg_set_exten(msg, "%s", p->exten);
res |= set_message_vars_from_req(msg, req);
if (res) { if (res) {
ast_msg_destroy(msg); ast_msg_destroy(msg);
transmit_response(p, "500 Internal Server Error", req);
} else { } else {
set_message_vars_from_req(msg, req);
ast_msg_queue(msg); ast_msg_queue(msg);
transmit_response(p, "202 Accepted", req);
} }
transmit_response(p, "202 Accepted", req);
sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT); sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
} }
@@ -20339,7 +20448,7 @@ static void cc_handle_publish_error(struct sip_pvt *pvt, const int resp, struct
ao2_ref(monitor_instance, -1); ao2_ref(monitor_instance, -1);
return; return;
} }
} else if (sscanf(min_expires, "%d", &pvt->expiry) != 1) { } else if (sscanf(min_expires, "%30d", &pvt->expiry) != 1) {
ast_cc_monitor_failed(cc_entry->core_id, monitor_instance->device_name, ast_cc_monitor_failed(cc_entry->core_id, monitor_instance->device_name,
"Min-Expires has non-numeric value"); "Min-Expires has non-numeric value");
ao2_ref(monitor_instance, -1); ao2_ref(monitor_instance, -1);
@@ -21380,7 +21489,7 @@ static int do_message_auth(struct sip_pvt *p, int resp, const char *rest, struct
append_history(p, "MessageAuth", "Try: %d", p->authtries); append_history(p, "MessageAuth", "Try: %d", p->authtries);
} }
transmit_message_with_text(p, p->msg_body, 0, 1); transmit_message(p, 0, 1);
return 0; return 0;
} }
@@ -21912,13 +22021,18 @@ static void *sip_park_thread(void *stuff)
res = ast_park_call_exten(transferee, transferer, d->park_exten, d->park_context, 0, &ext); res = ast_park_call_exten(transferee, transferer, d->park_exten, d->park_context, 0, &ext);
sip_pvt_lock(transferer->tech_pvt);
#ifdef WHEN_WE_KNOW_THAT_THE_CLIENT_SUPPORTS_MESSAGE #ifdef WHEN_WE_KNOW_THAT_THE_CLIENT_SUPPORTS_MESSAGE
if (res) { if (res) {
transmit_message_with_text(transferer->tech_pvt, "Unable to park call.\n", 0, 0); destroy_msg_headers(transferer->tech_pvt);
ast_string_field_set(transferer->tech_pvt, msg_body, "Unable to park call.");
transmit_message(transferer->tech_pvt, 0, 0);
} else { } else {
/* Then tell the transferer what happened */ /* Then tell the transferer what happened */
sprintf(buf, "Call parked on extension '%d'", ext); destroy_msg_headers(transferer->tech_pvt);
transmit_message_with_text(transferer->tech_pvt, buf, 0, 0); sprintf(buf, "Call parked on extension '%d'.", ext);
ast_string_field_set(transferer->tech_pvt, msg_body, buf);
transmit_message(transferer->tech_pvt, 0, 0);
} }
#endif #endif
@@ -21928,12 +22042,14 @@ static void *sip_park_thread(void *stuff)
/* Transfer succeeded */ /* Transfer succeeded */
append_history(transferer->tech_pvt, "SIPpark", "Parked call on %d", ext); append_history(transferer->tech_pvt, "SIPpark", "Parked call on %d", ext);
transmit_notify_with_sipfrag(transferer->tech_pvt, d->seqno, "200 OK", TRUE); transmit_notify_with_sipfrag(transferer->tech_pvt, d->seqno, "200 OK", TRUE);
sip_pvt_unlock(transferer->tech_pvt);
transferer->hangupcause = AST_CAUSE_NORMAL_CLEARING; transferer->hangupcause = AST_CAUSE_NORMAL_CLEARING;
ast_hangup(transferer); /* This will cause a BYE */ ast_hangup(transferer); /* This will cause a BYE */
ast_debug(1, "SIP Call parked on extension '%d'\n", ext); ast_debug(1, "SIP Call parked on extension '%d'\n", ext);
} else { } else {
transmit_notify_with_sipfrag(transferer->tech_pvt, d->seqno, "503 Service Unavailable", TRUE); transmit_notify_with_sipfrag(transferer->tech_pvt, d->seqno, "503 Service Unavailable", TRUE);
append_history(transferer->tech_pvt, "SIPpark", "Parking failed\n"); append_history(transferer->tech_pvt, "SIPpark", "Parking failed\n");
sip_pvt_unlock(transferer->tech_pvt);
ast_debug(1, "SIP Call parked failed \n"); ast_debug(1, "SIP Call parked failed \n");
/* Do not hangup call */ /* Do not hangup call */
} }
@@ -24475,11 +24591,56 @@ static const struct ast_msg_tech sip_msg_tech = {
.msg_send = sip_msg_send, .msg_send = sip_msg_send,
}; };
/*!
* \internal
* \brief Check if the given header name is blocked.
*
* \details Determine if the given header name from the user is
* blocked for outgoing MESSAGE packets.
*
* \param header_name Name of header to see if it is blocked.
*
* \retval TRUE if the given header is blocked.
*/
static int block_msg_header(const char *header_name)
{
int idx;
/*
* Don't block Content-Type or Max-Forwards headers because the
* user can override them.
*/
static const char *hdr[] = {
"To",
"From",
"Via",
"Route",
"Contact",
"Call-ID",
"CSeq",
"Allow",
"Content-Length",
};
for (idx = 0; idx < ARRAY_LEN(hdr); ++idx) {
if (!strcasecmp(header_name, hdr[idx])) {
/* Block addition of this header. */
return 1;
}
}
return 0;
}
static int sip_msg_send(const struct ast_msg *msg, const char *to, const char *from) static int sip_msg_send(const struct ast_msg *msg, const char *to, const char *from)
{ {
struct sip_pvt *pvt; struct sip_pvt *pvt;
int res; int res;
char *to_uri, *to_host, *to_user; char *to_uri;
char *to_host;
char *to_user;
const char *var;
const char *val;
struct ast_msg_var_iterator *iter;
struct sip_peer *peer_ptr; struct sip_peer *peer_ptr;
if (!(pvt = sip_alloc(NULL, NULL, 0, SIP_MESSAGE, NULL))) { if (!(pvt = sip_alloc(NULL, NULL, 0, SIP_MESSAGE, NULL))) {
@@ -24487,6 +24648,7 @@ static int sip_msg_send(const struct ast_msg *msg, const char *to, const char *f
} }
to_uri = ast_strdupa(to); to_uri = ast_strdupa(to);
to_uri = get_in_brackets(to_uri);
parse_uri(to_uri, "sip:,sips:", &to_user, NULL, &to_host, NULL); parse_uri(to_uri, "sip:,sips:", &to_user, NULL, &to_host, NULL);
if (ast_strlen_zero(to_host)) { if (ast_strlen_zero(to_host)) {
@@ -24541,7 +24703,33 @@ static int sip_msg_send(const struct ast_msg *msg, const char *to, const char *f
/* XXX Does pvt->expiry need to be set? */ /* XXX Does pvt->expiry need to be set? */
res = transmit_message_with_msg(pvt, msg); /* Save additional MESSAGE headers in case of authentication request. */
for (iter = ast_msg_var_iterator_init(msg);
ast_msg_var_iterator_next(msg, iter, &var, &val);
ast_msg_var_unref_current(iter)) {
if (!strcasecmp(var, "Max-Forwards")) {
/* Decrement Max-Forwards for SIP loop prevention. */
if (sscanf(val, "%30d", &pvt->maxforwards) != 1 || pvt->maxforwards < 1) {
sip_pvt_unlock(pvt);
dialog_unlink_all(pvt);
dialog_unref(pvt, "MESSAGE(Max-Forwards) reached zero.");
ast_log(LOG_NOTICE,
"MESSAGE(Max-Forwards) reached zero. MESSAGE not sent.\n");
return -1;
}
--pvt->maxforwards;
continue;
}
if (block_msg_header(var)) {
/* Block addition of this header. */
continue;
}
add_msg_header(pvt, var, val);
}
ast_msg_var_iterator_destroy(iter);
ast_string_field_set(pvt, msg_body, ast_msg_get_body(msg));
res = transmit_message(pvt, 1, 0);
sip_pvt_unlock(pvt); sip_pvt_unlock(pvt);
sip_scheddestroy(pvt, DEFAULT_TRANS_TIMEOUT); sip_scheddestroy(pvt, DEFAULT_TRANS_TIMEOUT);
@@ -25088,7 +25276,7 @@ static int handle_cc_subscribe(struct sip_pvt *p, struct sip_request *req)
int expires = -1; /* Just need it to be non-zero */ int expires = -1; /* Just need it to be non-zero */
if (!ast_strlen_zero(expires_str)) { if (!ast_strlen_zero(expires_str)) {
sscanf(expires_str, "%d", &expires); sscanf(expires_str, "%30d", &expires);
} }
if ((param_separator = strchr(uri, ';'))) { if ((param_separator = strchr(uri, ';'))) {

View File

@@ -966,6 +966,17 @@ struct offered_media {
char codecs[128]; char codecs[128];
}; };
/*! Additional headers to send with MESSAGE method packet. */
struct sip_msg_hdr {
AST_LIST_ENTRY(sip_msg_hdr) next;
/*! Name of header to stick in MESSAGE */
const char *name;
/*! Value of header to stick in MESSAGE */
const char *value;
/*! The name and value strings are stuffed here in that order. */
char stuff[0];
};
/*! \brief Structure used for each SIP dialog, ie. a call, a registration, a subscribe. /*! \brief Structure used for each SIP dialog, ie. a call, a registration, a subscribe.
* Created and initialized by sip_alloc(), the descriptor goes into the list of * Created and initialized by sip_alloc(), the descriptor goes into the list of
* descriptors (dialoglist). * descriptors (dialoglist).
@@ -1134,6 +1145,7 @@ struct sip_pvt {
struct sip_history_head *history; /*!< History of this SIP dialog */ struct sip_history_head *history; /*!< History of this SIP dialog */
size_t history_entries; /*!< Number of entires in the history */ size_t history_entries; /*!< Number of entires in the history */
struct ast_variable *chanvars; /*!< Channel variables to set for inbound call */ struct ast_variable *chanvars; /*!< Channel variables to set for inbound call */
AST_LIST_HEAD_NOLOCK(, sip_msg_hdr) msg_headers; /*!< Additional MESSAGE headers to send. */
AST_LIST_HEAD_NOLOCK(request_queue, sip_request) request_queue; /*!< Requests that arrived but could not be processed immediately */ AST_LIST_HEAD_NOLOCK(request_queue, sip_request) request_queue; /*!< Requests that arrived but could not be processed immediately */
struct sip_invite_param *options; /*!< Options for INVITE */ struct sip_invite_param *options; /*!< Options for INVITE */
struct sip_st_dlg *stimer; /*!< SIP Session-Timers */ struct sip_st_dlg *stimer; /*!< SIP Session-Timers */

View File

@@ -88,8 +88,11 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<para>This function will read from or write a value to a text message. <para>This function will read from or write a value to a text message.
It is used both to read the data out of an incoming message, as well as It is used both to read the data out of an incoming message, as well as
modify a message that will be sent outbound.</para> modify a message that will be sent outbound.</para>
<para>NOTE: If you want to set an outbound message to carry data in the <note>
current message, do Set(MESSAGE_DATA(key)=${MESSAGE_DATA(key)}).</para> <para>If you want to set an outbound message to carry data in the
current message, do
Set(MESSAGE_DATA(<replaceable>key</replaceable>)=${MESSAGE_DATA(<replaceable>key</replaceable>)}).</para>
</note>
</description> </description>
<see-also> <see-also>
<ref type="application">MessageSend</ref> <ref type="application">MessageSend</ref>
@@ -106,6 +109,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<parameter name="from" required="false"> <parameter name="from" required="false">
<para>A From URI for the message if needed for the <para>A From URI for the message if needed for the
message technology being used to send this message.</para> message technology being used to send this message.</para>
<note>
<para>For SIP the from parameter can be a configured peer name
or in the form of "display-name" &lt;URI&gt;.</para>
</note>
</parameter> </parameter>
</syntax> </syntax>
<description> <description>