Quellcode durchsuchen

- t_write_xxx() extended to print any optional header, avp or msg. body
- configuration is done via "tw_append" parameter:
tw_append = name:element[;element]
element = [title=]value
value = avp[avp_spec] | hdr[hdr_name] | msg[body]
- t_write_xxx() syntax:
t_write_xxx("unix_sock/fifo","application[/append_name]")

Andrei Pelinescu-Onciul vor 21 Jahren
Ursprung
Commit
8bc902c979
3 geänderte Dateien mit 500 neuen und 67 gelöschten Zeilen
  1. 476 50
      modules/tm/t_fifo.c
  2. 6 0
      modules/tm/t_fifo.h
  3. 18 17
      modules/tm/tm.c

+ 476 - 50
modules/tm/t_fifo.c

@@ -29,6 +29,7 @@
  * History:
  * -------
  *  2004-02-23  created by splitting it from t_funcs (bogdan)
+ *  2004-11-15  t_write_xxx can print whatever avp/hdr
  */
 
 
@@ -41,6 +42,8 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <sys/un.h>
+#include <ctype.h>
+#include <string.h>
 
 #include "../../str.h"
 #include "../../ut.h"
@@ -51,10 +54,12 @@
 #include "../../parser/parse_from.h"
 #include "../../parser/parse_rr.h"
 #include "../../parser/parse_nameaddr.h"
+#include "../../parser/parse_hname2.h"
 #include "../../parser/contact/parse_contact.h"
+#include "../../tsend.h"
 #include "t_lookup.h"
 #include "t_fwd.h"
-#include "../../tsend.h"
+#include "t_fifo.h"
 
 
 /* AF_LOCAL is not defined on solaris */
@@ -86,7 +91,7 @@ int tm_unix_tx_timeout = 2; /* Default is 2 seconds */
 
 #define IDBUF_LEN              128
 #define ROUTE_BUFFER_MAX       512
-#define HDRS_BUFFER_MAX        512
+#define APPEND_BUFFER_MAX      4096
 #define CMD_BUFFER_MAX         128
 
 #define append_str(_dest,_src,_len) \
@@ -118,6 +123,354 @@ static str   eol={"\n",1};
 
 static int sock;
 
+struct hdr_avp {
+	str title;
+	int type;
+	str sval;
+	int ival;
+	struct hdr_avp *next;
+};
+
+struct tw_append {
+	str name;
+	int add_body;
+	struct hdr_avp *elems;
+	struct tw_append *next;
+};
+
+struct tw_info {
+	str action;
+	struct tw_append *append;
+};
+
+#define ELEM_TYPE_AVP      "avp"
+#define ELEM_TYPE_AVP_LEN  (sizeof(ELEM_TYPE_AVP)-1)
+#define ELEM_TYPE_HDR      "hdr"
+#define ELEM_TYPE_HDR_LEN  (sizeof(ELEM_TYPE_HDR)-1)
+#define ELEM_TYPE_MSG      "msg"
+#define ELEM_TYPE_MSG_LEN  (sizeof(ELEM_TYPE_MSG)-1)
+#define ELEM_IS_AVP        (1<<0)
+#define ELEM_IS_HDR        (1<<1)
+#define ELEM_IS_MSG        (1<<2)
+
+#define ELEM_VAL_BODY      "body"
+#define ELEM_VAL_BODY_LEN  (sizeof(ELEM_VAL_BODY)-1)
+
+
+static struct tw_append *tw_appends;
+
+
+static void print_tw_append( struct tw_append *append)
+{
+	struct hdr_avp *ha;
+
+	if (!append)
+		return;
+
+	DBG("DEBUG:tm:print_tw_append: tw_append name=<%.*s>\n",
+		append->name.len,append->name.s);
+	for( ha=append->elems ; ha ; ha=ha->next ) {
+		DBG("\ttitle=<%.*s>\n",ha->title.len,ha->title.s);
+		DBG("\t\tttype=<%d>\n",ha->type);
+		DBG("\t\tsval=<%.*s>\n",ha->sval.len,ha->sval.s);
+		DBG("\t\tival=<%d>\n",ha->ival);
+	}
+}
+
+
+/* tw_append syntax:
+ * tw_append = name:element[;element]
+ * element   = [title=]value 
+ * value     = avp[avp_spec] | hdr[hdr_name] | msg[body] */
+int parse_tw_append( modparam_t type, param_func_param_t param_val)
+{
+	struct hdr_field hdr;
+	struct hdr_avp *last;
+	struct hdr_avp *ha;
+	struct tw_append *app;
+	int_str avp_name;
+	char *s;
+	char bar;
+	str foo;
+	int n;
+	
+	if (param_val.string==0 || param_val.string[0]==0)
+		return 0;
+	s = param_val.string;
+
+	/* start parsing - first the name */
+	while( *s && isspace((int)*s) )  s++;
+	if ( !*s || *s==':')
+		goto parse_error;
+	foo.s = s;
+	while ( *s && *s!=':' && !isspace((int)*s) ) s++;
+	if ( !*s || foo.s==s )
+		goto parse_error;
+	foo.len = s - foo.s;
+	/* parse separator */
+	while( *s && isspace((int)*s) )  s++;
+	if ( !*s || *s!=':')
+		goto parse_error;
+	s++;
+	while( *s && isspace((int)*s) )  s++;
+	if ( !*s )
+		goto parse_error;
+
+	/* check for name duplication */
+	for(app=tw_appends;app;app=app->next)
+		if (app->name.len==foo.len && !strncasecmp(app->name.s,foo.s,foo.len)){
+			LOG(L_ERR,"ERROR:tm:parse_tw_append: duplicated tw_append name "
+				"<%.*s>\n",foo.len,foo.s);
+			goto error;
+		}
+
+	/* new tw_append structure */
+	app = (struct tw_append*)pkg_malloc( sizeof(struct tw_append) );
+	if (app==0) {
+		LOG(L_ERR,"ERROR:tm:parse_tw_append: no more pkg memory\n");
+		goto error;
+	}
+	app->name.s = (char*)pkg_malloc( foo.len+1 );
+	if (app->name.s==0) {
+		LOG(L_ERR,"ERROR:tm:parse_tw_append: no more pkg memory\n");
+		goto error;
+	}
+	memcpy( app->name.s, foo.s, foo.len);
+	app->name.len = foo.len;
+	app->name.s[app->name.len] = 0;
+	last = app->elems = 0;
+	app->next = tw_appends;
+	tw_appends = app;
+
+	/* parse the elements */
+	while (*s) {
+		/* parse element title or element type */
+		foo.s = s;
+		while( *s && *s!='[' && *s!='=' && *s!=';' && !isspace((int)*s) ) s++;
+		if ( !*s || foo.s==s)
+			goto parse_error;
+		foo.len = s - foo.s;
+		/* new hdr_avp structure */
+		ha = (struct hdr_avp*)pkg_malloc( sizeof(struct hdr_avp) );
+		if (ha==0) {
+			LOG(L_ERR,"ERROR:tm:parse_tw_append: no more pkg memory\n");
+			goto error;
+		}
+		memset( ha, 0, sizeof(struct hdr_avp));
+		if (*s!='[') {
+			/* foo must by title or some error -> parse separator */
+			while( *s && isspace((int)*s) )  s++;
+			if ( !*s || *s!='=')
+				goto parse_error;
+			s++;
+			while( *s && isspace((int)*s) )  s++;
+			if ( !*s )
+				goto parse_error;
+			/* set the title */
+			ha->title.s = (char*)pkg_malloc( foo.len+1 );
+			if (ha->title.s==0) {
+				LOG(L_ERR,"ERROR:tm:parse_tw_append: no more pkg memory\n");
+				goto error;
+			}
+			memcpy( ha->title.s, foo.s, foo.len);
+			ha->title.len = foo.len;
+			ha->title.s[ha->title.len] = 0;
+			/* parse the type now */
+			foo.s = s;
+			while( *s && *s!='[' && *s!=']' && *s!=';' && !isspace((int)*s) )
+				s++;
+			if ( *s!='[' || foo.s==s)
+				goto parse_error;
+			foo.len = s - foo.s;
+		}
+		/* foo containes the elemet type */
+		if ( foo.len==ELEM_TYPE_AVP_LEN &&
+		!strncasecmp( foo.s, ELEM_TYPE_AVP, foo.len) ) {
+			ha->type = ELEM_IS_AVP;
+		} else if ( foo.len==ELEM_TYPE_HDR_LEN &&
+		!strncasecmp( foo.s, ELEM_TYPE_HDR, foo.len) ) {
+			ha->type = ELEM_IS_HDR;
+		} else if ( foo.len==ELEM_TYPE_MSG_LEN &&
+		!strncasecmp( foo.s, ELEM_TYPE_MSG, foo.len) ) {
+			ha->type = ELEM_IS_MSG;
+		} else {
+			LOG(L_ERR,"ERROR:tm:parse_tw_append: unknown type <%.*s>\n",
+				foo.len, foo.s);
+			goto error;
+		}
+		/* parse the element name */
+		s++;
+		foo.s = s;
+		while( *s && *s!=']' && *s!=';' && !isspace((int)*s) ) s++;
+		if ( *s!=']' || foo.s==s )
+			goto parse_error;
+		foo.len = s - foo.s;
+		s++;
+		/* process and optimize the element name */
+		if (ha->type==ELEM_IS_AVP) {
+			/* element is AVP */
+			if ( parse_avp_spec( &foo, &n, &avp_name)!=0 ) {
+				LOG(L_ERR,"ERROR:tm:parse_tw_append: bad alias spec "
+					"<%.*s>\n",foo.len, foo.s);
+				goto error;
+			}
+			if (n&AVP_NAME_STR) {
+				/* string name */
+				ha->sval.s = (char*)pkg_malloc(avp_name.s->len+1);
+				if (ha->sval.s==0) {
+					LOG(L_ERR,"ERROR:tm:parse_tw_append: no more pkg mem\n");
+					goto error;
+				}
+				memcpy( ha->sval.s, avp_name.s->s, avp_name.s->len);
+				ha->sval.len = avp_name.s->len;
+				ha->sval.s[ha->sval.len] = 0;
+				if (ha->title.s==0)
+					ha->title = ha->sval;
+			} else {
+				/* ID name - if title is missing, convert the ID to
+				 * string and us it a title */
+				ha->ival = avp_name.n;
+				if (ha->title.s==0) {
+					foo.s=int2str((unsigned long)ha->ival, &foo.len);
+					ha->title.s = (char*)pkg_malloc( n+1 );
+					if (ha->title.s==0) {
+						LOG(L_ERR,"ERROR:tm:parse_tw_append: no more pkg "
+							"memory\n");
+						goto error;
+					}
+					memcpy( ha->title.s, foo.s, foo.len);
+					ha->title.len = foo.len;
+					ha->title.s[ha->title.len] = 0;
+				}
+			}
+		} else if (ha->type==ELEM_IS_HDR) {
+			/* element is HDR -  try to get it's coded type if defined */
+			bar = foo.s[foo.len];
+			foo.s[foo.len] = ':';
+			/* parse header name */
+			if (parse_hname2( foo.s, foo.s+foo.len+1, &hdr)==0) {
+				LOG(L_ERR,"BUG:tm_parse_tw_append: parse header failed\n");
+				goto error;
+			}
+			foo.s[foo.len] = bar;
+			ha->ival = hdr.type;
+			if (hdr.type==HDR_OTHER || ha->title.s==0) {
+				/* duplicate hdr name */
+				ha->sval.s = (char*)pkg_malloc(foo.len+1);
+				if (ha->sval.s==0) {
+					LOG(L_ERR,"ERROR:tm:parse_tw_append: no more pkg mem\n");
+					goto error;
+				}
+				memcpy( ha->sval.s, foo.s, foo.len);
+				ha->sval.len = foo.len;
+				ha->sval.s[ha->sval.len] = 0;
+				if (ha->title.s==0)
+					ha->title = ha->sval;
+			}
+		} else {
+			/* element is MSG */
+			if ( !(foo.len==ELEM_VAL_BODY_LEN &&
+			!strncasecmp(ELEM_VAL_BODY,foo.s,foo.len)) ) {
+				LOG(L_ERR,"ERROR:tm:parse_tw_append: unsupported value <%.*s>"
+					" for msg type\n",foo.len,foo.s);
+				goto error;
+			}
+			app->add_body = 1;
+			pkg_free( ha );
+			ha = 0;
+		}
+
+		/* parse the element separator, if present */
+		while( *s && isspace((int)*s) )  s++;
+		if ( *s && *s!=';')
+			goto parse_error;
+		if (*s==';') {
+			s++;
+			while( *s && isspace((int)*s) )  s++;
+			if (!*s)
+				goto parse_error;
+		}
+
+		/* link the element to tw_append structure */
+		if (ha) {
+			if (last==0) {
+				last = app->elems = ha;
+			} else {
+				last->next = ha;
+				last = ha;
+			}
+		}
+
+	} /* end while */
+
+	print_tw_append( app );
+	/* free the old string */
+	pkg_free( param_val.string );
+	return 0;
+parse_error:
+	LOG(L_ERR,"ERROR:tm:parse_tw_append: parse error in <%s> around "
+		"position %d\n", param_val.string, s-param_val.string);
+error:
+	return -1;
+}
+
+
+static struct tw_append *search_tw_append(char *name, int len)
+{
+	struct tw_append * app;
+
+	for( app=tw_appends ; app ; app=app->next )
+		if (app->name.len==len && !strncasecmp(app->name.s,name,len) )
+			return app;
+	return 0;
+}
+
+
+int fixup_t_write( void** param, int param_no)
+{
+	struct tw_info *twi;
+	char *s;
+
+	if (param_no==2) {
+		twi = (struct tw_info*)pkg_malloc( sizeof(struct tw_info) );
+		if (twi==0) {
+			LOG(L_ERR,"ERROR:tm:fixup_t_write: no more pkg memory\n");
+			return E_OUT_OF_MEM;
+		}
+		memset( twi, 0 , sizeof(struct tw_info));
+		s = (char*)*param;
+		twi->action.s = s;
+		if ( (s=strchr(s,'/'))!=0) {
+			twi->action.len = s - twi->action.s;
+			if (twi->action.len==0) {
+				LOG(L_ERR,"ERROR:tm:fixup_t_write: empty action name\n");
+				return E_CFG;
+			}
+			s++;
+			if (*s==0) {
+				LOG(L_ERR,"ERROR:tm:fixup_t_write: empty append name\n");
+				return E_CFG;
+			}
+			twi->append = search_tw_append( s, strlen(s));
+			if (twi->append==0) {
+				LOG(L_ERR,"ERROR:tm:fixup_t_write: unknown append name "
+					"<%s>\n",s);
+				return E_CFG;
+			}
+			*param=(void*)twi;
+		} else {
+			twi->action.len = strlen(twi->action.s);
+		}
+	}
+
+	return 0;
+}
+
+
+
+
+
+
 int init_twrite_sock(void)
 {
 	int flags;
@@ -205,15 +558,109 @@ error:
 }
 
 
-#define EMAIL_AVP_ID  0xcaca
-static int assemble_msg(struct sip_msg* msg, char* action)
+static inline char* add2buf(char *buf, char *end, char *title, int title_len,
+												char *value , int value_len)
+{
+	if (buf+title_len+value_len+2+1>=end)
+		return 0;
+	memcpy( buf, title, title_len);
+	buf += title_len;
+	*(buf++) = ':';
+	*(buf++) = ' ';
+	memcpy( buf, value, value_len);
+	buf += value_len;
+	*(buf++) = '\n';
+	return buf;
+}
+
+
+static inline char* append2buf( char *buf, int len, struct sip_msg *req, 
+														struct hdr_avp *ha)
+{
+	struct hdr_field *hdr;
+	struct usr_avp   *avp;
+	int_str          avp_val;
+	char  *end;
+	str   foo;
+	int   msg_parsed;
+
+	end = buf+len;
+	msg_parsed = 0;
+
+	while(ha) {
+		if (ha->type==ELEM_IS_AVP) {
+			/* search for the AVP */
+			if (ha->sval.s) {
+				avp = search_first_avp( AVP_NAME_STR, (int_str)&ha->sval,
+					&avp_val);
+			} else {
+				avp = search_first_avp( 0, (int_str)ha->ival,
+					&avp_val);
+			}
+			if (avp) {
+				if (avp->flags&AVP_VAL_STR) {
+					buf=add2buf( buf, end, ha->title.s, ha->title.len,
+						avp_val.s->s , avp_val.s->len);
+					if (!buf)
+						goto overflow_err;
+				} else {
+					foo.s=int2str( (unsigned long)avp_val.n, &foo.len);
+					buf=add2buf( buf, end, ha->title.s, ha->title.len,
+						foo.s , foo.len);
+					if (!buf)
+						goto overflow_err;
+				}
+			}
+		} else if (ha->type==ELEM_IS_HDR) {
+			/* parse the HDRs */
+			if (!msg_parsed) {
+				if (parse_headers( req, HDR_EOH, 0)!=0) {
+					LOG(L_ERR,"ERROR:tm:append2buf: parsing hdrs failed\n");
+					goto error;
+				}
+				msg_parsed = 1;
+			}
+			/* search the HDR */
+			if (ha->ival==HDR_OTHER) {
+				for(hdr=req->headers;hdr;hdr=hdr->next)
+					if (ha->sval.len==hdr->name.len &&
+					strncasecmp( ha->sval.s, hdr->name.s, hdr->name.len)==0)
+						break;
+			} else {
+				for(hdr=req->headers;hdr;hdr=hdr->next)
+					if (ha->ival==hdr->type)
+						break;
+			}
+			if (hdr) {
+				buf=add2buf( buf, end, ha->title.s, ha->title.len,
+					hdr->body.s , hdr->body.len);
+				if (!buf)
+					goto overflow_err;
+			}
+		} else {
+			LOG(L_ERR,"BUG:tm:append2buf: unknown element type %d\n",
+				ha->type);
+			goto error;
+		}
+
+		ha = ha->next;
+	}
+
+	return buf;
+overflow_err:
+	LOG(L_ERR,"ERROR:tm:append2buf: overflow -> append exceeded %d len\n",len);
+error:
+	return 0;
+}
+
+
+static int assemble_msg(struct sip_msg* msg, struct tw_info *twi)
 {
 	static char     id_buf[IDBUF_LEN];
 	static char     route_buffer[ROUTE_BUFFER_MAX];
-	static char     hdrs_buf[HDRS_BUFFER_MAX];
+	static char     append_buf[APPEND_BUFFER_MAX];
 	static char     cmd_buf[CMD_BUFFER_MAX];
 	static str      empty_param = {".",1};
-	int_str           email_val;
 	unsigned int      hash_index, label;
 	contact_body_t*   cb=0;
 	contact_t*        c=0;
@@ -223,7 +670,7 @@ static int assemble_msg(struct sip_msg* msg, char* action)
 	param_hooks_t     hooks;
 	int               l;
 	char*             s, fproxy_lr;
-	str               route, next_hop, hdrs, tmp_s, body, str_uri;
+	str               route, next_hop, append, tmp_s, body, str_uri;
 
 	if(msg->first_line.type != SIP_REQUEST){
 		LOG(L_ERR,"assemble_msg: called for something else then"
@@ -231,9 +678,6 @@ static int assemble_msg(struct sip_msg* msg, char* action)
 		goto error;
 	}
 
-	email_val.s = 0;
-	body = empty_param;
-
 	/* parse all -- we will need every header field for a UAS */
 	if ( parse_headers(msg, HDR_EOH, 0)==-1) {
 		LOG(L_ERR,"assemble_msg: parse_headers failed\n");
@@ -356,67 +800,49 @@ static int assemble_msg(struct sip_msg* msg, char* action)
 	DBG("assemble_msg: next r-uri: %.*s\n",
 	    str_uri.len,str_uri.len ? str_uri.s : "");
 	
-	if( REQ_LINE(msg).method_value==METHOD_INVITE ) {
+	if ( REQ_LINE(msg).method_value==METHOD_INVITE || twi->append->add_body ) {
 		/* get body */
 		if( (body.s = get_body(msg)) == 0 ){
 			LOG(L_ERR, "assemble_msg: get_body failed\n");
 			goto error;
 		}
 		body.len = msg->len - (body.s - msg->buf);
-
-		/* get email (if any) */
-		search_first_avp( 0, (int_str)EMAIL_AVP_ID, &email_val);
+	} else {
+		body = empty_param;
 	}
 
 	/* additional headers */
-	hdrs.s = s = hdrs_buf;
-	l = sizeof(flag_t);
-	if (l+12+1 >= HDRS_BUFFER_MAX) {
+	append.s = s = append_buf;
+	if (sizeof(flag_t)+12+1 >= APPEND_BUFFER_MAX) {
 		LOG(L_ERR,"assemble_msg: buffer overflow "
 		    "while copying optional header\n");
 		goto error;
 	}
-	append_str(s,"P-MsgFlags: ",12); hdrs.len = 12;
+	append_str(s,"P-MsgFlags: ",12);
 	int2reverse_hex(&s, &l, (int)msg->msg_flags);
-	hdrs.len += sizeof(flag_t) - l;
-	append_chr(s,'\n'); hdrs.len++;
+	append_chr(s,'\n');
 
-	for(p_hdr = msg->headers;p_hdr;p_hdr = p_hdr->next) {
-		if( !(p_hdr->type&HDR_OTHER) )
-			continue;
-
-		if(hdrs.len+p_hdr->name.len+p_hdr->body.len+4 >= HDRS_BUFFER_MAX){
-			LOG(L_ERR,"assemble_msg: buffer overflow while "
-			    "copying optional header\n");
-			goto error;
-		}
-		append_str(s,p_hdr->name.s,p_hdr->name.len);
-		hdrs.len += p_hdr->name.len;
-		append_chr(s,':');append_chr(s,' '); hdrs.len+=2;
-		append_str(s,p_hdr->body.s,p_hdr->body.len);
-		hdrs.len += p_hdr->body.len;
-		if(*(s-1) != '\n'){
-			append_chr(s,'\n');
-			hdrs.len++;
-		}
-	}
+	if ( (s=append2buf( s, APPEND_BUFFER_MAX-(s-append.s), msg,
+	twi->append->elems))==0 )
+		goto error;
 
+	/* body separator */
 	append_chr(s,'.');
-	hdrs.len++;
+	append.len = s-append.s;
 
 	eol_line(1).s = s = cmd_buf;
-	if(strlen(action)+12 >= CMD_BUFFER_MAX){
+	if(twi->action.len+12 >= CMD_BUFFER_MAX){
 		LOG(L_ERR,"assemble_msg: buffer overflow while "
 		    "copying command name\n");
 		goto error;
 	}
 	append_str(s,"sip_request.",12);
-	append_str(s,action,strlen(action));
+	append_str(s,twi->action.s,twi->action.len);
 	eol_line(1).len = s-eol_line(1).s;
 
 	eol_line(2)=REQ_LINE(msg).method;     /* method type */
 	eol_line(3)=msg->parsed_uri.user;     /* user from r-uri */
-	eol_line(4)=(email_val.s)?(*email_val.s):(empty_param);  /* email */
+	eol_line(4)=empty_param;              /* email - TODO -remove it */
 	eol_line(5)=msg->parsed_uri.host;     /* domain */
 
 	eol_line(6)=msg->rcv.bind_address->address_str; /* dst ip */
@@ -456,7 +882,7 @@ static int assemble_msg(struct sip_msg* msg, char* action)
 
 	eol_line(17) = route.len ? route : empty_param;
 	eol_line(18) = next_hop;
-	eol_line(19) = hdrs;
+	eol_line(19) = append;
 	eol_line(20) = body;
 
 	/* success */
@@ -505,9 +931,9 @@ static int write_to_unixsock(char* sockname, int cnt)
 }
 
 
-int t_write_req(struct sip_msg* msg, char* vm_fifo, char* action)
+int t_write_req(struct sip_msg* msg, char* vm_fifo, char* info)
 {
-	if (assemble_msg(msg, action) < 0) {
+	if (assemble_msg(msg, (struct tw_info*)info) < 0) {
 		LOG(L_ERR, "ERROR:tm:t_write_req: Error int assemble_msg\n");
 		return -1;
 	}
@@ -523,13 +949,13 @@ int t_write_req(struct sip_msg* msg, char* vm_fifo, char* action)
 		LOG(L_ERR, "ERROR:tm:t_write_req: add_blind failed\n");
 		return -1;
 	}
-	return 0;
+	return 1;
 }
 
 
-int t_write_unix(struct sip_msg* msg, char* socket, char* action)
+int t_write_unix(struct sip_msg* msg, char* socket, char* info)
 {
-	if (assemble_msg(msg, action) < 0) {
+	if (assemble_msg(msg, (struct tw_info*)info) < 0) {
 		LOG(L_ERR, "ERROR:tm:t_write_unix: Error in assemble_msg\n");
 		return -1;
 	}
@@ -545,5 +971,5 @@ int t_write_unix(struct sip_msg* msg, char* socket, char* action)
 		LOG(L_ERR, "ERROR:tm:t_write_unix: add_blind failed\n");
 		return -1;
 	}
-	return 0;
+	return 1;
 }

+ 6 - 0
modules/tm/t_fifo.h

@@ -27,6 +27,7 @@
  * History:
  * --------
  *  2003-03-31  200 for INVITE/UAS resent even for UDP (jiri) 
+ *  2004-11-15  t_write_xxx can print whatever avp/hdr
  */
 
 
@@ -35,9 +36,14 @@
 #define _TM_T_FIFO_H_
 
 #include "../../parser/msg_parser.h"
+#include "../../sr_module.h"
 
 extern int tm_unix_tx_timeout;
 
+int fixup_t_write( void** param, int param_no);
+
+int parse_tw_append( modparam_t type, param_func_param_t param_val);
+
 int init_twrite_lines();
 
 int init_twrite_sock(void);

+ 18 - 17
modules/tm/tm.c

@@ -225,9 +225,9 @@ static cmd_export_t cmds[]={
 			REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE },
 	{"t_check_status",     t_check_status,          1, fixup_str2regexp,
 			REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE },
-	{"t_write_req",       t_write_req,              2, 0,
+	{"t_write_req",       t_write_req,              2, fixup_t_write,
 			REQUEST_ROUTE | FAILURE_ROUTE },
-	{"t_write_unix",      t_write_unix,             2, 0,
+	{"t_write_unix",      t_write_unix,             2, fixup_t_write,
 	                REQUEST_ROUTE | FAILURE_ROUTE },
 
 	/* not applicable from the script */
@@ -253,22 +253,23 @@ static cmd_export_t cmds[]={
 
 
 static param_export_t params[]={
-	{"ruri_matching",         INT_PARAM, &ruri_matching                         },
-	{"via1_matching",         INT_PARAM, &via1_matching                         },
-	{"fr_timer",              INT_PARAM, &(timer_id2timeout[FR_TIMER_LIST])     },
-	{"fr_inv_timer",          INT_PARAM, &(timer_id2timeout[FR_INV_TIMER_LIST]) },
-	{"wt_timer",              INT_PARAM, &(timer_id2timeout[WT_TIMER_LIST])     },
-	{"delete_timer",          INT_PARAM, &(timer_id2timeout[DELETE_LIST])       },
-	{"retr_timer1p1",         INT_PARAM, &(timer_id2timeout[RT_T1_TO_1])        },
-	{"retr_timer1p2",         INT_PARAM, &(timer_id2timeout[RT_T1_TO_2])        },
-	{"retr_timer1p3",         INT_PARAM, &(timer_id2timeout[RT_T1_TO_3])        },
-	{"retr_timer2",           INT_PARAM, &(timer_id2timeout[RT_T2])             },
-	{"noisy_ctimer",          INT_PARAM, &noisy_ctimer                          },
-	{"uac_from",              STR_PARAM, &uac_from                              },
-	{"unix_tx_timeout",       INT_PARAM, &tm_unix_tx_timeout                    },
+	{"ruri_matching",       INT_PARAM, &ruri_matching                        },
+	{"via1_matching",       INT_PARAM, &via1_matching                        },
+	{"fr_timer",            INT_PARAM, &(timer_id2timeout[FR_TIMER_LIST])    },
+	{"fr_inv_timer",        INT_PARAM, &(timer_id2timeout[FR_INV_TIMER_LIST])},
+	{"wt_timer",            INT_PARAM, &(timer_id2timeout[WT_TIMER_LIST])    },
+	{"delete_timer",        INT_PARAM, &(timer_id2timeout[DELETE_LIST])      },
+	{"retr_timer1p1",       INT_PARAM, &(timer_id2timeout[RT_T1_TO_1])       },
+	{"retr_timer1p2",       INT_PARAM, &(timer_id2timeout[RT_T1_TO_2])       },
+	{"retr_timer1p3",       INT_PARAM, &(timer_id2timeout[RT_T1_TO_3])       },
+	{"retr_timer2",         INT_PARAM, &(timer_id2timeout[RT_T2])            },
+	{"noisy_ctimer",        INT_PARAM, &noisy_ctimer                         },
+	{"uac_from",            STR_PARAM, &uac_from                             },
+	{"unix_tx_timeout",     INT_PARAM, &tm_unix_tx_timeout                   },
 	{"restart_fr_on_each_reply", INT_PARAM, &restart_fr_on_each_reply        },
-	{"fr_timer_avp",          STR_PARAM, &fr_timer_param.s                      },
-	{"fr_inv_timer_avp",      STR_PARAM, &fr_inv_timer_param.s                  },
+	{"fr_timer_avp",        STR_PARAM, &fr_timer_param.s                     },
+	{"fr_inv_timer_avp",    STR_PARAM, &fr_inv_timer_param.s                 },
+	{"tw_append",           STR_PARAM|USE_FUNC_PARAM, parse_tw_append        },
 	{0,0,0}
 };