浏览代码

- added (uint|int|str)_to_static_buffer functions to select_buffer
- fixed minor bug in struct msg_start where is not known start of first line when empty lines preceed (sip_msg.buff points before them), so added line field holding correct position of first_line, fixed usage in textops and xmlrpc modules
- added new select_core selects to resolve SER-158
- added new tm module select to resolve SER-158

Tomas Mandys 18 年之前
父节点
当前提交
7e381ae08c
共有 9 个文件被更改,包括 910 次插入138 次删除
  1. 195 0
      modules/tm/select.c
  2. 37 0
      modules/tm/select.h
  3. 6 1
      modules/tm/tm.c
  4. 2 1
      parser/parse_fline.c
  5. 1 0
      parser/parse_fline.h
  6. 49 0
      select_buf.c
  7. 5 0
      select_buf.h
  8. 473 130
      select_core.c
  9. 142 6
      select_core.h

+ 195 - 0
modules/tm/select.c

@@ -0,0 +1,195 @@
+/*
+ * $Id$
+ *
+ * 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
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * 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
+ *
+ */
+
+
+#include <stdio.h>
+#include "select.h"
+#include "h_table.h"
+#include "t_lookup.h"
+#include "../../dprint.h"
+#include "../../mem/mem.h"
+#include "../../ut.h"
+#include "../../select.h"
+#include "../../select_buf.h"
+
+#define RETURN0_res(x) {*res=(x);return 0;}
+
+inline static int select_tm_get_cell(struct sip_msg* msg, int *branch, struct cell **t) {
+
+	/* make sure we know the associated transaction ... */
+	if (t_check( msg  , branch )==-1)  /* it's not necessary whan calling from script because already done */ 
+		return -1;
+
+	/*... if there is none, tell the core router to fwd statelessly */
+	*t = get_t();
+	if ( (*t==0)||(*t==T_UNDEFINED)) return -1;
+
+	return 0;
+}	
+
+static int select_tm(str* res, select_t* s, struct sip_msg* msg) {
+	int branch;
+	struct cell *t;
+	if (select_tm_get_cell(msg, &branch, &t) < 0) {
+		res->s = "0";
+	}
+	else {
+		res->s = "1";
+	}
+	res->len = 1;
+	return 0;
+}
+
+#define SEL_BRANCH_POS 2
+#define BRANCH_NO(_s_) (_s_->params[SEL_BRANCH_POS].v.i)
+
+#define SELECT_check(msg) \
+	int branch; \
+	struct cell *t; \
+	if (select_tm_get_cell(msg, &branch, &t) < 0) return -1;
+
+#define SELECT_check_branch(_s_, _msg_) \
+	SELECT_check(_msg_); \
+	if (BRANCH_NO(_s_) >=t->nr_of_outgoings) return -1;
+ 
+
+/* string resides in shared memory but I think it's not worth copying to
+ * static buffer (str_to_static_buffer) as minimal probability that string 
+ * is changed by other process (or cell is already locked ?)
+ */
+ 
+static int select_tm_method(str* res, select_t* s, struct sip_msg* msg) {
+	SELECT_check(msg);
+	RETURN0_res(t->method);
+}
+
+static ABSTRACT_F(select_tm_uas);
+
+static int select_tm_uas_status(str* res, select_t* s, struct sip_msg* msg) {
+	SELECT_check(msg);
+	return int_to_static_buffer(res, t->uas.status);
+}
+
+/* transaction cell has request in sip_msg structure which brings idea to
+ * use selects from select_core.c (e.g. to avoid copy&paste automatically 
+ * generate select definitions in tm_init_selects()). But it's not so easy
+ * as select may perform any parsing which is stored in sip_msg structure.
+ * But transaction cell resides in shared memory while parsing is done in
+ * private memory. Therefore we support currently only complete request */
+ 
+static int select_tm_uas_request(str* res, select_t* s, struct sip_msg* msg) {
+	SELECT_check(msg);
+	res->s = t->uas.request->buf;
+	res->len = t->uas.request->len;
+	return 0; 
+}
+
+static int select_tm_uas_local_to_tag(str* res, select_t* s, struct sip_msg* msg) {
+	SELECT_check(msg);
+	RETURN0_res(t->uas.local_totag);
+}
+
+static int select_tm_uas_response(str* res, select_t* s, struct sip_msg* msg) {
+	SELECT_check(msg);
+	res->s = t->uas.response.buffer;	
+	res->len = t->uas.response.buffer_len;
+	return 0;	
+}
+
+static ABSTRACT_F(select_tm_uac);
+
+static int select_tm_uac_count(str* res, select_t* s, struct sip_msg* msg) {
+	SELECT_check(msg);
+	return int_to_static_buffer(res, t->nr_of_outgoings);
+}
+
+static int select_tm_uac_relayed(str* res, select_t* s, struct sip_msg* msg) {
+	SELECT_check(msg);
+	return int_to_static_buffer(res, t->relayed_reply_branch);
+}
+
+static ABSTRACT_F(select_tm_uac_branch);
+
+static int select_tm_uac_status(str* res, select_t* s, struct sip_msg* msg) {
+	SELECT_check_branch(s, msg);
+	return int_to_static_buffer(res, t->uac[BRANCH_NO(s)].last_received);
+}
+
+static int select_tm_uac_uri(str* res, select_t* s, struct sip_msg* msg) {
+	SELECT_check_branch(s, msg);
+	RETURN0_res(t->uac[BRANCH_NO(s)].uri);
+}
+
+/* see select_tm_uas_request comments */
+static int select_tm_uac_response(str* res, select_t* s, struct sip_msg* msg) {  // struct
+	SELECT_check_branch(s, msg);
+	if (t->uac[BRANCH_NO(s)].reply) {
+		res->s = t->uac[BRANCH_NO(s)].reply->buf;
+		res->len = t->uac[BRANCH_NO(s)].reply->len;
+		return 0;
+	}
+	else
+		return -1;
+}
+
+static int select_tm_uac_branch_request(str* res, select_t* s, struct sip_msg* msg) {
+	SELECT_check_branch(s, msg);
+	res->s = t->uac[BRANCH_NO(s)].request.buffer;	
+	res->len = t->uac[BRANCH_NO(s)].request.buffer_len;
+	return 0;	
+}
+
+static select_row_t select_declaration[] = {
+	{ NULL, SEL_PARAM_STR, STR_STATIC_INIT("tm"), select_tm, 0},
+	{ select_tm, SEL_PARAM_STR, STR_STATIC_INIT("method"), select_tm_method, 0},
+	{ select_tm, SEL_PARAM_STR, STR_STATIC_INIT("uas"), select_tm_uas, SEL_PARAM_EXPECTED},
+	{ select_tm_uas, SEL_PARAM_STR, STR_STATIC_INIT("status"), select_tm_uas_status, 0},
+	{ select_tm_uas, SEL_PARAM_STR, STR_STATIC_INIT("request"), select_tm_uas_request, 0},
+	{ select_tm_uas, SEL_PARAM_STR, STR_STATIC_INIT("req"), select_tm_uas_request, 0},
+	{ select_tm_uas, SEL_PARAM_STR, STR_STATIC_INIT("local_to_tag"), select_tm_uas_local_to_tag, 0},
+	{ select_tm_uas, SEL_PARAM_STR, STR_STATIC_INIT("response"), select_tm_uas_response, 0},
+	{ select_tm_uas, SEL_PARAM_STR, STR_STATIC_INIT("resp"), select_tm_uas_response, 0},
+
+	{ select_tm, SEL_PARAM_STR, STR_STATIC_INIT("uac"), select_tm_uac, SEL_PARAM_EXPECTED},
+	{ select_tm_uac, SEL_PARAM_STR, STR_STATIC_INIT("count"), select_tm_uac_count, 0},
+	{ select_tm_uac, SEL_PARAM_STR, STR_STATIC_INIT("relayed"), select_tm_uac_relayed, 0},
+	{ select_tm_uac, SEL_PARAM_INT, STR_NULL, select_tm_uac_branch, SEL_PARAM_EXPECTED},
+	{ select_tm_uac_branch, SEL_PARAM_STR, STR_STATIC_INIT("status"), select_tm_uac_status, 0},
+	{ select_tm_uac_branch, SEL_PARAM_STR, STR_STATIC_INIT("uri"), select_tm_uac_uri, 0},
+	{ select_tm_uac_branch, SEL_PARAM_STR, STR_STATIC_INIT("response"), select_tm_uac_response, 0},
+	{ select_tm_uac_branch, SEL_PARAM_STR, STR_STATIC_INIT("resp"), select_tm_uac_response, 0},
+	{ select_tm_uac_branch, SEL_PARAM_STR, STR_STATIC_INIT("request"), select_tm_uac_branch_request, 0},
+	{ select_tm_uac_branch, SEL_PARAM_STR, STR_STATIC_INIT("req"), select_tm_uac_branch_request, 0},
+
+	{ NULL, SEL_PARAM_INT, STR_NULL, NULL, 0}
+};
+
+int tm_init_selects() {
+	register_select_table(select_declaration);
+	return 0;
+}

+ 37 - 0
modules/tm/select.h

@@ -0,0 +1,37 @@
+/*
+ * $Id$
+ *
+ *
+ * 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
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * 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
+ *
+ */
+
+#ifndef _T_SELECT_H
+#define _T_SELECT_H
+
+
+int tm_init_selects();
+
+
+#endif

+ 6 - 1
modules/tm/tm.c

@@ -115,6 +115,7 @@
 #include "t_fifo.h"
 #include "timer.h"
 #include "t_msgbuilder.h"
+#include "select.h"
 
 MODULE_VERSION
 
@@ -339,7 +340,6 @@ static param_export_t params[]={
 	{0,0,0}
 };
 
-
 #ifdef STATIC_TM
 struct module_exports tm_exports = {
 #else
@@ -531,6 +531,11 @@ static int mod_init(void)
 	/* init static hidden values */
 	init_t();
 
+	if (tm_init_selects()==-1) {
+		LOG(L_ERR, "ERROR: mod_init: select init failed\n");
+		return -1;
+	}
+	
 	if (tm_init_timers()==-1) {
 		LOG(L_ERR, "ERROR: mod_init: timer init failed\n");
 		return -1;

+ 2 - 1
parser/parse_fline.c

@@ -92,7 +92,7 @@ char* parse_first_line(char* buffer, unsigned int len, struct msg_start * fl)
 		LOG(L_INFO, "ERROR: parse_first_line: message too short: %d\n", len);
 		goto error1;
 	}
-
+	fl->line.s = buffer;
 	tmp=buffer;
   	/* is it perhaps a reply, ie does it start with "SIP...." ? */
 	if ( 	(*tmp=='S' || *tmp=='s') && 
@@ -212,6 +212,7 @@ char* parse_first_line(char* buffer, unsigned int len, struct msg_start * fl)
 		}
 		offset+=tmp-third;
 	}
+	fl->line.len = tmp-fl->line.s;
 	nl=eat_line(tmp,len-offset);
 	if (nl>=end){ /* no crlf in packet or only 1 line > invalid */
 		goto error;

+ 1 - 0
parser/parse_fline.h

@@ -61,6 +61,7 @@
 
 struct msg_start {
 	int type;                         /* Type of the Message - Request/Response */
+	str line;                         /* len does not include CRLF, correct way how to point at second line is line.s+len */
 	int len; 						/* length including delimiter */
 	union {
 		struct {

+ 49 - 0
select_buf.c

@@ -40,6 +40,8 @@
 
 #include "dprint.h"
 #include "mem/mem.h"
+#include "str.h"
+#include "ut.h"
 
 /*
  * Placeholder for the buffer
@@ -130,3 +132,50 @@ int reset_static_buffer() {
 	active_buffer=0;
 	return 0;
 }
+
+int str_to_static_buffer(str* res, str* s)
+{
+	res->s = get_static_buffer(s->len);
+	if (!res->s) return -1;
+	memcpy(res->s, s->s, s->len);
+	res->len = s->len;
+	return 0;
+}
+
+int int_to_static_buffer(str* res, int val)
+{
+	char *c;
+	c = int2str(abs(val), &res->len);
+	res->s = get_static_buffer(res->len+(val<0)?1:0);
+	if (!res->s) return -1;
+	if (val < 0) {
+		res->s[0] = '-';	
+		memcpy(res->s+1, c, res->len);
+		res->len++;
+	}
+	else {
+		memcpy(res->s, c, res->len);
+	}
+	return 0;
+}
+
+int uint_to_static_buffer(str* res, unsigned int val)
+{
+	char *c;
+	c = int2str(val, &res->len);
+	res->s = get_static_buffer(res->len);
+	if (!res->s) return -1;
+	memcpy(res->s, c, res->len);
+	return 0;
+}
+
+int uint_to_static_buffer_ex(str* res, unsigned int val, int base, int pad)
+{
+	char *c;
+	c = int2str_base_0pad(val, &res->len, base, pad); 
+	res->s = get_static_buffer(res->len);
+	if (!res->s) return -1;
+	memcpy(res->s, c, res->len);
+	return 0;
+}
+

+ 5 - 0
select_buf.h

@@ -51,4 +51,9 @@ char* get_static_buffer(int req_size);
 
 int reset_static_buffer();
 
+int str_to_static_buffer(str* res, str* s);
+int int_to_static_buffer(str* res, int val);
+int uint_to_static_buffer(str* res, unsigned int val);
+int uint_ex_to_static_buffer(str* res, unsigned int val, int base, int pad);
+
 #endif /* SELECT_BUFFER_H */

+ 473 - 130
select_core.c

@@ -31,7 +31,7 @@
  *  2006-02-17  fixup call for select_anyhdr (mma)
  */
 
- 
+#include <stdlib.h> 
 #include "select.h"
 #include "select_core.h"
 #include "select_buf.h"
@@ -52,18 +52,15 @@
 #include "mem/mem.h"
 #include "parser/parse_hname2.h"
 #include "ip_addr.h"
+#include "parser/parse_expires.h"
+#include "parser/parse_refer_to.h"
+#include "parser/parse_rpid.h"
+#include "dset.h"
 
-#define RETURN0_res(x) {*res=x;return 0;}
-#define TRIM_RET0_res(x) {*res=x;trim(res);return 0;} 
-#define TEST_RET_res_body(x) if (x){*res=x->body;return 0;}else return 1;
-#define TEST_RET_res_value(x) if (x){*res=x->value;return 0;}else return 1;
-
-int select_method(str* res, select_t* s, struct sip_msg* msg)
-{
-	if (msg->first_line.type==SIP_REQUEST) {
-		RETURN0_res(msg->first_line.u.request.method);
-	} else return -1;
-}
+#define RETURN0_res(x) {*res=(x);return 0;}
+#define TRIM_RET0_res(x) {*res=(x);trim(res);return 0;} 
+#define TEST_RET_res_body(x) if (x){*res=(x)->body;return 0;}else return 1;
+#define TEST_RET_res_value(x) if (x){*res=(x)->value;return 0;}else return 1;
 
 int select_ruri(str* res, select_t* s, struct sip_msg* msg)
 {
@@ -101,50 +98,51 @@ int select_next_hop(str* res, select_t* s, struct sip_msg* msg)
 	return -1;
 }
 
-int select_from(str* res, select_t* s, struct sip_msg* msg)
-{
-	if (parse_from_header(msg)<0)
-		return -1;
-	RETURN0_res(msg->from->body);
-}
-
-int select_from_uri(str* res, select_t* s, struct sip_msg* msg)
-{
-	if (parse_from_header(msg)<0)
-		return -1;
-	RETURN0_res(get_from(msg)->uri);
-}
-
-int select_from_tag(str* res, select_t* s, struct sip_msg* msg)
-{
-	if (parse_from_header(msg)<0)
-		return -1;
-	RETURN0_res(get_from(msg)->tag_value);
-}
-
-int select_from_name(str* res, select_t* s, struct sip_msg* msg)
-{
-	if (parse_from_header(msg)<0)
-		return -1;
-	RETURN0_res(get_from(msg)->display);
-}
-
-int select_from_params(str* res, select_t* s, struct sip_msg* msg)
-{
-	struct to_param* p;
-	if (parse_from_header(msg)<0)
-		return -1;
-	
-	p = get_from(msg)->param_lst;
-	while (p) {
-		if ((p->name.len==s->params[s->n-1].v.s.len)
-		    && !strncasecmp(p->name.s, s->params[s->n-1].v.s.s,p->name.len)) {
-			RETURN0_res(p->value);
-		}
-		p = p->next;
-	}
-	return 1;
-}
+#define SELECT_uri_header(_name_) \
+int select_##_name_(str* res, select_t* s, struct sip_msg* msg) \
+{ \
+	if (parse_##_name_##_header(msg)<0) \
+		return -1; \
+	RETURN0_res(msg->_name_->body); \
+} \
+\
+int select_##_name_##_uri(str* res, select_t* s, struct sip_msg* msg) \
+{ \
+	if (parse_##_name_##_header(msg)<0) \
+		return -1; \
+	RETURN0_res(get_##_name_(msg)->uri); \
+} \
+\
+int select_##_name_##_tag(str* res, select_t* s, struct sip_msg* msg) \
+{ \
+	if (parse_##_name_##_header(msg)<0) \
+		return -1; \
+	RETURN0_res(get_##_name_(msg)->tag_value); \
+} \
+\
+int select_##_name_##_name(str* res, select_t* s, struct sip_msg* msg) \
+{ \
+	if (parse_##_name_##_header(msg)<0) \
+		return -1; \
+	RETURN0_res(get_##_name_(msg)->display); \
+} \
+\
+int select_##_name_##_params(str* res, select_t* s, struct sip_msg* msg) \
+{ \
+	struct to_param* p; \
+	if (parse_##_name_##_header(msg)<0) \
+		return -1; \
+	\
+	p = get_##_name_(msg)->param_lst; \
+	while (p) { \
+		if ((p->name.len==s->params[s->n-1].v.s.len) \
+		    && !strncasecmp(p->name.s, s->params[s->n-1].v.s.s,p->name.len)) { \
+			RETURN0_res(p->value); \
+		} \
+		p = p->next; \
+	} \
+	return 1; \
+} 
 
 int parse_to_header(struct sip_msg *msg)
 {
@@ -161,51 +159,10 @@ int parse_to_header(struct sip_msg *msg)
 		return -1;
 }
 
-int select_to(str* res, select_t* s, struct sip_msg* msg)
-{
-	if (parse_to_header(msg)<0)
-		return -1; 
-	RETURN0_res(msg->to->body);
-}
-
-int select_to_uri(str* res, select_t* s, struct sip_msg* msg)
-{
-	if (parse_to_header(msg)<0)
-		return -1;
-	RETURN0_res(get_to(msg)->uri);
-}
-
-int select_to_tag(str* res, select_t* s, struct sip_msg* msg)
-{
-	if (parse_to_header(msg)<0)
-		return -1;
-	RETURN0_res(get_to(msg)->tag_value);
-}
-
-int select_to_name(str* res, select_t* s, struct sip_msg* msg)
-{
-	if (parse_to_header(msg)<0)
-		return -1;
-	RETURN0_res(get_to(msg)->display);
-}
-
-int select_to_params(str* res, select_t* s, struct sip_msg* msg)
-{
-	struct to_param* p;
-
-	if (parse_to_header(msg)<0)
-		return -1;
-	
-	p = get_to(msg)->param_lst;
-	while (p) {
-		if ((p->name.len==s->params[s->n-1].v.s.len)
-		    && !strncasecmp(p->name.s, s->params[s->n-1].v.s.s,p->name.len)) {
-			RETURN0_res(p->value);
-		}
-		p = p->next;
-	}
-	return 1;
-}
+SELECT_uri_header(to)
+SELECT_uri_header(from)
+SELECT_uri_header(refer_to)
+SELECT_uri_header(rpid)
 
 int parse_contact_header( struct sip_msg *msg)
 {
@@ -492,16 +449,53 @@ int select_via_params_spec(str* res, select_t* s, struct sip_msg* msg)
 	return -1;
 }
 
-//ABSTRACT_F(select_msgheader)
-// Instead of ABSTRACT_F(select_msgheader)
-// use function which uses select_core_table
-// to avoid gcc warning about not used 
-int select_msgheader(str* res, select_t* s, struct sip_msg* msg)
+int select_msg(str* res, select_t* s, struct sip_msg* msg)
 {
-	if (select_core_table.next)
-		return -1;
-	else
-		return -1;
+	res->s = msg->buf;
+	res->len = msg->len;
+	return 0;
+}
+
+int select_msg_first_line(str* res, select_t* s, struct sip_msg* msg) 
+{
+	RETURN0_res(msg->first_line.line);
+}
+
+int select_msg_type(str* res, select_t* s, struct sip_msg* msg) {
+	return uint_to_static_buffer(res, msg->first_line.type);
+} 
+
+int select_msg_len(str* res, select_t* s, struct sip_msg* msg) {
+	return uint_to_static_buffer(res, msg->len);
+}
+
+int select_msg_id(str* res, select_t* s, struct sip_msg* msg) {
+	return uint_to_static_buffer(res, msg->id);
+}
+
+int select_msg_id_hex(str* res, select_t* s, struct sip_msg* msg) {
+	return uint_to_static_buffer_ex(res, msg->id, 16, 8);
+}
+
+int select_msg_flags(str* res, select_t* s, struct sip_msg* msg) { 
+	return uint_to_static_buffer(res, msg->flags);
+} 
+
+int select_msg_body(str* res, select_t* s, struct sip_msg* msg)
+{
+	res->s = get_body(msg);
+	res->len = msg->buf+msg->len - res->s;
+	return 0;	
+}
+
+int select_msg_header(str* res, select_t* s, struct sip_msg* msg)
+{
+	/* get all headers */
+	char *c;
+	res->s = msg->first_line.line.s + msg->first_line.len; 
+	c = get_body(msg);
+	res->len = c - res->s;
+	return 0;
 }
 
 int select_anyheader(str* res, select_t* s, struct sip_msg* msg)
@@ -515,22 +509,22 @@ int select_anyheader(str* res, select_t* s, struct sip_msg* msg)
 		if (res!=NULL) return -1;
 
 		/* "fixup" call, res & msg are NULL */
-		if (s->n <2) return -1;
+		if (s->n <3) return -1;
 
-		if (s->params[1].type==SEL_PARAM_STR) {
+		if (s->params[2].type==SEL_PARAM_STR) {
 				/* replace _ with - (for P-xxx headers) */
-			for (hi=s->params[1].v.s.len-1; hi>0; hi--)
-				if (s->params[1].v.s.s[hi]=='_')
-					s->params[1].v.s.s[hi]='-';
+			for (hi=s->params[2].v.s.len-1; hi>0; hi--)
+				if (s->params[2].v.s.s[hi]=='_')
+					s->params[2].v.s.s[hi]='-';
 				/* if header name is parseable, parse it and set SEL_PARAM_DIV */
-			c=s->params[1].v.s.s[s->params[1].v.s.len];
-			s->params[1].v.s.s[s->params[1].v.s.len]=':';
-			if (parse_hname2(s->params[1].v.s.s,s->params[1].v.s.s+(s->params[1].v.s.len<3?4:s->params[1].v.s.len+1),
+			c=s->params[2].v.s.s[s->params[2].v.s.len];
+			s->params[2].v.s.s[s->params[2].v.s.len]=':';
+			if (parse_hname2(s->params[2].v.s.s,s->params[2].v.s.s+(s->params[2].v.s.len<3?4:s->params[2].v.s.len+1),
 						&hdr)==0) {
 				ERR("select_anyhdr:fixup_call:parse error\n");
 				return -1;
 			}
-			s->params[1].v.s.s[s->params[1].v.s.len]=c;
+			s->params[2].v.s.s[s->params[2].v.s.len]=c;
 			
 			if (hdr.type!=HDR_OTHER_T && hdr.type!=HDR_ERROR_T) {
 				/* pkg_free(s->params[1].v.s.s); */
@@ -538,8 +532,8 @@ int select_anyheader(str* res, select_t* s, struct sip_msg* msg)
 				 * the parsed string can live inside larger string block
 				 * e.g. when xlog's select is parsed
 				 */
-				s->params[1].type = SEL_PARAM_DIV;
-				s->params[1].v.i = hdr.type;
+				s->params[2].type = SEL_PARAM_DIV;
+				s->params[2].v.i = hdr.type;
 			}
 		}
 		return 1;
@@ -548,9 +542,9 @@ int select_anyheader(str* res, select_t* s, struct sip_msg* msg)
 	hf0 = NULL;
 
 	/* extract header index if present */
-	if (s->param_offset[s->lvl+1] == 3) {
-		if (s->params[2].type == SEL_PARAM_INT) {
-			hi = s->params[2].v.i;
+	if (s->param_offset[s->lvl+1] == 4) {
+		if (s->params[3].type == SEL_PARAM_INT) {
+			hi = s->params[3].v.i;
 		} else {
 			hi = -1;
 		}
@@ -564,11 +558,11 @@ int select_anyheader(str* res, select_t* s, struct sip_msg* msg)
 		return -1;
 	}
 	for (hf=msg->headers; hf; hf=hf->next) {
-		if(s->params[1].type==SEL_PARAM_DIV) {
-			if (s->params[1].v.i!=hf->type)	continue;
-		} else if(s->params[1].type==SEL_PARAM_STR) {
-			if (s->params[1].v.s.len!=hf->name.len)	continue;
-			if (strncasecmp(s->params[1].v.s.s, hf->name.s, hf->name.len)!=0) continue;
+		if(s->params[2].type==SEL_PARAM_DIV) {
+			if (s->params[2].v.i!=hf->type)	continue;
+		} else if(s->params[2].type==SEL_PARAM_STR) {
+			if (s->params[2].v.s.len!=hf->name.len)	continue;
+			if (strncasecmp(s->params[2].v.s.s, hf->name.s, hf->name.len)!=0) continue;
 		}
 		hf0 = hf;
 		hi--;
@@ -582,7 +576,19 @@ int select_anyheader(str* res, select_t* s, struct sip_msg* msg)
 	return 0;
 }
 
-ABSTRACT_F(select_anyheader_params)
+//ABSTRACT_F(select_anyheader_params)
+// Instead of ABSTRACT_F(select_anyheader_params)
+// use function which uses select_core_table
+// to avoid gcc warning about not used
+ 
+int select_anyheader_params(str* res, select_t* s, struct sip_msg* msg)
+{
+	if (select_core_table.next)
+		return -1;
+	else
+		return -1;
+}
+
 ABSTRACT_F(select_any_uri)
 
 static struct sip_uri uri;
@@ -1138,3 +1144,340 @@ int select_ip_port(str* res, select_t* s, struct sip_msg* msg)
 
 }
 
+
+int select_expires(str* res, select_t* s, struct sip_msg* msg)
+{
+	if (!msg->expires && (parse_headers(msg, HDR_EXPIRES_F, 0) == -1)) {
+		return -1; /* error */
+	}
+
+	if (!msg->expires) {
+		return 1;  /* null */
+	}
+
+	if (msg->expires->parsed == NULL && parse_expires(msg->expires) < 0) {
+		return -1;
+	}
+
+	RETURN0_res(((struct exp_body*)msg->expires->parsed)->text);
+}
+
+#define SELECT_plain_header(_sel_name_,_fld_name_,_hdr_f_) \
+int select_##_sel_name_(str* res, select_t* s, struct sip_msg* msg) \
+{ \
+	if (!msg->_fld_name_ && (parse_headers(msg, _hdr_f_, 0) == -1)) { \
+		return -1; \
+	} \
+	if (!msg->_fld_name_) { \
+		return 1; \
+	} \
+	RETURN0_res(msg->_fld_name_->body); \
+}
+
+SELECT_plain_header(call_id, callid, HDR_CALLID_F)
+SELECT_plain_header(max_forwards, maxforwards, HDR_MAXFORWARDS_F)
+SELECT_plain_header(content_type, content_type, HDR_CONTENTTYPE_F)
+SELECT_plain_header(content_length, content_length, HDR_CONTENTLENGTH_F)
+SELECT_plain_header(user_agent, user_agent, HDR_USERAGENT_F)
+SELECT_plain_header(subject, subject, HDR_SUBJECT_F)
+SELECT_plain_header(organization, organization, HDR_ORGANIZATION_F)
+SELECT_plain_header(priority, priority, HDR_PRIORITY_F)
+SELECT_plain_header(session_expires, session_expires, HDR_SESSIONEXPIRES_F)
+SELECT_plain_header(min_se, min_se, HDR_MIN_SE_F)
+SELECT_plain_header(sip_if_match, sipifmatch, HDR_SIPIFMATCH_F)
+
+int select_msg_request(str* res, select_t* s, struct sip_msg* msg)
+{
+	if (msg->first_line.type==SIP_REQUEST) { 
+		return select_msg(res, s, msg); 
+	}
+	else
+		return -1;	
+}
+
+int select_msg_response(str* res, select_t* s, struct sip_msg* msg)
+{
+	if (msg->first_line.type==SIP_REPLY) {
+		return select_msg(res, s, msg); 
+	}
+	else
+		return -1;	
+}
+
+#define SELECT_first_line(_sel_name_,_type_,_fld_) \
+int select_msg_##_sel_name_(str* res, select_t* s, struct sip_msg* msg) {\
+	if (msg->first_line.type==_type_) { \
+		RETURN0_res(msg->first_line._fld_); \
+	} else return -1; \
+}
+
+SELECT_first_line(request_method,SIP_REQUEST,u.request.method)
+SELECT_first_line(request_uri,SIP_REQUEST,u.request.uri)
+SELECT_first_line(request_version,SIP_REQUEST,u.request.version)
+SELECT_first_line(response_version,SIP_REPLY,u.reply.version)
+SELECT_first_line(response_status,SIP_REPLY,u.reply.status)
+SELECT_first_line(response_reason,SIP_REPLY,u.reply.reason)
+
+
+int select_version(str* res, select_t* s, struct sip_msg* msg)
+{
+	switch (msg->first_line.type) { 
+		case SIP_REQUEST:
+			RETURN0_res(msg->first_line.u.request.version)
+			break;
+		case SIP_REPLY:
+			RETURN0_res(msg->first_line.u.reply.version)
+			break;
+		default:
+			return -1;
+	}
+}
+
+ABSTRACT_F(select_sys)
+
+int select_sys_pid(str* res, select_t* s, struct sip_msg* msg) {
+	return uint_to_static_buffer(res, getpid());
+}
+
+int select_sys_unique(str* res, select_t* s, struct sip_msg* msg) {
+	#define UNIQUE_ID_PID_LEN 4
+	#define UNIQUE_ID_TIME_LEN 8
+	#define UNIQUE_ID_FIX_LEN (UNIQUE_ID_PID_LEN+1+UNIQUE_ID_TIME_LEN+1)
+	#define UNIQUE_ID_RAND_LEN 8
+	static char uniq_id[UNIQUE_ID_FIX_LEN+UNIQUE_ID_RAND_LEN];
+	static int uniq_for_pid = -1;
+	int i;
+
+	if (uniq_for_pid != getpid()) {
+		/* first call for this process */
+		int cb, rb, x, l;
+		char *c;
+		/* init gloabally uniq part */
+		c = int2str_base_0pad(getpid(), &l, 16, UNIQUE_ID_PID_LEN);
+		memcpy(uniq_id, c, UNIQUE_ID_PID_LEN);
+		uniq_id[UNIQUE_ID_PID_LEN] = '-';
+		c = int2str_base_0pad(time(NULL), &l, 16, UNIQUE_ID_TIME_LEN);
+		memcpy(uniq_id+UNIQUE_ID_PID_LEN+1, c, UNIQUE_ID_TIME_LEN);
+		uniq_id[UNIQUE_ID_PID_LEN+1+UNIQUE_ID_TIME_LEN] = '-';
+
+		/* init random part */
+		for (i = RAND_MAX, rb=0; i; rb++, i>>=1);
+		for (i = UNIQUE_ID_FIX_LEN, cb = 0, x = 0; i < UNIQUE_ID_FIX_LEN+UNIQUE_ID_RAND_LEN; i++) {
+			if (!cb) {
+				cb = rb;
+				x = rand();
+			}
+			uniq_id[i] = fourbits2char[x & 0x0F];
+			x >>= rb;
+			cb -= rb;
+		}
+		uniq_for_pid = getpid();
+	}
+        for (i = UNIQUE_ID_FIX_LEN + UNIQUE_ID_RAND_LEN - 1; i >= UNIQUE_ID_FIX_LEN; i--) {
+		switch (uniq_id[i]) {
+			case '9':
+				uniq_id[i]='a';
+				i = 0;
+				break;
+			case 'f':
+				uniq_id[i]='0';
+				/* go on */
+				break;
+			default:
+				uniq_id[i]++;
+				i = 0;
+				break;
+		}
+	}
+	res->s = uniq_id;   /* I think it's not worth copying at static buffer, I hope there is no real meaning of @[email protected] */
+	res->len = UNIQUE_ID_FIX_LEN+UNIQUE_ID_RAND_LEN;
+	return 0;
+}
+
+
+int select_sys_now(str* res, select_t* s, struct sip_msg* msg) {
+	return uint_to_static_buffer(res, time(NULL));
+}
+
+int select_sys_now_fmt(str* res, select_t* s, struct sip_msg* msg)
+{
+#define SEL_POS 2
+	time_t t;
+	struct tm *tm;
+	
+	t = time(NULL);
+	switch (s->params[SEL_POS].v.i) {
+		case SEL_NOW_GMT:
+			tm = gmtime(&t);
+			break;
+	
+		case SEL_NOW_LOCAL:
+			tm = localtime(&t);
+			break;
+		default:
+			BUG("Unexpected parameter value 'now' \"%d\"\n", s->params[SEL_POS].v.i);
+			return -1;
+	}
+	if (s->n <= SEL_POS+1) {
+		char *c;
+		c = asctime(tm);
+		res->len = strlen(c);
+		while (res->len && c[res->len-1] < ' ') res->len--; /* rtrim */
+		res->s = get_static_buffer(res->len);
+		if (!res->s) return -1;
+		memcpy(res->s, c, res->len);
+	}
+	else {
+		char c, buff[80];
+		c = s->params[SEL_POS+1].v.s.s[s->params[SEL_POS+1].v.s.len];
+		s->params[SEL_POS+1].v.s.s[s->params[SEL_POS+1].v.s.len] = '\0';
+		res->len = strftime(buff, sizeof(buff)-1, s->params[SEL_POS+1].v.s.s, tm);
+		s->params[SEL_POS+1].v.s.s[s->params[SEL_POS+1].v.s.len] = c;
+		res->s = get_static_buffer(res->len);
+		if (!res->s) return -1;
+		memcpy(res->s, buff, res->len);
+	}
+	return 0;
+#undef SEL_POS
+}
+
+ABSTRACT_F(select_branch)
+
+int select_branch_count(str* res, select_t* s, struct sip_msg* msg) {
+	return uint_to_static_buffer(res, nr_branches);
+}
+
+int select_branch_uri(str* res, select_t* s, struct sip_msg* msg) {
+#define SEL_POS 1 
+#define Q_PARAM ">;q="
+#define Q_PARAM_LEN (sizeof(Q_PARAM) - 1)
+
+	qvalue_t q;
+	int l, n;
+	str dst_uri;
+	if (s->n <= SEL_POS+1 && nr_branches > 1) { /* get all branches, if nr_branches==1 then use faster algorithm */
+		int len;
+		unsigned l2;
+		char *c;
+		init_branch_iterator();
+		len = 0;
+		while ((c = next_branch(&l, &q, &dst_uri.s, &dst_uri.len, 0))) {
+
+			if (s->params[SEL_POS].v.i & SEL_BRANCH_DST_URI) {
+				l = dst_uri.len;
+				c = dst_uri.s;
+			}
+			if (s->params[SEL_POS].v.i & (SEL_BRANCH_URI|SEL_BRANCH_DST_URI) ) {
+				len += l;
+			}
+	                if (q != Q_UNSPECIFIED && (s->params[SEL_POS].v.i & SEL_BRANCH_Q)) {
+				len += len_q(q);
+				if (s->params[SEL_POS].v.i & SEL_BRANCH_URI) {
+					len += 1 + Q_PARAM_LEN;
+				}
+			}
+ 			len += 1;
+		}
+		if (!len) return 1;
+		res->s = get_static_buffer(len);
+		if (!res->s) return -1;
+		
+		init_branch_iterator();
+		res->len = 0;
+		n = 0;
+		while ((c = next_branch(&l, &q, &dst_uri.s, &dst_uri.len, 0))) {
+			if (s->params[SEL_POS].v.i & SEL_BRANCH_DST_URI) {
+				l = dst_uri.len;
+				c = dst_uri.s;
+			}
+			if (n) {
+				res->s[res->len] = ',';
+				res->len++;
+			}
+			if ((s->params[SEL_POS].v.i & SEL_BRANCH_Q) == 0) {
+				q = Q_UNSPECIFIED;
+			}
+			if ((s->params[SEL_POS].v.i & (SEL_BRANCH_URI|SEL_BRANCH_DST_URI)) && q != Q_UNSPECIFIED) {
+				res->s[res->len] = '<';
+				res->len++;
+				memcpy(res->s+res->len, c, l);
+				res->len += l; 
+				memcpy(res->s+res->len, Q_PARAM, Q_PARAM_LEN);
+				res->len += Q_PARAM_LEN;
+				c = q2str(q, &l2); l = l2;
+				memcpy(res->s+res->len, c, l);
+				res->len += l; 
+			}
+			else if (s->params[SEL_POS].v.i & (SEL_BRANCH_URI|SEL_BRANCH_DST_URI)) {
+				memcpy(res->s+res->len, c, l);
+				res->len += l; 
+			}
+			else if (q != Q_UNSPECIFIED) {
+				c = q2str(q, &l2); l = l2;
+				memcpy(res->s+res->len, c, l);
+				res->len += l; 
+			}
+			n++;
+		}
+	}
+	else {
+		unsigned l2;
+		char *c;
+		n = s->params[SEL_POS+1].v.i;
+		if (n < 0 || n >= nr_branches) 
+			return -1;
+		init_branch_iterator();
+		for (; (c = next_branch(&l, &q, &dst_uri.s, &dst_uri.len, 0)) && n; n--);
+		if (!c) return 1;
+		
+		if (s->params[SEL_POS].v.i & SEL_BRANCH_DST_URI) {
+			l = dst_uri.len;
+			c = dst_uri.s;
+		}
+		if ((s->params[SEL_POS].v.i & SEL_BRANCH_Q) == 0) {
+			q = Q_UNSPECIFIED;
+		}
+		if ((s->params[SEL_POS].v.i & (SEL_BRANCH_URI|SEL_BRANCH_DST_URI)) && q != Q_UNSPECIFIED) {
+
+			res->s = get_static_buffer(l + 1 + Q_PARAM_LEN + len_q(q));
+			if (!res->s) return -1;
+			res->len = 1;
+			res->s[0] = '<';
+			memcpy(res->s+res->len, c, l);
+			res->len += l; 
+			memcpy(res->s+res->len, Q_PARAM, Q_PARAM_LEN);
+			res->len += Q_PARAM_LEN;
+			c = q2str(q, &l2); l = l2;
+			memcpy(res->s+res->len, c, l);
+			res->len += l; 
+		}
+		else if (s->params[SEL_POS].v.i & (SEL_BRANCH_URI|SEL_BRANCH_DST_URI)) {
+			res->s = c;  /* not necessary to copy to static buffer */
+			res->len = l;
+		} 
+		else if (q != Q_UNSPECIFIED) {
+			c = q2str(q, &l2);
+			res->len = l2;
+			res->s = get_static_buffer(res->len);
+			if (!res->s) return -1;
+			memcpy(res->s, c, res->len);
+		}
+		else {
+			res->len = 0;
+		}
+	}
+	return 0;
+#undef SEL_POS
+}
+
+int select_branch_uriq(str* res, select_t* s, struct sip_msg* msg) {
+	return select_branch_uri(res, s, msg);
+}
+
+int select_branch_q(str* res, select_t* s, struct sip_msg* msg) {
+	return select_branch_uri(res, s, msg);
+}
+
+int select_branch_dst_uri(str* res, select_t* s, struct sip_msg* msg) {
+	return select_branch_uri(res, s, msg);
+}

+ 142 - 6
select_core.h

@@ -71,7 +71,17 @@ enum {
 	SEL_IP_PORT = SEL_IP | SEL_PORT,
 };
 
-SELECT_F(select_method)
+enum {
+	SEL_NOW_GMT = 1,
+	SEL_NOW_LOCAL = 2
+};
+
+enum {
+	SEL_BRANCH_URI = 1<<0,
+	SEL_BRANCH_Q = 1<<1,
+	SEL_BRANCH_DST_URI = 1<<2
+};
+
 SELECT_F(select_ruri)
 SELECT_F(select_dst_uri)
 SELECT_F(select_next_hop)
@@ -85,6 +95,16 @@ SELECT_F(select_to_uri)
 SELECT_F(select_to_tag)
 SELECT_F(select_to_name)
 SELECT_F(select_to_params)
+SELECT_F(select_refer_to)
+SELECT_F(select_refer_to_uri)
+SELECT_F(select_refer_to_tag)
+SELECT_F(select_refer_to_name)
+SELECT_F(select_refer_to_params)
+SELECT_F(select_rpid)
+SELECT_F(select_rpid_uri)
+SELECT_F(select_rpid_tag)
+SELECT_F(select_rpid_name)
+SELECT_F(select_rpid_params)
 SELECT_F(select_contact)
 SELECT_F(select_contact_uri)
 SELECT_F(select_contact_name)
@@ -100,9 +120,26 @@ SELECT_F(select_via_comment)
 SELECT_F(select_via_params)
 SELECT_F(select_via_params_spec)
 
-SELECT_F(select_msgheader)
+SELECT_F(select_msg)
+SELECT_F(select_msg_first_line)
+SELECT_F(select_msg_flags)
+SELECT_F(select_msg_type)
+SELECT_F(select_msg_len)
+SELECT_F(select_msg_id)
+SELECT_F(select_msg_id_hex)
+SELECT_F(select_msg_body)
+SELECT_F(select_msg_header)
 SELECT_F(select_anyheader)
 SELECT_F(select_anyheader_params)
+SELECT_F(select_msg_request)
+SELECT_F(select_msg_request_method)
+SELECT_F(select_msg_request_uri)
+SELECT_F(select_msg_request_version)
+SELECT_F(select_msg_response)
+SELECT_F(select_msg_response_version)
+SELECT_F(select_msg_response_status)
+SELECT_F(select_msg_response_reason)
+SELECT_F(select_version)
 
 SELECT_F(select_any_nameaddr)
 SELECT_F(select_nameaddr_name)
@@ -140,9 +177,35 @@ SELECT_F(select_dst)
 SELECT_F(select_rcv)
 SELECT_F(select_ip_port)
 
+SELECT_F(select_call_id)
+SELECT_F(select_expires)
+SELECT_F(select_max_forwards)
+SELECT_F(select_content_type)
+SELECT_F(select_content_length)
+SELECT_F(select_subject)
+SELECT_F(select_organization)
+SELECT_F(select_priority)
+SELECT_F(select_session_expires)
+SELECT_F(select_min_se)
+SELECT_F(select_user_agent)
+SELECT_F(select_sip_if_match)
+
+SELECT_F(select_sys)
+SELECT_F(select_sys_pid)
+SELECT_F(select_sys_unique)
+SELECT_F(select_sys_now)
+SELECT_F(select_sys_now_fmt)
+
+SELECT_F(select_branch)
+SELECT_F(select_branch_count)
+SELECT_F(select_branch_uri)
+SELECT_F(select_branch_dst_uri)
+SELECT_F(select_branch_uriq)
+SELECT_F(select_branch_q)
+
 static select_row_t select_core[] = {
-	{ NULL, SEL_PARAM_STR, STR_STATIC_INIT("method"), select_method, 0},
-	{ NULL, SEL_PARAM_STR, STR_STATIC_INIT("ruri"), select_ruri, 0},
+	{ NULL, SEL_PARAM_STR, STR_STATIC_INIT("ruri"), select_ruri, 0}, /* not the same as request.uri because it is involved by new_uri */
+	{ NULL, SEL_PARAM_STR, STR_STATIC_INIT("request_uri"), select_ruri, 0},
 	{ select_ruri, SEL_PARAM_STR, STR_NULL, select_any_uri, NESTED},
 	{ NULL, SEL_PARAM_STR, STR_STATIC_INIT("dst_uri"), select_dst_uri, 0},
 	{ select_dst_uri, SEL_PARAM_STR, STR_NULL, select_any_uri, NESTED},
@@ -160,6 +223,17 @@ static select_row_t select_core[] = {
 	{ select_to, SEL_PARAM_STR, STR_STATIC_INIT("tag"), select_to_tag, 0},
 	{ select_to, SEL_PARAM_STR, STR_STATIC_INIT("name"), select_to_name, 0},
 	{ select_to, SEL_PARAM_STR, STR_STATIC_INIT("params"), select_to_params, CONSUME_NEXT_STR},
+	{ NULL, SEL_PARAM_STR, STR_STATIC_INIT("refer_to"), select_refer_to, 0},
+	{ select_refer_to, SEL_PARAM_STR, STR_STATIC_INIT("uri"), select_refer_to_uri, 0},
+	{ select_refer_to, SEL_PARAM_STR, STR_STATIC_INIT("tag"), select_refer_to_tag, 0},
+	{ select_refer_to, SEL_PARAM_STR, STR_STATIC_INIT("name"), select_refer_to_name, 0},
+	{ select_refer_to, SEL_PARAM_STR, STR_STATIC_INIT("params"), select_refer_to_params, CONSUME_NEXT_STR},
+	{ NULL, SEL_PARAM_STR, STR_STATIC_INIT("remote_party_id"), select_rpid, 0},
+	{ NULL, SEL_PARAM_STR, STR_STATIC_INIT("rpid"), select_rpid, 0},
+	{ select_rpid, SEL_PARAM_STR, STR_STATIC_INIT("uri"), select_rpid_uri, 0},
+	{ select_rpid, SEL_PARAM_STR, STR_STATIC_INIT("tag"), select_rpid_tag, 0},
+	{ select_rpid, SEL_PARAM_STR, STR_STATIC_INIT("name"), select_rpid_name, 0},
+	{ select_rpid, SEL_PARAM_STR, STR_STATIC_INIT("params"), select_rpid_params, CONSUME_NEXT_STR},
 	{ NULL, SEL_PARAM_STR, STR_STATIC_INIT("contact"), select_contact, 0},
 	{ NULL, SEL_PARAM_STR, STR_STATIC_INIT("m"), select_contact, 0},
 	{ select_contact, SEL_PARAM_STR, STR_STATIC_INIT("uri"), select_contact_uri, 0},
@@ -187,6 +261,8 @@ static select_row_t select_core[] = {
 	
 	{ select_from_uri, SEL_PARAM_INT, STR_NULL, select_any_uri, NESTED},
 	{ select_to_uri, SEL_PARAM_INT, STR_NULL, select_any_uri, NESTED},
+	{ select_refer_to_uri, SEL_PARAM_INT, STR_NULL, select_any_uri, NESTED},
+	{ select_rpid_uri, SEL_PARAM_INT, STR_NULL, select_any_uri, NESTED},
 	{ select_contact_uri, SEL_PARAM_INT, STR_NULL, select_any_uri, NESTED},
 	{ select_rr_uri, SEL_PARAM_INT, STR_NULL, select_any_uri, NESTED},
 	{ select_any_uri, SEL_PARAM_STR, STR_STATIC_INIT("type"), select_uri_type, 0},
@@ -214,11 +290,40 @@ static select_row_t select_core[] = {
 	{ select_any_nameaddr, SEL_PARAM_STR, STR_STATIC_INIT("params"), select_nameaddr_params, OPTIONAL | CONSUME_NEXT_STR},
 	{ select_nameaddr_uri, SEL_PARAM_INT, STR_NULL, select_any_uri, NESTED},
 
-	{ NULL, SEL_PARAM_STR, STR_STATIC_INIT("msg"), select_msgheader, SEL_PARAM_EXPECTED},
-	{ select_msgheader, SEL_PARAM_STR, STR_NULL, select_anyheader, OPTIONAL | CONSUME_NEXT_INT | FIXUP_CALL},
+	{ NULL, SEL_PARAM_STR, STR_STATIC_INIT("msg"), select_msg, 0},
+	{ NULL, SEL_PARAM_STR, STR_STATIC_INIT("message"), select_msg, 0},
+	{ select_msg, SEL_PARAM_STR, STR_STATIC_INIT("first_line"), select_msg_first_line, 0},
+	{ select_msg, SEL_PARAM_STR, STR_STATIC_INIT("flags"), select_msg_flags, 0},
+	{ select_msg, SEL_PARAM_STR, STR_STATIC_INIT("len"), select_msg_len, 0},
+	{ select_msg, SEL_PARAM_STR, STR_STATIC_INIT("id"), select_msg_id, 0},
+	{ select_msg_id, SEL_PARAM_STR, STR_STATIC_INIT("hex"), select_msg_id_hex, 0},
+	{ select_msg, SEL_PARAM_STR, STR_STATIC_INIT("type"), select_msg_type, 0},
+	{ select_msg, SEL_PARAM_STR, STR_STATIC_INIT("header"), select_msg_header, 0},
+	{ select_msg, SEL_PARAM_STR, STR_STATIC_INIT("h"), select_msg_header, 0},
+	{ select_msg_header, SEL_PARAM_STR, STR_NULL, select_anyheader, OPTIONAL | CONSUME_NEXT_INT | FIXUP_CALL},
 	{ select_anyheader, SEL_PARAM_STR, STR_STATIC_INIT("nameaddr"), select_any_nameaddr, NESTED | CONSUME_NEXT_STR},
 	{ select_anyheader, SEL_PARAM_STR, STR_STATIC_INIT("params"), select_anyheader_params, NESTED},
 	{ select_anyheader_params, SEL_PARAM_STR, STR_STATIC_INIT("params"), select_any_params, CONSUME_NEXT_STR},
+	{ select_msg, SEL_PARAM_STR, STR_STATIC_INIT("body"), select_msg_body, 0},
+	{ select_msg, SEL_PARAM_STR, STR_STATIC_INIT("content"), select_msg_body, 0},
+	{ select_msg, SEL_PARAM_STR, STR_STATIC_INIT("request"), select_msg_request, 0},
+	{ select_msg, SEL_PARAM_STR, STR_STATIC_INIT("req"), select_msg_request, 0},
+	{ select_msg_request, SEL_PARAM_STR, STR_STATIC_INIT("method"), select_msg_request_method, 0},
+	{ select_msg_request, SEL_PARAM_STR, STR_STATIC_INIT("uri"), select_msg_request_uri, 0},
+	{ select_msg_request_uri, SEL_PARAM_STR, STR_NULL, select_any_uri, NESTED},
+	{ select_msg_request, SEL_PARAM_STR, STR_STATIC_INIT("version"), select_msg_request_version, 0},
+	{ select_msg, SEL_PARAM_STR, STR_STATIC_INIT("response"), select_msg_response, 0},
+	{ select_msg, SEL_PARAM_STR, STR_STATIC_INIT("res"), select_msg_response, 0},
+	{ select_msg_response, SEL_PARAM_STR, STR_STATIC_INIT("version"), select_msg_response_version, 0},
+	{ select_msg_response, SEL_PARAM_STR, STR_STATIC_INIT("status"), select_msg_response_status, 0},
+	{ select_msg_response, SEL_PARAM_STR, STR_STATIC_INIT("code"), select_msg_response_status, 0},
+	{ select_msg_response, SEL_PARAM_STR, STR_STATIC_INIT("reason"), select_msg_response_reason, 0},
+	/*short aliases*/
+	{ NULL, SEL_PARAM_STR, STR_STATIC_INIT("method"), select_msg_request_method, 0},
+	{ NULL, SEL_PARAM_STR, STR_STATIC_INIT("version"), select_version, 0},
+	{ NULL, SEL_PARAM_STR, STR_STATIC_INIT("status"), select_msg_response_status, 0},
+	{ NULL, SEL_PARAM_STR, STR_STATIC_INIT("code"), select_msg_response_status, 0},
+	{ NULL, SEL_PARAM_STR, STR_STATIC_INIT("reason"), select_msg_response_reason, 0},
 
 	{ NULL, SEL_PARAM_STR, STR_STATIC_INIT("proxy_authorization"), select_auth, CONSUME_NEXT_STR | DIVERSION | SEL_AUTH_PROXY},
 	{ NULL, SEL_PARAM_STR, STR_STATIC_INIT("authorization"), select_auth, CONSUME_NEXT_STR | DIVERSION | SEL_AUTH_WWW}, 
@@ -250,6 +355,37 @@ static select_row_t select_core[] = {
 	{ select_rcv, SEL_PARAM_STR, STR_STATIC_INIT("ip_port"), select_ip_port, DIVERSION | SEL_RCV | SEL_IP_PORT},
 	{ select_rcv, SEL_PARAM_STR, STR_STATIC_INIT("proto_ip_port"), select_ip_port, DIVERSION | SEL_RCV | SEL_PROTO | SEL_IP_PORT},
 
+	{ NULL, SEL_PARAM_STR, STR_STATIC_INIT("call_id"), select_call_id, 0},
+	{ NULL, SEL_PARAM_STR, STR_STATIC_INIT("expires"), select_expires, 0},
+	{ NULL, SEL_PARAM_STR, STR_STATIC_INIT("max_forwards"), select_max_forwards, 0},
+	{ NULL, SEL_PARAM_STR, STR_STATIC_INIT("content_type"), select_content_type, 0},
+	{ NULL, SEL_PARAM_STR, STR_STATIC_INIT("content_length"), select_content_length, 0},
+	{ NULL, SEL_PARAM_STR, STR_STATIC_INIT("subject"), select_subject, 0},
+	{ NULL, SEL_PARAM_STR, STR_STATIC_INIT("organization"), select_organization, 0},
+	{ NULL, SEL_PARAM_STR, STR_STATIC_INIT("priority"), select_priority, 0},
+	{ NULL, SEL_PARAM_STR, STR_STATIC_INIT("session_expires"), select_session_expires, 0},
+	{ NULL, SEL_PARAM_STR, STR_STATIC_INIT("min_se"), select_min_se, 0},
+	{ NULL, SEL_PARAM_STR, STR_STATIC_INIT("user_agent"), select_user_agent, 0},
+	{ NULL, SEL_PARAM_STR, STR_STATIC_INIT("sip_if_match"), select_sip_if_match, 0},
+
+	{ NULL, SEL_PARAM_STR, STR_STATIC_INIT("sys"), select_sys, SEL_PARAM_EXPECTED},
+	{ select_sys, SEL_PARAM_STR, STR_STATIC_INIT("pid"), select_sys_pid, 0},
+	{ select_sys, SEL_PARAM_STR, STR_STATIC_INIT("unique"), select_sys_unique, 0},
+	{ select_sys, SEL_PARAM_STR, STR_STATIC_INIT("now"), select_sys_now, 0},
+	{ select_sys_now, SEL_PARAM_STR, STR_STATIC_INIT("local"), select_sys_now_fmt, OPTIONAL | CONSUME_NEXT_STR | DIVERSION | SEL_NOW_LOCAL},
+	{ select_sys_now, SEL_PARAM_STR, STR_STATIC_INIT("gmt"), select_sys_now_fmt, OPTIONAL | CONSUME_NEXT_STR | DIVERSION | SEL_NOW_GMT},
+	{ select_sys_now, SEL_PARAM_STR, STR_STATIC_INIT("utc"), select_sys_now_fmt, OPTIONAL | CONSUME_NEXT_STR | DIVERSION | SEL_NOW_GMT},
+
+	{ NULL, SEL_PARAM_STR, STR_STATIC_INIT("branch"), select_branch, SEL_PARAM_EXPECTED},
+	{ select_branch, SEL_PARAM_STR, STR_STATIC_INIT("count"), select_branch_count, 0},
+	{ select_branch, SEL_PARAM_STR, STR_STATIC_INIT("uri"), select_branch_uri, OPTIONAL | CONSUME_NEXT_INT | DIVERSION | SEL_BRANCH_URI },
+	{ select_branch, SEL_PARAM_STR, STR_STATIC_INIT("dst_uri"), select_branch_dst_uri, OPTIONAL | CONSUME_NEXT_INT | DIVERSION | SEL_BRANCH_DST_URI},
+	{ select_branch_uri, SEL_PARAM_STR, STR_NULL, select_any_uri, NESTED},
+	{ select_branch_dst_uri, SEL_PARAM_STR, STR_NULL, select_any_uri, NESTED},
+	{ select_branch, SEL_PARAM_STR, STR_STATIC_INIT("uriq"), select_branch_uriq, OPTIONAL | CONSUME_NEXT_INT | DIVERSION | SEL_BRANCH_URI | SEL_BRANCH_Q},
+	{ select_branch_uriq, SEL_PARAM_STR, STR_NULL, select_any_nameaddr, NESTED},
+	{ select_branch, SEL_PARAM_STR, STR_STATIC_INIT("q"), select_branch_q, OPTIONAL | CONSUME_NEXT_INT | DIVERSION | SEL_BRANCH_Q},
+
 	{ NULL, SEL_PARAM_INT, STR_NULL, NULL, 0}
 };