Przeglądaj źródła

parser,modules/pv,modules/sipcapture: Improved parsing of
P-Asserted/Preferred-Identity headers

parser:
- Abstracted addr-spec parsing from parse_to.c into new file.
(parse_addr_spec.c)
- Added support for comma separated addr-spec values.
- Created new P-Asserted-Identity and P-Preferred-Identity header parsers
that parse all instances and allows comma separated values.
modules/pv:
- Added PV index to $ai, $pu, $pU, $pd and $pn variables to retreive the
n'th URI instance. E.g. $(ai[1])
modules/sipcapture:
- Updated to use the new structure
- Maintains previous behaviour - only uses the first URI

Hugh Waite 12 lat temu
rodzic
commit
09441e89d3

+ 0 - 77
lib/kcore/parse_pai.c

@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2006 Juha Heinanen
- *
- * This file is part of Kamailio, a free SIP server.
- *
- * Kamailio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * Kamailio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License 
- * along with this program; if not, write to the Free Software 
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-/*!
- * \file
- * \brief P-Asserted-Identity header parser
- * \ingroup parser
- */
-
-#include "../../parser/parse_from.h"
-#include "../../parser/parse_to.h"
-#include <stdlib.h>
-#include <string.h>
-#include "../../dprint.h"
-#include "../../parser/msg_parser.h"
-#include "../../ut.h"
-#include "../../mem/mem.h"
-
-/*!
- * This method is used to parse P-Asserted-Identity header (RFC 3325).
- *
- * Currently only one name-addr / addr-spec is supported in the header
- * and it must contain a sip or sips URI.
- * \param msg sip msg
- * \return 0 on success, -1 on failure.
- */
-int parse_pai_header( struct sip_msg *msg )
-{
-	struct to_body* pai_b;
-
-	if ( !msg->pai && (parse_headers(msg, HDR_PAI_F,0)==-1 || !msg->pai)) {
-		goto error;
-	}
-
-	/* maybe the header is already parsed! */
-	if (msg->pai->parsed)
-		return 0;
- 
-	/* bad luck! :-( - we have to parse it */
-	/* first, get some memory */
-	pai_b = pkg_malloc(sizeof(struct to_body));
-	if (pai_b == 0) {
-		LM_ERR("out of pkg_memory\n");
-		goto error;
-	}
- 
-	/* now parse it!! */
-	memset(pai_b, 0, sizeof(struct to_body));
-	parse_to(msg->pai->body.s, msg->pai->body.s + msg->pai->body.len+1, pai_b);
-	if (pai_b->error == PARSE_ERROR) {
-		LM_ERR("bad P-Asserted-Identity header\n");
-		free_to(pai_b);
-		goto error;
-	}
- 	msg->pai->parsed = pai_b;
- 
-	return 0;
-error:
-	return -1;
-}

+ 0 - 119
lib/kcore/parse_ppi.c

@@ -1,119 +0,0 @@
-/*
- * $Id$
- *
- * Copyright (C) 2006 Juha Heinanen
- *
- * This file is part of Kamailio, a free SIP server.
- *
- * Kamailio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * Kamailio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License 
- * along with this program; if not, write to the Free Software 
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-/*!
- * \file
- * \brief P-Preferred-Identity header parser
- * \ingroup parser
- */
-
-#include "parse_ppi.h"
-#include "../../parser/parse_to.h"
-#include "../../parser/parse_uri.h"
-#include <stdlib.h>
-#include <string.h>
-#include "../../dprint.h"
-#include "../../parser/msg_parser.h"
-#include "../../ut.h"
-#include "../../mem/mem.h"
-
-
-/*!
- * \brief This method is used to parse P-Preferred-Identity header (RFC 3325).
- *
- * Currently only one name-addr / addr-spec is supported in the header
- * and it must contain a sip or sips URI.
- * \param msg sip msg
- * \return 0 on success, -1 on failure.
- */
-int parse_ppi_header( struct sip_msg *msg )
-{
-    struct to_body* ppi_b;
-
-    if ( !msg->ppi &&
-	 (parse_headers(msg, HDR_PPI_F,0)==-1 || !msg->ppi)) {
-	goto error;
-    }
- 
-    /* maybe the header is already parsed! */
-    if (msg->ppi->parsed)
-	return 0;
- 
-    /* bad luck! :-( - we have to parse it */
-    /* first, get some memory */
-    ppi_b = pkg_malloc(sizeof(struct to_body));
-    if (ppi_b == 0) {
-	LM_ERR("out of pkg_memory\n");
-	goto error;
-    }
- 
-    /* now parse it!! */
-    memset(ppi_b, 0, sizeof(struct to_body));
-    parse_to(msg->ppi->body.s,
-	     msg->ppi->body.s + msg->ppi->body.len+1,
-	     ppi_b);
-    if (ppi_b->error == PARSE_ERROR) {
-	LM_ERR("bad P-Preferred-Identity header\n");
-	free_to(ppi_b);
-	goto error;
-    }
- 	msg->ppi->parsed = ppi_b;
- 
- 	return 0;
- error:
- 	return -1;
-}
-
-
-/*!
- * \brief Parse P-Preferred-Identity header URI
- */
-struct sip_uri *parse_ppi_uri(struct sip_msg *msg)
-{
-	struct to_body *tb = NULL;
-	
-	if(msg==NULL)
-		return NULL;
-
-	if(parse_ppi_header(msg)<0)
-	{
-		LM_ERR("cannot parse P-P-I header\n");
-		return NULL;
-	}
-	
-	if(msg->ppi==NULL || get_ppi(msg)==NULL)
-		return NULL;
-
-	tb = get_ppi(msg);
-
-	if(tb->parsed_uri.user.s!=NULL || tb->parsed_uri.host.s!=NULL)
-		return &tb->parsed_uri;
-
-	if (parse_uri(tb->uri.s, tb->uri.len , &tb->parsed_uri)<0)
-	{
-		LM_ERR("failed to parse P-P-I URI\n");
-		memset(&tb->parsed_uri, 0, sizeof(struct sip_uri));
-		return NULL;
-	}
-
-	return &tb->parsed_uri;
-}

+ 0 - 53
lib/kcore/parse_ppi.h

@@ -1,53 +0,0 @@
-/*
- * $Id$
- *
- * Copyright (C) 2006 Juha Heinanen
- *
- * This file is part of Kamailio, a free SIP server.
- *
- * Kamailio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * Kamailio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License 
- * along with this program; if not, write to the Free Software 
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- */
-
-/*!
- * \file
- * \brief P-Preferred-Identity header parser
- * \ingroup parser
- */
-
-#ifndef PARSE_PPI_H
-#define PARSE_PPI_H
-
-#include "../../parser/msg_parser.h"
-#include "../../parser/parse_to.h"
-
-
-/*! casting macro for accessing P-Preferred-Identity body */
-#define get_ppi(p_msg)  ((struct to_body*)(p_msg)->ppi->parsed)
-
-
-/*!
- * \brief This method is used to parse P-Preferred-Identity header (RFC 3325).
- *
- * Currently only one name-addr / addr-spec is supported in the header
- * and it must contain a sip or sips URI.
- * \param msg sip msg
- * \return 0 on success, -1 on failure.
- */
-int parse_ppi_header( struct sip_msg *msg);
-
-struct sip_uri *parse_ppi_uri(struct sip_msg *msg);
- 
-#endif /* PARSE_PPI_H */

+ 5 - 5
modules/pv/pv.c

@@ -97,7 +97,7 @@ static pv_export_t mod_pvs[] = {
 		pv_set_scriptvar, pv_parse_scriptvar_name, 0, 0, 0},
 		pv_set_scriptvar, pv_parse_scriptvar_name, 0, 0, 0},
 	{{"ai", (sizeof("ai")-1)}, /* */
 	{{"ai", (sizeof("ai")-1)}, /* */
 		PVT_OTHER, pv_get_pai, 0,
 		PVT_OTHER, pv_get_pai, 0,
-		0, 0, 0, 0},
+		0, pv_parse_index, 0, 0},
 	{{"adu", (sizeof("adu")-1)}, /* auth digest uri */
 	{{"adu", (sizeof("adu")-1)}, /* auth digest uri */
 		PVT_OTHER, pv_get_authattr, 0,
 		PVT_OTHER, pv_get_authattr, 0,
 		0, 0, pv_init_iname, 3},
 		0, 0, pv_init_iname, 3},
@@ -262,10 +262,10 @@ static pv_export_t mod_pvs[] = {
 		0, 0, pv_init_iname, 1},
 		0, 0, pv_init_iname, 1},
 	{{"pd", (sizeof("pd")-1)}, /* */
 	{{"pd", (sizeof("pd")-1)}, /* */
 		PVT_OTHER, pv_get_ppi_attr, 0,
 		PVT_OTHER, pv_get_ppi_attr, 0,
-		0, 0, pv_init_iname, 3},
+		0, pv_parse_index, pv_init_iname, 3},
 	{{"pn", (sizeof("pn")-1)}, /* */
 	{{"pn", (sizeof("pn")-1)}, /* */
 		PVT_OTHER, pv_get_ppi_attr, 0,
 		PVT_OTHER, pv_get_ppi_attr, 0,
-		0, 0, pv_init_iname, 4},
+		0, pv_parse_index, pv_init_iname, 4},
 	{{"pp", (sizeof("pp")-1)}, /* */
 	{{"pp", (sizeof("pp")-1)}, /* */
 		PVT_OTHER, pv_get_pid, 0,
 		PVT_OTHER, pv_get_pid, 0,
 		0, 0, 0, 0},
 		0, 0, 0, 0},
@@ -277,10 +277,10 @@ static pv_export_t mod_pvs[] = {
 		0, 0, 0, 0},
 		0, 0, 0, 0},
 	{{"pu", (sizeof("pu")-1)}, /* */
 	{{"pu", (sizeof("pu")-1)}, /* */
 		PVT_OTHER, pv_get_ppi_attr, 0,
 		PVT_OTHER, pv_get_ppi_attr, 0,
-		0, 0, pv_init_iname, 1},
+		0, pv_parse_index, pv_init_iname, 1},
 	{{"pU", (sizeof("pU")-1)}, /* */
 	{{"pU", (sizeof("pU")-1)}, /* */
 		PVT_OTHER, pv_get_ppi_attr, 0,
 		PVT_OTHER, pv_get_ppi_attr, 0,
-		0, 0, pv_init_iname, 2},
+		0, pv_parse_index, pv_init_iname, 2},
 	{{"rb", (sizeof("rb")-1)}, /* */
 	{{"rb", (sizeof("rb")-1)}, /* */
 		PVT_MSG_BODY, pv_get_msg_body, 0,
 		PVT_MSG_BODY, pv_get_msg_body, 0,
 		0, 0, 0, 0},
 		0, 0, 0, 0},

+ 114 - 28
modules/pv/pv_core.c

@@ -40,8 +40,7 @@
 #include "../../parser/parse_refer_to.h"
 #include "../../parser/parse_refer_to.h"
 #include "../../parser/parse_rpid.h"
 #include "../../parser/parse_rpid.h"
 #include "../../parser/parse_diversion.h"
 #include "../../parser/parse_diversion.h"
-#include "../../lib/kcore/parse_ppi.h"
-#include "../../lib/kcore/parse_pai.h"
+#include "../../parser/parse_ppi_pai.h"
 #include "../../parser/digest/digest.h"
 #include "../../parser/digest/digest.h"
 
 
 #include "pv_core.h"
 #include "pv_core.h"
@@ -865,38 +864,84 @@ int pv_get_rpid(struct sip_msg *msg, pv_param_t *param,
 int pv_get_ppi_attr(struct sip_msg *msg, pv_param_t *param,
 int pv_get_ppi_attr(struct sip_msg *msg, pv_param_t *param,
 		pv_value_t *res)
 		pv_value_t *res)
 {
 {
+    int idxf;
+    int idx;
     struct sip_uri *uri;
     struct sip_uri *uri;
-    
-    if(msg==NULL)
-	return -1;
+    p_id_body_t *ppi_body = NULL;
+	to_body_t *ppi_uri = NULL;
+	int i, cur_id;
 
 
-    if(parse_ppi_header(msg) < 0) {
-	LM_DBG("no P-Preferred-Identity header\n");
-	return pv_get_null(msg, param, res);
-    }
-	
-    if(msg->ppi == NULL || get_ppi(msg) == NULL) {
-	       LM_DBG("no P-Preferred-Identity header\n");
+    if(msg==NULL)
+		return -1;
+    
+	if(parse_ppi_header(msg) < 0)
+    {
+		LM_DBG("no P-Preferred-Identity header\n");
 		return pv_get_null(msg, param, res);
 		return pv_get_null(msg, param, res);
     }
     }
-    
+
+    if (pv_get_spec_index(msg, param, &idx, &idxf) != 0)
+    {
+    	LM_ERR("Invalid index\n");
+		return -1;
+    }
+
+    if (idxf == PV_IDX_ALL)
+	{
+		LM_ERR("Unable to return 'all' PPI values\n");
+		return -1;
+	}
+
+	ppi_body = get_ppi(msg);
+	ppi_uri = &ppi_body->id[0];
+	cur_id = 0;
+	i = 0;
+	while (i < idx)
+	{
+		cur_id++;
+		if (cur_id < ppi_body->num_ids)
+		{
+			ppi_uri = &ppi_body->id[cur_id];
+			i++;
+		}
+		else if (ppi_body->next != NULL)
+		{
+			ppi_body = ppi_body->next;
+			ppi_uri = &ppi_body->id[0];
+			cur_id = 0;
+			i++;
+		}
+		else
+		{
+			/* No more PPIs */
+			return pv_get_null(msg, param, res);
+		}
+
+	}
+	/* Found the ID at index 'idx' */
+
     if(param->pvn.u.isname.name.n == 1) { /* uri */
     if(param->pvn.u.isname.name.n == 1) { /* uri */
-		return pv_get_strval(msg, param, res, &(get_ppi(msg)->uri));
+		return pv_get_strval(msg, param, res, &(ppi_uri->uri));
     }
     }
 	
 	
     if(param->pvn.u.isname.name.n==4) { /* display name */
     if(param->pvn.u.isname.name.n==4) { /* display name */
-		if(get_ppi(msg)->display.s == NULL ||
-				get_ppi(msg)->display.len <= 0) {
+		if(ppi_uri->display.s == NULL ||
+				ppi_uri->display.len <= 0) {
 		    LM_DBG("no P-Preferred-Identity display name\n");
 		    LM_DBG("no P-Preferred-Identity display name\n");
 			return pv_get_null(msg, param, res);
 			return pv_get_null(msg, param, res);
 		}
 		}
-		return pv_get_strval(msg, param, res, &(get_ppi(msg)->display));
+		return pv_get_strval(msg, param, res, &(ppi_uri->display));
     }
     }
 
 
-    if((uri=parse_ppi_uri(msg))==NULL) {
-		LM_ERR("cannot parse P-Preferred-Identity URI\n");
-		return pv_get_null(msg, param, res);
-    }
+	uri = &ppi_uri->parsed_uri;
+	if (uri->host.s == NULL && uri->user.s == NULL)
+	{
+		if (parse_uri(ppi_uri->uri.s, ppi_uri->uri.len, uri) < 0)
+		{
+			LM_ERR("cannot parse P-Preferred-Identity URI\n");
+			return pv_get_null(msg, param, res);
+		}
+	}
 
 
     if(param->pvn.u.isname.name.n==2) { /* username */
     if(param->pvn.u.isname.name.n==2) { /* username */
 		if(uri->user.s==NULL || uri->user.len<=0) {
 		if(uri->user.s==NULL || uri->user.len<=0) {
@@ -920,21 +965,62 @@ int pv_get_ppi_attr(struct sip_msg *msg, pv_param_t *param,
 int pv_get_pai(struct sip_msg *msg, pv_param_t *param,
 int pv_get_pai(struct sip_msg *msg, pv_param_t *param,
 		pv_value_t *res)
 		pv_value_t *res)
 {
 {
+    int idxf;
+    int idx;
+    p_id_body_t *pai_body = NULL;
+	to_body_t *pai_uri = NULL;
+	int i, cur_id;
+
     if(msg==NULL)
     if(msg==NULL)
 		return -1;
 		return -1;
     
     
-    if(parse_pai_header(msg)==-1)
+	if(parse_pai_header(msg) < 0)
     {
     {
 		LM_DBG("no P-Asserted-Identity header\n");
 		LM_DBG("no P-Asserted-Identity header\n");
 		return pv_get_null(msg, param, res);
 		return pv_get_null(msg, param, res);
     }
     }
-	
-    if(msg->pai==NULL || get_pai(msg)==NULL) {
-		LM_DBG("no P-Asserted-Identity header\n");
-		return pv_get_null(msg, param, res);
+
+    if (pv_get_spec_index(msg, param, &idx, &idxf) != 0)
+    {
+    	LM_ERR("Invalid index\n");
+		return -1;
     }
     }
-    
-	return pv_get_strval(msg, param, res, &(get_pai(msg)->uri));
+
+    if (idxf == PV_IDX_ALL)
+	{
+		LM_ERR("Unable to return 'all' PAI values\n");
+		return -1;
+	}
+
+	pai_body = get_pai(msg);
+	pai_uri = &pai_body->id[0];
+	cur_id = 0;
+	i = 0;
+	while (i < idx)
+	{
+		cur_id++;
+		if (cur_id < pai_body->num_ids)
+		{
+			pai_uri = &pai_body->id[cur_id];
+			i++;
+		}
+		else if (pai_body->next != NULL)
+		{
+			pai_body = pai_body->next;
+			pai_uri = &pai_body->id[0];
+			cur_id = 0;
+			i++;
+		}
+		else
+		{
+			/* No more PAIs */
+			return pv_get_null(msg, param, res);
+		}
+
+	}
+	/* Found the ID at index 'idx' */
+
+	return pv_get_strval(msg, param, res, &(pai_uri->uri));
 }
 }
 
 
 /* proto of received message: $pr or $proto*/
 /* proto of received message: $pr or $proto*/

+ 27 - 25
modules/sipcapture/sipcapture.c

@@ -68,8 +68,7 @@
 #include "../../parser/parse_from.h"
 #include "../../parser/parse_from.h"
 #include "../../parser/parse_uri.h"
 #include "../../parser/parse_uri.h"
 #include "../../parser/digest/digest.h"
 #include "../../parser/digest/digest.h"
-#include "../../lib/kcore/parse_pai.h"
-#include "../../lib/kcore/parse_ppi.h"
+#include "../../parser/parse_ppi_pai.h"
 #include "../../pvar.h"
 #include "../../pvar.h"
 #include "../../str.h"
 #include "../../str.h"
 #include "../../onsend.h"
 #include "../../onsend.h"
@@ -957,7 +956,7 @@ error:
 static int sip_capture(struct sip_msg *msg, char *s1, char *s2)
 static int sip_capture(struct sip_msg *msg, char *s1, char *s2)
 {
 {
 	struct _sipcapture_object sco;
 	struct _sipcapture_object sco;
-	struct sip_uri from, to, pai, contact;
+	struct sip_uri from, to, contact;
 	struct hdr_field *hook1 = NULL;	 
 	struct hdr_field *hook1 = NULL;	 
 	hdr_field_t *tmphdr[4];       
 	hdr_field_t *tmphdr[4];       
 	contact_body_t*  cb=0;	        	        
 	contact_body_t*  cb=0;	        	        
@@ -1062,32 +1061,35 @@ static int sip_capture(struct sip_msg *msg, char *s1, char *s2)
         	EMPTY_STR(sco.to_user);
         	EMPTY_STR(sco.to_user);
         	EMPTY_STR(sco.to_tag);
         	EMPTY_STR(sco.to_tag);
         }
         }
-	
+
 	/* Call-id */
 	/* Call-id */
 	if(msg->callid) sco.callid = msg->callid->body;
 	if(msg->callid) sco.callid = msg->callid->body;
 	else { EMPTY_STR(sco.callid); }
 	else { EMPTY_STR(sco.callid); }
-	
+
 	/* P-Asserted-Id */
 	/* P-Asserted-Id */
-	if(msg->pai && (parse_pai_header(msg) == 0)) {
-
-	     if (parse_uri(get_pai(msg)->uri.s, get_pai(msg)->uri.len, &pai)<0){
-             	LM_DBG("DEBUG: do_action: bad pai: method:[%.*s] CID: [%.*s]\n", sco.method.len, sco.method.s, sco.callid.len, sco.callid.s);
-             }
-             else {
-	        LM_DBG("PARSE PAI: (%.*s)\n",get_pai(msg)->uri.len, get_pai(msg)->uri.s);
-	        sco.pid_user = pai.user;                          
-             }
-	}	
-	else if(msg->ppi && (parse_ppi_header(msg) == 0)) {
-		
-	     if (parse_uri(get_ppi(msg)->uri.s, get_ppi(msg)->uri.len, &pai)<0){
-             	LM_DBG("DEBUG: do_action: bad ppi: method:[%.*s] CID: [%.*s]\n", sco.method.len, sco.method.s, sco.callid.len, sco.callid.s);
-             }
-             else {
-	        sco.pid_user = pai.user;
-             }
-        }
-        else { EMPTY_STR(sco.pid_user); }
+	if((parse_pai_header(msg) == 0) && (msg->pai) && (msg->pai->parsed)) {
+		to_body_t *pai = get_pai(msg)->id; /* This returns the first entry */
+		if ((pai->parsed_uri.user.s == NULL) &&
+			(parse_uri(pai->uri.s, pai->uri.len, &pai->parsed_uri) < 0)){
+			LM_DBG("DEBUG: do_action: bad pai: method:[%.*s] CID: [%.*s]\n", sco.method.len, sco.method.s, sco.callid.len, sco.callid.s);
+		}
+		else {
+			LM_DBG("PARSE PAI: (%.*s)\n", pai->uri.len, pai->uri.s);
+			sco.pid_user = pai->parsed_uri.user;
+		}
+	}
+	else if((parse_ppi_header(msg) == 0) && (msg->ppi) && (msg->ppi->parsed)) {
+		to_body_t *ppi = get_ppi(msg)->id; /* This returns the first entry */
+		if ((ppi->parsed_uri.user.s == NULL) &&
+			(parse_uri(ppi->uri.s, ppi->uri.len, &ppi->parsed_uri) < 0)){
+			LM_DBG("DEBUG: do_action: bad ppi: method:[%.*s] CID: [%.*s]\n", sco.method.len, sco.method.s, sco.callid.len, sco.callid.s);
+		}
+		else {
+			LM_DBG("PARSE PPI: (%.*s)\n", ppi->uri.len, ppi->uri.s);
+			sco.pid_user = ppi->parsed_uri.user;
+		}
+	}
+	else { EMPTY_STR(sco.pid_user); }
 	
 	
 	/* Auth headers */
 	/* Auth headers */
         if(msg->proxy_auth != NULL) hook1 = msg->proxy_auth;
         if(msg->proxy_auth != NULL) hook1 = msg->proxy_auth;

+ 3 - 2
parser/hf.c

@@ -57,6 +57,7 @@
 #include "parse_disposition.h"
 #include "parse_disposition.h"
 #include "parse_allow.h"
 #include "parse_allow.h"
 #include "../ut.h"
 #include "../ut.h"
+#include "parse_ppi_pai.h"
 
 
 /** Frees a hdr_field structure.
 /** Frees a hdr_field structure.
  * WARNING: it frees only parsed (and not name.s, body.s)
  * WARNING: it frees only parsed (and not name.s, body.s)
@@ -122,11 +123,11 @@ void clean_hdr_field(struct hdr_field* const hf)
 			break;
 			break;
 
 
 		case HDR_PAI_T:
 		case HDR_PAI_T:
-			free_to(hf->parsed);
+			free_pai_ppi_body(hf->parsed);
 			break;
 			break;
 
 
 		case HDR_PPI_T:
 		case HDR_PPI_T:
-			free_to(hf->parsed);
+			free_pai_ppi_body(hf->parsed);
 			break;
 			break;
 
 
 		case HDR_PROXYAUTH_T:
 		case HDR_PROXYAUTH_T:

+ 926 - 0
parser/parse_addr_spec.c

@@ -0,0 +1,926 @@
+/*
+ * Copyright (C) 2001-2003 Fhg Fokus
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * ser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * History:
+ * ---------
+ * 2003-04-26 ZSW (jiri)
+ * 2010-03-03  fix multi-token no-quotes display name (andrei)
+ */
+
+/** Parser :: Parse To: header.
+ * @file
+ * @ingroup parser
+ */
+
+#include "parse_to.h"
+#include <stdlib.h>
+#include <string.h>
+#include "../dprint.h"
+#include "msg_parser.h"
+#include "parse_uri.h"
+#include "../ut.h"
+#include "../mem/mem.h"
+
+
+enum {
+	START_TO, DISPLAY_QUOTED, E_DISPLAY_QUOTED, DISPLAY_TOKEN,
+	DISPLAY_TOKEN_SP, S_URI_ENCLOSED, URI_ENCLOSED, E_URI_ENCLOSED,
+	URI_OR_TOKEN, MAYBE_URI_END, END, F_CR, F_LF, F_CRLF
+};
+
+
+enum {
+	S_PARA_NAME=20, PARA_NAME, S_EQUAL, S_PARA_VALUE, TAG1, TAG2,
+	TAG3, PARA_VALUE_TOKEN , PARA_VALUE_QUOTED, E_PARA_VALUE
+};
+
+
+
+#define add_param( _param , _body , _newparam ) \
+	do{\
+		DBG("DEBUG: add_param: %.*s=%.*s\n",param->name.len,ZSW(param->name.s),\
+			param->value.len,ZSW(param->value.s));\
+		if (!(_body)->param_lst)  (_body)->param_lst=(_param);\
+		else (_body)->last_param->next=(_param);\
+		(_body)->last_param =(_param);\
+		if ((_param)->type==TAG_PARAM)\
+			memcpy(&((_body)->tag_value),&((_param)->value),sizeof(str));\
+		_newparam = 0;\
+	}while(0);
+
+
+
+
+
+static char* parse_to_param(char* const buffer, const char* const end,
+					struct to_body* const to_b, const int allow_comma_sep,
+					int* const returned_status)
+{
+	struct to_param *param;
+	struct to_param *newparam;
+	int status;
+	int saved_status;
+	char  *tmp;
+
+	param=0;
+	newparam=0;
+	status=E_PARA_VALUE;
+	saved_status=E_PARA_VALUE;
+	for( tmp=buffer; tmp<end; tmp++)
+	{
+		switch(*tmp)
+		{
+			case ' ':
+			case '\t':
+				switch (status)
+				{
+					case TAG3:
+						param->type=TAG_PARAM;
+					case PARA_NAME:
+					case TAG1:
+					case TAG2:
+						param->name.len = tmp-param->name.s;
+						status = S_EQUAL;
+						break;
+					case PARA_VALUE_TOKEN:
+						param->value.len = tmp-param->value.s;
+						status = E_PARA_VALUE;
+						add_param(param, to_b, newparam);
+						break;
+					case F_CRLF:
+					case F_LF:
+					case F_CR:
+						/*previous=crlf and now =' '*/
+						status=saved_status;
+						break;
+				}
+				break;
+			case '\n':
+				switch (status)
+				{
+					case S_PARA_NAME:
+					case S_EQUAL:
+					case S_PARA_VALUE:
+					case E_PARA_VALUE:
+						saved_status=status;
+						status=F_LF;
+						break;
+					case TAG3:
+						param->type=TAG_PARAM;
+					case PARA_NAME:
+					case TAG1:
+					case TAG2:
+						param->name.len = tmp-param->name.s;
+						saved_status = S_EQUAL;
+						status = F_LF;
+						break;
+					case PARA_VALUE_TOKEN:
+						param->value.len = tmp-param->value.s;
+						saved_status = E_PARA_VALUE;
+						status = F_LF;
+						add_param(param, to_b, newparam);
+						break;
+					case F_CR:
+						status=F_CRLF;
+						break;
+					case F_CRLF:
+					case F_LF:
+						status=saved_status;
+						goto endofheader;
+					default:
+						LOG( L_ERR , "ERROR: parse_to_param : "
+							"unexpected char [%c] in status %d: <<%.*s>> .\n",
+							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
+						goto error;
+				}
+				break;
+			case '\r':
+				switch (status)
+				{
+					case S_PARA_NAME:
+					case S_EQUAL:
+					case S_PARA_VALUE:
+					case E_PARA_VALUE:
+						saved_status=status;
+						status=F_CR;
+						break;
+					case TAG3:
+						param->type=TAG_PARAM;
+					case PARA_NAME:
+					case TAG1:
+					case TAG2:
+						param->name.len = tmp-param->name.s;
+						saved_status = S_EQUAL;
+						status = F_CR;
+						break;
+					case PARA_VALUE_TOKEN:
+						param->value.len = tmp-param->value.s;
+						saved_status = E_PARA_VALUE;
+						status = F_CR;
+						add_param(param, to_b, newparam);
+						break;
+					case F_CRLF:
+					case F_CR:
+					case F_LF:
+						status=saved_status;
+						goto endofheader;
+					default:
+						LOG( L_ERR , "ERROR: parse_to_param : "
+							"unexpected char [%c] in status %d: <<%.*s>> .\n",
+							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
+						goto error;
+				}
+				break;
+			case 0:
+				switch (status)
+				{
+					case TAG3:
+						param->type = TAG_PARAM;
+					case PARA_NAME:
+					case TAG1:
+					case TAG2:
+						param->name.len = tmp-param->name.s;
+						status = S_EQUAL;
+					case S_EQUAL:
+					case S_PARA_VALUE:
+						saved_status=status;
+						goto endofheader;
+					case PARA_VALUE_TOKEN:
+						status = E_PARA_VALUE;
+						param->value.len = tmp-param->value.s;
+						add_param(param , to_b, newparam);
+					case E_PARA_VALUE:
+						saved_status = status;
+						goto endofheader;
+						break;
+					default:
+						LOG( L_ERR , "ERROR: parse_to_param : "
+							"unexpected char [%c] in status %d: <<%.*s>> .\n",
+							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
+						goto error;
+				}
+				break;
+			case '\\':
+				switch (status)
+				{
+					case PARA_VALUE_QUOTED:
+						switch (*(tmp+1))
+						{
+							case '\r':
+							case '\n':
+								break;
+							default:
+								tmp++;
+						}
+					default:
+						LOG( L_ERR , "ERROR: parse_to_param : "
+							"unexpected char [%c] in status %d: <<%.*s>> .\n",
+							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
+						goto error;
+				}
+				break;
+			case '"':
+				switch (status)
+				{
+					case S_PARA_VALUE:
+						param->value.s = tmp+1;
+						status = PARA_VALUE_QUOTED;
+						break;
+					case PARA_VALUE_QUOTED:
+						param->value.len=tmp-param->value.s;
+						add_param(param, to_b, newparam);
+						status = E_PARA_VALUE;
+						break;
+					case F_CRLF:
+					case F_LF:
+					case F_CR:
+						/*previous=crlf and now !=' '*/
+						goto endofheader;
+					default:
+						LOG( L_ERR , "ERROR: parse_to_param :"
+							"unexpected char [%c] in status %d: <<%.*s>> .\n",
+							*tmp,status,(int)(tmp-buffer), ZSW(buffer));
+						goto error;
+				}
+				break;
+			case ';' :
+				switch (status)
+				{
+					case PARA_VALUE_QUOTED:
+						break;
+					case TAG3:
+						param->type = TAG_PARAM;
+					case PARA_NAME:
+					case TAG1:
+					case TAG2:
+						param->name.len = tmp-param->name.s;
+					case S_EQUAL:
+						param->value.s = 0;
+						param->value.len = 0;
+						goto semicolon_add_param;
+					case S_PARA_VALUE:
+						param->value.s = tmp;
+					case PARA_VALUE_TOKEN:
+						param->value.len=tmp-param->value.s;
+semicolon_add_param:
+						add_param(param, to_b, newparam);
+					case E_PARA_VALUE:
+						param = (struct to_param*)
+							pkg_malloc(sizeof(struct to_param));
+						if (!param){
+							LOG( L_ERR , "ERROR: parse_to_param"
+							" - out of memory\n" );
+							goto error;
+						}
+						memset(param,0,sizeof(struct to_param));
+						param->type=GENERAL_PARAM;
+						status = S_PARA_NAME;
+						/* link to free mem if not added in to_body list */
+						newparam = param;
+						break;
+					case F_CRLF:
+					case F_LF:
+					case F_CR:
+						/*previous=crlf and now !=' '*/
+						goto endofheader;
+					default:
+						LOG( L_ERR , "ERROR: parse_to_param :"
+							"unexpected char [%c] in status %d: <<%.*s>> .\n",
+							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
+						goto error;
+				}
+				break;
+			case 'T':
+			case 't' :
+				switch (status)
+				{
+					case PARA_VALUE_QUOTED:
+					case PARA_VALUE_TOKEN:
+					case PARA_NAME:
+						break;
+					case S_PARA_NAME:
+						param->name.s = tmp;
+						status = TAG1;
+						break;
+					case S_PARA_VALUE:
+						param->value.s = tmp;
+						status = PARA_VALUE_TOKEN;
+						break;
+					case TAG1:
+					case TAG2:
+					case TAG3:
+						status = PARA_NAME;
+						break;
+					case F_CRLF:
+					case F_LF:
+					case F_CR:
+						/*previous=crlf and now !=' '*/
+						goto endofheader;
+					default:
+						LOG( L_ERR , "ERROR: parse_to_param :"
+							"unexpected char [%c] in status %d: <<%.*s>> .\n",
+							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
+						goto error;
+				}
+				break;
+			case 'A':
+			case 'a' :
+				switch (status)
+				{
+					case PARA_VALUE_QUOTED:
+					case PARA_VALUE_TOKEN:
+					case PARA_NAME:
+						break;
+					case S_PARA_NAME:
+						param->name.s = tmp;
+						status = PARA_NAME;
+						break;
+					case S_PARA_VALUE:
+						param->value.s = tmp;
+						status = PARA_VALUE_TOKEN;
+						break;
+					case TAG1:
+						status = TAG2;
+						break;
+					case TAG2:
+					case TAG3:
+						status = PARA_NAME;
+						break;
+					case F_CRLF:
+					case F_LF:
+					case F_CR:
+						/*previous=crlf and now !=' '*/
+						goto endofheader;
+					default:
+						LOG( L_ERR , "ERROR: parse_to_param : "
+							"unexpected char [%c] in status %d: <<%.*s>> .\n",
+							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
+						goto error;
+				}
+				break;
+			case 'G':
+			case 'g' :
+				switch (status)
+				{
+					case PARA_VALUE_QUOTED:
+					case PARA_VALUE_TOKEN:
+					case PARA_NAME:
+						break;
+					case S_PARA_NAME:
+						param->name.s = tmp;
+						status = PARA_NAME;
+						break;
+					case S_PARA_VALUE:
+						param->value.s = tmp;
+						status = PARA_VALUE_TOKEN;
+						break;
+					case TAG1:
+					case TAG3:
+						status = PARA_NAME;
+						break;
+					case TAG2:
+						status = TAG3;
+						break;
+					case F_CRLF:
+					case F_LF:
+					case F_CR:
+						/*previous=crlf and now !=' '*/
+						goto endofheader;
+					default:
+						LOG( L_ERR , "ERROR: parse_to_param : "
+							"unexpected char [%c] in status %d: <<%.*s>> .\n",
+							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
+						goto error;
+				}
+				break;
+			case '=':
+				switch (status)
+				{
+					case PARA_VALUE_QUOTED:
+						break;
+					case TAG3:
+						param->type=TAG_PARAM;
+					case PARA_NAME:
+					case TAG1:
+					case TAG2:
+						param->name.len = tmp-param->name.s;
+						status = S_PARA_VALUE;
+						break;
+					case S_EQUAL:
+						status = S_PARA_VALUE;
+						break;
+					case F_CRLF:
+					case F_LF:
+					case F_CR:
+						/*previous=crlf and now !=' '*/
+						goto endofheader;
+					default:
+						LOG( L_ERR , "ERROR: parse_to_param : "
+							"unexpected char [%c] in status %d: <<%.*s>> .\n",
+							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
+						goto error;
+				}
+				break;
+			case ',':
+				if (allow_comma_sep)
+				{
+					switch (status)
+					{
+						case S_PARA_NAME:
+						case S_EQUAL:
+						case S_PARA_VALUE:
+						case E_PARA_VALUE:
+							saved_status=status;
+							status=E_PARA_VALUE;
+							goto endofheader;
+						case TAG3:
+							param->type=TAG_PARAM;
+						case PARA_NAME:
+						case TAG1:
+						case TAG2:
+							param->name.len = tmp-param->name.s;
+							saved_status = S_EQUAL;
+							status = E_PARA_VALUE;
+							goto endofheader;
+						case PARA_VALUE_TOKEN:
+							param->value.len = tmp-param->value.s;
+							saved_status = E_PARA_VALUE;
+							status = E_PARA_VALUE;
+							add_param(param, to_b, newparam);
+							goto endofheader;
+						case F_CRLF:
+						case F_CR:
+						case F_LF:
+							status=saved_status;
+							goto endofheader;
+						default:
+							LOG( L_ERR , "ERROR: parse_to_param : "
+								"unexpected char [%c] in status %d: <<%.*s>> .\n",
+								*tmp,status, (int)(tmp-buffer), ZSW(buffer));
+							goto error;
+					}
+					break;
+				}
+				else
+				{
+					LOG( L_ERR, "ERROR parse_to_param : "
+							"invalid character ',' in status %d: <<%.*s>>\n",
+							status, (int)(tmp-buffer), ZSW(buffer));
+				}
+			default:
+				switch (status)
+				{
+					case TAG1:
+					case TAG2:
+					case TAG3:
+						status = PARA_NAME;
+						break;
+					case PARA_VALUE_TOKEN:
+					case PARA_NAME:
+					case PARA_VALUE_QUOTED:
+						break;
+					case S_PARA_NAME:
+						param->name.s = tmp;
+						status = PARA_NAME;
+						break;
+					case S_PARA_VALUE:
+						param->value.s = tmp;
+						status = PARA_VALUE_TOKEN;
+						break;
+					case F_CRLF:
+					case F_LF:
+					case F_CR:
+						/*previous=crlf and now !=' '*/
+						goto endofheader;
+					default:
+						LOG(L_ERR, "ERROR: parse_to_param: "
+							"spitting out [%c] in status %d\n",*tmp,status );
+						goto error;
+				}
+		}/*switch*/
+	}/*for*/
+	if (!(status==F_CR || status==F_LF || status==F_CRLF))
+		saved_status=status;
+
+
+endofheader:
+	switch(saved_status){
+		case TAG3:
+			param->type = TAG_PARAM; /* tag at the end */
+			/* no break */
+		case PARA_NAME:
+		case TAG1:
+		case TAG2:
+			param->name.len = tmp-param->name.s;
+			/* no break */
+		case S_EQUAL:
+			/* parameter without '=', e.g. foo */
+			param->value.s=0;
+			param->value.len=0;
+			add_param(param, to_b, newparam);
+			saved_status=E_PARA_VALUE;
+			break;
+		case S_PARA_VALUE:
+			/* parameter with null value, e.g. foo= */
+			param->value.s=tmp;
+			param->value.len=0;
+			add_param(param, to_b, newparam);
+			saved_status=E_PARA_VALUE;
+			break;
+		case PARA_VALUE_TOKEN:
+			param->value.len=tmp-param->value.s;
+			add_param(param, to_b, newparam);
+			saved_status=E_PARA_VALUE;
+			break;
+		case E_PARA_VALUE:
+			break;
+		default:
+			LOG( L_ERR , "ERROR: parse_to_param : unexpected end of header,"
+						" status %d: <<%.*s>> .\n",
+						saved_status, (int)(tmp-buffer), ZSW(buffer));
+			goto error;
+	}
+	*returned_status=saved_status;
+	return tmp;
+
+error:
+	if (newparam) pkg_free(newparam);
+	to_b->error=PARSE_ERROR;
+	*returned_status = status;
+	return tmp;
+}
+
+
+
+char* parse_addr_spec(char* const buffer, const char* const end, struct to_body* const to_b, const int allow_comma_sep)
+{
+	int status;
+	int saved_status;
+	char  *tmp,*foo;
+	
+	saved_status=START_TO; /* fixes gcc 4.x warning */
+	status=START_TO;
+	memset(to_b, 0, sizeof(struct to_body));
+	to_b->error=PARSE_OK;
+	foo=0;
+
+	for( tmp=buffer; tmp<end; tmp++)
+	{
+		switch(*tmp)
+		{
+			case ' ':
+			case '\t':
+				switch (status)
+				{
+					case F_CRLF:
+					case F_LF:
+					case F_CR:
+						/*previous=crlf and now =' '*/
+						status=saved_status;
+						break;
+					case URI_ENCLOSED:
+						to_b->uri.len = tmp - to_b->uri.s;
+						status = E_URI_ENCLOSED;
+						break;
+					case URI_OR_TOKEN:
+						foo = tmp;
+						status = MAYBE_URI_END;
+						break;
+					case DISPLAY_TOKEN:
+						foo = tmp;
+						status = DISPLAY_TOKEN_SP;
+						break;
+				}
+				break;
+			case '\n':
+				switch (status)
+				{
+					case URI_OR_TOKEN:
+						foo = tmp;
+						status = MAYBE_URI_END;
+					case MAYBE_URI_END:
+					case DISPLAY_TOKEN_SP:
+					case E_DISPLAY_QUOTED:
+					case END:
+						saved_status=status;
+						status=F_LF;
+						break;
+					case DISPLAY_TOKEN:
+						foo=tmp;
+						saved_status=DISPLAY_TOKEN_SP;
+						status=F_LF;
+						break;
+					case F_CR:
+						status=F_CRLF;
+						break;
+					case F_CRLF:
+					case F_LF:
+						status=saved_status;
+						goto endofheader;
+					default:
+						LOG( L_ERR , "ERROR: parse_to : unexpected char [%c] "
+							"in status %d: <<%.*s>> .\n",
+							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
+						goto error;
+				}
+				break;
+			case '\r':
+				switch (status)
+				{
+					case URI_OR_TOKEN:
+						foo = tmp;
+						status = MAYBE_URI_END;
+					case MAYBE_URI_END:
+					case DISPLAY_TOKEN_SP:
+					case E_DISPLAY_QUOTED:
+					case END:
+						saved_status=status;
+						status=F_CR;
+						break;
+					case DISPLAY_TOKEN:
+						foo=tmp;
+						saved_status=DISPLAY_TOKEN_SP;
+						status=F_CR;
+						break;
+					case F_CRLF:
+					case F_CR:
+					case F_LF:
+						status=saved_status;
+						goto endofheader;
+					default:
+						LOG( L_ERR , "ERROR: parse_to : unexpected char [%c] "
+							"in status %d: <<%.*s>> .\n",
+							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
+						goto error;
+				}
+				break;
+			case 0:
+				switch (status)
+				{
+					case URI_OR_TOKEN:
+					case MAYBE_URI_END:
+						to_b->uri.len = tmp - to_b->uri.s;
+					case END:
+						saved_status = status = END;
+						goto endofheader;
+					default:
+						LOG( L_ERR , "ERROR: parse_to : unexpected char [%c] "
+							"in status %d: <<%.*s>> .\n",
+							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
+						goto error;
+				}
+				break;
+			case '\\':
+				switch (status)
+				{
+					case DISPLAY_QUOTED:
+						tmp++; /* jump over next char */
+						break;
+					default:
+						LOG( L_ERR , "ERROR: parse_to : unexpected char [%c] "
+							"in status %d: <<%.*s>> .\n",
+							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
+						goto error;
+				}
+				break;
+			case '<':
+				switch (status)
+				{
+					case START_TO:
+						to_b->body.s=tmp;
+						status = S_URI_ENCLOSED;
+						break;
+					case DISPLAY_QUOTED:
+						break;
+					case E_DISPLAY_QUOTED:
+						status = S_URI_ENCLOSED;
+						break;
+					case URI_OR_TOKEN:
+					case DISPLAY_TOKEN:
+						to_b->display.len=tmp-to_b->display.s;
+						status = S_URI_ENCLOSED;
+						break;
+					case DISPLAY_TOKEN_SP:
+					case MAYBE_URI_END:
+						to_b->display.len=foo-to_b->display.s;
+						status = S_URI_ENCLOSED;
+						break;
+					case F_CRLF:
+					case F_LF:
+					case F_CR:
+						/*previous=crlf and now !=' '*/
+						goto endofheader;
+					default:
+						LOG( L_ERR , "ERROR: parse_to : unexpected char [%c] "
+							"in status %d: <<%.*s>> .\n",
+							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
+						goto error;
+				}
+				break;
+			case '>':
+				switch (status)
+				{
+					case DISPLAY_QUOTED:
+						break;
+					case URI_ENCLOSED:
+						to_b->uri.len = tmp - to_b->uri.s;
+					case E_URI_ENCLOSED:
+						status = END;
+						foo = 0;
+						break;
+					case F_CRLF:
+					case F_LF:
+					case F_CR:
+						/*previous=crlf and now !=' '*/
+						goto endofheader;
+					default:
+						LOG( L_ERR , "ERROR: parse_to : unexpected char [%c] "
+							"in status %d: <<%.*s>> .\n",
+							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
+						goto error;
+				}
+				break;
+			case '"':
+				switch (status)
+				{
+					case START_TO:
+						to_b->body.s = tmp;
+						to_b->display.s = tmp;
+						status = DISPLAY_QUOTED;
+						break;
+					case DISPLAY_QUOTED:
+						status = E_DISPLAY_QUOTED;
+						to_b->display.len = tmp-to_b->display.s+1;
+						break;
+					case F_CRLF:
+					case F_LF:
+					case F_CR:
+						/*previous=crlf and now !=' '*/
+						goto endofheader;
+					default:
+						LOG( L_ERR , "ERROR: parse_to : unexpected char [%c] "
+							"in status %d: <<%.*s>> .\n",
+							*tmp,status, (int)(tmp-buffer), buffer);
+						goto error;
+				}
+				break;
+			case ';' :
+				switch (status)
+				{
+					case DISPLAY_QUOTED:
+					case URI_ENCLOSED:
+						break;
+					case URI_OR_TOKEN:
+						foo = tmp;
+					case MAYBE_URI_END:
+						to_b->uri.len = foo - to_b->uri.s;
+					case END:
+						to_b->body.len = tmp-to_b->body.s;
+						tmp = parse_to_param(tmp,end,to_b,allow_comma_sep,&saved_status);
+						goto endofheader;
+					case F_CRLF:
+					case F_LF:
+					case F_CR:
+						/*previous=crlf and now !=' '*/
+						goto endofheader;
+					default:
+						LOG( L_ERR , "ERROR: parse_to : unexpected char [%c] "
+							"in status %d: <<%.*s>> .\n",
+							*tmp,status, (int)(tmp-buffer), buffer);
+						goto error;
+				}
+				break;
+			case ',' :
+				if (allow_comma_sep)
+				{
+					switch (status)
+					{
+						case DISPLAY_QUOTED:
+						case URI_ENCLOSED:
+							break;
+						case URI_OR_TOKEN:
+							foo = tmp;
+						case MAYBE_URI_END:
+							to_b->uri.len = foo - to_b->uri.s;
+						case END:
+							to_b->body.len = tmp-to_b->body.s;
+							saved_status = END;
+							goto endofheader;
+						case F_CRLF:
+						case F_LF:
+						case F_CR:
+							/*previous=crlf and now !=' '*/
+							goto endofheader;
+						default:
+							LOG( L_ERR , "ERROR: parse_to : unexpected char [%c] "
+								"in status %d: <<%.*s>> .\n",
+								*tmp,status, (int)(tmp-buffer), buffer);
+							goto error;
+					}
+					break;
+				}
+				/* If commas not allowed treat as a default character */
+			default:
+				switch (status)
+				{
+					case START_TO:
+						to_b->uri.s = to_b->body.s = tmp;
+						status = URI_OR_TOKEN;
+						to_b->display.s=tmp;
+						break;
+					case S_URI_ENCLOSED:
+						to_b->uri.s=tmp;
+						status=URI_ENCLOSED;
+						break;
+					case MAYBE_URI_END:
+					case DISPLAY_TOKEN_SP:
+						status = DISPLAY_TOKEN;
+					case DISPLAY_QUOTED:
+					case DISPLAY_TOKEN:
+					case URI_ENCLOSED:
+					case URI_OR_TOKEN:
+						break;
+					case F_CRLF:
+					case F_LF:
+					case F_CR:
+						/*previous=crlf and now !=' '*/
+						goto endofheader;
+					default:
+						DBG("DEBUG:parse_to: spitting out [%c] in status %d\n",
+						*tmp,status );
+						goto error;
+				}
+		}/*char switch*/
+	}/*for*/
+
+	/* Reached end of buffer */
+	switch (status)
+	{
+		case URI_OR_TOKEN:
+		case MAYBE_URI_END:
+		case END:
+			saved_status = status;
+			foo = tmp;
+	}
+
+endofheader:
+	if (to_b->display.len==0) to_b->display.s=0;
+	status=saved_status;
+	DBG("end of header reached, state=%d\n", status);
+	/* check if error*/
+	switch(status){
+		case URI_OR_TOKEN:
+		case MAYBE_URI_END:
+			to_b->uri.len = foo - to_b->uri.s;
+		case END:
+			to_b->body.len = tmp - to_b->body.s;
+		case E_PARA_VALUE:
+			break;
+		default:
+			LOG(L_ERR, "ERROR: parse_to: invalid To -  unexpected "
+					"end of header in state %d\n", status);
+			goto error;
+	}
+	return tmp;
+
+error:
+	to_b->error=PARSE_ERROR;
+	return tmp;
+
+}
+
+
+void free_to_params(struct to_body* const tb)
+{
+	struct to_param *tp=tb->param_lst;
+	struct to_param *foo;
+	while (tp){
+		foo = tp->next;
+		pkg_free(tp);
+		tp=foo;
+	}
+}
+
+
+void free_to(struct to_body* const tb)
+{
+	free_to_params(tb);
+	pkg_free(tb);
+}
+

+ 70 - 0
parser/parse_addr_spec.h

@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2001-2003 Fhg Fokus
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*! \file
+ * \brief Parser :: Parse addr-spec
+ *
+ * \ingroup parser
+ */
+
+#ifndef PARSE_ADDR_SPEC
+#define PARSE_ADDR_SPEC
+
+#include "../str.h"
+#include "msg_parser.h"
+
+enum {
+	TAG_PARAM = 400, GENERAL_PARAM
+};
+
+typedef struct to_param{
+	int type;              /*!< Type of parameter */
+	str name;              /*!< Name of parameter */
+	str value;             /*!< Parameter value */
+	struct to_param* next; /*!< Next parameter in the list */
+} to_param_t;
+
+
+typedef struct to_body{
+	int error;                    /*!< Error code */
+	str body;                     /*!< The whole header field body */
+	str uri;                      /*!< URI */
+	str display;				  /*!< Display Name */
+	str tag_value;                /*!< Value of tag */
+	struct sip_uri parsed_uri;
+	struct to_param *param_lst;   /*!< Linked list of parameters */
+	struct to_param *last_param;  /*!< Last parameter in the list */
+} to_body_t;
+
+
+/*! \brief
+ * To header field parser
+ */
+char* parse_addr_spec(char* const buffer, const char* const end, struct to_body* const to_b, int allow_comma_separated);
+
+void free_to_params(struct to_body* const tb);
+
+void free_to(struct to_body* const tb);
+
+int parse_to_header(struct sip_msg* const msg);
+
+sip_uri_t *parse_to_uri(struct sip_msg* const msg);
+
+#endif

+ 211 - 0
parser/parse_ppi_pai.c

@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2013 Hugh Waite
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * History:
+ * ---------
+ * 2013-03-06 Created (hpw)
+ */
+
+/** Parser :: Parse P-Asserted-Identity: header.
+ * @file
+ * @ingroup parser
+ */
+
+#include "parse_ppi_pai.h"
+#include <stdlib.h>
+#include <string.h>
+#include "../dprint.h"
+#include "msg_parser.h"
+#include "parse_uri.h"
+#include "../ut.h"
+#include "../mem/mem.h"
+
+/* 
+ * A P-Asserted-Identity or P-Preferred-Identity header value is an addr-spec or name-addr
+ * There can be only one of any URI scheme (sip(s), tel etc), which may occur on separate
+ * headers or can be comma separated in a single header.
+ * RFC3325 only mentions sip(s) and tel schemes, but there is no reason why other schemes
+ * cannot be used in the future.
+ */
+
+/*!
+ *
+ */
+#define NUM_PAI_BODIES 10
+int parse_pai_ppi_body(char *buf, int len, p_id_body_t **body)
+{
+	static to_body_t uri_b[NUM_PAI_BODIES]; /* Temporary storage */
+	int num_uri = 0;
+	char *tmp;
+	int i;
+	memset(uri_b, 0, NUM_PAI_BODIES * sizeof(to_body_t));
+
+	tmp = parse_addr_spec(buf, buf+len, &uri_b[num_uri], 1);
+	if (uri_b[num_uri].error == PARSE_ERROR)
+	{
+		LM_ERR("Error parsing PAI/PPI body %u '%.*s'\n", num_uri, len, buf);
+		return -1;
+	}
+	num_uri++;
+	while ((*tmp == ',') && (num_uri < NUM_PAI_BODIES))
+	{
+		tmp++;
+		tmp = parse_addr_spec(tmp, buf+len, &uri_b[num_uri], 1);
+		if (uri_b[num_uri].error == PARSE_ERROR)
+		{
+			LM_ERR("Error parsing PAI/PPI body %u '%.*s'\n", num_uri, len, buf);
+			return -1;
+		}
+		num_uri++;
+	}
+	if (num_uri >= NUM_PAI_BODIES)
+	{
+		LM_WARN("Too many bodies in PAI/PPI header '%.*s'\n", len, buf);
+		LM_WARN("Ignoring bodies beyond %u\n", NUM_PAI_BODIES);
+	}
+	*body = pkg_malloc(sizeof(p_id_body_t) + num_uri * sizeof(to_body_t));
+	if (*body == NULL)
+	{
+		LM_ERR("No pkg memory for pai/ppi body\n");
+		return -1;
+	}
+	memset(*body, 0, sizeof(p_id_body_t));
+	(*body)->id = (to_body_t*)((char*)(*body) + sizeof(p_id_body_t));
+	(*body)->num_ids = num_uri;
+	for (i=0; i< num_uri; i++)
+	{
+		memcpy(&(*body)->id[i], &uri_b[i], sizeof(to_body_t));
+	}
+	return 0;
+}
+
+int free_pai_ppi_body(p_id_body_t *pid_b)
+{
+	if (pid_b != NULL)
+	{
+		pkg_free(pid_b);
+	}
+	return 0;
+}
+
+/*!
+ * \brief Parse all P-Asserted-Identity headers
+ * \param msg The SIP message structure
+ * \return 0 on success, -1 on failure
+ */
+int parse_pai_header(struct sip_msg* const msg)
+{
+	p_id_body_t *pai_b;
+	p_id_body_t **prev_pid_b;
+	hdr_field_t *hf;
+
+	if ( !msg->pai )
+	{
+		if (parse_headers(msg, HDR_PAI_F, 0) < 0)
+		{
+			LM_ERR("Error parsing PAI header\n");
+			return -1;
+		}
+		if ( !msg->pai )
+			/* No PAI headers */
+			return -1;
+	}
+
+	if ( msg->pai->parsed )
+		return 0;
+
+	prev_pid_b = (p_id_body_t**)(&msg->pai->parsed);
+
+	for (hf = msg->pai; hf != NULL; hf = next_sibling_hdr(hf))
+	{
+		if (parse_pai_ppi_body(hf->body.s, hf->body.len, &pai_b) < 0)
+		{
+			return -1;
+		}
+		hf->parsed = (void*)pai_b;
+		*prev_pid_b = pai_b;
+		prev_pid_b = &pai_b->next;
+
+		if (parse_headers(msg, HDR_PAI_F, 1) < 0)
+		{
+			LM_ERR("Error looking for subsequent PAI header");
+			return -1;
+		}
+	}
+	return 0;
+}
+
+/*!
+ * \brief Parse all P-Preferred-Identity headers
+ * \param msg The SIP message structure
+ * \return 0 on success, -1 on failure
+ */
+int parse_ppi_header(struct sip_msg* const msg)
+{
+	p_id_body_t *ppi_b, *prev_pidb;
+	hdr_field_t *hf;
+
+	if ( !msg->ppi )
+	{
+		if (parse_headers(msg, HDR_PPI_F, 0) < 0)
+		{
+			LM_ERR("Error parsing PPI header\n");
+			return -1;
+		}
+		if ( !msg->ppi )
+			/* No PPI headers */
+			return -1;
+	}
+
+	if ( msg->ppi->parsed )
+		return 0;
+
+	if (parse_pai_ppi_body(msg->ppi->body.s, msg->ppi->body.len, &ppi_b) < 0)
+	{
+		return -1;
+	}
+	msg->ppi->parsed = (void*)ppi_b;
+
+	if (parse_headers(msg, HDR_PPI_F, 1) < 0)
+	{
+		LM_ERR("Error looking for subsequent PPI header");
+		return -1;
+	}
+	prev_pidb = ppi_b;
+	hf = msg->ppi;
+
+	if ((hf = next_sibling_hdr(hf)) != NULL)
+	{
+		if (parse_pai_ppi_body(hf->body.s, hf->body.len, &ppi_b) < 0)
+		{
+			return -1;
+		}
+		hf->parsed = (void*)ppi_b;
+
+		if (parse_headers(msg, HDR_PPI_F, 1) < 0)
+		{
+			LM_ERR("Error looking for subsequent PPI header");
+			return -1;
+		}
+		prev_pidb->next = ppi_b;
+		prev_pidb = ppi_b;
+	}
+	return 0;
+}
+

+ 22 - 16
lib/kcore/parse_pai.h → parser/parse_ppi_pai.h

@@ -1,6 +1,5 @@
 /*
 /*
- *
- * Copyright (C) 2006 Juha Heinanen
+ * Copyright (C) 2013 Hugh Waite
  *
  *
  * This file is part of Kamailio, a free SIP server.
  * This file is part of Kamailio, a free SIP server.
  *
  *
@@ -17,29 +16,36 @@
  * You should have received a copy of the GNU General Public License 
  * You should have received a copy of the GNU General Public License 
  * along with this program; if not, write to the Free Software 
  * along with this program; if not, write to the Free Software 
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
  */
  */
 
 
-/*!
- * \file
- * \brief P-Asserted-Identity header parser
+/*! \file
+ * \brief Parser :: Parse P-Asserted-Identity: header
+ *
  * \ingroup parser
  * \ingroup parser
  */
  */
 
 
-#ifndef PARSE_PAI_H
-#define PARSE_PAI_H
+#ifndef PARSE_PAI_PPI_H
+#define PARSE_PAI_PPI_H
 
 
-#include "../../parser/msg_parser.h"
-#include "../../parser/parse_to.h"
+#include "../str.h"
+#include "msg_parser.h"
+#include "parse_to.h"
 
 
+typedef struct p_id_body {
+	to_body_t *id;
+	int num_ids;
+	struct p_id_body *next;
+} p_id_body_t;
+
+int parse_pai_header(struct sip_msg* const msg);
+int parse_ppi_header(struct sip_msg* const msg);
 
 
 /*! casting macro for accessing P-Asserted-Identity body */
 /*! casting macro for accessing P-Asserted-Identity body */
-#define get_pai(p_msg)  ((struct to_body*)(p_msg)->pai->parsed)
+#define get_pai(p_msg)  ((p_id_body_t*)(p_msg)->pai->parsed)
 
 
+/*! casting macro for accessing P-Preferred-Identity body */
+#define get_ppi(p_msg)  ((p_id_body_t*)(p_msg)->ppi->parsed)
 
 
-/*!
- * P-Asserted-Identity header field parser
- */
-int parse_pai_header( struct sip_msg *msg);
+int free_pai_ppi_body(p_id_body_t *pid_b);
 
 
-#endif /* PARSE_PAI_H */
+#endif

+ 2 - 795
parser/parse_to.c

@@ -29,6 +29,7 @@
  */
  */
 
 
 #include "parse_to.h"
 #include "parse_to.h"
+#include "parse_addr_spec.h"
 #include <stdlib.h>
 #include <stdlib.h>
 #include <string.h>
 #include <string.h>
 #include "../dprint.h"
 #include "../dprint.h"
@@ -38,803 +39,9 @@
 #include "../mem/mem.h"
 #include "../mem/mem.h"
 
 
 
 
-enum {
-	START_TO, DISPLAY_QUOTED, E_DISPLAY_QUOTED, DISPLAY_TOKEN,
-	DISPLAY_TOKEN_SP, S_URI_ENCLOSED, URI_ENCLOSED, E_URI_ENCLOSED,
-	URI_OR_TOKEN, MAYBE_URI_END, END, F_CR, F_LF, F_CRLF
-};
-
-
-enum {
-	S_PARA_NAME=20, PARA_NAME, S_EQUAL, S_PARA_VALUE, TAG1, TAG2,
-	TAG3, PARA_VALUE_TOKEN , PARA_VALUE_QUOTED, E_PARA_VALUE
-};
-
-
-
-#define add_param( _param , _body , _newparam ) \
-	do{\
-		DBG("DEBUG: add_param: %.*s=%.*s\n",param->name.len,ZSW(param->name.s),\
-			param->value.len,ZSW(param->value.s));\
-		if (!(_body)->param_lst)  (_body)->param_lst=(_param);\
-		else (_body)->last_param->next=(_param);\
-		(_body)->last_param =(_param);\
-		if ((_param)->type==TAG_PARAM)\
-			memcpy(&((_body)->tag_value),&((_param)->value),sizeof(str));\
-		_newparam = 0;\
-	}while(0);
-
-
-
-
-
-static char* parse_to_param(char* const buffer, const char* const end,
-					struct to_body* const to_b,
-					int* const returned_status)
-{
-	struct to_param *param;
-	struct to_param *newparam;
-	int status;
-	int saved_status;
-	char  *tmp;
-
-	param=0;
-	newparam=0;
-	status=E_PARA_VALUE;
-	saved_status=E_PARA_VALUE;
-	for( tmp=buffer; tmp<end; tmp++)
-	{
-		switch(*tmp)
-		{
-			case ' ':
-			case '\t':
-				switch (status)
-				{
-					case TAG3:
-						param->type=TAG_PARAM;
-					case PARA_NAME:
-					case TAG1:
-					case TAG2:
-						param->name.len = tmp-param->name.s;
-						status = S_EQUAL;
-						break;
-					case PARA_VALUE_TOKEN:
-						param->value.len = tmp-param->value.s;
-						status = E_PARA_VALUE;
-						add_param(param, to_b, newparam);
-						break;
-					case F_CRLF:
-					case F_LF:
-					case F_CR:
-						/*previous=crlf and now =' '*/
-						status=saved_status;
-						break;
-				}
-				break;
-			case '\n':
-				switch (status)
-				{
-					case S_PARA_NAME:
-					case S_EQUAL:
-					case S_PARA_VALUE:
-					case E_PARA_VALUE:
-						saved_status=status;
-						status=F_LF;
-						break;
-					case TAG3:
-						param->type=TAG_PARAM;
-					case PARA_NAME:
-					case TAG1:
-					case TAG2:
-						param->name.len = tmp-param->name.s;
-						saved_status = S_EQUAL;
-						status = F_LF;
-						break;
-					case PARA_VALUE_TOKEN:
-						param->value.len = tmp-param->value.s;
-						saved_status = E_PARA_VALUE;
-						status = F_LF;
-						add_param(param, to_b, newparam);
-						break;
-					case F_CR:
-						status=F_CRLF;
-						break;
-					case F_CRLF:
-					case F_LF:
-						status=saved_status;
-						goto endofheader;
-					default:
-						LOG( L_ERR , "ERROR: parse_to_param : "
-							"unexpected char [%c] in status %d: <<%.*s>> .\n",
-							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
-						goto error;
-				}
-				break;
-			case '\r':
-				switch (status)
-				{
-					case S_PARA_NAME:
-					case S_EQUAL:
-					case S_PARA_VALUE:
-					case E_PARA_VALUE:
-						saved_status=status;
-						status=F_CR;
-						break;
-					case TAG3:
-						param->type=TAG_PARAM;
-					case PARA_NAME:
-					case TAG1:
-					case TAG2:
-						param->name.len = tmp-param->name.s;
-						saved_status = S_EQUAL;
-						status = F_CR;
-						break;
-					case PARA_VALUE_TOKEN:
-						param->value.len = tmp-param->value.s;
-						saved_status = E_PARA_VALUE;
-						status = F_CR;
-						add_param(param, to_b, newparam);
-						break;
-					case F_CRLF:
-					case F_CR:
-					case F_LF:
-						status=saved_status;
-						goto endofheader;
-					default:
-						LOG( L_ERR , "ERROR: parse_to_param : "
-							"unexpected char [%c] in status %d: <<%.*s>> .\n",
-							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
-						goto error;
-				}
-				break;
-			case 0:
-				switch (status)
-				{
-					case TAG3:
-						param->type = TAG_PARAM;
-					case PARA_NAME:
-					case TAG1:
-					case TAG2:
-						param->name.len = tmp-param->name.s;
-						status = S_EQUAL;
-					case S_EQUAL:
-					case S_PARA_VALUE:
-						saved_status=status;
-						goto endofheader;
-					case PARA_VALUE_TOKEN:
-						status = E_PARA_VALUE;
-						param->value.len = tmp-param->value.s;
-						add_param(param , to_b, newparam);
-					case E_PARA_VALUE:
-						saved_status = status;
-						goto endofheader;
-						break;
-					default:
-						LOG( L_ERR , "ERROR: parse_to_param : "
-							"unexpected char [%c] in status %d: <<%.*s>> .\n",
-							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
-						goto error;
-				}
-				break;
-			case '\\':
-				switch (status)
-				{
-					case PARA_VALUE_QUOTED:
-						switch (*(tmp+1))
-						{
-							case '\r':
-							case '\n':
-								break;
-							default:
-								tmp++;
-						}
-					default:
-						LOG( L_ERR , "ERROR: parse_to_param : "
-							"unexpected char [%c] in status %d: <<%.*s>> .\n",
-							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
-						goto error;
-				}
-				break;
-			case '"':
-				switch (status)
-				{
-					case S_PARA_VALUE:
-						param->value.s = tmp+1;
-						status = PARA_VALUE_QUOTED;
-						break;
-					case PARA_VALUE_QUOTED:
-						param->value.len=tmp-param->value.s;
-						add_param(param, to_b, newparam);
-						status = E_PARA_VALUE;
-						break;
-					case F_CRLF:
-					case F_LF:
-					case F_CR:
-						/*previous=crlf and now !=' '*/
-						goto endofheader;
-					default:
-						LOG( L_ERR , "ERROR: parse_to_param :"
-							"unexpected char [%c] in status %d: <<%.*s>> .\n",
-							*tmp,status,(int)(tmp-buffer), ZSW(buffer));
-						goto error;
-				}
-				break;
-			case ';' :
-				switch (status)
-				{
-					case PARA_VALUE_QUOTED:
-						break;
-					case TAG3:
-						param->type = TAG_PARAM;
-					case PARA_NAME:
-					case TAG1:
-					case TAG2:
-						param->name.len = tmp-param->name.s;
-					case S_EQUAL:
-						param->value.s = 0;
-						param->value.len = 0;
-						goto semicolon_add_param;
-					case S_PARA_VALUE:
-						param->value.s = tmp;
-					case PARA_VALUE_TOKEN:
-						param->value.len=tmp-param->value.s;
-semicolon_add_param:
-						add_param(param, to_b, newparam);
-					case E_PARA_VALUE:
-						param = (struct to_param*)
-							pkg_malloc(sizeof(struct to_param));
-						if (!param){
-							LOG( L_ERR , "ERROR: parse_to_param"
-							" - out of memory\n" );
-							goto error;
-						}
-						memset(param,0,sizeof(struct to_param));
-						param->type=GENERAL_PARAM;
-						status = S_PARA_NAME;
-						/* link to free mem if not added in to_body list */
-						newparam = param;
-						break;
-					case F_CRLF:
-					case F_LF:
-					case F_CR:
-						/*previous=crlf and now !=' '*/
-						goto endofheader;
-					default:
-						LOG( L_ERR , "ERROR: parse_to_param :"
-							"unexpected char [%c] in status %d: <<%.*s>> .\n",
-							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
-						goto error;
-				}
-				break;
-			case 'T':
-			case 't' :
-				switch (status)
-				{
-					case PARA_VALUE_QUOTED:
-					case PARA_VALUE_TOKEN:
-					case PARA_NAME:
-						break;
-					case S_PARA_NAME:
-						param->name.s = tmp;
-						status = TAG1;
-						break;
-					case S_PARA_VALUE:
-						param->value.s = tmp;
-						status = PARA_VALUE_TOKEN;
-						break;
-					case TAG1:
-					case TAG2:
-					case TAG3:
-						status = PARA_NAME;
-						break;
-					case F_CRLF:
-					case F_LF:
-					case F_CR:
-						/*previous=crlf and now !=' '*/
-						goto endofheader;
-					default:
-						LOG( L_ERR , "ERROR: parse_to_param :"
-							"unexpected char [%c] in status %d: <<%.*s>> .\n",
-							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
-						goto error;
-				}
-				break;
-			case 'A':
-			case 'a' :
-				switch (status)
-				{
-					case PARA_VALUE_QUOTED:
-					case PARA_VALUE_TOKEN:
-					case PARA_NAME:
-						break;
-					case S_PARA_NAME:
-						param->name.s = tmp;
-						status = PARA_NAME;
-						break;
-					case S_PARA_VALUE:
-						param->value.s = tmp;
-						status = PARA_VALUE_TOKEN;
-						break;
-					case TAG1:
-						status = TAG2;
-						break;
-					case TAG2:
-					case TAG3:
-						status = PARA_NAME;
-						break;
-					case F_CRLF:
-					case F_LF:
-					case F_CR:
-						/*previous=crlf and now !=' '*/
-						goto endofheader;
-					default:
-						LOG( L_ERR , "ERROR: parse_to_param : "
-							"unexpected char [%c] in status %d: <<%.*s>> .\n",
-							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
-						goto error;
-				}
-				break;
-			case 'G':
-			case 'g' :
-				switch (status)
-				{
-					case PARA_VALUE_QUOTED:
-					case PARA_VALUE_TOKEN:
-					case PARA_NAME:
-						break;
-					case S_PARA_NAME:
-						param->name.s = tmp;
-						status = PARA_NAME;
-						break;
-					case S_PARA_VALUE:
-						param->value.s = tmp;
-						status = PARA_VALUE_TOKEN;
-						break;
-					case TAG1:
-					case TAG3:
-						status = PARA_NAME;
-						break;
-					case TAG2:
-						status = TAG3;
-						break;
-					case F_CRLF:
-					case F_LF:
-					case F_CR:
-						/*previous=crlf and now !=' '*/
-						goto endofheader;
-					default:
-						LOG( L_ERR , "ERROR: parse_to_param : "
-							"unexpected char [%c] in status %d: <<%.*s>> .\n",
-							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
-						goto error;
-				}
-				break;
-			case '=':
-				switch (status)
-				{
-					case PARA_VALUE_QUOTED:
-						break;
-					case TAG3:
-						param->type=TAG_PARAM;
-					case PARA_NAME:
-					case TAG1:
-					case TAG2:
-						param->name.len = tmp-param->name.s;
-						status = S_PARA_VALUE;
-						break;
-					case S_EQUAL:
-						status = S_PARA_VALUE;
-						break;
-					case F_CRLF:
-					case F_LF:
-					case F_CR:
-						/*previous=crlf and now !=' '*/
-						goto endofheader;
-					default:
-						LOG( L_ERR , "ERROR: parse_to_param : "
-							"unexpected char [%c] in status %d: <<%.*s>> .\n",
-							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
-						goto error;
-				}
-				break;
-			default:
-				switch (status)
-				{
-					case TAG1:
-					case TAG2:
-					case TAG3:
-						status = PARA_NAME;
-						break;
-					case PARA_VALUE_TOKEN:
-					case PARA_NAME:
-					case PARA_VALUE_QUOTED:
-						break;
-					case S_PARA_NAME:
-						param->name.s = tmp;
-						status = PARA_NAME;
-						break;
-					case S_PARA_VALUE:
-						param->value.s = tmp;
-						status = PARA_VALUE_TOKEN;
-						break;
-					case F_CRLF:
-					case F_LF:
-					case F_CR:
-						/*previous=crlf and now !=' '*/
-						goto endofheader;
-					default:
-						LOG(L_ERR, "ERROR: parse_to_param: "
-							"spitting out [%c] in status %d\n",*tmp,status );
-						goto error;
-				}
-		}/*switch*/
-	}/*for*/
-	if (!(status==F_CR || status==F_LF || status==F_CRLF))
-		saved_status=status;
-
-
-endofheader:
-	switch(saved_status){
-		case TAG3:
-			param->type = TAG_PARAM; /* tag at the end */
-			/* no break */
-		case PARA_NAME:
-		case TAG1:
-		case TAG2:
-			param->name.len = tmp-param->name.s;
-			/* no break */
-		case S_EQUAL:
-			/* parameter without '=', e.g. foo */
-			param->value.s=0;
-			param->value.len=0;
-			add_param(param, to_b, newparam);
-			saved_status=E_PARA_VALUE;
-			break;
-		case S_PARA_VALUE:
-			/* parameter with null value, e.g. foo= */
-			param->value.s=tmp;
-			param->value.len=0;
-			add_param(param, to_b, newparam);
-			saved_status=E_PARA_VALUE;
-			break;
-		case PARA_VALUE_TOKEN:
-			param->value.len=tmp-param->value.s;
-			add_param(param, to_b, newparam);
-			saved_status=E_PARA_VALUE;
-			break;
-		case E_PARA_VALUE:
-			break;
-		default:
-			LOG( L_ERR , "ERROR: parse_to_param : unexpected end of header,"
-						" status %d: <<%.*s>> .\n",
-						saved_status, (int)(tmp-buffer), ZSW(buffer));
-			goto error;
-	}
-	*returned_status=saved_status;
-	return tmp;
-
-error:
-	if (newparam) pkg_free(newparam);
-	to_b->error=PARSE_ERROR;
-	*returned_status = status;
-	return tmp;
-}
-
-
-
 char* parse_to(char* const buffer, const char* const end, struct to_body* const to_b)
 char* parse_to(char* const buffer, const char* const end, struct to_body* const to_b)
 {
 {
-	int status;
-	int saved_status;
-	char  *tmp,*foo;
-	
-	saved_status=START_TO; /* fixes gcc 4.x warning */
-	status=START_TO;
-	memset(to_b, 0, sizeof(struct to_body));
-	to_b->error=PARSE_OK;
-	foo=0;
-
-	for( tmp=buffer; tmp<end; tmp++)
-	{
-		switch(*tmp)
-		{
-			case ' ':
-			case '\t':
-				switch (status)
-				{
-					case F_CRLF:
-					case F_LF:
-					case F_CR:
-						/*previous=crlf and now =' '*/
-						status=saved_status;
-						break;
-					case URI_ENCLOSED:
-						to_b->uri.len = tmp - to_b->uri.s;
-						status = E_URI_ENCLOSED;
-						break;
-					case URI_OR_TOKEN:
-						foo = tmp;
-						status = MAYBE_URI_END;
-						break;
-					case DISPLAY_TOKEN:
-						foo = tmp;
-						status = DISPLAY_TOKEN_SP;
-						break;
-				}
-				break;
-			case '\n':
-				switch (status)
-				{
-					case URI_OR_TOKEN:
-						foo = tmp;
-						status = MAYBE_URI_END;
-					case MAYBE_URI_END:
-					case DISPLAY_TOKEN_SP:
-					case E_DISPLAY_QUOTED:
-					case END:
-						saved_status=status;
-						status=F_LF;
-						break;
-					case DISPLAY_TOKEN:
-						foo=tmp;
-						saved_status=DISPLAY_TOKEN_SP;
-						status=F_LF;
-						break;
-					case F_CR:
-						status=F_CRLF;
-						break;
-					case F_CRLF:
-					case F_LF:
-						status=saved_status;
-						goto endofheader;
-					default:
-						LOG( L_ERR , "ERROR: parse_to : unexpected char [%c] "
-							"in status %d: <<%.*s>> .\n",
-							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
-						goto error;
-				}
-				break;
-			case '\r':
-				switch (status)
-				{
-					case URI_OR_TOKEN:
-						foo = tmp;
-						status = MAYBE_URI_END;
-					case MAYBE_URI_END:
-					case DISPLAY_TOKEN_SP:
-					case E_DISPLAY_QUOTED:
-					case END:
-						saved_status=status;
-						status=F_CR;
-						break;
-					case DISPLAY_TOKEN:
-						foo=tmp;
-						saved_status=DISPLAY_TOKEN_SP;
-						status=F_CR;
-						break;
-					case F_CRLF:
-					case F_CR:
-					case F_LF:
-						status=saved_status;
-						goto endofheader;
-					default:
-						LOG( L_ERR , "ERROR: parse_to : unexpected char [%c] "
-							"in status %d: <<%.*s>> .\n",
-							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
-						goto error;
-				}
-				break;
-			case 0:
-				switch (status)
-				{
-					case URI_OR_TOKEN:
-					case MAYBE_URI_END:
-						to_b->uri.len = tmp - to_b->uri.s;
-					case END:
-						saved_status = status = END;
-						goto endofheader;
-					default:
-						LOG( L_ERR , "ERROR: parse_to : unexpected char [%c] "
-							"in status %d: <<%.*s>> .\n",
-							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
-						goto error;
-				}
-				break;
-			case '\\':
-				switch (status)
-				{
-					case DISPLAY_QUOTED:
-						tmp++; /* jump over next char */
-						break;
-					default:
-						LOG( L_ERR , "ERROR: parse_to : unexpected char [%c] "
-							"in status %d: <<%.*s>> .\n",
-							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
-						goto error;
-				}
-				break;
-			case '<':
-				switch (status)
-				{
-					case START_TO:
-						to_b->body.s=tmp;
-						status = S_URI_ENCLOSED;
-						break;
-					case DISPLAY_QUOTED:
-						break;
-					case E_DISPLAY_QUOTED:
-						status = S_URI_ENCLOSED;
-						break;
-					case URI_OR_TOKEN:
-					case DISPLAY_TOKEN:
-						to_b->display.len=tmp-to_b->display.s;
-						status = S_URI_ENCLOSED;
-						break;
-					case DISPLAY_TOKEN_SP:
-					case MAYBE_URI_END:
-						to_b->display.len=foo-to_b->display.s;
-						status = S_URI_ENCLOSED;
-						break;
-					case F_CRLF:
-					case F_LF:
-					case F_CR:
-						/*previous=crlf and now !=' '*/
-						goto endofheader;
-					default:
-						LOG( L_ERR , "ERROR: parse_to : unexpected char [%c] "
-							"in status %d: <<%.*s>> .\n",
-							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
-						goto error;
-				}
-				break;
-			case '>':
-				switch (status)
-				{
-					case DISPLAY_QUOTED:
-						break;
-					case URI_ENCLOSED:
-						to_b->uri.len = tmp - to_b->uri.s;
-					case E_URI_ENCLOSED:
-						status = END;
-						foo = 0;
-						break;
-					case F_CRLF:
-					case F_LF:
-					case F_CR:
-						/*previous=crlf and now !=' '*/
-						goto endofheader;
-					default:
-						LOG( L_ERR , "ERROR: parse_to : unexpected char [%c] "
-							"in status %d: <<%.*s>> .\n",
-							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
-						goto error;
-				}
-				break;
-			case '"':
-				switch (status)
-				{
-					case START_TO:
-						to_b->body.s = tmp;
-						to_b->display.s = tmp;
-						status = DISPLAY_QUOTED;
-						break;
-					case DISPLAY_QUOTED:
-						status = E_DISPLAY_QUOTED;
-						to_b->display.len = tmp-to_b->display.s+1;
-						break;
-					case F_CRLF:
-					case F_LF:
-					case F_CR:
-						/*previous=crlf and now !=' '*/
-						goto endofheader;
-					default:
-						LOG( L_ERR , "ERROR: parse_to : unexpected char [%c] "
-							"in status %d: <<%.*s>> .\n",
-							*tmp,status, (int)(tmp-buffer), buffer);
-						goto error;
-				}
-				break;
-			case ';' :
-				switch (status)
-				{
-					case DISPLAY_QUOTED:
-					case URI_ENCLOSED:
-						break;
-					case URI_OR_TOKEN:
-						foo = tmp;
-					case MAYBE_URI_END:
-						to_b->uri.len = foo - to_b->uri.s;
-					case END:
-						to_b->body.len = tmp-to_b->body.s;
-						tmp = parse_to_param(tmp,end,to_b,&saved_status);
-						goto endofheader;
-					case F_CRLF:
-					case F_LF:
-					case F_CR:
-						/*previous=crlf and now !=' '*/
-						goto endofheader;
-					default:
-						LOG( L_ERR , "ERROR: parse_to : unexpected char [%c] "
-							"in status %d: <<%.*s>> .\n",
-							*tmp,status, (int)(tmp-buffer), buffer);
-						goto error;
-				}
-				break;
-			default:
-				switch (status)
-				{
-					case START_TO:
-						to_b->uri.s = to_b->body.s = tmp;
-						status = URI_OR_TOKEN;
-						to_b->display.s=tmp;
-						break;
-					case S_URI_ENCLOSED:
-						to_b->uri.s=tmp;
-						status=URI_ENCLOSED;
-						break;
-					case MAYBE_URI_END:
-					case DISPLAY_TOKEN_SP:
-						status = DISPLAY_TOKEN;
-					case DISPLAY_QUOTED:
-					case DISPLAY_TOKEN:
-					case URI_ENCLOSED:
-					case URI_OR_TOKEN:
-						break;
-					case F_CRLF:
-					case F_LF:
-					case F_CR:
-						/*previous=crlf and now !=' '*/
-						goto endofheader;
-					default:
-						DBG("DEBUG:parse_to: spitting out [%c] in status %d\n",
-						*tmp,status );
-						goto error;
-				}
-		}/*char switch*/
-	}/*for*/
-
-endofheader:
-	if (to_b->display.len==0) to_b->display.s=0;
-	status=saved_status;
-	DBG("end of header reached, state=%d\n", status);
-	/* check if error*/
-	switch(status){
-		case MAYBE_URI_END:
-			to_b->uri.len = foo - to_b->uri.s;
-		case END:
-			to_b->body.len = tmp - to_b->body.s;
-		case E_PARA_VALUE:
-			break;
-		default:
-			LOG(L_ERR, "ERROR: parse_to: invalid To -  unexpected "
-					"end of header in state %d\n", status);
-			goto error;
-	}
-	return tmp;
-
-error:
-	to_b->error=PARSE_ERROR;
-	return tmp;
-
-}
-
-
-void free_to_params(struct to_body* const tb)
-{
-	struct to_param *tp=tb->param_lst;
-	struct to_param *foo;
-	while (tp){
-		foo = tp->next;
-		pkg_free(tp);
-		tp=foo;
-	}
-}
-
-
-void free_to(struct to_body* const tb)
-{
-	free_to_params(tb);
-	pkg_free(tb);
+	return parse_addr_spec(buffer, end, to_b, 0);
 }
 }
 
 
 
 

+ 1 - 28
parser/parse_to.h

@@ -29,30 +29,7 @@
 
 
 #include "../str.h"
 #include "../str.h"
 #include "msg_parser.h"
 #include "msg_parser.h"
-
-enum {
-	TAG_PARAM = 400, GENERAL_PARAM
-};
-
-typedef struct to_param{
-	int type;              /*!< Type of parameter */
-	str name;              /*!< Name of parameter */
-	str value;             /*!< Parameter value */
-	struct to_param* next; /*!< Next parameter in the list */
-} to_param_t;
-
-
-typedef struct to_body{
-	int error;                    /*!< Error code */
-	str body;                     /*!< The whole header field body */
-	str uri;                      /*!< URI */
-	str display;				  /*!< Display Name */
-	str tag_value;                /*!< Value of tag */
-	struct sip_uri parsed_uri;
-	struct to_param *param_lst;   /*!< Linked list of parameters */
-	struct to_param *last_param;  /*!< Last parameter in the list */
-} to_body_t;
-
+#include "parse_addr_spec.h"
 
 
 /* casting macro for accessing To body */
 /* casting macro for accessing To body */
 #define get_to(p_msg)      ((struct to_body*)(p_msg)->to->parsed)
 #define get_to(p_msg)      ((struct to_body*)(p_msg)->to->parsed)
@@ -65,10 +42,6 @@ typedef struct to_body{
  */
  */
 char* parse_to(char* const buffer, const char* const end, struct to_body* const to_b);
 char* parse_to(char* const buffer, const char* const end, struct to_body* const to_b);
 
 
-void free_to_params(struct to_body* const tb);
-
-void free_to(struct to_body* const tb);
-
 int parse_to_header(struct sip_msg* const msg);
 int parse_to_header(struct sip_msg* const msg);
 
 
 sip_uri_t *parse_to_uri(struct sip_msg* const msg);
 sip_uri_t *parse_to_uri(struct sip_msg* const msg);