Fixes for sending SIP MESSAGE outside of calls.
authorRichard Mudgett <rmudgett@digium.com>
Wed, 25 Jan 2012 17:23:25 +0000 (17:23 +0000)
committerRichard Mudgett <rmudgett@digium.com>
Wed, 25 Jan 2012 17:23:25 +0000 (17:23 +0000)
* 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

CHANGES
channels/chan_sip.c
channels/sip/include/sip.h
main/message.c

diff --git a/CHANGES b/CHANGES
index fb7f5cf..7beaa46 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -147,6 +147,12 @@ RTP changes
    mode has successfully exited. These changes are based on how pjmedia handles
    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 -------------------
 ------------------------------------------------------------------------------
index f987852..7db4d74 100644 (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_digit(struct sip_pvt *p, const char digit, unsigned int duration);
 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_with_msg(struct sip_pvt *p, const struct ast_msg *msg);
+static int transmit_message(struct sip_pvt *p, int init, int auth);
 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_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_content(struct sip_request *req, const char *line);
 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_rpid(struct sip_request *req, struct sip_pvt *p);
 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));
        }
 
-       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;
 }
 
@@ -5605,7 +5610,7 @@ static int sip_call(struct ast_channel *ast, char *dest, int timeout)
                        /* We're replacing a call. */
                        p->options->replaces = ast_var_value(current);
                } 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.");
                        }
                }
@@ -5863,6 +5868,8 @@ void __sip_destroy(struct sip_pvt *p, int lockowner, int lockdialoglist)
                p->chanvars = NULL;
        }
 
+       destroy_msg_headers(p);
+
        if (p->srtp) {
                sip_srtp_destroy(p->srtp);
                p->srtp = NULL;
@@ -7340,35 +7347,37 @@ static char *get_body(struct sip_request *req, char *name, char delimiter)
        return "";
 }
 
+/*! \brief Structure for conversion between compressed SIP and "normal" SIP headers */
+struct cfalias {
+       const char *fullname;
+       const char *shortname;
+};
+static const struct cfalias aliases[] = {
+       { "Content-Type",           "c" },
+       { "Content-Encoding",       "e" },
+       { "From",                   "f" },
+       { "Call-ID",                "i" },
+       { "Contact",                "m" },
+       { "Content-Length",         "l" },
+       { "Subject",                "s" },
+       { "To",                     "t" },
+       { "Supported",              "k" },
+       { "Refer-To",               "r" },
+       { "Referred-By",            "b" },
+       { "Allow-Events",           "u" },
+       { "Event",                  "o" },
+       { "Via",                    "v" },
+       { "Accept-Contact",         "a" },
+       { "Reject-Contact",         "j" },
+       { "Request-Disposition",    "d" },
+       { "Session-Expires",        "x" },
+       { "Identity",               "y" },
+       { "Identity-Info",          "n" },
+};
+
 /*! \brief Find compressed SIP alias */
 static const char *find_alias(const char *name, const char *_default)
 {
-       /*! \brief Structure for conversion between compressed SIP and "normal" SIP */
-       static const struct cfalias {
-               char * const fullname;
-               char * const shortname;
-       } aliases[] = {
-               { "Content-Type",        "c" },
-               { "Content-Encoding",    "e" },
-               { "From",                "f" },
-               { "Call-ID",             "i" },
-               { "Contact",             "m" },
-               { "Content-Length",      "l" },
-               { "Subject",             "s" },
-               { "To",                  "t" },
-               { "Supported",           "k" },
-               { "Refer-To",            "r" },
-               { "Referred-By",         "b" },
-               { "Allow-Events",        "u" },
-               { "Event",               "o" },
-               { "Via",                 "v" },
-               { "Accept-Contact",      "a" },
-               { "Reject-Contact",      "j" },
-               { "Request-Disposition", "d" },
-               { "Session-Expires",     "x" },
-               { "Identity",            "y" },
-               { "Identity-Info",       "n" },
-       };
        int 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;
 }
 
+/*! \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)
 {
        int pass;
@@ -10981,12 +11006,80 @@ static int transmit_provisional_response(struct sip_pvt *p, const char *msg, con
        return res;
 }
 
+/*!
+ * \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, const char *text)
+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 */
-       add_header(req, "Content-Type", "text/plain;charset=UTF-8");
-       add_content(req, text);
+       add_content(req, p->msg_body);
        return 0;
 }
 
@@ -13615,38 +13708,16 @@ static int transmit_register(struct sip_registry *r, int sipmethod, const char *
        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)
-{
-       struct sip_request req;
-       struct ast_msg_var_iterator *i;
-       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)
+/*!
+ * \brief Transmit with SIP MESSAGE method
+ * \note The p->msg_headers and p->msg_body are already setup.
+ */
+static int transmit_message(struct sip_pvt *p, int init, int auth)
 {
        struct sip_request req;
 
        if (init) {
                initreqprep(&req, p, SIP_MESSAGE, NULL);
-               ast_string_field_set(p, msg_body, text);
                initialize_initreq(p, &req);
        } else {
                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) {
                return transmit_request_with_auth(p, SIP_MESSAGE, p->ocseq, XMIT_RELIABLE, 0);
        } else {
-               add_text(&req, text);
+               add_text(&req, p);
                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);
                }
        }
-       /* If we are hanging up and know a cause for that, send it in clear text to make
-               debugging easier. */
-       if (sipmethod == SIP_BYE)       {
+
+       switch (sipmethod) {
+       case SIP_BYE:
+       {
                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) {
-                       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, "X-Asterisk-HangupCause", ast_cause2str(p->hangupcause));
                snprintf(buf, sizeof(buf), "%d", p->hangupcause);
                add_header(&resp, "X-Asterisk-HangupCauseCode", buf);
+               break;
        }
-
-       if (sipmethod == SIP_MESSAGE) {
-               add_text(&resp, p->msg_body);
+       case SIP_MESSAGE:
+               add_text(&resp, p);
+               break;
+       default:
+               break;
        }
 
        return send_request(p, &resp, reliable, seqno ? seqno : p->ocseq);      
@@ -16514,22 +16593,33 @@ static int get_msg_text2(struct ast_str **buf, struct sip_request *req)
        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;
-       char name_buf[1024] = "";
-       char val_buf[1024] = "";
+       char name_buf[1024];
+       char val_buf[1024];
+       const char *name;
        char *c;
+       int res = 0;
 
        for (x = 0; x < req->headers; x++) {
                const char *header = REQ_OFFSET_TO_STR(req, header[x]);
+
                if ((c = strchr(header, ':'))) {
                        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_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);
@@ -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");
        struct ast_msg *msg;
        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 */
                transmit_response(p, "415 Unsupported Media Type", req); /* Good enough, or? */
-               if (!p->owner)
+               if (!p->owner) {
                        sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
+               }
                return;
        }
 
@@ -16585,8 +16678,9 @@ static void receive_message(struct sip_pvt *p, struct sip_request *req, struct a
        ast_str_truncate(buf, len);
 
        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));
+               }
                memset(&f, 0, sizeof(f));
                f.frametype = AST_FRAME_TEXT;
                f.subclass.integer = 0;
@@ -16598,6 +16692,13 @@ static void receive_message(struct sip_pvt *p, struct sip_request *req, struct a
                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) {
                /* Message outside of a call, we do not support that */
                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 == AUTH_FAKE_AUTH) {
                                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 {
                                ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", sip_get_header(req, "From"));
                                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())) {
                transmit_response(p, "500 Internal Server Error", req);
-               if (!p->owner) {
-                       sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
-               }
+               sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
                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"));
 
        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_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 |= set_message_vars_from_req(msg, req);
 
        if (res) {
                ast_msg_destroy(msg);
+               transmit_response(p, "500 Internal Server Error", req);
        } else {
-               set_message_vars_from_req(msg, req);
                ast_msg_queue(msg);
+               transmit_response(p, "202 Accepted", req);
        }
 
-       transmit_response(p, "202 Accepted", req);
        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);
                        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,
                                "Min-Expires has non-numeric value");
                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);
        }
 
-       transmit_message_with_text(p, p->msg_body, 0, 1);
+       transmit_message(p, 0, 1);
        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);
 
+       sip_pvt_lock(transferer->tech_pvt);
 #ifdef WHEN_WE_KNOW_THAT_THE_CLIENT_SUPPORTS_MESSAGE
        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 {
                /* Then tell the transferer what happened */
-               sprintf(buf, "Call parked on extension '%d'", ext);
-               transmit_message_with_text(transferer->tech_pvt, buf, 0, 0);
+               destroy_msg_headers(transferer->tech_pvt);
+               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
 
@@ -21928,12 +22042,14 @@ static void *sip_park_thread(void *stuff)
                /* Transfer succeeded */
                append_history(transferer->tech_pvt, "SIPpark", "Parked call on %d", ext);
                transmit_notify_with_sipfrag(transferer->tech_pvt, d->seqno, "200 OK", TRUE);
+               sip_pvt_unlock(transferer->tech_pvt);
                transferer->hangupcause = AST_CAUSE_NORMAL_CLEARING;
                ast_hangup(transferer); /* This will cause a BYE */
                ast_debug(1, "SIP Call parked on extension '%d'\n", ext);
        } else {
                transmit_notify_with_sipfrag(transferer->tech_pvt, d->seqno, "503 Service Unavailable", TRUE);
                append_history(transferer->tech_pvt, "SIPpark", "Parking failed\n");
+               sip_pvt_unlock(transferer->tech_pvt);
                ast_debug(1, "SIP Call parked failed \n");
                /* Do not hangup call */
        }
@@ -24475,11 +24591,56 @@ static const struct ast_msg_tech sip_msg_tech = {
        .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)
 {
        struct sip_pvt *pvt;
        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;
 
        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 = get_in_brackets(to_uri);
        parse_uri(to_uri, "sip:,sips:", &to_user, NULL, &to_host, NULL);
 
        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? */
 
-       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_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 */
 
        if (!ast_strlen_zero(expires_str)) {
-               sscanf(expires_str, "%d", &expires);
+               sscanf(expires_str, "%30d", &expires);
        }
 
        if ((param_separator = strchr(uri, ';'))) {
index ad9e781..f370193 100644 (file)
@@ -966,6 +966,17 @@ struct offered_media {
        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.
  * Created and initialized by sip_alloc(), the descriptor goes into the list of
  * descriptors (dialoglist).
@@ -1134,6 +1145,7 @@ struct sip_pvt {
        struct sip_history_head *history;   /*!< History of this SIP dialog */
        size_t history_entries;             /*!< Number of entires in the history */
        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 */
        struct sip_invite_param *options;   /*!< Options for INVITE */
        struct sip_st_dlg *stimer;          /*!< SIP Session-Timers */
index 4247751..c4d2c43 100644 (file)
@@ -88,15 +88,18 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        <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
                        modify a message that will be sent outbound.</para>
-                       <para>NOTE: If you want to set an outbound message to carry data in the
-                       current message, do Set(MESSAGE_DATA(key)=${MESSAGE_DATA(key)}).</para>
+                       <note>
+                               <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>
                <see-also>
                        <ref type="application">MessageSend</ref>
                </see-also>
        </function>
        <application name="MessageSend" language="en_US">
-               <synopsis>
+               <synopsis>
                        Send a text message.
                </synopsis>
                <syntax>
@@ -106,6 +109,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        <parameter name="from" required="false">
                                <para>A From URI for the message if needed for the
                                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>
                </syntax>
                <description>