Index: channels/chan_sip.c
===================================================================
--- channels/chan_sip.c (revision 239425)
+++ channels/chan_sip.c (working copy)
@@ -346,6 +346,23 @@
that name to retrieve. Headers start at offset 1.
+
+
+ Gets the specified SIP body part.
+
+
+
+
+
+ Since the body of SIP INVITE message may contain different content types
+ (not just SDP) or may be a multipart body, this function gets the body of the
+ requested Content-Type. In case more body parts with the same Content-Type are
+ availabe, just the first is returned. As line delimiter \r\n is returned (body
+ part always ends with \r\n). Note: this function only works on the INVITE that
+ starts a dialog. Body parts from other SIP messages can't be managed from the
+ dial plan.
+
+
Gets SIP peer information.
@@ -2493,6 +2510,7 @@
static const char *get_sdp_iterate(int* start, struct sip_request *req, const char *name);
static char get_sdp_line(int *start, int stop, struct sip_request *req, const char **value);
static int find_sdp(struct sip_request *req);
+static int find_content(struct sip_request *req, const char *cont, unsigned int *start, unsigned int *end, unsigned int *length);
static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action);
static int process_sdp_o(const char *o, struct sip_pvt *p);
static int process_sdp_c(const char *c, struct ast_hostent *hp);
@@ -8211,94 +8229,24 @@
*/
static int find_sdp(struct sip_request *req)
{
- const char *content_type;
- const char *content_length;
- const char *search;
- char *boundary;
- unsigned int x;
- int boundaryisquoted = FALSE;
- int found_application_sdp = FALSE;
- int found_end_of_headers = FALSE;
- content_length = get_header(req, "Content-Length");
+ const char *content_type = "application/sdp";
+ unsigned int start = 0;
+ unsigned int end = 0;
+ unsigned int length = 0;
- if (!ast_strlen_zero(content_length)) {
- if (sscanf(content_length, "%30u", &x) != 1) {
- ast_log(LOG_WARNING, "Invalid Content-Length: %s\n", content_length);
- return 0;
- }
+ find_content(req, content_type, &start, &end, &length);
- /* Content-Length of zero means there can't possibly be an
- SDP here, even if the Content-Type says there is */
- if (x == 0)
- return 0;
- }
+ req->sdp_count = end - start;
+ req->sdp_start = start;
- content_type = get_header(req, "Content-Type");
+ if ((start == 0) && (end == 0)) {
+ return 0;
+ }
- /* if the body contains only SDP, this is easy */
- if (!strncasecmp(content_type, "application/sdp", 15)) {
- req->sdp_start = 0;
- req->sdp_count = req->lines;
- return req->lines ? 1 : 0;
- }
+ return TRUE;
- /* if it's not multipart/mixed, there cannot be an SDP */
- if (strncasecmp(content_type, "multipart/mixed", 15))
- return 0;
- /* if there is no boundary marker, it's invalid */
- if ((search = strcasestr(content_type, ";boundary=")))
- search += 10;
- else if ((search = strcasestr(content_type, "; boundary=")))
- search += 11;
- else
- return 0;
-
- if (ast_strlen_zero(search))
- return 0;
-
- /* If the boundary is quoted with ", remove quote */
- if (*search == '\"') {
- search++;
- boundaryisquoted = TRUE;
- }
-
- /* make a duplicate of the string, with two extra characters
- at the beginning */
- boundary = ast_strdupa(search - 2);
- boundary[0] = boundary[1] = '-';
- /* Remove final quote */
- if (boundaryisquoted)
- boundary[strlen(boundary) - 1] = '\0';
-
- /* search for the boundary marker, the empty line delimiting headers from
- sdp part and the end boundry if it exists */
-
- for (x = 0; x < (req->lines); x++) {
- const char *line = REQ_OFFSET_TO_STR(req, line[x]);
- if (!strncasecmp(line, boundary, strlen(boundary))){
- if (found_application_sdp && found_end_of_headers) {
- req->sdp_count = (x - 1) - req->sdp_start;
- return 1;
- }
- found_application_sdp = FALSE;
- }
- if (!strcasecmp(line, "Content-Type: application/sdp"))
- found_application_sdp = TRUE;
-
- if (ast_strlen_zero(line)) {
- if (found_application_sdp && !found_end_of_headers){
- req->sdp_start = x;
- found_end_of_headers = TRUE;
- }
- }
- }
- if (found_application_sdp && found_end_of_headers) {
- req->sdp_count = x - req->sdp_start;
- return TRUE;
- }
- return FALSE;
}
@@ -17873,7 +17821,218 @@
return 0;
}
+
+
+/*! \brief Finds a specific body part
+\return Returns 0 if body part not found
+\note can be used to find the specified body part by content-type. Set length to 1 to get back the sum of characters of all the
+ lines of the respective body part.
+*/
+static int find_content(struct sip_request *req, const char *cont, unsigned int *start, unsigned int *end, unsigned int *length)
+{
+ const char *content_type;
+ const char *content_length;
+ const char *search;
+ char *boundary;
+ unsigned int x;
+ int boundaryisquoted = FALSE;
+ int found_content_type = FALSE;
+ int found_end_of_headers = FALSE;
+
+ *start = 0;
+ *end = 0;
+
+ content_length = get_header(req, "Content-Length");
+
+ if (!ast_strlen_zero(content_length)) {
+ if (sscanf(content_length, "%ud", &x) != 1) {
+ ast_log(LOG_WARNING, "Invalid Content-Length: %s\n", content_length);
+ return 0;
+ }
+
+ /* Content-Length of zero means there can't possibly be a
+ body here, even if the Content-Type says there is */
+ if (x == 0) {
+ return 0;
+ }
+ }
+
+ content_type = get_header(req, "Content-Type");
+
+ /* if the body contains only SDP, this is easy */
+ if (!strncasecmp(content_type, cont, strlen(cont))) {
+ *start = 0;
+ *end = req->lines;
+
+ /* calculate the real length of the body if requested (in case content length is wrong) */
+ if (*length == 1) {
+ *length = 0;
+ for (x = 0; x < (req->lines); x++) {
+ const char *line = REQ_OFFSET_TO_STR(req, line[x]);
+ *length += strlen(line);
+ }
+ }
+
+ return req->lines ? 1 : 0;
+ }
+
+ /* if it's not multipart/mixed, there cannot be the content type we are looking for */
+ if (strncasecmp(content_type, "multipart/mixed", 15)) {
+ return 0;
+ }
+
+ /* if there is no boundary marker, it's invalid */
+ if ((search = strcasestr(content_type, ";boundary="))) {
+ search += 10;
+ } else if ((search = strcasestr(content_type, "; boundary="))) {
+ search += 11;
+ } else {
+ return 0;
+ }
+
+ if (ast_strlen_zero(search)) {
+ return 0;
+ }
+
+ /* If the boundary is quoted with ", remove quote */
+ if (*search == '\"') {
+ search++;
+ boundaryisquoted = TRUE;
+ }
+
+ /* make a duplicate of the string, with two extra characters
+ at the beginning */
+ boundary = ast_strdupa(search - 2);
+ boundary[0] = boundary[1] = '-';
+ /* Remove final quote */
+ if (boundaryisquoted) {
+ boundary[strlen(boundary) - 1] = '\0';
+ }
+
+ /* search for the boundary marker, the empty line delimiting headers from
+ sdp part and the end boundry if it exists */
+ *length = 0; /* calculate the length anyway since we are iterating through the lines */
+
+ for (x = 0; x < (req->lines); x++) {
+ const char *line = REQ_OFFSET_TO_STR(req, line[x]);
+ if (!strncasecmp(line, boundary, strlen(boundary))){
+ if (found_content_type && found_end_of_headers) {
+ *end = x-1;
+ return 1;
+ }
+ found_content_type = FALSE;
+ }
+ const char * r = "Content-Type:";
+ if(!strncmp(line, r, 13)) {
+ const char * ct = ast_skip_blanks(line+13);
+ if (!strncasecmp(cont, ct, strlen(cont))) {
+ found_content_type = TRUE;
+ }
+ }
+
+
+
+ if (found_content_type && found_end_of_headers) {
+ *length += strlen(line);
+ }
+
+ if (ast_strlen_zero(line)) {
+ if (found_content_type && !found_end_of_headers) {
+ *start = x;
+ found_end_of_headers = TRUE;
+ }
+ }
+
+ }
+
+ if (found_content_type && found_end_of_headers) {
+ *end = x;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+
+/*! \brief Read SIP body (dialplan function), finds first body part of given content type */
+static int func_body_read(struct ast_channel *chan, const char *function, char *data, struct ast_str **buf, ssize_t maxlen)
+{
+ unsigned int start = 0;
+ unsigned int end = 0;
+ unsigned int length = 1; /* we request the total length of our body part for allocation enough memory. */
+ struct sip_pvt *p = chan->tech_pvt;
+ struct sip_request *req = &p->initreq;
+ int x, size;
+ char *tmp;
+
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(content_type);
+ );
+
+
+ if (ast_strlen_zero(data)) {
+ ast_log(LOG_WARNING, "This function requires a content type.\n");
+ return -1;
+ }
+
+ ast_channel_lock(chan);
+ if (!IS_SIP_TECH(chan->tech)) {
+ ast_log(LOG_WARNING, "This function can only be used on SIP channels.\n");
+ ast_channel_unlock(chan);
+ return -1;
+ }
+
+ AST_STANDARD_APP_ARGS(args, data);
+
+ /* If there is no private structure, this channel is no longer alive */
+ if (!p) {
+ ast_channel_unlock(chan);
+ return -1;
+ }
+
+ find_content(req, args.content_type, &start, &end, &length);
+
+ if ((start == 0) && (end == 0)) {
+ ast_channel_unlock(chan);
+ return -1;
+ }
+
+ size = length + (end - start + 1) * 2 + 1; /* total length of our body part + for \r\n in each line and \0 at the end. */
+ tmp = ast_calloc(size, sizeof(char));
+
+ if (!tmp) {
+ ast_channel_unlock(chan);
+ return -1;
+ }
+
+ for (x = start; x <= end; x++) {
+ const char *line = REQ_OFFSET_TO_STR(req, line[x]);
+ strcat(tmp, line);
+ strcat(tmp, "\r\n");
+ }
+
+ if ( ( (maxlen < 0 ) && (ast_str_size(*buf) < size)) || ( (maxlen > 0) && (maxlen < size) ) ) {
+ ast_log(LOG_WARNING, "Buffer size too small - body part truncated");
+ }
+
+ if (maxlen < 0) {
+ maxlen = -1;
+ }
+
+ ast_str_set(buf, maxlen, "%s", tmp);
+
+ ast_channel_unlock(chan);
+
+ ast_free(tmp);
+ return 0;
+}
+
+static struct ast_custom_function sip_body_function = {
+ .name = "SIP_BODY",
+ .read2 = func_body_read,
+};
+
/*! \brief Read SIP header (dialplan function) */
static int func_header_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
{
@@ -26930,6 +27089,7 @@
/* Register dialplan functions */
ast_custom_function_register(&sip_header_function);
+ ast_custom_function_register(&sip_body_function);
ast_custom_function_register(&sippeer_function);
ast_custom_function_register(&sipchaninfo_function);
ast_custom_function_register(&checksipdomain_function);
@@ -26979,6 +27139,7 @@
ast_custom_function_unregister(&sipchaninfo_function);
ast_custom_function_unregister(&sippeer_function);
ast_custom_function_unregister(&sip_header_function);
+ ast_custom_function_unregister(&sip_body_function);
ast_custom_function_unregister(&checksipdomain_function);
/* Unregister dial plan applications */