瀏覽代碼

textops: functions to convert, append and remove multipart bodies

Victor Seva 11 年之前
父節點
當前提交
a9d5d28b8b
共有 1 個文件被更改,包括 673 次插入94 次删除
  1. 673 94
      modules/textops/textops.c

+ 673 - 94
modules/textops/textops.c

@@ -123,6 +123,14 @@ static int append_time_f(struct sip_msg* msg, char* , char *);
 static int append_time_request_f(struct sip_msg* msg, char* , char *);
 static int set_body_f(struct sip_msg* msg, char*, char *);
 static int set_rpl_body_f(struct sip_msg* msg, char*, char *);
+static int set_multibody_0(struct sip_msg* msg, char*, char *, char *);
+static int set_multibody_1(struct sip_msg* msg, char*, char *, char *);
+static int set_multibody_2(struct sip_msg* msg, char*, char *, char *);
+static int set_multibody_3(struct sip_msg* msg, char*, char *, char *);
+static int append_multibody_2(struct sip_msg* msg, char*, char *);
+static int append_multibody_3(struct sip_msg* msg, char*, char *, char *);
+static int fixup_multibody_f(void** param, int param_no);
+static int remove_multibody_f(struct sip_msg *msg, char *);
 static int is_method_f(struct sip_msg* msg, char* , char *);
 static int has_body_f(struct sip_msg *msg, char *type, char *str2 );
 static int in_list_f(struct sip_msg* _msg, char* _subject, char* _list,
@@ -275,6 +283,27 @@ static cmd_export_t cmds[]={
 
 	{"bind_textops",      (cmd_function)bind_textops,       0, 0, 0,
 		0},
+	{"set_body_multipart",         (cmd_function)set_multibody_0,        0,
+		0, 0,
+		REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
+	{"set_body_multipart",         (cmd_function)set_multibody_1,        1,
+		fixup_spve_null, 0,
+		REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
+	{"set_body_multipart",         (cmd_function)set_multibody_2,        2,
+		fixup_spve_spve, 0,
+		REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
+	{"set_body_multipart",         (cmd_function)set_multibody_3,        3,
+		fixup_multibody_f, 0,
+		REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
+	{"append_body_part",     (cmd_function)append_multibody_2,    2,
+		fixup_spve_spve, 0,
+		REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
+	{"append_body_part",     (cmd_function)append_multibody_3,    3,
+		fixup_multibody_f, 0,
+		REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
+	{"remove_body_part",     (cmd_function)remove_multibody_f,    1,
+		fixup_spve_null, 0,
+		REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
 
 	{0,0,0,0,0,0}
 };
@@ -866,6 +895,23 @@ static inline int find_line_start(char *text, unsigned int text_len,
     return 0;
 }
 
+/**
+ * return:
+ *  1: multipart
+ */
+static int check_multipart(struct sip_msg *msg)
+{
+	int mime;
+
+	/* the function search for and parses the Content-Type hdr */
+	mime = parse_content_type_hdr (msg);
+	if(mime<0) {
+		LM_ERR("failed to extract content type hdr\n");
+		return -1;
+	}
+	if(mime!=MIMETYPE(MULTIPART,MIXED)) return 0;
+	return 1;
+}
 
 /* Filters multipart/mixed body by leaving out everything else except
  * first body part of given content type. */
@@ -874,10 +920,8 @@ static int filter_body_f(struct sip_msg* msg, char* _content_type,
 {
 	char *start;
 	unsigned int len;
-	str *content_type, body, params, boundary;
-	param_hooks_t hooks;
-	param_t *p, *list;
-	unsigned int mime;
+	str *content_type, body;
+	str boundary = {0,0};
 
 	body.s = get_body(msg);
 	if (body.s == 0) {
@@ -889,106 +933,73 @@ static int filter_body_f(struct sip_msg* msg, char* _content_type,
 		LM_DBG("message body has zero length\n");
 		return -1;
 	}
-	
-	content_type = (str *)_content_type;
 
-	mime = parse_content_type_hdr(msg);
-	if (mime <= 0) {
-	    LM_ERR("failed to parse Content-Type hdr\n");
-	    return -1;
-	}
-	if (mime != ((TYPE_MULTIPART << 16) + SUBTYPE_MIXED)) {
-	    LM_ERR("content type is not multipart/mixed\n");
-	    return -1;
-	}
-
-	params.s = memchr(msg->content_type->body.s, ';', 
-			  msg->content_type->body.len);
-	if (params.s == NULL) {
-	    LM_ERR("Content-Type hdr has no params\n");
-	    return -1;
-	}
-	params.len = msg->content_type->body.len - 
-	    (params.s - msg->content_type->body.s);
-	if (parse_params(&params, CLASS_ANY, &hooks, &list) < 0) {
-	    LM_ERR("while parsing Content-Type params\n");
-	    return -1;
-	}
-	boundary.s = NULL;
-	boundary.len = 0;
-	for (p = list; p; p = p->next) {
-	    if ((p->name.len == 8)
-		&& (strncasecmp(p->name.s, "boundary", 8) == 0)) {
-		boundary.s = pkg_malloc(p->body.len + 2);
-		if (boundary.s == NULL) {
-		    free_params(list);
-		    LM_ERR("no memory for boundary string\n");
-		    return -1;
-		}
-		*(boundary.s) = '-';
-		*(boundary.s + 1) = '-';
-		memcpy(boundary.s + 2, p->body.s, p->body.len);
-		boundary.len = 2 + p->body.len;
-		LM_DBG("boundary is <%.*s>\n", boundary.len, boundary.s);
-		break;
-	    }
+	if(check_multipart(msg)!=1) {
+		LM_WARN("body not multipart\n");
+		return -1;
 	}
-	free_params(list);
-	if (boundary.s == NULL) {
-	    LM_ERR("no mandatory param \";boundary\"\n");
-	    return -1;
+	if(get_boundary(msg, &boundary)!=0) {
+		return -1;
 	}
-	
+	content_type = (str *)_content_type;
 	start = body.s;
 	len = body.len;
-	
-	while (find_line_start("Content-Type: ", 14, &start, &len)) {
-	    start = start + 14;
-	    len = len - 14;
-	    if (len > content_type->len + 2) {
-		if (strncasecmp(start, content_type->s, content_type->len)
-		    == 0) {
-		    LM_DBG("found content type %.*s\n",
-			    content_type->len, content_type->s);
-		    start = start + content_type->len;
-		    if ((*start != 13) || (*(start + 1) != 10)) {
-			LM_ERR("no CRLF found after content type\n");
-			goto err;
-		    }
-		    start = start + 2;
-		    len = len - content_type->len - 2;
-		    while ((len > 0) && ((*start == 13) || (*start == 10))) {
-			len = len - 1;
-			start = start + 1;
-		    }
-		    if (del_lump(msg, body.s - msg->buf, start - body.s, 0)
-			== 0) {
-			LM_ERR("deleting lump <%.*s> failed\n",
-			       (int)(start - body.s), body.s);
-			goto err;
-		    }
-		    if (find_line_start(boundary.s, boundary.len, &start,
-					&len)) { 
-			if (del_lump(msg, start - msg->buf, len, 0) == 0) {
-			    LM_ERR("deleting lump <%.*s> failed\n",
-				   len, start);
-			    goto err;
-			} else {
-			    pkg_free(boundary.s);
-			    return 1;
+
+	while (find_line_start("Content-Type: ", 14, &start, &len))
+	{
+		start = start + 14;
+		len = len - 14;
+		LM_DBG("line: [%.*s]\n", len, start);
+		if (len > content_type->len + 2) {
+			if (strncasecmp(start, content_type->s, content_type->len)== 0)
+			{
+				LM_DBG("found content type %.*s\n",
+					content_type->len, content_type->s);
+				start = start + content_type->len;
+				if ((*start != 13) || (*(start + 1) != 10))
+				{
+					LM_ERR("no CRLF found after content type\n");
+					goto err;
+				}
+				start = start + 2;
+				len = len - content_type->len - 2;
+				while ((len > 0) && ((*start == 13) || (*start == 10)))
+				{
+					len = len - 1;
+					start = start + 1;
+				}
+				if (del_lump(msg, body.s - msg->buf, start - body.s, 0)== 0)
+				{
+					LM_ERR("deleting lump <%.*s> failed\n",
+					(int)(start - body.s), body.s);
+					goto err;
+				}
+				if (find_line_start(boundary.s, boundary.len, &start,
+					&len))
+				{
+					if (del_lump(msg, start - msg->buf, len, 0) == 0)
+					{
+						LM_ERR("deleting lump <%.*s> failed\n", len, start);
+						goto err;
+					}
+					else
+					{
+						pkg_free(boundary.s);
+						return 1;
+					}
+				}
+				else
+				{
+					LM_ERR("boundary not found after content\n");
+					goto err;
+				}
 			}
-		    } else {
-			LM_ERR("boundary not found after content\n");
+		} else {
 			goto err;
-		    }
 		}
-	    } else {
-		pkg_free(boundary.s);
-		return -1;
-	    }
 	}
  err:
-	pkg_free(boundary.s);
+	if(boundary.s) pkg_free(boundary.s);
 	return -1;
 }
 
@@ -1444,7 +1455,575 @@ static int set_rpl_body_f(struct sip_msg* msg, char* p1, char* p2)
 	return 1;
 }
 
+static str* generate_boundary(str txt, str content_type,
+	str content_disposition, str delimiter, unsigned int initial)
+{
+	unsigned int i = 0;
+	str cth = {"Content-Type: ", 14};
+	str cdh = {"Content-Disposition: ", 21};
+	str* n;
+	unsigned int flag = 0;
 
+	if(txt.len==0||content_type.len==0||delimiter.len==0)
+	{
+		LM_ERR("invalid parameters\n");
+		return NULL;
+	}
+	n = pkg_malloc(sizeof(str));
+	if(n==NULL)
+	{
+		LM_ERR("out of pkg memory\n");
+		return NULL;
+	}
+	n->len = delimiter.len + 2 + CRLF_LEN;
+	if(initial) n->len = 2*n->len;
+	if(strncmp("\r\n\r\n", txt.s+txt.len-4,4)!=0)
+	{
+		n->len = n->len + CRLF_LEN;
+		flag = 1;
+		LM_DBG("adding final CRLF+CRLF\n");
+	}
+	n->len=n->len + cth.len + content_type.len + 2*CRLF_LEN;
+	if(content_disposition.len>0)
+	{
+		n->len = n->len + cdh.len + content_disposition.len + CRLF_LEN;
+	}
+	n->len = n->len + txt.len;
+
+	n->s = pkg_malloc(sizeof(char)*(n->len));
+	if(n->s==0)
+	{
+		LM_ERR("out of pkg memory\n");
+		pkg_free(n);
+		return NULL;
+	}
+	if(initial)
+	{
+		memcpy(n->s, "--", 2); i=2;
+		memcpy(n->s+i, delimiter.s, delimiter.len); i=i+delimiter.len;
+		memcpy(n->s+i, CRLF, CRLF_LEN); i=i+CRLF_LEN;
+	}
+
+	memcpy(n->s+i, cth.s, cth.len); i=i+cth.len;
+	memcpy(n->s+i, content_type.s, content_type.len); i=i+content_type.len;
+	memcpy(n->s+i, CRLF, CRLF_LEN); i=i+CRLF_LEN;
+
+	if(content_disposition.len>0)
+	{
+		memcpy(n->s+i, cdh.s, cdh.len); i=i+cdh.len;
+		memcpy(n->s+i, content_disposition.s, content_disposition.len);
+		i=i+content_disposition.len;
+		memcpy(n->s+i, CRLF, CRLF_LEN); i=i+CRLF_LEN;
+	}
+	memcpy(n->s+i, CRLF, CRLF_LEN); i=i+CRLF_LEN;
+
+	memcpy(n->s+i, txt.s, txt.len); i=i+txt.len;
+	if(flag) { memcpy(n->s+i, CRLF, CRLF_LEN); i=i+CRLF_LEN; }
+
+	memcpy(n->s+i, "--", 2); i=i+2;
+	memcpy(n->s+i, delimiter.s, delimiter.len); i=i+delimiter.len;
+	memcpy(n->s+i, CRLF, CRLF_LEN); i=i+CRLF_LEN;
+
+	if(i!=n->len)
+	{
+		LM_ERR("out of bounds\n");
+	}
+	return n;
+}
+
+int set_multibody_helper(struct sip_msg* msg, char* p1, char* p2, char* p3)
+{
+	struct lump *anchor;
+	char* buf = NULL;
+	int len;
+	char* value_s;
+	int value_len;
+	str body = {0,0};
+	str nb = {0,0};
+	str oc = {0,0};
+	str cd = {0,0};
+	str delimiter = {0,0};
+	str default_delimiter = {"unique-boundary-1", 17};
+	str nc = {0,0};
+	str cth = {"Content-Type: ", 14};
+	str* nbb;
+	unsigned int convert = 0;
+	fparam_t header;
+	header.orig = NULL;
+	header.type = FPARAM_STR;
+	header.v.str.s = "Mime-Version: 1.0\r\n";
+	header.v.str.len = 19;
+
+	if(p3==0)
+	{
+		delimiter.s = default_delimiter.s;
+		delimiter.len = default_delimiter.len;
+	}
+	else
+	{
+		if(fixup_get_svalue(msg, (gparam_p)p3, &delimiter)!=0)
+		{
+			LM_ERR("unable to get p3\n");
+			return -1;
+		}
+		if(delimiter.s==NULL || delimiter.len == 0)
+		{
+			LM_ERR("invalid boundary parameter\n");
+			return -1;
+		}
+	}
+	LM_DBG("delimiter<%d>:[%.*s]\n", delimiter.len, delimiter.len, delimiter.s);
+	if(p1==0 || p2==0)
+	{
+		if(check_multipart(msg)==1) {
+			LM_WARN("body is already multipart. Do nothing\n");
+			return -1;
+		}
+		convert = 1;
+	}
+	else
+	{
+		if(fixup_get_svalue(msg, (gparam_p)p1, &nb)!=0)
+		{
+			LM_ERR("unable to get p1\n");
+			return -1;
+		}
+		if(nb.s==NULL || nb.len == 0)
+		{
+			LM_ERR("invalid body parameter\n");
+			return -1;
+		}
+		if(fixup_get_svalue(msg, (gparam_p)p2, &oc)!=0)
+		{
+			LM_ERR("unable to get p2\n");
+			return -1;
+		}
+		if(oc.s==NULL || oc.len==0)
+		{
+			LM_ERR("invalid content-type parameter\n");
+			return -1;
+		}
+		if(check_multipart(msg)==1) {
+			convert = -1;
+		}
+	}
+
+	body.len = 0;
+	body.s = get_body(msg);
+	if(body.s==0)
+	{
+		LM_ERR("malformed sip message\n");
+		return -1;
+	}
+	body.len = msg->len -(int)(body.s-msg->buf);
+
+	del_nonshm_lump( &(msg->body_lumps) );
+	msg->body_lumps = NULL;
+
+	if(msg->content_length)
+	{
+		if(body.len > 0)
+		{
+			if(body.s+body.len>msg->buf+msg->len)
+			{
+				LM_ERR("invalid content length: %d\n", body.len);
+				return -1;
+			}
+			if(convert==1)
+			{
+				/* need to copy body */
+				nb.s=pkg_malloc(sizeof(char)*body.len);
+				if (nb.s==0)
+				{
+					LM_ERR("out of pkg memory\n");
+					return -1;
+				}
+				memcpy(nb.s, body.s, body.len);
+				nb.len = body.len;
+				if(msg->content_type!=NULL && msg->content_type->body.s!=NULL)
+				{
+					oc.len = msg->content_type->body.len;
+					oc.s=pkg_malloc(sizeof(char)*oc.len);
+					if (oc.s==0)
+					{
+						LM_ERR("out of pkg memory\n");
+						goto error;
+					}
+					memcpy(oc.s, msg->content_type->body.s, oc.len);
+				}
+			}
+			if(del_lump(msg, body.s-msg->buf, body.len, 0) == 0)
+			{
+				LM_ERR("cannot delete existing body");
+				goto error;
+			}
+		}
+	}
+
+	anchor = anchor_lump(msg, msg->unparsed-msg->buf, 0, 0);
+	if(anchor==0)
+	{
+		LM_ERR("failed to get anchor\n");
+		goto error;
+	}
+
+	/* get initial boundary */
+	nbb = generate_boundary(nb, oc, cd, delimiter, 1);
+	if(nbb==NULL)
+	{
+		LM_ERR("couldn't create initial boundary\n");
+		goto error;
+	}
+
+	if(msg->content_length==0)
+	{
+		/* need to add Content-Length */
+		len = nbb->len;
+		value_s=int2str(len, &value_len);
+
+		len=CONTENT_LENGTH_LEN+value_len+CRLF_LEN;
+		buf=pkg_malloc(sizeof(char)*len);
+
+		if (buf==0)
+		{
+			LM_ERR("out of pkg memory\n");
+			goto error;
+		}
+
+		memcpy(buf, CONTENT_LENGTH, CONTENT_LENGTH_LEN);
+		memcpy(buf+CONTENT_LENGTH_LEN, value_s, value_len);
+		memcpy(buf+CONTENT_LENGTH_LEN+value_len, CRLF, CRLF_LEN);
+		if (insert_new_lump_after(anchor, buf, len, 0) == 0)
+		{
+			LM_ERR("failed to insert content-length lump\n");
+			goto error;
+		}
+		buf = NULL;
+	}
+
+	if(convert!=-1)
+	{
+		/* set new content type with delimiter */
+		nc.len = delimiter.len + 27;
+		nc.s = pkg_malloc(sizeof(char)*nc.len);
+		memcpy(nc.s, "multipart/mixed;boundary=\"", 26);
+		memcpy(nc.s+26, delimiter.s, delimiter.len);
+		nc.s[26+delimiter.len] = '"';
+		LM_DBG("content-type<%d>:[%.*s]\n", nc.len, nc.len, nc.s);
+		/* add content-type */
+		if(msg->content_type==NULL || msg->content_type->body.len!=nc.len
+				|| strncmp(msg->content_type->body.s, nc.s, nc.len)!=0)
+		{
+			if(msg->content_type!=NULL)
+				if(del_lump(msg, msg->content_type->name.s-msg->buf,
+							msg->content_type->len, 0) == 0)
+				{
+					LM_ERR("failed to delete content type\n");
+					goto error;
+				}
+			value_len = nc.len;
+			len = cth.len + value_len + CRLF_LEN;
+			buf = pkg_malloc(sizeof(char)*len);
+
+			if(buf==0)
+			{
+				LM_ERR("out of pkg memory\n");
+				goto error;
+			}
+			memcpy(buf, cth.s, cth.len);
+			memcpy(buf + cth.len, nc.s, value_len);
+			memcpy(buf + cth.len + value_len, CRLF, CRLF_LEN);
+			if (insert_new_lump_after(anchor, buf, len, 0) == 0)
+			{
+				LM_ERR("failed to insert content-type lump\n");
+				goto error;
+			}
+			buf = NULL;
+		}
+		/* add Mime-Version header */
+		if(add_hf_helper(msg, 0, 0, &header, 0, 0)<0)
+		{
+			LM_ERR("failed to add Mime-Version header\n");
+			goto error;
+		}
+	}
+	anchor = anchor_lump(msg, body.s - msg->buf, 0, 0);
+	if(anchor==0)
+	{
+		LM_ERR("failed to get body anchor\n");
+		goto error;
+	}
+
+	if(insert_new_lump_after(anchor, nbb->s, nbb->len, 0)==0)
+	{
+		LM_ERR("failed to insert body lump\n");
+		goto error;
+	}
+	pkg_free(nbb);
+	if(nc.s!=NULL) pkg_free(nc.s);
+	LM_DBG("set flag FL_BODY_MULTIPART\n");
+	msg->msg_flags |= FL_BODY_MULTIPART;
+	return 1;
+
+error:
+	if(nbb!=NULL) { pkg_free(nbb->s); pkg_free(nbb); }
+	if(nc.s!=NULL) pkg_free(nc.s);
+	if(buf!=NULL) pkg_free(buf);
+	if(convert && nb.s!=NULL) pkg_free(nb.s);
+	if(convert && oc.s!=NULL) pkg_free(oc.s);
+	return -1;
+}
+
+static int set_multibody_0(struct sip_msg* msg, char* p1, char* p2, char* p3)
+{
+	return set_multibody_helper(msg, NULL, NULL, NULL);
+}
+
+static int set_multibody_1(struct sip_msg* msg, char* p1, char* p2, char* p3)
+{
+	return set_multibody_helper(msg, NULL, NULL, p1);
+}
+
+static int set_multibody_2(struct sip_msg* msg, char* p1, char* p2, char* p3)
+{
+	return set_multibody_helper(msg, p1, p2, NULL);
+}
+
+static int set_multibody_3(struct sip_msg* msg, char* p1, char* p2, char *p3)
+{
+	return set_multibody_helper(msg, p1, p2, p3);
+}
+
+int append_multibody_helper(struct sip_msg* msg, char* p1, char* p2, char* p3)
+{
+	struct lump *l;
+	int off;
+	str body = {0,0};
+	str nc = {0,0};
+	str cd = {0,0};
+	str txt = {0,0};
+	str* nbb = NULL;
+	str delimiter = {0,0};
+
+	if(p1==0 || p2==0)
+	{
+		LM_ERR("invalid parameters\n");
+		return -1;
+	}
+
+	if(fixup_get_svalue(msg, (gparam_p)p1, &txt)!=0)
+	{
+		LM_ERR("unable to get p1\n");
+		return -1;
+	}
+	if(txt.s==NULL || txt.len==0)
+	{
+		LM_ERR("invalid body parameter\n");
+		return -1;
+	}
+	if(fixup_get_svalue(msg, (gparam_p)p2, &nc)!=0)
+	{
+		LM_ERR("unable to get p2\n");
+		return -1;
+	}
+	if(nc.s==NULL || nc.len==0)
+	{
+		LM_ERR("invalid content-type parameter\n");
+		return -1;
+	}
+	if(p3!=NULL)
+	{
+		if(fixup_get_svalue(msg, (gparam_p)p3, &cd)!=0)
+		{
+			LM_ERR("unable to get p3\n");
+			return -1;
+		}
+	}
+
+	body.s = get_body(msg);
+	if(body.s==0) {
+		LM_ERR("failed to get the message body\n");
+		return -1;
+	}
+	body.len = msg->len -(int)(body.s-msg->buf);
+	if(body.len==0) {
+		LM_DBG("message body has zero length\n");
+		return -1;
+	}
+
+	off=body.s-msg->buf;
+	if((l=anchor_lump(msg, off+body.len, 0, 0))==0)
+	{
+		LM_ERR("WTF\n");
+		return -1;
+	}
+	/* get boundary */
+	if(get_boundary(msg, &delimiter)!=0) {
+		LM_ERR("Cannot get boundary. Is body multipart?\n");
+		return -1;
+	}
+	nbb = generate_boundary(txt, nc, cd, delimiter, 0);
+	if(nbb==NULL)
+	{
+		LM_ERR("couldn't create initial boundary\n");
+		pkg_free(delimiter.s);
+		return -1;
+	}
+	pkg_free(delimiter.s);
+	if(insert_new_lump_after(l, nbb->s, nbb->len, 0)==0){
+		LM_ERR("could not insert new lump\n");
+		pkg_free(nbb->s); pkg_free(nbb);
+		return -1;
+	}
+	pkg_free(nbb);
+	if(!(msg->msg_flags&FL_BODY_MULTIPART))
+	{
+		LM_DBG("set flag FL_BODY_MULTIPART\n");
+		msg->msg_flags |= FL_BODY_MULTIPART;
+	}
+	return 1;
+}
+
+static int append_multibody_2(struct sip_msg* msg, char* p1, char* p2)
+{
+	return append_multibody_helper(msg, p1, p2, NULL);
+}
+
+static int append_multibody_3(struct sip_msg* msg, char* p1, char* p2, char *p3)
+{
+	return append_multibody_helper(msg, p1, p2, p3);
+}
+
+static int fixup_multibody_f(void** param, int param_no)
+{
+	int ret;
+	fparam_t* fp;
+
+	if(param_no<=3){
+		if((ret=fix_param_types(FPARAM_PVE, param))<0){
+			ERR("Cannot convert function parameter %d to spve \n",
+					param_no);
+			return E_UNSPEC;
+		} else {
+			fp=(fparam_t*)*param;
+			if((ret==0) && (fp->v.pve->spec==0
+						|| fp->v.pve->spec->getf==0)){
+				fparam_free_restore(param);
+				return fix_param_types(FPARAM_STR, param);
+			} else if(ret==1)
+				return fix_param_types(FPARAM_STR, param);
+			return ret;
+		}
+	} else {
+		LM_ERR("wrong number of parameters\n");
+		return E_UNSPEC;
+	}
+}
+
+static inline int get_line(char *s, int len)
+{
+	char *ch;
+
+	if ((ch = memchr(s, 13, len))) {
+		if (*(ch + 1) != 10) {
+			LM_ERR("No LF after CR\n");
+			return 0;
+		}
+		return ch - s + 2;
+	} else {
+		LM_ERR("No CRLF found\n");
+		return len;
+	}
+	return 0;
+}
+
+static int remove_multibody_f(struct sip_msg* msg, char* p1)
+{
+	char *start, *end;
+	unsigned int len, t;
+	str content_type, body;
+	str boundary = {0,0};
+
+	if(p1==0)
+	{
+		LM_ERR("invalid parameters\n");
+		return -1;
+	}
+
+	if(fixup_get_svalue(msg, (gparam_p)p1, &content_type)!=0)
+	{
+		LM_ERR("unable to get p1\n");
+		return -1;
+	}
+
+	body.s = get_body(msg);
+	if (body.s == 0) {
+		LM_ERR("failed to get the message body\n");
+		return -1;
+	}
+	body.len = msg->len - (int)(body.s - msg->buf);
+	if (body.len == 0) {
+		LM_DBG("message body has zero length\n");
+		return -1;
+	}
+
+	if(get_boundary(msg, &boundary)!=0) {
+		LM_ERR("Cannot get boundary. Is body multipart?\n");
+		return -1;
+	}
+
+	start = body.s;
+	len = body.len;
+
+	while (find_line_start("Content-Type: ", 14, &start, &len))
+	{
+		end = start + 14;
+		len = len - 14;
+		if (len > (content_type.len + 2)) {
+			if (strncasecmp(end, content_type.s, content_type.len)== 0)
+			{
+				LM_DBG("found content type %.*s\n",
+					content_type.len, content_type.s);
+				end = end + content_type.len;
+				if ((*end != 13) || (*(end + 1) != 10))
+				{
+					LM_ERR("no CRLF found after content type\n");
+					goto err;
+				}
+				end = end + 2;
+				len = len - content_type.len - 2;
+				if (find_line_start(boundary.s, boundary.len, &end,
+					&len))
+				{
+					LM_DBG("found boundary %.*s\n", boundary.len, boundary.s);
+					end = end + boundary.len;
+					len = len - boundary.len;
+					if (!(t = get_line(end, len))) goto err;
+					end += t; len = end-start;
+					if (del_lump(msg, start - msg->buf, len, 0) == 0)
+					{
+						LM_ERR("deleting lump <%.*s> failed\n", len, start);
+						goto err;
+					}
+					pkg_free(boundary.s);
+					if(!(msg->msg_flags&FL_BODY_MULTIPART))
+					{
+						LM_DBG("set flag FL_BODY_MULTIPART\n");
+						msg->msg_flags |= FL_BODY_MULTIPART;
+					}
+					return 1;
+				}
+				LM_ERR("boundary not found after content\n");
+				goto err;
+			}
+			start = end;
+		}
+		else goto err;
+	}
+ err:
+	pkg_free(boundary.s);
+	return -1;
+}
 
 static int append_to_reply_f(struct sip_msg* msg, char* key, char* str0)
 {