- fixed ":" in port_no_str bug. Now port_no_str no longer contains the colon
[sip-router] / msg_translator.c
1 /* 
2  * $Id$
3  *
4  *
5  * Copyright (C) 2001-2003 Fhg Fokus
6  *
7  * This file is part of ser, a free SIP server.
8  *
9  * ser is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version
13  *
14  * For a license to use the ser software under conditions
15  * other than those described here, or to purchase support for this
16  * software, please contact iptel.org by e-mail at the following addresses:
17  *    info@iptel.org
18  *
19  * ser is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License 
25  * along with this program; if not, write to the Free Software 
26  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
27  * 
28  *
29  * History:
30  * --------
31  * 2003-01-20  bug_fix: use of return value of snprintf aligned to C99 (jiri)
32  * 2003-01-23  added rport patches, contributed by 
33  *              Maxim Sobolev <sobomax@FreeBSD.org> and heavily modified by me
34  *              (andrei)
35  * 2003-01-24  added i param to via of outgoing requests (used by tcp),
36  *              modified via_builder params (andrei)
37  * 2003-01-27  more rport fixes (make use of new via_param->start)  (andrei)
38  * 2003-01-27  next baby-step to removing ZT - PRESERVE_ZT (jiri)
39  * 2003-01-29  scratchpad removed (jiri)
40  * 2003-02-28  scratchpad compatibility abandoned (jiri)
41  * 2003-03-01  VOICE_MAIL defs removed (jiri)
42  * 2003-03-06  totags in outgoing replies bookmarked to enable
43  *             ACK/200 tag matching (andrei)
44  * 2003-03-18  killed the build_warning snprintf (andrei)
45  * 2003-03-31  added subst lump support (andrei)
46  * 2003-04-01  added opt (conditional) lump support (andrei)
47  *
48  */
49
50
51
52 #include <sys/types.h>
53 #include <sys/socket.h>
54 #include <netdb.h>
55 #include <string.h>
56 #include <stdio.h>
57 #include <stdlib.h>
58
59 #include "comp_defs.h"
60 #include "msg_translator.h"
61 #include "globals.h"
62 #include "error.h"
63 #include "mem/mem.h"
64 #include "dprint.h"
65 #include "config.h"
66 #include "md5utils.h"
67 #include "data_lump_rpl.h"
68 #include "ip_addr.h"
69 #include "resolve.h"
70 #include "ut.h"
71 #include "pt.h"
72
73
74 #define append_str(_dest,_src,_len) \
75         do{\
76                 memcpy( (_dest) , (_src) , (_len) );\
77                 (_dest) += (_len) ;\
78         }while(0);
79
80 #define append_str_trans(_dest,_src,_len,_msg) \
81         append_str( (_dest), (_src), (_len) );
82
83 extern char version[];
84 extern int version_len;
85
86
87
88
89
90 /* checks if ip is in host(name) and ?host(ip)=name?
91  * ip must be in network byte order!
92  *  resolver = DO_DNS | DO_REV_DNS; if 0 no dns check is made
93  * return 0 if equal */
94 static int check_via_address(struct ip_addr* ip, str *name, 
95                                 unsigned short port, int resolver)
96 {
97         struct hostent* he;
98         int i;
99         char* s;
100
101         /* maybe we are lucky and name it's an ip */
102         s=ip_addr2a(ip);
103         if (s){
104                 DBG("check_address(%s, %.*s, %d)\n", 
105                         s, name->len, name->s, resolver);
106
107         #ifdef USE_IPV6
108                 if ((ip->af==AF_INET6) && (strncasecmp(name->s, s, name->len)==0))
109                         return 0;
110                 else
111         #endif
112
113                         if (strncmp(name->s, s, name->len)==0) 
114                                 return 0;
115         }else{
116                 LOG(L_CRIT, "check_address: BUG: could not convert ip address\n");
117                 return -1;
118         }
119
120         if (port==0) port=SIP_PORT;
121         if (resolver&DO_DNS){
122                 DBG("check_address: doing dns lookup\n");
123                 /* try all names ips */
124                 he=sip_resolvehost(name, &port, 0); /* FIXME proto? */
125                 if (he && ip->af==he->h_addrtype){
126                         for(i=0;he && he->h_addr_list[i];i++){
127                                 if ( memcmp(&he->h_addr_list[i], ip->u.addr, ip->len)==0)
128                                         return 0;
129                         }
130                 }
131         }
132         if (resolver&DO_REV_DNS){
133                 DBG("check_address: doing rev. dns lookup\n");
134                 /* try reverse dns */
135                 he=rev_resolvehost(ip);
136                 if (he && (strncmp(he->h_name, name->s, name->len)==0))
137                         return 0;
138                 for (i=0; he && he->h_aliases[i];i++){
139                         if (strncmp(he->h_aliases[i],name->s, name->len)==0)
140                                 return 0;
141                 }
142         }
143         return -1;
144 }
145
146
147 static char * warning_builder( struct sip_msg *msg, unsigned int *returned_len)
148 {
149         static char buf[MAX_WARNING_LEN];
150         static unsigned int fix_len=0;
151         str *foo;
152         int print_len, l;
153         int clen;
154         char* t;
155
156 #define str_pair_print(string, string2, string2_len) \
157                 do{ \
158                         l=strlen((string)); \
159                 if ((clen+(string2_len)+l)>MAX_WARNING_LEN) \
160                         goto error_overflow; \
161                 memcpy(buf+clen, (string), l); \
162                 clen+=l; \
163                 memcpy(buf+clen, (string2), (string2_len)); \
164                 clen+=(string2_len); }while(0)
165                 
166                 
167 #define str_int_print(string, intval)\
168                 do{\
169                         t=int2str((intval), &print_len); \
170                         str_pair_print(string, t, print_len);\
171                 } while(0)
172                 
173 #define str_ipaddr_print(string, ipaddr_val)\
174                 do{\
175                         t=ip_addr2a((ipaddr_val)); \
176                         print_len=strlen(t); \
177                         str_pair_print(string, t, print_len);\
178                 } while(0)
179         
180         if (!fix_len)
181         {
182                 memcpy(buf+fix_len,WARNING, WARNING_LEN);
183                 fix_len +=WARNING_LEN;
184                 memcpy(buf+fix_len, bind_address->name.s,bind_address->name.len);
185                 fix_len += bind_address->name.len;
186                 *(buf+fix_len) = ':'; fix_len++;
187                 memcpy(buf+fix_len,bind_address->port_no_str.s,
188                         bind_address->port_no_str.len);
189                 fix_len += bind_address->port_no_str.len;
190                 memcpy(buf+fix_len, WARNING_PHRASE,WARNING_PHRASE_LEN);
191                 fix_len += WARNING_PHRASE_LEN;
192         }
193         
194         /*adding out_uri*/
195         if (msg->new_uri.s)
196                 foo=&(msg->new_uri);
197         else
198                 foo=&(msg->first_line.u.request.uri);
199                 clen=fix_len;
200                 
201                 /* pid= */
202                 str_int_print("pid=", my_pid());
203                 /* req_src_ip= */
204                 str_ipaddr_print(" req_src_ip=", &msg->rcv.src_ip);
205                 str_int_print(" req_src_port=", ntohs(msg->rcv.src_port));
206                 str_pair_print(" in_uri=", msg->first_line.u.request.uri.s,
207                                                                         msg->first_line.u.request.uri.len);
208                 str_pair_print(" out_uri=", foo->s, foo->len);
209                 str_pair_print(" via_cnt", msg->parsed_flag & HDR_EOH ? "=" : ">", 1);
210                 str_int_print("=", via_cnt);
211                 if (clen<MAX_WARNING_LEN){ buf[clen]='"'; clen++; }
212                 else goto error_overflow;
213                 
214                 
215                 *returned_len=clen;
216                 return buf;
217 error_overflow:
218                 LOG(L_ERR, "ERROR: warning_builder: buffer size exceeded\n");
219                 *returned_len=0;
220                 return 0;
221 }
222
223
224
225
226 char* received_builder(struct sip_msg *msg, unsigned int *received_len)
227 {
228         char *buf;
229         int  len;
230         struct ip_addr *source_ip;
231         char *tmp;
232         int  tmp_len;
233         int extra_len;
234
235         extra_len = 0;
236         source_ip=&msg->rcv.src_ip;
237
238         buf=pkg_malloc(sizeof(char)*MAX_RECEIVED_SIZE);
239         if (buf==0){
240                 ser_error=E_OUT_OF_MEM;
241                 LOG(L_ERR, "ERROR: received_builder: out of memory\n");
242                 return 0;
243         }
244         memcpy(buf, RECEIVED, RECEIVED_LEN);
245         if ( (tmp=ip_addr2a(source_ip))==0)
246                 return 0; /* error*/
247         tmp_len=strlen(tmp);
248         len=RECEIVED_LEN+tmp_len;
249         if(source_ip->af==AF_INET6){
250                 len+=2;
251                 buf[RECEIVED_LEN]='[';
252                 buf[RECEIVED_LEN+tmp_len+1]=']';
253                 extra_len=1;
254         }
255         
256         memcpy(buf+RECEIVED_LEN+extra_len, tmp, tmp_len);
257         buf[len]=0; /*null terminate it */
258
259         *received_len = len;
260         return buf;
261 }
262
263
264
265 char* rport_builder(struct sip_msg *msg, unsigned int *rport_len)
266 {
267         char* buf;
268         char* tmp;
269         int tmp_len;
270         int len;
271         
272         tmp_len=0;
273         tmp=int2str(ntohs(msg->rcv.src_port), &tmp_len);
274         len=RPORT_LEN+tmp_len;
275         buf=pkg_malloc(sizeof(char)*(len+1));/* space for null term */
276         if (buf==0){
277                 ser_error=E_OUT_OF_MEM;
278                 LOG(L_ERR, "ERROR: rport_builder: out of memory\n");
279                 return 0;
280         }
281         memcpy(buf, RPORT, RPORT_LEN);
282         memcpy(buf+RPORT_LEN, tmp, tmp_len);
283         buf[len]=0; /*null terminate it*/
284         
285         *rport_len=len;
286         return buf;
287 }
288
289
290
291 char* id_builder(struct sip_msg* msg, unsigned int *id_len)
292 {
293         char* buf;
294         int len, value_len;
295         char revhex[sizeof(int)*2];
296         char* p;
297         int size;
298         
299         size=sizeof(int)*2;
300         p=&revhex[0];
301         if (int2reverse_hex(&p, &size, msg->rcv.proto_reserved1)==-1){
302                 LOG(L_CRIT, "BUG: id_builder: not enough space for id\n");
303                 return 0;
304         }
305         value_len=p-&revhex[0];
306         len=ID_PARAM_LEN+value_len; 
307         buf=pkg_malloc(sizeof(char)*(len+1));/* place for ending \0 */
308         if (buf==0){
309                 ser_error=E_OUT_OF_MEM;
310                 LOG(L_ERR, "ERROR: rport_builder: out of memory\n");
311                 return 0;
312         }
313         memcpy(buf, ID_PARAM, ID_PARAM_LEN);
314         memcpy(buf+ID_PARAM_LEN, revhex, value_len);
315         buf[len]=0; /* null terminate it */
316         *id_len=len;
317         return buf;
318 }
319
320
321
322 char* clen_builder(struct sip_msg* msg, unsigned int *clen_len)
323 {
324         char* buf;
325         int len;
326         int value;
327         char* value_s;
328         int value_len;
329         char* body;
330         
331         
332         body=get_body(msg);
333         if (body==0){
334                 ser_error=E_BAD_REQ;
335                 LOG(L_ERR, "ERROR: clen_builder: no message body found"
336                                         " (missing crlf?)");
337                 return 0;
338         }
339         value=msg->len-(int)(body-msg->buf);
340         value_s=int2str(value, &value_len);
341         DBG("clen_builder: content-length: %d (%s)\n", value, value_s);
342                 
343         len=CONTENT_LENGTH_LEN+value_len+CRLF_LEN;
344         buf=pkg_malloc(sizeof(char)*(len+1));
345         if (buf==0){
346                 ser_error=E_OUT_OF_MEM;
347                 LOG(L_ERR, "ERROR: clen_builder: out of memory\n");
348                 return 0;
349         }
350         memcpy(buf, CONTENT_LENGTH, CONTENT_LENGTH_LEN);
351         memcpy(buf+CONTENT_LENGTH_LEN, value_s, value_len);
352         memcpy(buf+CONTENT_LENGTH_LEN+value_len, CRLF, CRLF_LEN);
353         buf[len]=0; /* null terminate it */
354         *clen_len=len;
355         return buf;
356 }
357
358
359
360 /* checks if a lump opt condition 
361  * returns 1 if cond is true, 0 if false */
362 static inline int lump_check_opt(       enum lump_conditions cond,
363                                                                         struct sip_msg* msg,
364                                                                         struct socket_info* snd_s
365                                                                         )
366 {
367         struct ip_addr* ip;
368         unsigned short port;
369         int proto;
370
371 #define get_ip_port_proto \
372                         if (snd_s==0){ \
373                                 LOG(L_CRIT, "ERROR: lump_check_opt: null send socket\n"); \
374                                 return 1; /* we presume they are different :-) */ \
375                         } \
376                         if (msg->rcv.bind_address){ \
377                                 ip=&msg->rcv.bind_address->address; \
378                                 port=msg->rcv.bind_address->port_no; \
379                                 proto=msg->rcv.bind_address->proto; \
380                         }else{ \
381                                 ip=&msg->rcv.dst_ip; \
382                                 port=msg->rcv.dst_port; \
383                                 proto=msg->rcv.proto; \
384                         } \
385                         
386         switch(cond){
387                 case COND_FALSE:
388                         return 0;
389                 case COND_TRUE:
390                         return 1;
391                 case COND_IF_DIFF_REALMS:
392                         get_ip_port_proto;
393                         /* faster tests first */
394                         if ((port==snd_s->port_no)&&(proto==snd_s->proto)&&
395                                 (ip_addr_cmp(ip, &snd_s->address)))
396                                 return 0;
397                         else return 1;
398                 case COND_IF_DIFF_AF:
399                         get_ip_port_proto;
400                         if (ip->af!=snd_s->address.af) return 1;
401                         else return 0;
402                 case COND_IF_DIFF_PROTO:
403                         get_ip_port_proto;
404                         if (proto!=snd_s->proto) return 1;
405                         else return 0;
406                 case COND_IF_DIFF_PORT:
407                         get_ip_port_proto;
408                         if (port!=snd_s->port_no) return 1;
409                         else return 0;
410                 case COND_IF_DIFF_IP:
411                         get_ip_port_proto;
412                         if (ip_addr_cmp(ip, &snd_s->address)) return 0;
413                         else return 1;
414                 case COND_IF_RAND:
415                         return (rand()>=RAND_MAX/2);
416                 default:
417                         LOG(L_CRIT, "BUG: lump_check_opt: unknown lump condition %d\n",
418                                         cond);
419         }
420         return 0; /* false */
421 }
422
423
424
425 /* computes the "unpacked" len of a lump list,
426    code moved from build_req_from_req */
427 static inline int lumps_len(struct sip_msg* msg, struct socket_info* send_sock)
428 {
429         int s_offset;
430         int new_len;
431         struct lump* t;
432         struct lump* r;
433
434 #define SUBST_LUMP_LEN(subst_l) \
435                 switch((subst_l)->u.subst){ \
436                         case SUBST_RCV_IP: \
437                                 if (msg->rcv.bind_address){ \
438                                         new_len+=msg->rcv.bind_address->address_str.len; \
439                                         if (msg->rcv.bind_address->address.af!=AF_INET) \
440                                                 new_len+=2; \
441                                 }else{ \
442                                         /* FIXME */ \
443                                         LOG(L_CRIT, "FIXME: null bind_address\n"); \
444                                 }; \
445                                 break; \
446                         case SUBST_RCV_PORT: \
447                                 if (msg->rcv.bind_address){ \
448                                         new_len+=msg->rcv.bind_address->port_no_str.len; \
449                                 }else{ \
450                                         /* FIXME */ \
451                                         LOG(L_CRIT, "FIXME: null bind_address\n"); \
452                                 }; \
453                                 break; \
454                         case SUBST_RCV_PROTO: \
455                                 if (msg->rcv.bind_address){ \
456                                         new_len+=send_sock->port_no_str.len; \
457                                 }else{ \
458                                         /* FIXME */ \
459                                         LOG(L_CRIT, "FIXME: null bind_address\n"); \
460                                 }; \
461                                 break; \
462                         case SUBST_SND_IP: \
463                                 if (send_sock){ \
464                                         new_len+=send_sock->address_str.len; \
465                                         if (send_sock->address.af!=AF_INET) \
466                                                 new_len+=2; \
467                                 }else{ \
468                                         LOG(L_CRIT, "FIXME: lumps_len called with" \
469                                                         " null send_sock\n"); \
470                                 }; \
471                                 break; \
472                         case SUBST_SND_PORT: \
473                                 if (send_sock){ \
474                                         new_len+=send_sock->port_no_str.len; \
475                                 }else{ \
476                                         LOG(L_CRIT, "FIXME: lumps_len called with" \
477                                                         " null send_sock\n"); \
478                                 }; \
479                                 break; \
480                         case SUBST_SND_PROTO: \
481                                 if (send_sock){ \
482                                         new_len+=3; /* tcp, udp or tls*/ \
483                                 }else{ \
484                                         LOG(L_CRIT, "FIXME: lumps_len called with" \
485                                                         " null send_sock\n"); \
486                                 }; \
487                                 break; \
488                         case SUBST_NOP: /* do nothing */ \
489                                 break; \
490                         default: \
491                                 LOG(L_CRIT, "BUG: unknown subst type %d\n", \
492                                                 (subst_l)->u.subst); \
493                 }
494         
495         s_offset=0;
496         new_len=0;
497         
498         for(t=msg->add_rm;t;t=t->next){
499                 /* skip if this is an OPT lump and the condition is not satisfied */
500                 if ((t->op==LUMP_ADD_OPT) && !lump_check_opt(t->u.cond, msg, send_sock))
501                         continue;
502                 for(r=t->before;r;r=r->before){
503                         switch(r->op){
504                                 case LUMP_ADD:
505                                         new_len+=r->len;
506                                         break;
507                                 case LUMP_ADD_SUBST:
508                                         SUBST_LUMP_LEN(r);
509                                         break;
510                                 case LUMP_ADD_OPT:
511                                         /* skip if this is an OPT lump and the condition is 
512                                          * not satisfied */
513                                         if (!lump_check_opt(r->u.cond, msg, send_sock))
514                                                 goto skip_before;
515                                         break;
516                                 default:
517                                         /* only ADD allowed for before/after */
518                                                 LOG(L_CRIT, "BUG: lumps_len: invalid op "
519                                                         "for data lump (%x)\n", r->op);
520                         }
521                 }
522 skip_before:
523                 switch(t->op){
524                         case LUMP_ADD:
525                                 new_len+=t->len;
526                                 break;
527                         case LUMP_ADD_SUBST:
528                                 SUBST_LUMP_LEN(t);
529                                 break;
530                         case LUMP_ADD_OPT:
531                                 /* we don't do anything here, it's only a condition for
532                                  * before & after */
533                                 break;
534                         case LUMP_DEL:
535                                 /* fix overlapping deleted zones */
536                                 if (t->u.offset < s_offset){
537                                         /* change len */
538                                         if (t->len>s_offset-t->u.offset)
539                                                         t->len-=s_offset-t->u.offset;
540                                         else t->len=0;
541                                         t->u.offset=s_offset;
542                                 }
543                                 s_offset=t->u.offset+t->len;
544                                 new_len-=t->len;
545                                 break;
546                         case LUMP_NOP:
547                                 /* fix offset if overlapping on a deleted zone */
548                                 if (t->u.offset < s_offset){
549                                         t->u.offset=s_offset;
550                                 }else
551                                         s_offset=t->u.offset;
552                                 /* do nothing */
553                                 break;
554                         default:
555                                 LOG(L_CRIT,"BUG:lumps_len: invalid"
556                                                         " op for data lump (%x)\n", r->op);
557                 }
558                 for (r=t->after;r;r=r->after){
559                         switch(r->op){
560                                 case LUMP_ADD:
561                                         new_len+=r->len;
562                                         break;
563                                 case LUMP_ADD_SUBST:
564                                         SUBST_LUMP_LEN(r);
565                                         break;
566                                 case LUMP_ADD_OPT:
567                                         /* skip if this is an OPT lump and the condition is 
568                                          * not satisfied */
569                                         if (!lump_check_opt(r->u.cond, msg, send_sock))
570                                                 goto skip_after;
571                                         break;
572                                 default:
573                                         /* only ADD allowed for before/after */
574                                         LOG(L_CRIT, "BUG:lumps_len: invalid"
575                                                                 " op for data lump (%x)\n", r->op);
576                         }
577                 }
578 skip_after:
579         }
580         return new_len;
581 }
582
583
584
585 /* another helper functions, adds/Removes the lump,
586         code moved form build_req_from_req  */
587
588 static inline void process_lumps(       struct sip_msg* msg,    
589                                                                         char* new_buf, 
590                                                                         unsigned int* new_buf_offs, 
591                                                                         unsigned int* orig_offs,
592                                                                         struct socket_info* send_sock)
593 {
594         struct lump *t;
595         struct lump *r;
596         char* orig;
597         int size;
598         int offset;
599         int s_offset;
600
601 #define SUBST_LUMP(subst_l) \
602         switch((subst_l)->u.subst){ \
603                 case SUBST_RCV_IP: \
604                         if (msg->rcv.bind_address){  \
605                                 if (msg->rcv.bind_address->address.af!=AF_INET){\
606                                         new_buf[offset]='['; offset++; \
607                                 }\
608                                 memcpy(new_buf+offset, msg->rcv.bind_address->address_str.s, \
609                                                 msg->rcv.bind_address->address_str.len); \
610                                 offset+=msg->rcv.bind_address->address_str.len; \
611                                 if (msg->rcv.bind_address->address.af!=AF_INET){\
612                                         new_buf[offset]=']'; offset++; \
613                                 }\
614                         }else{  \
615                                 /*FIXME*/ \
616                                 LOG(L_CRIT, "FIXME: process_lumps: null bind_address\n"); \
617                         }; \
618                         break; \
619                 case SUBST_RCV_PORT: \
620                         if (msg->rcv.bind_address){  \
621                                 memcpy(new_buf+offset, msg->rcv.bind_address->port_no_str.s, \
622                                                 msg->rcv.bind_address->port_no_str.len); \
623                                 offset+=msg->rcv.bind_address->port_no_str.len; \
624                         }else{  \
625                                 /*FIXME*/ \
626                                 LOG(L_CRIT, "FIXME: process_lumps: null bind_address\n"); \
627                         }; \
628                         break; \
629                 case SUBST_SND_IP: \
630                         if (send_sock){  \
631                                 if (send_sock->address.af!=AF_INET){\
632                                         new_buf[offset]='['; offset++; \
633                                 }\
634                                 memcpy(new_buf+offset, send_sock->address_str.s, \
635                                                                         send_sock->address_str.len); \
636                                 offset+=send_sock->address_str.len; \
637                                 if (send_sock->address.af!=AF_INET){\
638                                         new_buf[offset]=']'; offset++; \
639                                 }\
640                         }else{  \
641                                 /*FIXME*/ \
642                                 LOG(L_CRIT, "FIXME: process_lumps: called with" \
643                                                         " null send_sock\n"); \
644                         }; \
645                         break; \
646                 case SUBST_SND_PORT: \
647                         if (send_sock){  \
648                                 memcpy(new_buf+offset, send_sock->port_no_str.s, \
649                                                                         send_sock->port_no_str.len); \
650                                 offset+=send_sock->port_no_str.len; \
651                         }else{  \
652                                 /*FIXME*/ \
653                                 LOG(L_CRIT, "FIXME: process_lumps: called with" \
654                                                 " null send_sock\n"); \
655                         }; \
656                         break; \
657                 case SUBST_RCV_PROTO: \
658                         if (msg->rcv.bind_address){ \
659                                 switch(msg->rcv.bind_address->proto){ \
660                                         case PROTO_NONE: \
661                                         case PROTO_UDP: \
662                                                 memcpy(new_buf+offset, "udp", 3); \
663                                                 offset+=3; \
664                                                 break; \
665                                         case PROTO_TCP: \
666                                                 memcpy(new_buf+offset, "tcp", 3); \
667                                                 offset+=3; \
668                                                 break; \
669                                         case PROTO_TLS: \
670                                                 memcpy(new_buf+offset, "tls", 3); \
671                                                 offset+=3; \
672                                                 break; \
673                                         default: \
674                                                 LOG(L_CRIT, "BUG: process_lumps: unknown proto %d\n", \
675                                                                 msg->rcv.bind_address->proto); \
676                                 } \
677                         }else{  \
678                                 /*FIXME*/ \
679                                 LOG(L_CRIT, "FIXME: process lumps: null bind_address\n"); \
680                         }; \
681                         break; \
682                 case  SUBST_SND_PROTO: \
683                         if (send_sock){ \
684                                 switch(send_sock->proto){ \
685                                         case PROTO_NONE: \
686                                         case PROTO_UDP: \
687                                                 memcpy(new_buf+offset, "udp", 3); \
688                                                 offset+=3; \
689                                                 break; \
690                                         case PROTO_TCP: \
691                                                 memcpy(new_buf+offset, "tcp", 3); \
692                                                 offset+=3; \
693                                                 break; \
694                                         case PROTO_TLS: \
695                                                 memcpy(new_buf+offset, "tls", 3); \
696                                                 offset+=3; \
697                                                 break; \
698                                         default: \
699                                                 LOG(L_CRIT, "BUG: process_lumps: unknown proto %d\n", \
700                                                                 send_sock->proto); \
701                                 } \
702                         }else{  \
703                                 /*FIXME*/ \
704                                 LOG(L_CRIT, "FIXME: process_lumps: called with null" \
705                                                         " send_sock \n"); \
706                         }; \
707                         break; \
708                 default: \
709                                         LOG(L_CRIT, "BUG: process_lumps: unknown subst type %d\n", \
710                                                         (subst_l)->u.subst); \
711         } \
712  \
713         
714         
715         
716         orig=msg->buf;
717         offset=*new_buf_offs;
718         s_offset=*orig_offs;
719         
720         for (t=msg->add_rm;t;t=t->next){
721                 switch(t->op){
722                         case LUMP_ADD:
723                         case LUMP_ADD_SUBST:
724                         case LUMP_ADD_OPT:
725                                 /* skip if this is an OPT lump and the condition is 
726                                  * not satisfied */
727                                 if ((t->op==LUMP_ADD_OPT) &&
728                                                 (!lump_check_opt(t->u.cond, msg, send_sock))) 
729                                         continue;
730                                 break;
731                                 /* just add it here! */
732                                 /* process before  */
733                                 for(r=t->before;r;r=r->before){
734                                         switch (r->op){
735                                                 case LUMP_ADD:
736                                                         /*just add it here*/
737                                                         memcpy(new_buf+offset, r->u.value, r->len);
738                                                         offset+=r->len;
739                                                         break;
740                                                 case LUMP_ADD_SUBST:
741                                                         SUBST_LUMP(r);
742                                                         break;
743                                                 case LUMP_ADD_OPT:
744                                                         /* skip if this is an OPT lump and the condition is 
745                                                         * not satisfied */
746                                                         if (!lump_check_opt(r->u.cond, msg, send_sock))
747                                                                 goto skip_before;
748                                                         break;
749                                                 default:
750                                                         /* only ADD allowed for before/after */
751                                                         LOG(L_CRIT, "BUG:process_lumps: "
752                                                                         "invalid op for data lump (%x)\n", r->op);
753                                         }
754                                 }
755 skip_before:
756                                 /* copy "main" part */
757                                 switch(t->op){
758                                         case LUMP_ADD:
759                                                 memcpy(new_buf+offset, t->u.value, t->len);
760                                                 offset+=t->len;
761                                                 break;
762                                         case LUMP_ADD_SUBST:
763                                                 SUBST_LUMP(t);
764                                                 break;
765                                         case LUMP_ADD_OPT:
766                                                 /* do nothing, it's only a condition */
767                                                 break;
768                                         default: 
769                                                 /* should not ever get here */
770                                                 LOG(L_CRIT, "BUG: process_lumps: unhandled data lump "
771                                                                 " op %d\n", t->op);
772                                 }
773                                 /* process after */
774                                 for(r=t->after;r;r=r->after){
775                                         switch (r->op){
776                                                 case LUMP_ADD:
777                                                         /*just add it here*/
778                                                         memcpy(new_buf+offset, r->u.value, r->len);
779                                                         offset+=r->len;
780                                                         break;
781                                                 case LUMP_ADD_SUBST:
782                                                         SUBST_LUMP(r);
783                                                         break;
784                                                 case LUMP_ADD_OPT:
785                                                         /* skip if this is an OPT lump and the condition is 
786                                                         * not satisfied */
787                                                         if (!lump_check_opt(r->u.cond, msg, send_sock))
788                                                                 goto skip_after;
789                                                         break;
790                                                 default:
791                                                         /* only ADD allowed for before/after */
792                                                         LOG(L_CRIT, "BUG:process_lumps: "
793                                                                         "invalid op for data lump (%x)\n", r->op);
794                                         }
795                                 }
796 skip_after:
797                                 break;
798                         case LUMP_NOP:
799                         case LUMP_DEL:
800                                 /* copy till offset */
801                                 if (s_offset>t->u.offset){
802                                         DBG("Warning: (%d) overlapped lumps offsets,"
803                                                 " ignoring(%x, %x)\n", t->op, s_offset,t->u.offset);
804                                         /* this should've been fixed above (when computing len) */
805                                         /* just ignore it*/
806                                         break;
807                                 }
808                                 size=t->u.offset-s_offset;
809                                 if (size){
810                                         memcpy(new_buf+offset, orig+s_offset,size);
811                                         offset+=size;
812                                         s_offset+=size;
813                                 }
814                                 /* process before  */
815                                 for(r=t->before;r;r=r->before){
816                                         switch (r->op){
817                                                 case LUMP_ADD:
818                                                         /*just add it here*/
819                                                         memcpy(new_buf+offset, r->u.value, r->len);
820                                                         offset+=r->len;
821                                                         break;
822                                                 case LUMP_ADD_SUBST:
823                                                         SUBST_LUMP(r);
824                                                         break;
825                                                 case LUMP_ADD_OPT:
826                                                         /* skip if this is an OPT lump and the condition is 
827                                                         * not satisfied */
828                                                         if (!lump_check_opt(r->u.cond, msg, send_sock))
829                                                                 goto skip_nop_before;
830                                                         break;
831                                                 default:
832                                                         /* only ADD allowed for before/after */
833                                                         LOG(L_CRIT, "BUG:process_lumps: "
834                                                                         "invalid op for data lump (%x)\n",r->op);
835                                         }
836                                 }
837 skip_nop_before:
838                                 /* process main (del only) */
839                                 if (t->op==LUMP_DEL){
840                                         /* skip len bytes from orig msg */
841                                         s_offset+=t->len;
842                                 }
843                                 /* process after */
844                                 for(r=t->after;r;r=r->after){
845                                         switch (r->op){
846                                                 case LUMP_ADD:
847                                                         /*just add it here*/
848                                                         memcpy(new_buf+offset, r->u.value, r->len);
849                                                         offset+=r->len;
850                                                         break;
851                                                 case LUMP_ADD_SUBST:
852                                                         SUBST_LUMP(r);
853                                                         break;
854                                                 case LUMP_ADD_OPT:
855                                                         /* skip if this is an OPT lump and the condition is 
856                                                         * not satisfied */
857                                                         if (!lump_check_opt(r->u.cond, msg, send_sock)) 
858                                                                 goto skip_nop_after;
859                                                         break;
860                                                 default:
861                                                         /* only ADD allowed for before/after */
862                                                         LOG(L_CRIT, "BUG:process_lumps: "
863                                                                         "invalid op for data lump (%x)\n", r->op);
864                                         }
865                                 }
866 skip_nop_after:
867                                 break;
868                         default:
869                                         LOG(L_CRIT, "BUG: process_lumps: "
870                                                         "unknown op (%x)\n", t->op);
871                 }
872         }
873         *new_buf_offs=offset;
874         *orig_offs=s_offset;
875 }
876
877
878
879 char * build_req_buf_from_sip_req( struct sip_msg* msg,
880                                                                 unsigned int *returned_len,
881                                                                 struct socket_info* send_sock, int proto)
882 {
883         unsigned int len, new_len, received_len, rport_len, uri_len, via_len;
884         char* line_buf;
885         char* received_buf;
886         char* rport_buf;
887         char* new_buf;
888         char* buf;
889         unsigned int offset, s_offset, size;
890         struct lump* anchor;
891         int r;
892         str branch;
893         str extra_params;
894         
895 #ifdef USE_TCP
896         char* id_buf;
897         unsigned int id_len;
898         char* clen_buf;
899         unsigned int clen_len;
900         
901         
902         id_buf=0;
903         id_len=0;
904         clen_buf=0;
905         clen_len=0;
906 #endif
907         extra_params.len=0;
908         extra_params.s=0;
909         uri_len=0;
910         buf=msg->buf;
911         len=msg->len;
912         received_len=0;
913         rport_len=0;
914         new_buf=0;
915         received_buf=0;
916         rport_buf=0;
917         line_buf=0;
918
919         
920 #ifdef USE_TCP
921         /* add id if tcp */
922         if (msg->rcv.proto==PROTO_TCP){
923                 if  ((id_buf=id_builder(msg, &id_len))==0){
924                         LOG(L_ERR, "ERROR: build_req_buf_from_sip_req:"
925                                                         " id_builder failed\n");
926                         goto error01; /* free everything */
927                 }
928                 extra_params.s=id_buf;
929                 extra_params.len=id_len;
930         }
931         /* if sending proto == tcp, check if Content-Length needs to be added*/
932         if (proto==PROTO_TCP){
933                 /* first of all parse content-length */
934                 if (parse_headers(msg, HDR_CONTENTLENGTH, 0)==-1){
935                         LOG(L_ERR, "build_req_buf_from_sip_req:"
936                                                         " error parsing content-length\n");
937                         goto skip_clen;
938                 }
939                 if (msg->content_length==0){
940                         /* we need to add it */
941                         if ((clen_buf=clen_builder(msg, &clen_len))==0){
942                                 LOG(L_ERR, "build_req_buf_from_sip_req:" 
943                                                                 " clen_builder failed\n");
944                                 goto skip_clen;
945                         }
946                 }
947         }
948 skip_clen:
949 #endif
950         branch.s=msg->add_to_branch_s;
951         branch.len=msg->add_to_branch_len;
952         line_buf = via_builder( &via_len, send_sock, &branch,
953                                                         extra_params.len?&extra_params:0, proto);
954         if (!line_buf){
955                 LOG(L_ERR,"ERROR: build_req_buf_from_sip_req: no via received!\n");
956                 goto error00;
957         }
958         /* check if received needs to be added */
959         r=check_via_address(&msg->rcv.src_ip, &msg->via1->host, 
960                 msg->via1->port, received_dns);
961         if (r!=0){
962                 if ((received_buf=received_builder(msg,&received_len))==0){
963                         LOG(L_ERR, "ERROR: build_req_buf_from_sip_req:"
964                                                         " received_builder failed\n");
965                         goto error01;  /* free also line_buf */
966                 }
967         }
968         
969         /* check if rport needs to be updated */
970         if (msg->via1->rport && msg->via1->rport->value.s==0){
971                 if ((rport_buf=rport_builder(msg, &rport_len))==0){
972                         LOG(L_ERR, "ERROR: build_req_buf_from_sip_req:"
973                                                         " rport_builder failed\n");
974                         goto error01; /* free everything */
975                 }
976         }
977
978         /* add via header to the list */
979         /* try to add it before msg. 1st via */
980         /* add first via, as an anchor for second via*/
981         anchor=anchor_lump(&(msg->add_rm), msg->via1->hdr.s-buf, 0, HDR_VIA);
982         if (anchor==0) goto error01;
983         if (insert_new_lump_before(anchor, line_buf, via_len, HDR_VIA)==0)
984                 goto error01;
985         /* if received needs to be added, add anchor after host and add it */
986         if (received_len){
987                 if (msg->via1->params.s){
988                                 size= msg->via1->params.s-msg->via1->hdr.s-1; /*compensate
989                                                                                                                           for ';' */
990                 }else{
991                                 size= msg->via1->host.s-msg->via1->hdr.s+msg->via1->host.len;
992                                 if (msg->via1->port!=0){
993                                         /*size+=strlen(msg->via1->hdr.s+size+1)+1;*/
994                                         size += msg->via1->port_str.len + 1; /* +1 for ':'*/
995                                 }
996                         #ifdef USE_IPV6
997                                 if(send_sock->address.af==AF_INET6) size+=1; /* +1 for ']'*/
998                         #endif
999                 }
1000                 anchor=anchor_lump(&(msg->add_rm),msg->via1->hdr.s-buf+size,0,
1001                                 HDR_VIA);
1002                 if (anchor==0) goto error02; /* free received_buf */
1003                 if (insert_new_lump_after(anchor, received_buf, received_len, HDR_VIA)
1004                                 ==0 ) goto error02; /* free received_buf */
1005         }
1006         /* if rport needs to be updated, delete it and add it's value */
1007         if (rport_len){
1008                 anchor=del_lump(&(msg->add_rm), msg->via1->rport->start-buf-1, /*';'*/
1009                                                         msg->via1->rport->size+1 /* ; */, HDR_VIA);
1010                 if (anchor==0) goto error03; /* free rport_buf*/
1011                 if (insert_new_lump_after(anchor, rport_buf, rport_len, HDR_VIA)==0)
1012                         goto error03; /* free rport_buf*/
1013         }
1014 #ifdef USE_TCP
1015         /* if clen needs to be added, add it */
1016         if (clen_len){
1017                 /* msg->unparsed should point just before the final crlf,
1018                  * parse_headers is called from clen_builder */
1019                 anchor=anchor_lump(&(msg->add_rm), msg->unparsed-buf, 0,
1020                                                          HDR_CONTENTLENGTH);
1021                 if (anchor==0) goto error04; /* free clen_buf*/
1022                 if (insert_new_lump_after(anchor, clen_buf, clen_len,
1023                                         HDR_CONTENTLENGTH)==0)
1024                         goto error04; /* free clen_buf*/
1025         }
1026 #endif
1027
1028         /* compute new msg len and fix overlapping zones*/
1029         new_len=len+lumps_len(msg, send_sock);
1030
1031         if (msg->new_uri.s){
1032                 uri_len=msg->new_uri.len;
1033                 new_len=new_len-msg->first_line.u.request.uri.len+uri_len;
1034         }
1035         new_buf=(char*)pkg_malloc(new_len+1);
1036         if (new_buf==0){
1037                 ser_error=E_OUT_OF_MEM;
1038                 LOG(L_ERR, "ERROR: build_req_buf_from_sip_req: out of memory\n");
1039                 goto error00;
1040         }
1041
1042         offset=s_offset=0;
1043         if (msg->new_uri.s){
1044                 /* copy message up to uri */
1045                 size=msg->first_line.u.request.uri.s-buf;
1046                 memcpy(new_buf, buf, size);
1047                 offset+=size;
1048                 s_offset+=size;
1049                 /* add our uri */
1050                 memcpy(new_buf+offset, msg->new_uri.s, uri_len);
1051                 offset+=uri_len;
1052                 s_offset+=msg->first_line.u.request.uri.len; /* skip original uri */
1053         }
1054         new_buf[new_len]=0;
1055         /* copy msg adding/removing lumps */
1056         process_lumps(msg, new_buf, &offset, &s_offset, send_sock);
1057         /* copy the rest of the message */
1058         memcpy(new_buf+offset, buf+s_offset, len-s_offset);
1059         new_buf[new_len]=0;
1060
1061 #ifdef DBG_MSG_QA
1062         if (new_buf[new_len-1]==0) {
1063                 LOG(L_ERR, "ERROR: build_req_buf_from_sip_req: 0 in the end\n");
1064                 abort();
1065         }
1066 #endif
1067
1068         *returned_len=new_len;
1069         return new_buf;
1070
1071 error01:
1072         pkg_free(line_buf);
1073 #ifdef USE_TCP
1074         if (id_buf) pkg_free(id_buf);
1075 #endif
1076 error02:
1077         if (received_buf) pkg_free(received_buf);
1078 error03:
1079         if (rport_buf) pkg_free(rport_buf);
1080 #ifdef USE_TCP
1081 error04:
1082         if (clen_buf) pkg_free(clen_buf);
1083 #endif
1084 error00:
1085         *returned_len=0;
1086         return 0;
1087 }
1088
1089
1090
1091 char * build_res_buf_from_sip_res( struct sip_msg* msg,
1092                                 unsigned int *returned_len)
1093 {
1094         unsigned int new_len, via_len;
1095         char* new_buf;
1096         unsigned offset, s_offset, via_offset;
1097         char* buf;
1098         unsigned int len;
1099 #ifdef USE_TCP
1100         struct lump* anchor;
1101         char* clen_buf;
1102         unsigned int clen_len;
1103         
1104         clen_buf=0;
1105         clen_len=0;
1106 #endif
1107         buf=msg->buf;
1108         len=msg->len;
1109         new_buf=0;
1110         /* we must remove the first via */
1111         if (msg->via1->next) {
1112                 via_len=msg->via1->bsize;
1113                 via_offset=msg->h_via1->body.s-buf;
1114         } else {
1115                 via_len=msg->h_via1->len;
1116                 via_offset=msg->h_via1->name.s-buf;
1117         }
1118
1119 #ifdef USE_TCP
1120
1121         /* if sending proto == tcp, check if Content-Length needs to be added*/
1122         if (msg->via2 && (msg->via2->proto==PROTO_TCP)){
1123                 DBG("build_res_from_sip_res: checking content-length for \n%.*s\n",
1124                                 (int)msg->len, msg->buf);
1125                 /* first of all parse content-length */
1126                 if (parse_headers(msg, HDR_CONTENTLENGTH, 0)==-1){
1127                         LOG(L_ERR, "build_res_buf_from_sip_res:"
1128                                                         " error parsing content-length\n");
1129                         goto skip_clen;
1130                 }
1131                 if (msg->content_length==0){
1132                         DBG("build_res_from_sip_res: no content_length hdr found\n");
1133                         /* we need to add it */
1134                         if ((clen_buf=clen_builder(msg, &clen_len))==0){
1135                                 LOG(L_ERR, "build_res_buf_from_sip_res:" 
1136                                                                 " clen_builder failed\n");
1137                                 goto skip_clen;
1138                         }
1139                 }
1140         }
1141 skip_clen:
1142 #endif
1143         
1144         /* remove the first via*/
1145         if (del_lump( &(msg->add_rm), via_offset, via_len, HDR_VIA)==0){
1146                 LOG(L_ERR, "build_res_buf_from_sip_res: error trying to remove first"
1147                                         "via\n");
1148                 goto error;
1149         }
1150 #ifdef USE_TCP
1151         /* if clen needs to be added, add it */
1152         if (clen_len){
1153                 /* msg->unparsed should point just before the final crlf,
1154                  * parse_headers is called from clen_builder */
1155                 anchor=anchor_lump(&(msg->add_rm), msg->unparsed-buf, 0, 
1156                                                         HDR_CONTENTLENGTH);
1157                 DBG("build_res_from_sip_res: adding content-length: %.*s\n",
1158                                 (int)clen_len, clen_buf);
1159                 if (anchor==0) goto error_clen; /* free clen_buf*/
1160                 if (insert_new_lump_after(anchor, clen_buf, clen_len,
1161                                         HDR_CONTENTLENGTH)==0)
1162                         goto error_clen; /* free clen_buf*/
1163         }
1164 #endif
1165         new_len=len+lumps_len(msg, 0); /*FIXME: we don't know the send sock */
1166         
1167         DBG(" old size: %d, new size: %d\n", len, new_len);
1168         new_buf=(char*)pkg_malloc(new_len+1); /* +1 is for debugging 
1169                                                                                          (\0 to print it )*/
1170         if (new_buf==0){
1171                 LOG(L_ERR, "ERROR: build_res_buf_from_sip_res: out of mem\n");
1172                 goto error;
1173         }
1174         new_buf[new_len]=0; /* debug: print the message */
1175         offset=s_offset=0;
1176         process_lumps(msg, new_buf, &offset, &s_offset, 0); /*FIXME: no send sock*/
1177         /* copy the rest of the message */
1178         memcpy(new_buf+offset,
1179                 buf+s_offset, 
1180                 len-s_offset);
1181          /* send it! */
1182         DBG("build_res_from_sip_res: copied size: orig:%d, new: %d, rest: %d"
1183                         " msg=\n%s\n", s_offset, offset, len-s_offset, new_buf);
1184
1185         *returned_len=new_len;
1186         return new_buf;
1187 #ifdef USE_TCP
1188 error_clen:
1189         if (clen_buf) pkg_free(clen_buf);
1190 #endif
1191 error:
1192         *returned_len=0;
1193         return 0;
1194 }
1195
1196
1197
1198
1199
1200 char * build_res_buf_from_sip_req( unsigned int code, char *text,
1201                                         char *new_tag, unsigned int new_tag_len,
1202                                         struct sip_msg* msg, unsigned int *returned_len,
1203                                         struct bookmark *bmark)
1204 {
1205     return build_res_buf_with_body_from_sip_req(code,text,new_tag,new_tag_len,
1206                                                 0,0, /* no body */
1207                                                 0,0, /* no content type */
1208                                                 msg,returned_len, bmark);
1209 }
1210
1211 char * build_res_buf_with_body_from_sip_req( unsigned int code, char *text ,
1212                                              char *new_tag, unsigned int new_tag_len ,
1213                                              char *body, unsigned int body_len,
1214                                              char *content_type, unsigned int content_type_len,
1215                                              struct sip_msg* msg, unsigned int *returned_len,
1216                                                  struct bookmark *bmark)
1217 {
1218         char              *buf, *p;
1219         unsigned int      len,foo;
1220         struct hdr_field  *hdr;
1221         struct lump_rpl   *lump;
1222         int               i;
1223         char              backup;
1224         char              *received_buf;
1225         char              *rport_buf;
1226         unsigned int      received_len;
1227         unsigned int      rport_len;
1228         unsigned int      delete_len;
1229         char              *warning;
1230         unsigned int      warning_len;
1231         unsigned int      text_len;
1232         int  r;
1233         int  content_len_len;
1234         char *content_len;
1235         char content_len_buf[MAX_CONTENT_LEN_BUF];
1236         char *after_body;
1237         str  to_tag;
1238         char *totags;
1239
1240         received_buf=0;
1241         received_len=0;
1242         rport_buf=0;
1243         rport_len=0;
1244         delete_len=0;
1245         buf=0;
1246         /* make -Wall happy */
1247         warning=0;
1248         content_len=0;
1249
1250         text_len=strlen(text);
1251
1252         /* force parsing all headers -- we want to return all
1253         Via's in the reply and they may be scattered down to the
1254         end of header (non-block Vias are a really poor property
1255         of SIP :( ) */
1256         if (parse_headers( msg, HDR_EOH, 0 )==-1) {
1257                 LOG(L_ERR, "ERROR: build_res_buf_from_sip_req: "
1258                         "alas, parse_headers failed\n");
1259                 goto error00;
1260         }
1261
1262         /* check if received needs to be added */
1263         backup = msg->via1->host.s[msg->via1->host.len];
1264         msg->via1->host.s[msg->via1->host.len] = 0;
1265         r=check_via_address(&msg->rcv.src_ip, &msg->via1->host, 
1266                 msg->via1->port, received_dns);
1267         msg->via1->host.s[msg->via1->host.len] = backup;
1268         if (r!=0) {
1269                 if ((received_buf=received_builder(msg,&received_len))==0) {
1270                         LOG(L_ERR, "ERROR: build_res_buf_from_sip_req: "
1271                                 "alas, received_builder failed\n");
1272                         goto error00;
1273                 }
1274         }
1275         /* check if rport needs to be updated */
1276         if (msg->via1->rport && msg->via1->rport->value.s==0){
1277                 if ((rport_buf=rport_builder(msg, &rport_len))==0){
1278                         LOG(L_ERR, "ERROR: build_res_buf_from_sip_req:"
1279                                                         " rport_builder failed\n");
1280                         goto error01; /* free everything */
1281                 }
1282                 delete_len=msg->via1->rport->size+1; /* include ';' */
1283         }
1284
1285         /*computes the lenght of the new response buffer*/
1286         len = 0;
1287         /* first line */
1288         len += SIP_VERSION_LEN + 1/*space*/ + 3/*code*/ + 1/*space*/ +
1289                 text_len + CRLF_LEN/*new line*/;
1290         /*headers that will be copied (TO, FROM, CSEQ,CALLID,VIA)*/
1291         for ( hdr=msg->headers ; hdr ; hdr=hdr->next ) {
1292                 if (hdr->type==HDR_TO) {
1293                         if (new_tag)
1294                         {
1295                                 to_tag=get_to(msg)->tag_value;
1296                                 if (to_tag.s )
1297                                         len+=new_tag_len-to_tag.len;
1298                                 else
1299                                         len+=new_tag_len+TOTAG_TOKEN_LEN/*";tag="*/;
1300                         }
1301                         else {
1302                                 len+=hdr->len;
1303                                 continue;
1304                         }
1305                 } else if (hdr->type==HDR_VIA) {
1306                                 /* we always add CRLF to via*/
1307                                 len+=(hdr->body.s+hdr->body.len)-hdr->name.s+CRLF_LEN;
1308                                 if (hdr==msg->h_via1) len += received_len+rport_len;
1309                                 continue;
1310                 } else if (hdr->type==HDR_RECORDROUTE) {
1311                                 /* RR only for 1xx and 2xx replies */
1312                                 if (code<180 || code>=300) continue;
1313                 } else if (!(hdr->type==HDR_FROM 
1314                                         || hdr->type==HDR_CALLID
1315                                         || hdr->type==HDR_CSEQ)) {
1316                         continue;
1317                 }
1318                 len += hdr->len; /* we keep the original termination for these 
1319                                                         headers*/
1320         }
1321         len-=delete_len;
1322         /*lumps length*/
1323         for(lump=msg->reply_lump;lump;lump=lump->next)
1324                 len += lump->text.len;
1325         if (server_signature) {
1326                 /*server header*/
1327                 len += SERVER_HDR_LEN + CRLF_LEN;
1328         }
1329
1330         if (body_len) {
1331                 content_len=int2str(body_len, &content_len_len);
1332                 memcpy(content_len_buf,content_len,content_len_len+1);
1333                 content_len = content_len_buf;
1334                 len += CONTENT_LENGTH_LEN + content_len_len + CRLF_LEN;
1335                 len += body_len;
1336         } else {
1337                 len +=CONTENT_LENGTH_LEN+1 + CRLF_LEN;
1338         }
1339         if(content_type_len) {
1340             len += content_type_len + CRLF_LEN;
1341         }
1342
1343         if (sip_warning) {
1344                 warning = warning_builder(msg,&warning_len);
1345                 if (warning) len += warning_len + CRLF_LEN;
1346                 else LOG(L_WARN, "WARNING: warning skipped -- too big\n");
1347         }
1348         /* end of message */
1349         len += CRLF_LEN; /*new line*/
1350
1351         /*allocating mem*/
1352         buf = (char*) pkg_malloc( len+1 );
1353         if (!buf)
1354         {
1355                 LOG(L_ERR, "ERROR: build_res_buf_from_sip_req: out of memory "
1356                         " ; needs %d\n",len);
1357                 goto error01;
1358         }
1359
1360         /* filling the buffer*/
1361         p=buf;
1362         /* first line */
1363         memcpy( p , SIP_VERSION , SIP_VERSION_LEN );
1364         p += SIP_VERSION_LEN;
1365         *(p++) = ' ' ;
1366         /*code*/
1367         for ( i=2 , foo = code  ;  i>=0  ;  i-- , foo=foo/10 )
1368                 *(p+i) = '0' + foo - ( foo/10 )*10;
1369         p += 3;
1370         *(p++) = ' ' ;
1371         memcpy( p , text , text_len );
1372         p += text_len;
1373         memcpy( p, CRLF, CRLF_LEN );
1374         p+=CRLF_LEN;
1375         /* headers*/
1376         for ( hdr=msg->headers ; hdr ; hdr=hdr->next )
1377                 switch (hdr->type)
1378                 {
1379                         case HDR_VIA:
1380                                 if (hdr==msg->h_via1){
1381                                         if (rport_buf){
1382                                                 /* copy until rport */
1383                                                 append_str_trans( p, hdr->name.s ,
1384                                                         msg->via1->rport->start-hdr->name.s-1,msg);
1385                                                 /* copy new rport */
1386                                                 append_str(p, rport_buf, rport_len);
1387                                                 /* copy the rest of the via */
1388                                                 append_str_trans(p, msg->via1->rport->start+
1389                                                                                         msg->via1->rport->size, 
1390                                                                                         hdr->body.s+hdr->body.len-
1391                                                                                         msg->via1->rport->start-
1392                                                                                         msg->via1->rport->size, msg);
1393                                         }else{
1394                                                 /* normal whole via copy */
1395                                                 append_str_trans( p, hdr->name.s , 
1396                                                                 (hdr->body.s+hdr->body.len)-hdr->name.s, msg);
1397                                         }
1398                                         if (received_buf)
1399                                                 append_str( p, received_buf, received_len);
1400                                 }else{
1401                                         /* normal whole via copy */
1402                                         append_str_trans( p, hdr->name.s,
1403                                                         (hdr->body.s+hdr->body.len)-hdr->name.s, msg);
1404                                 }
1405                                 append_str( p, CRLF,CRLF_LEN);
1406                                 break;
1407                         case HDR_RECORDROUTE:
1408                                 /* RR only for 1xx and 2xx replies */
1409                                 if (code<180 || code>=300) break;
1410                                 append_str(p, hdr->name.s, hdr->len);
1411                                 break;
1412                         case HDR_TO:
1413                                 if (new_tag){
1414                                         if (to_tag.s ) { /* replacement */
1415                                                 /* before to-tag */
1416                                                 append_str( p, hdr->name.s, to_tag.s-hdr->name.s);
1417                                                 /* to tag replacement */
1418                                                 bmark->to_tag_val.s=p;
1419                                                 bmark->to_tag_val.len=new_tag_len;
1420                                                 append_str( p, new_tag,new_tag_len);
1421                                                 /* the rest after to-tag */
1422                                                 append_str( p, to_tag.s+to_tag.len,
1423                                                         hdr->name.s+hdr->len-(to_tag.s+to_tag.len));
1424                                         }else{ /* adding a new to-tag */
1425                                                 after_body=hdr->body.s+hdr->body.len;
1426                                                 append_str( p, hdr->name.s, after_body-hdr->name.s);
1427                                                 append_str(p, TOTAG_TOKEN, TOTAG_TOKEN_LEN);
1428                                                 bmark->to_tag_val.s=p;
1429                                                 bmark->to_tag_val.len=new_tag_len;
1430                                                 append_str( p, new_tag,new_tag_len);
1431                                                 append_str( p, after_body, 
1432                                                                                 hdr->name.s+hdr->len-after_body);
1433                                         }
1434                                         break;
1435                                 } /* no new to-tag -- proceed to 1:1 copying  */
1436                                 totags=((struct to_body*)(hdr->parsed))->tag_value.s;
1437                                 if (totags) {
1438                                         bmark->to_tag_val.s=p+(totags-hdr->name.s);
1439                                         bmark->to_tag_val.len=
1440                                                         ((struct to_body*)(hdr->parsed))->tag_value.len;
1441                                 };
1442                         case HDR_FROM:
1443                         case HDR_CALLID:
1444                         case HDR_CSEQ:
1445                                         append_str(p, hdr->name.s, hdr->len);
1446                 } /* for switch */
1447         /*lumps*/
1448         for(lump=msg->reply_lump;lump;lump=lump->next)
1449         {
1450                 memcpy(p,lump->text.s,lump->text.len);
1451                 p += lump->text.len;
1452         }
1453         if (server_signature) {
1454                 /*server header*/
1455                 memcpy( p, SERVER_HDR , SERVER_HDR_LEN );
1456                 p+=SERVER_HDR_LEN;
1457                 memcpy( p, CRLF, CRLF_LEN );
1458                 p+=CRLF_LEN;
1459         }
1460         
1461         if (body_len) {
1462                 memcpy(p, CONTENT_LENGTH, CONTENT_LENGTH_LEN );
1463                 p+=CONTENT_LENGTH_LEN;
1464                 memcpy( p, content_len, content_len_len );
1465                 p+=content_len_len;
1466                 memcpy( p, CRLF, CRLF_LEN );
1467                 p+=CRLF_LEN;
1468         } else {
1469                 /* content length header*/
1470                 memcpy( p, CONTENT_LENGTH "0" CRLF, CONTENT_LENGTH_LEN+1+CRLF_LEN );
1471                 p+=CONTENT_LENGTH_LEN+1+CRLF_LEN;
1472         }
1473         if(content_type_len){
1474             memcpy( p, content_type, content_type_len );
1475             p+=content_type_len;
1476             memcpy( p, CRLF, CRLF_LEN );
1477             p+=CRLF_LEN;
1478         }
1479         if (sip_warning && warning) {
1480                 memcpy( p, warning, warning_len);
1481                 p+=warning_len;
1482                 memcpy( p, CRLF, CRLF_LEN);
1483                 p+=CRLF_LEN;
1484         }
1485         /*end of message*/
1486         memcpy( p, CRLF, CRLF_LEN );
1487         p+=CRLF_LEN;
1488         if(body_len){
1489             memcpy ( p, body, body_len );
1490             p+=body_len;
1491         }
1492         *(p) = 0;
1493         *returned_len = len;
1494         DBG("build_*: len=%d, diff=%d\n", len, p-buf);
1495         DBG("build_*: rport_len=%d, delete_len=%d\n", rport_len, delete_len);
1496         DBG("build_*: message=\n%.*s\n", (int)len, buf);
1497         /* in req2reply, received_buf is not introduced to lumps and
1498            needs to be deleted here
1499         */
1500         if (received_buf) pkg_free(received_buf);
1501         if (rport_buf) pkg_free(rport_buf);
1502         return buf;
1503
1504 error01:
1505         if (received_buf) pkg_free(received_buf);
1506         if (rport_buf) pkg_free(rport_buf);
1507 error00:
1508         *returned_len=0;
1509         return 0;
1510 }
1511
1512 /* return number of chars printed or 0 if space exceeded;
1513    assumes buffer sace of at least MAX_BRANCH_PARAM_LEN
1514  */
1515
1516 int branch_builder( unsigned int hash_index,
1517         /* only either parameter useful */
1518         unsigned int label, char * char_v,
1519         int branch,
1520         char *branch_str, int *len )
1521 {
1522
1523         char *begin;
1524         int size;
1525
1526         /* hash id provided ... start with it */
1527         size=MAX_BRANCH_PARAM_LEN;
1528         begin=branch_str;
1529         *len=0;
1530
1531         memcpy(begin, MCOOKIE, MCOOKIE_LEN );
1532         size-=MCOOKIE_LEN;begin+=MCOOKIE_LEN;
1533
1534         if (int2reverse_hex( &begin, &size, hash_index)==-1)
1535                 return 0;
1536
1537         if (size) {
1538                 *begin=BRANCH_SEPARATOR;
1539                 begin++; size--;
1540         } else return 0;
1541
1542         /* string with request's characteristic value ... use it ... */
1543         if (char_v) {
1544                 if (memcpy(begin,char_v,MD5_LEN)) {
1545                         begin+=MD5_LEN; size-=MD5_LEN;
1546                 } else return 0;
1547         } else { /* ... use the "label" value otherwise */
1548                 if (int2reverse_hex( &begin, &size, label )==-1)
1549                         return 0;
1550         }
1551
1552         if (size) {
1553                 *begin=BRANCH_SEPARATOR;
1554                 begin++; size--;
1555         } else return 0;
1556
1557         if (int2reverse_hex( &begin, &size, branch)==-1)
1558                 return 0;
1559
1560         *len=MAX_BRANCH_PARAM_LEN-size;
1561         return size;
1562                 
1563 }
1564
1565
1566 char* via_builder( unsigned int *len, 
1567         struct socket_info* send_sock,
1568         str* branch, str* extra_params, int proto )
1569 {
1570         unsigned int  via_len, extra_len;
1571         char               *line_buf;
1572         int max_len;
1573
1574
1575         max_len=MY_VIA_LEN+send_sock->address_str.len /* space in MY_VIA */
1576                 +2 /* just in case it is a v6 address ... [ ] */
1577                 +1 /*':'*/+send_sock->port_no_str.len
1578                 +(branch?(MY_BRANCH_LEN+branch->len):0)
1579                 +(extra_params?extra_params->len:0)
1580                 +CRLF_LEN+1;
1581         line_buf=pkg_malloc( max_len );
1582         if (line_buf==0){
1583                 ser_error=E_OUT_OF_MEM;
1584                 LOG(L_ERR, "ERROR: via_builder: out of memory\n");
1585                 return 0;
1586         }
1587
1588         extra_len=0;
1589
1590         via_len=MY_VIA_LEN+send_sock->address_str.len; /*space included in MY_VIA*/
1591
1592         memcpy(line_buf, MY_VIA, MY_VIA_LEN-4); /* without "UPD " */
1593         if (proto==PROTO_UDP)
1594                 memcpy(line_buf+MY_VIA_LEN-4, "UDP ", 4);
1595         else if (proto==PROTO_TCP)
1596                 memcpy(line_buf+MY_VIA_LEN-4, "TCP ", 4);
1597         else{
1598                 LOG(L_CRIT, "BUG: via_builder: unknown proto %d\n", proto);
1599                 return 0;
1600         }
1601 #       ifdef USE_IPV6
1602         if (send_sock->address.af==AF_INET6) {
1603                 line_buf[MY_VIA_LEN]='[';
1604                 line_buf[MY_VIA_LEN+1+send_sock->address_str.len]=']';
1605                 extra_len=1;
1606                 via_len+=2; /* [ ]*/
1607         }
1608 #       endif
1609         memcpy(line_buf+MY_VIA_LEN+extra_len, send_sock->address_str.s,
1610                 send_sock->address_str.len);
1611         if (send_sock->port_no!=SIP_PORT){
1612                 line_buf[via_len]=':'; via_len++;
1613                 memcpy(line_buf+via_len, send_sock->port_no_str.s,
1614                          send_sock->port_no_str.len);
1615                 via_len+=send_sock->port_no_str.len;
1616         }
1617
1618         /* branch parameter */
1619         if (branch){
1620                 memcpy(line_buf+via_len, MY_BRANCH, MY_BRANCH_LEN );
1621                 via_len+=MY_BRANCH_LEN;
1622                 memcpy(line_buf+via_len, branch->s, branch->len );
1623                 via_len+=branch->len;
1624         }
1625         /* extra params  */
1626         if (extra_params){
1627                 memcpy(line_buf+via_len, extra_params->s, extra_params->len);
1628                 via_len+=extra_params->len;
1629         }
1630         
1631         memcpy(line_buf+via_len, CRLF, CRLF_LEN);
1632         via_len+=CRLF_LEN;
1633         line_buf[via_len]=0; /* null terminate the string*/
1634
1635         *len = via_len;
1636         return line_buf;
1637 }