Browse code

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 authored on 11/03/2013 16:55:23
Showing 13 changed files
1 1
deleted file mode 100644
... ...
@@ -1,77 +0,0 @@
1
-/*
2
- * Copyright (C) 2006 Juha Heinanen
3
- *
4
- * This file is part of Kamailio, a free SIP server.
5
- *
6
- * Kamailio is free software; you can redistribute it and/or modify
7
- * it under the terms of the GNU General Public License as published by
8
- * the Free Software Foundation; either version 2 of the License, or
9
- * (at your option) any later version
10
- *
11
- * Kamailio is distributed in the hope that it will be useful,
12
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
- * GNU General Public License for more details.
15
- *
16
- * You should have received a copy of the GNU General Public License 
17
- * along with this program; if not, write to the Free Software 
18
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
- */
20
-
21
-/*!
22
- * \file
23
- * \brief P-Asserted-Identity header parser
24
- * \ingroup parser
25
- */
26
-
27
-#include "../../parser/parse_from.h"
28
-#include "../../parser/parse_to.h"
29
-#include <stdlib.h>
30
-#include <string.h>
31
-#include "../../dprint.h"
32
-#include "../../parser/msg_parser.h"
33
-#include "../../ut.h"
34
-#include "../../mem/mem.h"
35
-
36
-/*!
37
- * This method is used to parse P-Asserted-Identity header (RFC 3325).
38
- *
39
- * Currently only one name-addr / addr-spec is supported in the header
40
- * and it must contain a sip or sips URI.
41
- * \param msg sip msg
42
- * \return 0 on success, -1 on failure.
43
- */
44
-int parse_pai_header( struct sip_msg *msg )
45
-{
46
-	struct to_body* pai_b;
47
-
48
-	if ( !msg->pai && (parse_headers(msg, HDR_PAI_F,0)==-1 || !msg->pai)) {
49
-		goto error;
50
-	}
51
-
52
-	/* maybe the header is already parsed! */
53
-	if (msg->pai->parsed)
54
-		return 0;
55
- 
56
-	/* bad luck! :-( - we have to parse it */
57
-	/* first, get some memory */
58
-	pai_b = pkg_malloc(sizeof(struct to_body));
59
-	if (pai_b == 0) {
60
-		LM_ERR("out of pkg_memory\n");
61
-		goto error;
62
-	}
63
- 
64
-	/* now parse it!! */
65
-	memset(pai_b, 0, sizeof(struct to_body));
66
-	parse_to(msg->pai->body.s, msg->pai->body.s + msg->pai->body.len+1, pai_b);
67
-	if (pai_b->error == PARSE_ERROR) {
68
-		LM_ERR("bad P-Asserted-Identity header\n");
69
-		free_to(pai_b);
70
-		goto error;
71
-	}
72
- 	msg->pai->parsed = pai_b;
73
- 
74
-	return 0;
75
-error:
76
-	return -1;
77
-}
78 0
deleted file mode 100644
... ...
@@ -1,119 +0,0 @@
1
-/*
2
- * $Id$
3
- *
4
- * Copyright (C) 2006 Juha Heinanen
5
- *
6
- * This file is part of Kamailio, a free SIP server.
7
- *
8
- * Kamailio is free software; you can redistribute it and/or modify
9
- * it under the terms of the GNU General Public License as published by
10
- * the Free Software Foundation; either version 2 of the License, or
11
- * (at your option) any later version
12
- *
13
- * Kamailio is distributed in the hope that it will be useful,
14
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
- * GNU General Public License for more details.
17
- *
18
- * You should have received a copy of the GNU General Public License 
19
- * along with this program; if not, write to the Free Software 
20
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21
- */
22
-
23
-/*!
24
- * \file
25
- * \brief P-Preferred-Identity header parser
26
- * \ingroup parser
27
- */
28
-
29
-#include "parse_ppi.h"
30
-#include "../../parser/parse_to.h"
31
-#include "../../parser/parse_uri.h"
32
-#include <stdlib.h>
33
-#include <string.h>
34
-#include "../../dprint.h"
35
-#include "../../parser/msg_parser.h"
36
-#include "../../ut.h"
37
-#include "../../mem/mem.h"
38
-
39
-
40
-/*!
41
- * \brief This method is used to parse P-Preferred-Identity header (RFC 3325).
42
- *
43
- * Currently only one name-addr / addr-spec is supported in the header
44
- * and it must contain a sip or sips URI.
45
- * \param msg sip msg
46
- * \return 0 on success, -1 on failure.
47
- */
48
-int parse_ppi_header( struct sip_msg *msg )
49
-{
50
-    struct to_body* ppi_b;
51
-
52
-    if ( !msg->ppi &&
53
-	 (parse_headers(msg, HDR_PPI_F,0)==-1 || !msg->ppi)) {
54
-	goto error;
55
-    }
56
- 
57
-    /* maybe the header is already parsed! */
58
-    if (msg->ppi->parsed)
59
-	return 0;
60
- 
61
-    /* bad luck! :-( - we have to parse it */
62
-    /* first, get some memory */
63
-    ppi_b = pkg_malloc(sizeof(struct to_body));
64
-    if (ppi_b == 0) {
65
-	LM_ERR("out of pkg_memory\n");
66
-	goto error;
67
-    }
68
- 
69
-    /* now parse it!! */
70
-    memset(ppi_b, 0, sizeof(struct to_body));
71
-    parse_to(msg->ppi->body.s,
72
-	     msg->ppi->body.s + msg->ppi->body.len+1,
73
-	     ppi_b);
74
-    if (ppi_b->error == PARSE_ERROR) {
75
-	LM_ERR("bad P-Preferred-Identity header\n");
76
-	free_to(ppi_b);
77
-	goto error;
78
-    }
79
- 	msg->ppi->parsed = ppi_b;
80
- 
81
- 	return 0;
82
- error:
83
- 	return -1;
84
-}
85
-
86
-
87
-/*!
88
- * \brief Parse P-Preferred-Identity header URI
89
- */
90
-struct sip_uri *parse_ppi_uri(struct sip_msg *msg)
91
-{
92
-	struct to_body *tb = NULL;
93
-	
94
-	if(msg==NULL)
95
-		return NULL;
96
-
97
-	if(parse_ppi_header(msg)<0)
98
-	{
99
-		LM_ERR("cannot parse P-P-I header\n");
100
-		return NULL;
101
-	}
102
-	
103
-	if(msg->ppi==NULL || get_ppi(msg)==NULL)
104
-		return NULL;
105
-
106
-	tb = get_ppi(msg);
107
-
108
-	if(tb->parsed_uri.user.s!=NULL || tb->parsed_uri.host.s!=NULL)
109
-		return &tb->parsed_uri;
110
-
111
-	if (parse_uri(tb->uri.s, tb->uri.len , &tb->parsed_uri)<0)
112
-	{
113
-		LM_ERR("failed to parse P-P-I URI\n");
114
-		memset(&tb->parsed_uri, 0, sizeof(struct sip_uri));
115
-		return NULL;
116
-	}
117
-
118
-	return &tb->parsed_uri;
119
-}
120 0
deleted file mode 100644
... ...
@@ -1,53 +0,0 @@
1
-/*
2
- * $Id$
3
- *
4
- * Copyright (C) 2006 Juha Heinanen
5
- *
6
- * This file is part of Kamailio, a free SIP server.
7
- *
8
- * Kamailio is free software; you can redistribute it and/or modify
9
- * it under the terms of the GNU General Public License as published by
10
- * the Free Software Foundation; either version 2 of the License, or
11
- * (at your option) any later version
12
- *
13
- * Kamailio is distributed in the hope that it will be useful,
14
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
- * GNU General Public License for more details.
17
- *
18
- * You should have received a copy of the GNU General Public License 
19
- * along with this program; if not, write to the Free Software 
20
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21
- *
22
- */
23
-
24
-/*!
25
- * \file
26
- * \brief P-Preferred-Identity header parser
27
- * \ingroup parser
28
- */
29
-
30
-#ifndef PARSE_PPI_H
31
-#define PARSE_PPI_H
32
-
33
-#include "../../parser/msg_parser.h"
34
-#include "../../parser/parse_to.h"
35
-
36
-
37
-/*! casting macro for accessing P-Preferred-Identity body */
38
-#define get_ppi(p_msg)  ((struct to_body*)(p_msg)->ppi->parsed)
39
-
40
-
41
-/*!
42
- * \brief This method is used to parse P-Preferred-Identity header (RFC 3325).
43
- *
44
- * Currently only one name-addr / addr-spec is supported in the header
45
- * and it must contain a sip or sips URI.
46
- * \param msg sip msg
47
- * \return 0 on success, -1 on failure.
48
- */
49
-int parse_ppi_header( struct sip_msg *msg);
50
-
51
-struct sip_uri *parse_ppi_uri(struct sip_msg *msg);
52
- 
53
-#endif /* PARSE_PPI_H */
... ...
@@ -97,7 +97,7 @@ static pv_export_t mod_pvs[] = {
97 97
 		pv_set_scriptvar, pv_parse_scriptvar_name, 0, 0, 0},
98 98
 	{{"ai", (sizeof("ai")-1)}, /* */
99 99
 		PVT_OTHER, pv_get_pai, 0,
100
-		0, 0, 0, 0},
100
+		0, pv_parse_index, 0, 0},
101 101
 	{{"adu", (sizeof("adu")-1)}, /* auth digest uri */
102 102
 		PVT_OTHER, pv_get_authattr, 0,
103 103
 		0, 0, pv_init_iname, 3},
... ...
@@ -262,10 +262,10 @@ static pv_export_t mod_pvs[] = {
262 262
 		0, 0, pv_init_iname, 1},
263 263
 	{{"pd", (sizeof("pd")-1)}, /* */
264 264
 		PVT_OTHER, pv_get_ppi_attr, 0,
265
-		0, 0, pv_init_iname, 3},
265
+		0, pv_parse_index, pv_init_iname, 3},
266 266
 	{{"pn", (sizeof("pn")-1)}, /* */
267 267
 		PVT_OTHER, pv_get_ppi_attr, 0,
268
-		0, 0, pv_init_iname, 4},
268
+		0, pv_parse_index, pv_init_iname, 4},
269 269
 	{{"pp", (sizeof("pp")-1)}, /* */
270 270
 		PVT_OTHER, pv_get_pid, 0,
271 271
 		0, 0, 0, 0},
... ...
@@ -277,10 +277,10 @@ static pv_export_t mod_pvs[] = {
277 277
 		0, 0, 0, 0},
278 278
 	{{"pu", (sizeof("pu")-1)}, /* */
279 279
 		PVT_OTHER, pv_get_ppi_attr, 0,
280
-		0, 0, pv_init_iname, 1},
280
+		0, pv_parse_index, pv_init_iname, 1},
281 281
 	{{"pU", (sizeof("pU")-1)}, /* */
282 282
 		PVT_OTHER, pv_get_ppi_attr, 0,
283
-		0, 0, pv_init_iname, 2},
283
+		0, pv_parse_index, pv_init_iname, 2},
284 284
 	{{"rb", (sizeof("rb")-1)}, /* */
285 285
 		PVT_MSG_BODY, pv_get_msg_body, 0,
286 286
 		0, 0, 0, 0},
... ...
@@ -40,8 +40,7 @@
40 40
 #include "../../parser/parse_refer_to.h"
41 41
 #include "../../parser/parse_rpid.h"
42 42
 #include "../../parser/parse_diversion.h"
43
-#include "../../lib/kcore/parse_ppi.h"
44
-#include "../../lib/kcore/parse_pai.h"
43
+#include "../../parser/parse_ppi_pai.h"
45 44
 #include "../../parser/digest/digest.h"
46 45
 
47 46
 #include "pv_core.h"
... ...
@@ -865,38 +864,84 @@ int pv_get_rpid(struct sip_msg *msg, pv_param_t *param,
865 864
 int pv_get_ppi_attr(struct sip_msg *msg, pv_param_t *param,
866 865
 		pv_value_t *res)
867 866
 {
867
+    int idxf;
868
+    int idx;
868 869
     struct sip_uri *uri;
869
-    
870
-    if(msg==NULL)
871
-	return -1;
870
+    p_id_body_t *ppi_body = NULL;
871
+	to_body_t *ppi_uri = NULL;
872
+	int i, cur_id;
872 873
 
873
-    if(parse_ppi_header(msg) < 0) {
874
-	LM_DBG("no P-Preferred-Identity header\n");
875
-	return pv_get_null(msg, param, res);
876
-    }
877
-	
878
-    if(msg->ppi == NULL || get_ppi(msg) == NULL) {
879
-	       LM_DBG("no P-Preferred-Identity header\n");
874
+    if(msg==NULL)
875
+		return -1;
876
+    
877
+	if(parse_ppi_header(msg) < 0)
878
+    {
879
+		LM_DBG("no P-Preferred-Identity header\n");
880 880
 		return pv_get_null(msg, param, res);
881 881
     }
882
-    
882
+
883
+    if (pv_get_spec_index(msg, param, &idx, &idxf) != 0)
884
+    {
885
+    	LM_ERR("Invalid index\n");
886
+		return -1;
887
+    }
888
+
889
+    if (idxf == PV_IDX_ALL)
890
+	{
891
+		LM_ERR("Unable to return 'all' PPI values\n");
892
+		return -1;
893
+	}
894
+
895
+	ppi_body = get_ppi(msg);
896
+	ppi_uri = &ppi_body->id[0];
897
+	cur_id = 0;
898
+	i = 0;
899
+	while (i < idx)
900
+	{
901
+		cur_id++;
902
+		if (cur_id < ppi_body->num_ids)
903
+		{
904
+			ppi_uri = &ppi_body->id[cur_id];
905
+			i++;
906
+		}
907
+		else if (ppi_body->next != NULL)
908
+		{
909
+			ppi_body = ppi_body->next;
910
+			ppi_uri = &ppi_body->id[0];
911
+			cur_id = 0;
912
+			i++;
913
+		}
914
+		else
915
+		{
916
+			/* No more PPIs */
917
+			return pv_get_null(msg, param, res);
918
+		}
919
+
920
+	}
921
+	/* Found the ID at index 'idx' */
922
+
883 923
     if(param->pvn.u.isname.name.n == 1) { /* uri */
884
-		return pv_get_strval(msg, param, res, &(get_ppi(msg)->uri));
924
+		return pv_get_strval(msg, param, res, &(ppi_uri->uri));
885 925
     }
886 926
 	
887 927
     if(param->pvn.u.isname.name.n==4) { /* display name */
888
-		if(get_ppi(msg)->display.s == NULL ||
889
-				get_ppi(msg)->display.len <= 0) {
928
+		if(ppi_uri->display.s == NULL ||
929
+				ppi_uri->display.len <= 0) {
890 930
 		    LM_DBG("no P-Preferred-Identity display name\n");
891 931
 			return pv_get_null(msg, param, res);
892 932
 		}
893
-		return pv_get_strval(msg, param, res, &(get_ppi(msg)->display));
933
+		return pv_get_strval(msg, param, res, &(ppi_uri->display));
894 934
     }
895 935
 
896
-    if((uri=parse_ppi_uri(msg))==NULL) {
897
-		LM_ERR("cannot parse P-Preferred-Identity URI\n");
898
-		return pv_get_null(msg, param, res);
899
-    }
936
+	uri = &ppi_uri->parsed_uri;
937
+	if (uri->host.s == NULL && uri->user.s == NULL)
938
+	{
939
+		if (parse_uri(ppi_uri->uri.s, ppi_uri->uri.len, uri) < 0)
940
+		{
941
+			LM_ERR("cannot parse P-Preferred-Identity URI\n");
942
+			return pv_get_null(msg, param, res);
943
+		}
944
+	}
900 945
 
901 946
     if(param->pvn.u.isname.name.n==2) { /* username */
902 947
 		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,
920 965
 int pv_get_pai(struct sip_msg *msg, pv_param_t *param,
921 966
 		pv_value_t *res)
922 967
 {
968
+    int idxf;
969
+    int idx;
970
+    p_id_body_t *pai_body = NULL;
971
+	to_body_t *pai_uri = NULL;
972
+	int i, cur_id;
973
+
923 974
     if(msg==NULL)
924 975
 		return -1;
925 976
     
926
-    if(parse_pai_header(msg)==-1)
977
+	if(parse_pai_header(msg) < 0)
927 978
     {
928 979
 		LM_DBG("no P-Asserted-Identity header\n");
929 980
 		return pv_get_null(msg, param, res);
930 981
     }
931
-	
932
-    if(msg->pai==NULL || get_pai(msg)==NULL) {
933
-		LM_DBG("no P-Asserted-Identity header\n");
934
-		return pv_get_null(msg, param, res);
982
+
983
+    if (pv_get_spec_index(msg, param, &idx, &idxf) != 0)
984
+    {
985
+    	LM_ERR("Invalid index\n");
986
+		return -1;
935 987
     }
936
-    
937
-	return pv_get_strval(msg, param, res, &(get_pai(msg)->uri));
988
+
989
+    if (idxf == PV_IDX_ALL)
990
+	{
991
+		LM_ERR("Unable to return 'all' PAI values\n");
992
+		return -1;
993
+	}
994
+
995
+	pai_body = get_pai(msg);
996
+	pai_uri = &pai_body->id[0];
997
+	cur_id = 0;
998
+	i = 0;
999
+	while (i < idx)
1000
+	{
1001
+		cur_id++;
1002
+		if (cur_id < pai_body->num_ids)
1003
+		{
1004
+			pai_uri = &pai_body->id[cur_id];
1005
+			i++;
1006
+		}
1007
+		else if (pai_body->next != NULL)
1008
+		{
1009
+			pai_body = pai_body->next;
1010
+			pai_uri = &pai_body->id[0];
1011
+			cur_id = 0;
1012
+			i++;
1013
+		}
1014
+		else
1015
+		{
1016
+			/* No more PAIs */
1017
+			return pv_get_null(msg, param, res);
1018
+		}
1019
+
1020
+	}
1021
+	/* Found the ID at index 'idx' */
1022
+
1023
+	return pv_get_strval(msg, param, res, &(pai_uri->uri));
938 1024
 }
939 1025
 
940 1026
 /* proto of received message: $pr or $proto*/
... ...
@@ -68,8 +68,7 @@
68 68
 #include "../../parser/parse_from.h"
69 69
 #include "../../parser/parse_uri.h"
70 70
 #include "../../parser/digest/digest.h"
71
-#include "../../lib/kcore/parse_pai.h"
72
-#include "../../lib/kcore/parse_ppi.h"
71
+#include "../../parser/parse_ppi_pai.h"
73 72
 #include "../../pvar.h"
74 73
 #include "../../str.h"
75 74
 #include "../../onsend.h"
... ...
@@ -957,7 +956,7 @@ error:
957 956
 static int sip_capture(struct sip_msg *msg, char *s1, char *s2)
958 957
 {
959 958
 	struct _sipcapture_object sco;
960
-	struct sip_uri from, to, pai, contact;
959
+	struct sip_uri from, to, contact;
961 960
 	struct hdr_field *hook1 = NULL;	 
962 961
 	hdr_field_t *tmphdr[4];       
963 962
 	contact_body_t*  cb=0;	        	        
... ...
@@ -1062,32 +1061,35 @@ static int sip_capture(struct sip_msg *msg, char *s1, char *s2)
1062 1061
         	EMPTY_STR(sco.to_user);
1063 1062
         	EMPTY_STR(sco.to_tag);
1064 1063
         }
1065
-	
1064
+
1066 1065
 	/* Call-id */
1067 1066
 	if(msg->callid) sco.callid = msg->callid->body;
1068 1067
 	else { EMPTY_STR(sco.callid); }
1069
-	
1068
+
1070 1069
 	/* P-Asserted-Id */
1071
-	if(msg->pai && (parse_pai_header(msg) == 0)) {
1072
-
1073
-	     if (parse_uri(get_pai(msg)->uri.s, get_pai(msg)->uri.len, &pai)<0){
1074
-             	LM_DBG("DEBUG: do_action: bad pai: method:[%.*s] CID: [%.*s]\n", sco.method.len, sco.method.s, sco.callid.len, sco.callid.s);
1075
-             }
1076
-             else {
1077
-	        LM_DBG("PARSE PAI: (%.*s)\n",get_pai(msg)->uri.len, get_pai(msg)->uri.s);
1078
-	        sco.pid_user = pai.user;                          
1079
-             }
1080
-	}	
1081
-	else if(msg->ppi && (parse_ppi_header(msg) == 0)) {
1082
-		
1083
-	     if (parse_uri(get_ppi(msg)->uri.s, get_ppi(msg)->uri.len, &pai)<0){
1084
-             	LM_DBG("DEBUG: do_action: bad ppi: method:[%.*s] CID: [%.*s]\n", sco.method.len, sco.method.s, sco.callid.len, sco.callid.s);
1085
-             }
1086
-             else {
1087
-	        sco.pid_user = pai.user;
1088
-             }
1089
-        }
1090
-        else { EMPTY_STR(sco.pid_user); }
1070
+	if((parse_pai_header(msg) == 0) && (msg->pai) && (msg->pai->parsed)) {
1071
+		to_body_t *pai = get_pai(msg)->id; /* This returns the first entry */
1072
+		if ((pai->parsed_uri.user.s == NULL) &&
1073
+			(parse_uri(pai->uri.s, pai->uri.len, &pai->parsed_uri) < 0)){
1074
+			LM_DBG("DEBUG: do_action: bad pai: method:[%.*s] CID: [%.*s]\n", sco.method.len, sco.method.s, sco.callid.len, sco.callid.s);
1075
+		}
1076
+		else {
1077
+			LM_DBG("PARSE PAI: (%.*s)\n", pai->uri.len, pai->uri.s);
1078
+			sco.pid_user = pai->parsed_uri.user;
1079
+		}
1080
+	}
1081
+	else if((parse_ppi_header(msg) == 0) && (msg->ppi) && (msg->ppi->parsed)) {
1082
+		to_body_t *ppi = get_ppi(msg)->id; /* This returns the first entry */
1083
+		if ((ppi->parsed_uri.user.s == NULL) &&
1084
+			(parse_uri(ppi->uri.s, ppi->uri.len, &ppi->parsed_uri) < 0)){
1085
+			LM_DBG("DEBUG: do_action: bad ppi: method:[%.*s] CID: [%.*s]\n", sco.method.len, sco.method.s, sco.callid.len, sco.callid.s);
1086
+		}
1087
+		else {
1088
+			LM_DBG("PARSE PPI: (%.*s)\n", ppi->uri.len, ppi->uri.s);
1089
+			sco.pid_user = ppi->parsed_uri.user;
1090
+		}
1091
+	}
1092
+	else { EMPTY_STR(sco.pid_user); }
1091 1093
 	
1092 1094
 	/* Auth headers */
1093 1095
         if(msg->proxy_auth != NULL) hook1 = msg->proxy_auth;
... ...
@@ -57,6 +57,7 @@
57 57
 #include "parse_disposition.h"
58 58
 #include "parse_allow.h"
59 59
 #include "../ut.h"
60
+#include "parse_ppi_pai.h"
60 61
 
61 62
 /** Frees a hdr_field structure.
62 63
  * WARNING: it frees only parsed (and not name.s, body.s)
... ...
@@ -122,11 +123,11 @@ void clean_hdr_field(struct hdr_field* const hf)
122 123
 			break;
123 124
 
124 125
 		case HDR_PAI_T:
125
-			free_to(hf->parsed);
126
+			free_pai_ppi_body(hf->parsed);
126 127
 			break;
127 128
 
128 129
 		case HDR_PPI_T:
129
-			free_to(hf->parsed);
130
+			free_pai_ppi_body(hf->parsed);
130 131
 			break;
131 132
 
132 133
 		case HDR_PROXYAUTH_T:
133 134
new file mode 100644
... ...
@@ -0,0 +1,926 @@
1
+/*
2
+ * Copyright (C) 2001-2003 Fhg Fokus
3
+ *
4
+ * This file is part of ser, a free SIP server.
5
+ *
6
+ * ser is free software; you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License as published by
8
+ * the Free Software Foundation; either version 2 of the License, or
9
+ * (at your option) any later version
10
+ *
11
+ * ser is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+ * GNU General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU General Public License 
17
+ * along with this program; if not, write to the Free Software 
18
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
+ *
20
+ * History:
21
+ * ---------
22
+ * 2003-04-26 ZSW (jiri)
23
+ * 2010-03-03  fix multi-token no-quotes display name (andrei)
24
+ */
25
+
26
+/** Parser :: Parse To: header.
27
+ * @file
28
+ * @ingroup parser
29
+ */
30
+
31
+#include "parse_to.h"
32
+#include <stdlib.h>
33
+#include <string.h>
34
+#include "../dprint.h"
35
+#include "msg_parser.h"
36
+#include "parse_uri.h"
37
+#include "../ut.h"
38
+#include "../mem/mem.h"
39
+
40
+
41
+enum {
42
+	START_TO, DISPLAY_QUOTED, E_DISPLAY_QUOTED, DISPLAY_TOKEN,
43
+	DISPLAY_TOKEN_SP, S_URI_ENCLOSED, URI_ENCLOSED, E_URI_ENCLOSED,
44
+	URI_OR_TOKEN, MAYBE_URI_END, END, F_CR, F_LF, F_CRLF
45
+};
46
+
47
+
48
+enum {
49
+	S_PARA_NAME=20, PARA_NAME, S_EQUAL, S_PARA_VALUE, TAG1, TAG2,
50
+	TAG3, PARA_VALUE_TOKEN , PARA_VALUE_QUOTED, E_PARA_VALUE
51
+};
52
+
53
+
54
+
55
+#define add_param( _param , _body , _newparam ) \
56
+	do{\
57
+		DBG("DEBUG: add_param: %.*s=%.*s\n",param->name.len,ZSW(param->name.s),\
58
+			param->value.len,ZSW(param->value.s));\
59
+		if (!(_body)->param_lst)  (_body)->param_lst=(_param);\
60
+		else (_body)->last_param->next=(_param);\
61
+		(_body)->last_param =(_param);\
62
+		if ((_param)->type==TAG_PARAM)\
63
+			memcpy(&((_body)->tag_value),&((_param)->value),sizeof(str));\
64
+		_newparam = 0;\
65
+	}while(0);
66
+
67
+
68
+
69
+
70
+
71
+static char* parse_to_param(char* const buffer, const char* const end,
72
+					struct to_body* const to_b, const int allow_comma_sep,
73
+					int* const returned_status)
74
+{
75
+	struct to_param *param;
76
+	struct to_param *newparam;
77
+	int status;
78
+	int saved_status;
79
+	char  *tmp;
80
+
81
+	param=0;
82
+	newparam=0;
83
+	status=E_PARA_VALUE;
84
+	saved_status=E_PARA_VALUE;
85
+	for( tmp=buffer; tmp<end; tmp++)
86
+	{
87
+		switch(*tmp)
88
+		{
89
+			case ' ':
90
+			case '\t':
91
+				switch (status)
92
+				{
93
+					case TAG3:
94
+						param->type=TAG_PARAM;
95
+					case PARA_NAME:
96
+					case TAG1:
97
+					case TAG2:
98
+						param->name.len = tmp-param->name.s;
99
+						status = S_EQUAL;
100
+						break;
101
+					case PARA_VALUE_TOKEN:
102
+						param->value.len = tmp-param->value.s;
103
+						status = E_PARA_VALUE;
104
+						add_param(param, to_b, newparam);
105
+						break;
106
+					case F_CRLF:
107
+					case F_LF:
108
+					case F_CR:
109
+						/*previous=crlf and now =' '*/
110
+						status=saved_status;
111
+						break;
112
+				}
113
+				break;
114
+			case '\n':
115
+				switch (status)
116
+				{
117
+					case S_PARA_NAME:
118
+					case S_EQUAL:
119
+					case S_PARA_VALUE:
120
+					case E_PARA_VALUE:
121
+						saved_status=status;
122
+						status=F_LF;
123
+						break;
124
+					case TAG3:
125
+						param->type=TAG_PARAM;
126
+					case PARA_NAME:
127
+					case TAG1:
128
+					case TAG2:
129
+						param->name.len = tmp-param->name.s;
130
+						saved_status = S_EQUAL;
131
+						status = F_LF;
132
+						break;
133
+					case PARA_VALUE_TOKEN:
134
+						param->value.len = tmp-param->value.s;
135
+						saved_status = E_PARA_VALUE;
136
+						status = F_LF;
137
+						add_param(param, to_b, newparam);
138
+						break;
139
+					case F_CR:
140
+						status=F_CRLF;
141
+						break;
142
+					case F_CRLF:
143
+					case F_LF:
144
+						status=saved_status;
145
+						goto endofheader;
146
+					default:
147
+						LOG( L_ERR , "ERROR: parse_to_param : "
148
+							"unexpected char [%c] in status %d: <<%.*s>> .\n",
149
+							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
150
+						goto error;
151
+				}
152
+				break;
153
+			case '\r':
154
+				switch (status)
155
+				{
156
+					case S_PARA_NAME:
157
+					case S_EQUAL:
158
+					case S_PARA_VALUE:
159
+					case E_PARA_VALUE:
160
+						saved_status=status;
161
+						status=F_CR;
162
+						break;
163
+					case TAG3:
164
+						param->type=TAG_PARAM;
165
+					case PARA_NAME:
166
+					case TAG1:
167
+					case TAG2:
168
+						param->name.len = tmp-param->name.s;
169
+						saved_status = S_EQUAL;
170
+						status = F_CR;
171
+						break;
172
+					case PARA_VALUE_TOKEN:
173
+						param->value.len = tmp-param->value.s;
174
+						saved_status = E_PARA_VALUE;
175
+						status = F_CR;
176
+						add_param(param, to_b, newparam);
177
+						break;
178
+					case F_CRLF:
179
+					case F_CR:
180
+					case F_LF:
181
+						status=saved_status;
182
+						goto endofheader;
183
+					default:
184
+						LOG( L_ERR , "ERROR: parse_to_param : "
185
+							"unexpected char [%c] in status %d: <<%.*s>> .\n",
186
+							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
187
+						goto error;
188
+				}
189
+				break;
190
+			case 0:
191
+				switch (status)
192
+				{
193
+					case TAG3:
194
+						param->type = TAG_PARAM;
195
+					case PARA_NAME:
196
+					case TAG1:
197
+					case TAG2:
198
+						param->name.len = tmp-param->name.s;
199
+						status = S_EQUAL;
200
+					case S_EQUAL:
201
+					case S_PARA_VALUE:
202
+						saved_status=status;
203
+						goto endofheader;
204
+					case PARA_VALUE_TOKEN:
205
+						status = E_PARA_VALUE;
206
+						param->value.len = tmp-param->value.s;
207
+						add_param(param , to_b, newparam);
208
+					case E_PARA_VALUE:
209
+						saved_status = status;
210
+						goto endofheader;
211
+						break;
212
+					default:
213
+						LOG( L_ERR , "ERROR: parse_to_param : "
214
+							"unexpected char [%c] in status %d: <<%.*s>> .\n",
215
+							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
216
+						goto error;
217
+				}
218
+				break;
219
+			case '\\':
220
+				switch (status)
221
+				{
222
+					case PARA_VALUE_QUOTED:
223
+						switch (*(tmp+1))
224
+						{
225
+							case '\r':
226
+							case '\n':
227
+								break;
228
+							default:
229
+								tmp++;
230
+						}
231
+					default:
232
+						LOG( L_ERR , "ERROR: parse_to_param : "
233
+							"unexpected char [%c] in status %d: <<%.*s>> .\n",
234
+							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
235
+						goto error;
236
+				}
237
+				break;
238
+			case '"':
239
+				switch (status)
240
+				{
241
+					case S_PARA_VALUE:
242
+						param->value.s = tmp+1;
243
+						status = PARA_VALUE_QUOTED;
244
+						break;
245
+					case PARA_VALUE_QUOTED:
246
+						param->value.len=tmp-param->value.s;
247
+						add_param(param, to_b, newparam);
248
+						status = E_PARA_VALUE;
249
+						break;
250
+					case F_CRLF:
251
+					case F_LF:
252
+					case F_CR:
253
+						/*previous=crlf and now !=' '*/
254
+						goto endofheader;
255
+					default:
256
+						LOG( L_ERR , "ERROR: parse_to_param :"
257
+							"unexpected char [%c] in status %d: <<%.*s>> .\n",
258
+							*tmp,status,(int)(tmp-buffer), ZSW(buffer));
259
+						goto error;
260
+				}
261
+				break;
262
+			case ';' :
263
+				switch (status)
264
+				{
265
+					case PARA_VALUE_QUOTED:
266
+						break;
267
+					case TAG3:
268
+						param->type = TAG_PARAM;
269
+					case PARA_NAME:
270
+					case TAG1:
271
+					case TAG2:
272
+						param->name.len = tmp-param->name.s;
273
+					case S_EQUAL:
274
+						param->value.s = 0;
275
+						param->value.len = 0;
276
+						goto semicolon_add_param;
277
+					case S_PARA_VALUE:
278
+						param->value.s = tmp;
279
+					case PARA_VALUE_TOKEN:
280
+						param->value.len=tmp-param->value.s;
281
+semicolon_add_param:
282
+						add_param(param, to_b, newparam);
283
+					case E_PARA_VALUE:
284
+						param = (struct to_param*)
285
+							pkg_malloc(sizeof(struct to_param));
286
+						if (!param){
287
+							LOG( L_ERR , "ERROR: parse_to_param"
288
+							" - out of memory\n" );
289
+							goto error;
290
+						}
291
+						memset(param,0,sizeof(struct to_param));
292
+						param->type=GENERAL_PARAM;
293
+						status = S_PARA_NAME;
294
+						/* link to free mem if not added in to_body list */
295
+						newparam = param;
296
+						break;
297
+					case F_CRLF:
298
+					case F_LF:
299
+					case F_CR:
300
+						/*previous=crlf and now !=' '*/
301
+						goto endofheader;
302
+					default:
303
+						LOG( L_ERR , "ERROR: parse_to_param :"
304
+							"unexpected char [%c] in status %d: <<%.*s>> .\n",
305
+							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
306
+						goto error;
307
+				}
308
+				break;
309
+			case 'T':
310
+			case 't' :
311
+				switch (status)
312
+				{
313
+					case PARA_VALUE_QUOTED:
314
+					case PARA_VALUE_TOKEN:
315
+					case PARA_NAME:
316
+						break;
317
+					case S_PARA_NAME:
318
+						param->name.s = tmp;
319
+						status = TAG1;
320
+						break;
321
+					case S_PARA_VALUE:
322
+						param->value.s = tmp;
323
+						status = PARA_VALUE_TOKEN;
324
+						break;
325
+					case TAG1:
326
+					case TAG2:
327
+					case TAG3:
328
+						status = PARA_NAME;
329
+						break;
330
+					case F_CRLF:
331
+					case F_LF:
332
+					case F_CR:
333
+						/*previous=crlf and now !=' '*/
334
+						goto endofheader;
335
+					default:
336
+						LOG( L_ERR , "ERROR: parse_to_param :"
337
+							"unexpected char [%c] in status %d: <<%.*s>> .\n",
338
+							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
339
+						goto error;
340
+				}
341
+				break;
342
+			case 'A':
343
+			case 'a' :
344
+				switch (status)
345
+				{
346
+					case PARA_VALUE_QUOTED:
347
+					case PARA_VALUE_TOKEN:
348
+					case PARA_NAME:
349
+						break;
350
+					case S_PARA_NAME:
351
+						param->name.s = tmp;
352
+						status = PARA_NAME;
353
+						break;
354
+					case S_PARA_VALUE:
355
+						param->value.s = tmp;
356
+						status = PARA_VALUE_TOKEN;
357
+						break;
358
+					case TAG1:
359
+						status = TAG2;
360
+						break;
361
+					case TAG2:
362
+					case TAG3:
363
+						status = PARA_NAME;
364
+						break;
365
+					case F_CRLF:
366
+					case F_LF:
367
+					case F_CR:
368
+						/*previous=crlf and now !=' '*/
369
+						goto endofheader;
370
+					default:
371
+						LOG( L_ERR , "ERROR: parse_to_param : "
372
+							"unexpected char [%c] in status %d: <<%.*s>> .\n",
373
+							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
374
+						goto error;
375
+				}
376
+				break;
377
+			case 'G':
378
+			case 'g' :
379
+				switch (status)
380
+				{
381
+					case PARA_VALUE_QUOTED:
382
+					case PARA_VALUE_TOKEN:
383
+					case PARA_NAME:
384
+						break;
385
+					case S_PARA_NAME:
386
+						param->name.s = tmp;
387
+						status = PARA_NAME;
388
+						break;
389
+					case S_PARA_VALUE:
390
+						param->value.s = tmp;
391
+						status = PARA_VALUE_TOKEN;
392
+						break;
393
+					case TAG1:
394
+					case TAG3:
395
+						status = PARA_NAME;
396
+						break;
397
+					case TAG2:
398
+						status = TAG3;
399
+						break;
400
+					case F_CRLF:
401
+					case F_LF:
402
+					case F_CR:
403
+						/*previous=crlf and now !=' '*/
404
+						goto endofheader;
405
+					default:
406
+						LOG( L_ERR , "ERROR: parse_to_param : "
407
+							"unexpected char [%c] in status %d: <<%.*s>> .\n",
408
+							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
409
+						goto error;
410
+				}
411
+				break;
412
+			case '=':
413
+				switch (status)
414
+				{
415
+					case PARA_VALUE_QUOTED:
416
+						break;
417
+					case TAG3:
418
+						param->type=TAG_PARAM;
419
+					case PARA_NAME:
420
+					case TAG1:
421
+					case TAG2:
422
+						param->name.len = tmp-param->name.s;
423
+						status = S_PARA_VALUE;
424
+						break;
425
+					case S_EQUAL:
426
+						status = S_PARA_VALUE;
427
+						break;
428
+					case F_CRLF:
429
+					case F_LF:
430
+					case F_CR:
431
+						/*previous=crlf and now !=' '*/
432
+						goto endofheader;
433
+					default:
434
+						LOG( L_ERR , "ERROR: parse_to_param : "
435
+							"unexpected char [%c] in status %d: <<%.*s>> .\n",
436
+							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
437
+						goto error;
438
+				}
439
+				break;
440
+			case ',':
441
+				if (allow_comma_sep)
442
+				{
443
+					switch (status)
444
+					{
445
+						case S_PARA_NAME:
446
+						case S_EQUAL:
447
+						case S_PARA_VALUE:
448
+						case E_PARA_VALUE:
449
+							saved_status=status;
450
+							status=E_PARA_VALUE;
451
+							goto endofheader;
452
+						case TAG3:
453
+							param->type=TAG_PARAM;
454
+						case PARA_NAME:
455
+						case TAG1:
456
+						case TAG2:
457
+							param->name.len = tmp-param->name.s;
458
+							saved_status = S_EQUAL;
459
+							status = E_PARA_VALUE;
460
+							goto endofheader;
461
+						case PARA_VALUE_TOKEN:
462
+							param->value.len = tmp-param->value.s;
463
+							saved_status = E_PARA_VALUE;
464
+							status = E_PARA_VALUE;
465
+							add_param(param, to_b, newparam);
466
+							goto endofheader;
467
+						case F_CRLF:
468
+						case F_CR:
469
+						case F_LF:
470
+							status=saved_status;
471
+							goto endofheader;
472
+						default:
473
+							LOG( L_ERR , "ERROR: parse_to_param : "
474
+								"unexpected char [%c] in status %d: <<%.*s>> .\n",
475
+								*tmp,status, (int)(tmp-buffer), ZSW(buffer));
476
+							goto error;
477
+					}
478
+					break;
479
+				}
480
+				else
481
+				{
482
+					LOG( L_ERR, "ERROR parse_to_param : "
483
+							"invalid character ',' in status %d: <<%.*s>>\n",
484
+							status, (int)(tmp-buffer), ZSW(buffer));
485
+				}
486
+			default:
487
+				switch (status)
488
+				{
489
+					case TAG1:
490
+					case TAG2:
491
+					case TAG3:
492
+						status = PARA_NAME;
493
+						break;
494
+					case PARA_VALUE_TOKEN:
495
+					case PARA_NAME:
496
+					case PARA_VALUE_QUOTED:
497
+						break;
498
+					case S_PARA_NAME:
499
+						param->name.s = tmp;
500
+						status = PARA_NAME;
501
+						break;
502
+					case S_PARA_VALUE:
503
+						param->value.s = tmp;
504
+						status = PARA_VALUE_TOKEN;
505
+						break;
506
+					case F_CRLF:
507
+					case F_LF:
508
+					case F_CR:
509
+						/*previous=crlf and now !=' '*/
510
+						goto endofheader;
511
+					default:
512
+						LOG(L_ERR, "ERROR: parse_to_param: "
513
+							"spitting out [%c] in status %d\n",*tmp,status );
514
+						goto error;
515
+				}
516
+		}/*switch*/
517
+	}/*for*/
518
+	if (!(status==F_CR || status==F_LF || status==F_CRLF))
519
+		saved_status=status;
520
+
521
+
522
+endofheader:
523
+	switch(saved_status){
524
+		case TAG3:
525
+			param->type = TAG_PARAM; /* tag at the end */
526
+			/* no break */
527
+		case PARA_NAME:
528
+		case TAG1:
529
+		case TAG2:
530
+			param->name.len = tmp-param->name.s;
531
+			/* no break */
532
+		case S_EQUAL:
533
+			/* parameter without '=', e.g. foo */
534
+			param->value.s=0;
535
+			param->value.len=0;
536
+			add_param(param, to_b, newparam);
537
+			saved_status=E_PARA_VALUE;
538
+			break;
539
+		case S_PARA_VALUE:
540
+			/* parameter with null value, e.g. foo= */
541
+			param->value.s=tmp;
542
+			param->value.len=0;
543
+			add_param(param, to_b, newparam);
544
+			saved_status=E_PARA_VALUE;
545
+			break;
546
+		case PARA_VALUE_TOKEN:
547
+			param->value.len=tmp-param->value.s;
548
+			add_param(param, to_b, newparam);
549
+			saved_status=E_PARA_VALUE;
550
+			break;
551
+		case E_PARA_VALUE:
552
+			break;
553
+		default:
554
+			LOG( L_ERR , "ERROR: parse_to_param : unexpected end of header,"
555
+						" status %d: <<%.*s>> .\n",
556
+						saved_status, (int)(tmp-buffer), ZSW(buffer));
557
+			goto error;
558
+	}
559
+	*returned_status=saved_status;
560
+	return tmp;
561
+
562
+error:
563
+	if (newparam) pkg_free(newparam);
564
+	to_b->error=PARSE_ERROR;
565
+	*returned_status = status;
566
+	return tmp;
567
+}
568
+
569
+
570
+
571
+char* parse_addr_spec(char* const buffer, const char* const end, struct to_body* const to_b, const int allow_comma_sep)
572
+{
573
+	int status;
574
+	int saved_status;
575
+	char  *tmp,*foo;
576
+	
577
+	saved_status=START_TO; /* fixes gcc 4.x warning */
578
+	status=START_TO;
579
+	memset(to_b, 0, sizeof(struct to_body));
580
+	to_b->error=PARSE_OK;
581
+	foo=0;
582
+
583
+	for( tmp=buffer; tmp<end; tmp++)
584
+	{
585
+		switch(*tmp)
586
+		{
587
+			case ' ':
588
+			case '\t':
589
+				switch (status)
590
+				{
591
+					case F_CRLF:
592
+					case F_LF:
593
+					case F_CR:
594
+						/*previous=crlf and now =' '*/
595
+						status=saved_status;
596
+						break;
597
+					case URI_ENCLOSED:
598
+						to_b->uri.len = tmp - to_b->uri.s;
599
+						status = E_URI_ENCLOSED;
600
+						break;
601
+					case URI_OR_TOKEN:
602
+						foo = tmp;
603
+						status = MAYBE_URI_END;
604
+						break;
605
+					case DISPLAY_TOKEN:
606
+						foo = tmp;
607
+						status = DISPLAY_TOKEN_SP;
608
+						break;
609
+				}
610
+				break;
611
+			case '\n':
612
+				switch (status)
613
+				{
614
+					case URI_OR_TOKEN:
615
+						foo = tmp;
616
+						status = MAYBE_URI_END;
617
+					case MAYBE_URI_END:
618
+					case DISPLAY_TOKEN_SP:
619
+					case E_DISPLAY_QUOTED:
620
+					case END:
621
+						saved_status=status;
622
+						status=F_LF;
623
+						break;
624
+					case DISPLAY_TOKEN:
625
+						foo=tmp;
626
+						saved_status=DISPLAY_TOKEN_SP;
627
+						status=F_LF;
628
+						break;
629
+					case F_CR:
630
+						status=F_CRLF;
631
+						break;
632
+					case F_CRLF:
633
+					case F_LF:
634
+						status=saved_status;
635
+						goto endofheader;
636
+					default:
637
+						LOG( L_ERR , "ERROR: parse_to : unexpected char [%c] "
638
+							"in status %d: <<%.*s>> .\n",
639
+							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
640
+						goto error;
641
+				}
642
+				break;
643
+			case '\r':
644
+				switch (status)
645
+				{
646
+					case URI_OR_TOKEN:
647
+						foo = tmp;
648
+						status = MAYBE_URI_END;
649
+					case MAYBE_URI_END:
650
+					case DISPLAY_TOKEN_SP:
651
+					case E_DISPLAY_QUOTED:
652
+					case END:
653
+						saved_status=status;
654
+						status=F_CR;
655
+						break;
656
+					case DISPLAY_TOKEN:
657
+						foo=tmp;
658
+						saved_status=DISPLAY_TOKEN_SP;
659
+						status=F_CR;
660
+						break;
661
+					case F_CRLF:
662
+					case F_CR:
663
+					case F_LF:
664
+						status=saved_status;
665
+						goto endofheader;
666
+					default:
667
+						LOG( L_ERR , "ERROR: parse_to : unexpected char [%c] "
668
+							"in status %d: <<%.*s>> .\n",
669
+							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
670
+						goto error;
671
+				}
672
+				break;
673
+			case 0:
674
+				switch (status)
675
+				{
676
+					case URI_OR_TOKEN:
677
+					case MAYBE_URI_END:
678
+						to_b->uri.len = tmp - to_b->uri.s;
679
+					case END:
680
+						saved_status = status = END;
681
+						goto endofheader;
682
+					default:
683
+						LOG( L_ERR , "ERROR: parse_to : unexpected char [%c] "
684
+							"in status %d: <<%.*s>> .\n",
685
+							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
686
+						goto error;
687
+				}
688
+				break;
689
+			case '\\':
690
+				switch (status)
691
+				{
692
+					case DISPLAY_QUOTED:
693
+						tmp++; /* jump over next char */
694
+						break;
695
+					default:
696
+						LOG( L_ERR , "ERROR: parse_to : unexpected char [%c] "
697
+							"in status %d: <<%.*s>> .\n",
698
+							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
699
+						goto error;
700
+				}
701
+				break;
702
+			case '<':
703
+				switch (status)
704
+				{
705
+					case START_TO:
706
+						to_b->body.s=tmp;
707
+						status = S_URI_ENCLOSED;
708
+						break;
709
+					case DISPLAY_QUOTED:
710
+						break;
711
+					case E_DISPLAY_QUOTED:
712
+						status = S_URI_ENCLOSED;
713
+						break;
714
+					case URI_OR_TOKEN:
715
+					case DISPLAY_TOKEN:
716
+						to_b->display.len=tmp-to_b->display.s;
717
+						status = S_URI_ENCLOSED;
718
+						break;
719
+					case DISPLAY_TOKEN_SP:
720
+					case MAYBE_URI_END:
721
+						to_b->display.len=foo-to_b->display.s;
722
+						status = S_URI_ENCLOSED;
723
+						break;
724
+					case F_CRLF:
725
+					case F_LF:
726
+					case F_CR:
727
+						/*previous=crlf and now !=' '*/
728
+						goto endofheader;
729
+					default:
730
+						LOG( L_ERR , "ERROR: parse_to : unexpected char [%c] "
731
+							"in status %d: <<%.*s>> .\n",
732
+							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
733
+						goto error;
734
+				}
735
+				break;
736
+			case '>':
737
+				switch (status)
738
+				{
739
+					case DISPLAY_QUOTED:
740
+						break;
741
+					case URI_ENCLOSED:
742
+						to_b->uri.len = tmp - to_b->uri.s;
743
+					case E_URI_ENCLOSED:
744
+						status = END;
745
+						foo = 0;
746
+						break;
747
+					case F_CRLF:
748
+					case F_LF:
749
+					case F_CR:
750
+						/*previous=crlf and now !=' '*/
751
+						goto endofheader;
752
+					default:
753
+						LOG( L_ERR , "ERROR: parse_to : unexpected char [%c] "
754
+							"in status %d: <<%.*s>> .\n",
755
+							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
756
+						goto error;
757
+				}
758
+				break;
759
+			case '"':
760
+				switch (status)
761
+				{
762
+					case START_TO:
763
+						to_b->body.s = tmp;
764
+						to_b->display.s = tmp;
765
+						status = DISPLAY_QUOTED;
766
+						break;
767
+					case DISPLAY_QUOTED:
768
+						status = E_DISPLAY_QUOTED;
769
+						to_b->display.len = tmp-to_b->display.s+1;
770
+						break;
771
+					case F_CRLF:
772
+					case F_LF:
773
+					case F_CR:
774
+						/*previous=crlf and now !=' '*/
775
+						goto endofheader;
776
+					default:
777
+						LOG( L_ERR , "ERROR: parse_to : unexpected char [%c] "
778
+							"in status %d: <<%.*s>> .\n",
779
+							*tmp,status, (int)(tmp-buffer), buffer);
780
+						goto error;
781
+				}
782
+				break;
783
+			case ';' :
784
+				switch (status)
785
+				{
786
+					case DISPLAY_QUOTED:
787
+					case URI_ENCLOSED:
788
+						break;
789
+					case URI_OR_TOKEN:
790
+						foo = tmp;
791
+					case MAYBE_URI_END:
792
+						to_b->uri.len = foo - to_b->uri.s;
793
+					case END:
794
+						to_b->body.len = tmp-to_b->body.s;
795
+						tmp = parse_to_param(tmp,end,to_b,allow_comma_sep,&saved_status);
796
+						goto endofheader;
797
+					case F_CRLF:
798
+					case F_LF:
799
+					case F_CR:
800
+						/*previous=crlf and now !=' '*/
801
+						goto endofheader;
802
+					default:
803
+						LOG( L_ERR , "ERROR: parse_to : unexpected char [%c] "
804
+							"in status %d: <<%.*s>> .\n",
805
+							*tmp,status, (int)(tmp-buffer), buffer);
806
+						goto error;
807
+				}
808
+				break;
809
+			case ',' :
810
+				if (allow_comma_sep)
811
+				{
812
+					switch (status)
813
+					{
814
+						case DISPLAY_QUOTED:
815
+						case URI_ENCLOSED:
816
+							break;
817
+						case URI_OR_TOKEN:
818
+							foo = tmp;
819
+						case MAYBE_URI_END:
820
+							to_b->uri.len = foo - to_b->uri.s;
821
+						case END:
822
+							to_b->body.len = tmp-to_b->body.s;
823
+							saved_status = END;
824
+							goto endofheader;
825
+						case F_CRLF:
826
+						case F_LF:
827
+						case F_CR:
828
+							/*previous=crlf and now !=' '*/
829
+							goto endofheader;
830
+						default:
831
+							LOG( L_ERR , "ERROR: parse_to : unexpected char [%c] "
832
+								"in status %d: <<%.*s>> .\n",
833
+								*tmp,status, (int)(tmp-buffer), buffer);
834
+							goto error;
835
+					}
836
+					break;
837
+				}
838
+				/* If commas not allowed treat as a default character */
839
+			default:
840
+				switch (status)
841
+				{
842
+					case START_TO:
843
+						to_b->uri.s = to_b->body.s = tmp;
844
+						status = URI_OR_TOKEN;