be31b3d7e027f5f50b1ef22c2facd564cbb43ba7
[sip-router] / msg_translator.c
1 /* $Id$
2  *
3  */
4
5
6 #include <sys/types.h>
7 #include <sys/socket.h>
8 #include <netdb.h>
9 #include <string.h>
10 #include <stdio.h>
11
12 #include "msg_translator.h"
13 #include "globals.h"
14 #include "mem/mem.h"
15 #include "dprint.h"
16 #include "config.h"
17 #include "md5utils.h"
18 #include "data_lump_rpl.h"
19 #include "ip_addr.h"
20 #include "resolve.h"
21
22
23
24 #define MAX_VIA_LINE_SIZE      240
25 #define MAX_RECEIVED_SIZE  57
26
27 /* mallocs for local stuff (not needed to be shared mem?)*/
28 #define local_malloc pkg_malloc
29 #define local_free   pkg_free
30
31
32 #define append_str(_dest,_src,_len,_msg) \
33         do{\
34                 memcpy( (_dest) , (_src) , (_len) );\
35                 (_dest) += (_len) ;\
36         }while(0);
37
38 #define append_str_trans(_dest,_src,_len,_msg) \
39         do{\
40                 memcpy( (_dest) , (_msg)->orig+((_src)-(_msg)->buf) , (_len) );\
41                 (_dest) += (_len) ;\
42         }while(0);
43
44 extern char version[];
45 extern int version_len;
46
47
48
49 /* checks if ip is in host(name) and ?host(ip)=name?
50  * ip must be in network byte order!
51  *  resolver = DO_DNS | DO_REV_DNS; if 0 no dns check is made
52  * return 0 if equal */
53 int check_address(struct ip_addr* ip, char *name, int resolver)
54 {
55         struct hostent* he;
56         int i;
57
58         /* maybe we are lucky and name it's an ip */
59         if (strcmp(name, ip_addr2a(ip))==0)
60                 return 0;
61         if (resolver&DO_DNS){
62                 DBG("check_address: doing dns lookup\n");
63                 /* try all names ips */
64                 he=resolvehost(name);
65                 if (ip->af==he->h_addrtype){
66                         for(i=0;he && he->h_addr_list[i];i++){
67                                 if ( memcmp(&he->h_addr_list[i], ip->u.addr, ip->len)==0)
68                                         return 0;
69                         }
70                 }
71         }
72         if (resolver&DO_REV_DNS){
73                 DBG("check_address: doing rev. dns lookup\n");
74                 /* try reverse dns */
75                 he=rev_resolvehost(ip);
76                 if (he && (strcmp(he->h_name, name)==0))
77                         return 0;
78                 for (i=0; he && he->h_aliases[i];i++){
79                         if (strcmp(he->h_aliases[i],name)==0)
80                                 return 0;
81                 }
82         }
83         return -1;
84 }
85
86
87
88
89
90
91
92
93 char* via_builder( struct sip_msg *msg , unsigned int *len, 
94                                         struct socket_info* send_sock )
95 {
96         unsigned int  via_len, branch_len, extra_len;
97         char               *line_buf;
98
99         line_buf=0;
100         extra_len=0;
101
102         line_buf=pkg_malloc(sizeof(char)*MAX_VIA_LINE_SIZE);
103         if (line_buf==0){
104                 LOG(L_ERR, "ERROR: via_builder: out of memory\n");
105                 goto error;
106         }
107         via_len=MY_VIA_LEN+send_sock->address_str.len; /*space included in MY_VIA*/
108 #ifdef USE_IPV6
109         if (send_sock->address.af==AF_INET6) via_len+=2; /* [ ]*/
110 #endif
111
112         /* jku: if we compute branches using MD5 it will take 32 bytes */
113         branch_len= (loop_checks ? MY_BRANCH_LEN : MY_BRANCH_LEN -1 + MD5_LEN)+
114                                         msg->add_to_branch_len;
115
116         if ((via_len+send_sock->port_no_str.len+branch_len
117                                                                 +CRLF_LEN)<MAX_VIA_LINE_SIZE){
118                 memcpy(line_buf, MY_VIA, MY_VIA_LEN);
119 #ifdef USE_IPV6
120         if (send_sock->address.af==AF_INET6) {
121                 line_buf[MY_VIA_LEN]='[';
122                 line_buf[MY_VIA_LEN+1+send_sock->address_str.len]=']';
123                 extra_len=1;
124         }
125 #endif
126                 memcpy(line_buf+MY_VIA_LEN+extra_len, send_sock->address_str.s,
127                                                                         send_sock->address_str.len);
128                 if (send_sock->port_no!=SIP_PORT){
129                         memcpy(line_buf+via_len, send_sock->port_no_str.s,
130                                                                          send_sock->port_no_str.len);
131                         via_len+=send_sock->port_no_str.len;
132                 }
133
134                 /* jku: branch parameter */
135                 memcpy(line_buf+via_len, MY_BRANCH, MY_BRANCH_LEN );
136                 via_len+=MY_BRANCH_LEN;
137                 /* loop checks ?
138                 if (loop_checks) {
139                         if (check_transaction_quadruple( msg )) {
140                                 str src[5];
141                                 int r;
142                                 src[0]= msg->from->body;
143                                 src[1]= msg->to->body;
144                                 src[2]= msg->callid->body;
145                                 src[3]= msg->first_line.u.request.uri;
146                                 src[4]= get_cseq( msg )->number;
147                                 MDStringArray ( line_buf+via_len-1, src, 5 );
148                                 via_len+=MD5_LEN - 1;
149                         } else DBG("DEBUG: via_builder: required HFs for "
150                                         "loop checking missing\n");
151                 }  */
152                 /* someone wants me to add something to branch here ? */
153                 if ( msg->add_to_branch_len ){
154                         memcpy(line_buf+via_len-1, msg->add_to_branch_s,
155                                 msg->add_to_branch_len );
156                         via_len+=msg->add_to_branch_len-1;
157                 }
158
159                 memcpy(line_buf+via_len, CRLF, CRLF_LEN);
160                 via_len+=CRLF_LEN;
161                 line_buf[via_len]=0; /* null terminate the string*/
162         }else{
163                 LOG(L_ERR, " ERROR: via_builder: via too long (%d)\n",
164                                 via_len);
165                 goto error;
166         }
167
168         *len = via_len;
169         return line_buf;
170
171 error:
172         if (line_buf) pkg_free(line_buf);
173         return 0;
174 }
175
176
177
178
179 #ifdef VERY_NOISY_REPLIES
180 char * warning_builder( struct sip_msg *msg, unsigned int *returned_len)
181 {
182         static char buf[MAX_WARNING_LEN];
183         static unsigned int fix_len=0;
184         str *foo;
185         char *p;
186
187         if (!fix_len)
188         {
189                 memcpy(buf+fix_len,"Warning: 392 ",13);
190                 fix_len +=13;
191                 memcpy(buf+fix_len, sock_info[0].name.s,sock_info[0].name.len);
192                 fix_len += sock_info[0].name.len;
193                 //*(buf+fix_len++) = ':';
194                 memcpy(buf+fix_len,sock_info[0].port_no_str.s,
195                         sock_info[0].port_no_str.len);
196                 fix_len += sock_info[0].port_no_str.len;
197                 memcpy(buf+fix_len, " \"Noisy feedback tells: ",24);
198                 fix_len += 24;
199         }
200
201         p = buf+fix_len;
202         /* adding pid */
203         if (p-buf+10+2>=MAX_WARNING_LEN)
204                 goto done;
205         p += sprintf(p, "pid=%d", pids?pids[process_no]:0 );
206         *(p++)=' ';
207
208         /*adding src_ip*/
209         if (p-buf+26+2>=MAX_WARNING_LEN)
210                 goto done;
211         p += sprintf(p,"req_src_ip=%s",ip_addr2a(&msg->src_ip));
212         *(p++)=' ';
213
214         /*adding in_uri*/
215         if(p-buf+7+msg->first_line.u.request.uri.len+2>=MAX_WARNING_LEN)
216                 goto done;
217         p += sprintf( p, "in_uri=%.*s",msg->first_line.u.request.uri.len,
218                 msg->first_line.u.request.uri.s);
219         *(p++) = ' ';
220
221         /*adding out_uri*/
222         if (msg->new_uri.s)
223                 foo=&(msg->new_uri);
224         else
225                 foo=&(msg->first_line.u.request.uri);
226         if(p-buf+8+foo->len+2>=MAX_WARNING_LEN)
227                 goto done;
228         p += sprintf( p, "out_uri=%.*s", foo->len, foo->s);
229
230 done:
231         *(p++) = '\"';
232         *(p) = 0;
233         *returned_len = p-buf;
234         return buf;
235 }
236 #endif
237
238
239
240
241 char * build_req_buf_from_sip_req( struct sip_msg* msg,
242                                                                 unsigned int *returned_len,
243                                                                 struct socket_info* send_sock)
244 {
245         unsigned int len, new_len, received_len, uri_len, via_len, extra_len;
246         char* line_buf;
247         char* received_buf;
248         char* tmp;
249         int tmp_len;
250         char* new_buf;
251         char* orig;
252         char* buf;
253         char  backup;
254         unsigned int offset, s_offset, size;
255         struct ip_addr* source_ip;
256         struct lump *t,*r;
257         struct lump* anchor;
258
259         uri_len=0;
260         orig=msg->orig;
261         buf=msg->buf;
262         len=msg->len;
263         source_ip=&msg->src_ip;
264         received_len=0;
265         new_buf=0;
266         received_buf=0;
267         extra_len=0;
268
269
270         line_buf = via_builder( msg, &via_len, send_sock);
271         if (!line_buf){
272                 LOG(L_ERR,"ERROR: build_req_buf_from_sip_req: no via received!\n");
273                 goto error1;
274         }
275         /* check if received needs to be added */
276         backup = msg->via1->host.s[msg->via1->host.len];
277         msg->via1->host.s[msg->via1->host.len] = 0;
278         if (check_address(source_ip, msg->via1->host.s, received_dns)!=0){
279                 received_buf=pkg_malloc(sizeof(char)*MAX_RECEIVED_SIZE);
280                 if (received_buf==0){
281                         LOG(L_ERR, "ERROR: build_req_buf_from_sip_req: out of memory\n");
282                         goto error1;
283                 }
284                 /*
285                 received_len=snprintf(received_buf, MAX_RECEIVED_SIZE,
286                                                                 ";received=%s",
287                                                                 inet_ntoa(*(struct in_addr *)&source_ip));
288                 */
289                 memcpy(received_buf, RECEIVED, RECEIVED_LEN);
290                 tmp=ip_addr2a(source_ip);
291                 tmp_len=strlen(tmp);
292                 received_len=RECEIVED_LEN+tmp_len;
293                 if(source_ip->af==AF_INET6){
294                         received_len+=2;
295                         received_buf[RECEIVED_LEN]='[';
296                         received_buf[RECEIVED_LEN+tmp_len+1]=']';
297                         extra_len=1;
298                 }
299                 
300                 memcpy(received_buf+RECEIVED_LEN+extra_len, tmp, tmp_len);
301                 received_buf[received_len]=0; /*null terminate it */
302         }
303         msg->via1->host.s[msg->via1->host.len] = backup;
304
305         /* add via header to the list */
306         /* try to add it before msg. 1st via */
307         /* add first via, as an anchor for second via*/
308         anchor=anchor_lump(&(msg->add_rm), msg->via1->hdr.s-buf, 0, HDR_VIA);
309         if (anchor==0) goto error;
310         if (insert_new_lump_before(anchor, line_buf, via_len, HDR_VIA)==0)
311                 goto error;
312         /* if received needs to be added, add anchor after host and add it */
313         if (received_len){
314                 if (msg->via1->params.s){
315                                 size= msg->via1->params.s-msg->via1->hdr.s-1; /*compensate
316                                                                                                                           for ';' */
317                 }else{
318                                 size= msg->via1->host.s-msg->via1->hdr.s+msg->via1->host.len;
319                                 if (msg->via1->port!=0){
320                                         /*size+=strlen(msg->via1->hdr.s+size+1)+1;*/
321                                         size += msg->via1->port_str.len + 1; /* +1 for ':'*/
322                                 }
323                 }
324                 anchor=anchor_lump(&(msg->add_rm),msg->via1->hdr.s-buf+size,0,
325                                 HDR_VIA);
326                 if (anchor==0) goto error;
327                 if (insert_new_lump_after(anchor, received_buf, received_len, HDR_VIA)
328                                 ==0 ) goto error;
329         }
330
331         /* compute new msg len and fix overlapping zones*/
332         new_len=len;
333         s_offset=0;
334         for(t=msg->add_rm;t;t=t->next){
335                 for(r=t->before;r;r=r->before){
336                         switch(r->op){
337                                 case LUMP_ADD:
338                                         new_len+=r->len;
339                                         break;
340                                 default:
341                                         /* only ADD allowed for before/after */
342                                         LOG(L_CRIT, "BUG:build_req_buf_from_sip_req: invalid op "
343                                                         "for data lump (%x)\n", r->op);
344                         }
345                 }
346                 switch(t->op){
347                         case LUMP_ADD:
348                                 new_len+=t->len;
349                                 break;
350                         case LUMP_DEL:
351                                 /* fix overlapping deleted zones */
352                                 if (t->u.offset < s_offset){
353                                         /* change len */
354                                         if (t->len>s_offset-t->u.offset)
355                                                         t->len-=s_offset-t->u.offset;
356                                         else t->len=0;
357                                         t->u.offset=s_offset;
358                                 }
359                                 s_offset=t->u.offset+t->len;
360                                 new_len-=t->len;
361                                 break;
362                         case LUMP_NOP:
363                                 /* fix offset if overlapping on a deleted zone */
364                                 if (t->u.offset < s_offset){
365                                         t->u.offset=s_offset;
366                                 }else
367                                         s_offset=t->u.offset;
368                                 /* do nothing */
369                                 break;
370                         default:
371                                 LOG(L_CRIT,"BUG:build_req_buf_from_sip_req: invalid"
372                                                         " op for data lump (%x)\n", r->op);
373                 }
374                 for (r=t->after;r;r=r->after){
375                         switch(r->op){
376                                 case LUMP_ADD:
377                                         new_len+=r->len;
378                                         break;
379                                 default:
380                                         /* only ADD allowed for before/after */
381                                         LOG(L_CRIT, "BUG:build_req_buf_from_sip_req: invalid"
382                                                                 " op for data lump (%x)\n", r->op);
383                         }
384                 }
385         }
386
387         if (msg->new_uri.s){
388                 uri_len=msg->new_uri.len;
389                 new_len=new_len-msg->first_line.u.request.uri.len+uri_len;
390         }
391         new_buf=(char*)local_malloc(new_len+1);
392         if (new_buf==0){
393                 LOG(L_ERR, "ERROR: build_req_buf_from_sip_req: out of memory\n");
394                 goto error;
395         }
396
397         offset=s_offset=0;
398         if (msg->new_uri.s){
399                 /* copy message up to uri */
400                 size=msg->first_line.u.request.uri.s-buf;
401                 memcpy(new_buf, orig, size);
402                 offset+=size;
403                 s_offset+=size;
404                 /* add our uri */
405                 memcpy(new_buf+offset, msg->new_uri.s, uri_len);
406                 offset+=uri_len;
407                 s_offset+=msg->first_line.u.request.uri.len; /* skip original uri */
408         }
409         new_buf[new_len]=0;
410         /* copy msg adding/removing lumps */
411         for (t=msg->add_rm;t;t=t->next){
412                 switch(t->op){
413                         case LUMP_ADD:
414                                 /* just add it here! */
415                                 /* process before  */
416                                 for(r=t->before;r;r=r->before){
417                                         switch (r->op){
418                                                 case LUMP_ADD:
419                                                         /*just add it here*/
420                                                         memcpy(new_buf+offset, r->u.value, r->len);
421                                                         offset+=r->len;
422                                                         break;
423                                                 default:
424                                                         /* only ADD allowed for before/after */
425                                                         LOG(L_CRIT, "BUG:build_req_buf_from_sip_req: "
426                                                                         "invalid op for data lump (%x)\n", r->op);
427                                         }
428                                 }
429                                 /* copy "main" part */
430                                 memcpy(new_buf+offset, t->u.value, t->len);
431                                 offset+=t->len;
432                                 /* process after */
433                                 for(r=t->after;r;r=r->after){
434                                         switch (r->op){
435                                                 case LUMP_ADD:
436                                                         /*just add it here*/
437                                                         memcpy(new_buf+offset, r->u.value, r->len);
438                                                         offset+=r->len;
439                                                         break;
440                                                 default:
441                                                         /* only ADD allowed for before/after */
442                                                         LOG(L_CRIT, "BUG:build_req_buf_from_sip_req: "
443                                                                         "invalid op for data lump (%x)\n", r->op);
444                                         }
445                                 }
446                                 break;
447                         case LUMP_NOP:
448                         case LUMP_DEL:
449                                 /* copy till offset */
450                                 if (s_offset>t->u.offset){
451                                         DBG("Warning: (%d) overlapped lumps offsets,"
452                                                 " ignoring(%x, %x)\n", t->op, s_offset,t->u.offset);
453                                         /* this should've been fixed above (when computing len) */
454                                         /* just ignore it*/
455                                         break;
456                                 }
457                                 size=t->u.offset-s_offset;
458                                 if (size){
459                                         memcpy(new_buf+offset, orig+s_offset,size);
460                                         offset+=size;
461                                         s_offset+=size;
462                                 }
463                                 /* process before  */
464                                 for(r=t->before;r;r=r->before){
465                                         switch (r->op){
466                                                 case LUMP_ADD:
467                                                         /*just add it here*/
468                                                         memcpy(new_buf+offset, r->u.value, r->len);
469                                                         offset+=r->len;
470                                                         break;
471                                                 default:
472                                                         /* only ADD allowed for before/after */
473                                                         LOG(L_CRIT, "BUG:build_req_buf_from_sip_req: "
474                                                                         "invalid op for data lump (%x)\n",r->op);
475                                         }
476                                 }
477                                 /* process main (del only) */
478                                 if (t->op==LUMP_DEL){
479                                         /* skip len bytes from orig msg */
480                                         s_offset+=t->len;
481                                 }
482                                 /* process after */
483                                 for(r=t->after;r;r=r->after){
484                                         switch (r->op){
485                                                 case LUMP_ADD:
486                                                         /*just add it here*/
487                                                         memcpy(new_buf+offset, r->u.value, r->len);
488                                                         offset+=r->len;
489                                                         break;
490                                                 default:
491                                                         /* only ADD allowed for before/after */
492                                                         LOG(L_CRIT, "BUG:build_req_buf_from_sip_req: "
493                                                                         "invalid op for data lump (%x)\n", r->op);
494                                         }
495                                 }
496                                 break;
497                         default:
498                                         LOG(L_CRIT, "BUG: build_req_buf_from_sip_req: "
499                                                         "unknown op (%x)\n", t->op);
500                 }
501         }
502         /* copy the rest of the message */
503         memcpy(new_buf+offset, orig+s_offset, len-s_offset);
504         new_buf[new_len]=0;
505
506         *returned_len=new_len;
507         return new_buf;
508
509 error1:
510         if (received_buf) pkg_free(received_buf);
511         if (line_buf) pkg_free(line_buf);
512 error:
513         if (new_buf) local_free(new_buf);
514         *returned_len=0;
515         return 0;
516 }
517
518
519
520
521 char * build_res_buf_from_sip_res( struct sip_msg* msg,
522                                 unsigned int *returned_len)
523 {
524         unsigned int new_len, via_len;
525         char* new_buf;
526         unsigned offset, s_offset, size;
527         char* orig;
528         char* buf;
529         unsigned int len;
530
531         orig=msg->orig;
532         buf=msg->buf;
533         len=msg->len;
534         new_buf=0;
535         /* we must remove the first via */
536         via_len=msg->via1->bsize;
537         size=msg->via1->hdr.s-buf;
538         DBG("via len: %d, initial size: %d\n", via_len, size);
539         if (msg->via1->next){
540                 /* add hdr size*/
541                 size+=msg->via1->hdr.len+1;
542             DBG(" adjusted via len: %d, initial size: %d\n",
543                                 via_len, size);
544         }else{
545                 /* add hdr size ("Via:")*/
546                 via_len+=msg->via1->hdr.len+1;
547         }
548         new_len=len-via_len;
549
550         DBG(" old size: %d, new size: %d\n", len, new_len);
551         new_buf=(char*)local_malloc(new_len+1);/* +1 is for debugging
552                                                                                         (\0 to print it )*/
553         if (new_buf==0){
554                 LOG(L_ERR, "ERROR: build_res_buf_from_sip_res: out of memory\n");
555                 goto error;
556         }
557         new_buf[new_len]=0; /* debug: print the message */
558         memcpy(new_buf, orig, size);
559         offset=size;
560         s_offset=size+via_len;
561         memcpy(new_buf+offset,orig+s_offset, len-s_offset);
562          /* send it! */
563         DBG(" copied size: orig:%d, new: %d, rest: %d\n",
564                         s_offset, offset,
565                         len-s_offset );
566
567         *returned_len=new_len;
568         return new_buf;
569 error:
570         if (new_buf) local_free(new_buf);
571         *returned_len=0;
572         return 0;
573 }
574
575
576
577
578
579 char * build_res_buf_from_sip_req( unsigned int code, char *text,
580                                         char *new_tag, unsigned int new_tag_len,
581                                         struct sip_msg* msg, unsigned int *returned_len)
582 {
583         char              *buf, *p;
584         unsigned int      len,foo;
585         struct hdr_field  *hdr;
586         struct lump_rpl   *lump;
587         int               i;
588         str               *tag_str;
589 #ifdef VERY_NOISY_REPLIES
590         char              *warning;
591         unsigned int      warning_len;
592 #endif
593
594         /* force parsing all headers -- we want to return all
595         Via's in the reply and they may be scattered down to the
596         end of header (non-block Vias are a really poor property
597         of SIP :( ) */
598         parse_headers( msg, HDR_EOH );
599
600         /*computes the lenght of the new response buffer*/
601         len = 0;
602         /* first line */
603         len += SIP_VERSION_LEN + 1/*space*/ + 3/*code*/ + 1/*space*/ +
604                 strlen(text) + CRLF_LEN/*new line*/;
605         /*headers that will be copied (TO, FROM, CSEQ,CALLID,VIA)*/
606         for ( hdr=msg->headers ; hdr ; hdr=hdr->next )
607                 switch (hdr->type)
608                 {
609                         case HDR_TO:
610                                 if (new_tag)
611                                 {
612                                         if (get_to(msg)->tag_value.s )
613                                                 len+=new_tag_len-get_to(msg)->tag_value.len;
614                                         else
615                                                 len+=new_tag_len+5/*";tag="*/;
616                                 }
617                         case HDR_VIA:
618                         case HDR_FROM:
619                         case HDR_CALLID:
620                         case HDR_CSEQ:
621                                 len += ((hdr->body.s+hdr->body.len )-hdr->name.s )+CRLF_LEN;
622                 }
623         /*lumps length*/
624         for(lump=msg->reply_lump;lump;lump=lump->next)
625                 len += lump->text.len;
626 #ifdef NOISY_REPLIES
627         /*server header*/
628         len += SERVER_HDR_LEN + CRLF_LEN;
629         /*content length header*/
630         len +=CONTENT_LEN_LEN + CRLF_LEN;
631 #endif
632 #ifdef VERY_NOISY_REPLIES
633         warning = warning_builder(msg,&warning_len);
634         len += warning_len + CRLF_LEN;
635 #endif
636         /* end of message */
637         len += CRLF_LEN; /*new line*/
638         /*allocating mem*/
639         buf = 0;
640         buf = (char*) local_malloc( len+1 );
641         if (!buf)
642         {
643                 LOG(L_ERR, "ERROR: build_res_buf_from_sip_req: out of memory "
644                         " ; needs %d\n",len);
645                 goto error;
646         }
647
648         /* filling the buffer*/
649         p=buf;
650         /* first line */
651         memcpy( p , SIP_VERSION , SIP_VERSION_LEN );
652         p += SIP_VERSION_LEN;
653         *(p++) = ' ' ;
654         /*code*/
655         for ( i=2 , foo = code  ;  i>=0  ;  i-- , foo=foo/10 )
656                 *(p+i) = '0' + foo - ( foo/10 )*10;
657         p += 3;
658         *(p++) = ' ' ;
659         memcpy( p , text , strlen(text) );
660         p += strlen(text);
661         memcpy( p, CRLF, CRLF_LEN );
662         p+=CRLF_LEN;
663         /* headers*/
664         for ( hdr=msg->headers ; hdr ; hdr=hdr->next )
665                 switch (hdr->type)
666                 {
667                         case HDR_TO:
668                                 if (new_tag){
669                                         if (get_to(msg)->tag_value.s ) {
670                                                 tag_str =&(get_to(msg)->tag_value);
671                                                 append_str_trans( p, hdr->name.s ,
672                                                         tag_str->s-hdr->name.s,msg);
673                                                 append_str( p, new_tag,new_tag_len,msg);
674                                                 append_str_trans( p,tag_str->s+tag_str->len,
675                                                         ((hdr->body.s+hdr->body.len )-
676                                                         (tag_str->s+tag_str->len)),msg);
677                                                 append_str( p, CRLF,CRLF_LEN,msg);
678                                         }else{
679                                                 append_str_trans( p, hdr->name.s ,
680                                                         ((hdr->body.s+hdr->body.len )-hdr->name.s ),
681                                                         msg);
682                                                 append_str( p, ";tag=",5,msg);
683                                                 append_str( p, new_tag,new_tag_len,msg);
684                                                 append_str( p, CRLF,CRLF_LEN,msg);
685                                         }
686                                         break;
687                                 }
688                         case HDR_VIA:
689                         case HDR_FROM:
690                         case HDR_CALLID:
691                         case HDR_CSEQ:
692                                 append_str_trans( p, hdr->name.s ,
693                                         ((hdr->body.s+hdr->body.len )-hdr->name.s ),msg);
694                                 append_str( p, CRLF,CRLF_LEN,msg);
695                 }
696         /*lumps*/
697         for(lump=msg->reply_lump;lump;lump=lump->next)
698         {
699                 memcpy(p,lump->text.s,lump->text.len);
700                 p += lump->text.len;
701         }
702 #ifdef NOISY_REPLIES
703         /*server header*/
704         memcpy( p, SERVER_HDR , SERVER_HDR_LEN );
705         p+=SERVER_HDR_LEN;
706         memcpy( p, CRLF, CRLF_LEN );
707         p+=CRLF_LEN;
708         /* content length header*/
709         memcpy( p, CONTENT_LEN , CONTENT_LEN_LEN );
710         p+=CONTENT_LEN_LEN;
711         memcpy( p, CRLF, CRLF_LEN );
712         p+=CRLF_LEN;
713 #endif
714 #ifdef VERY_NOISY_REPLIES
715         memcpy( p, warning, warning_len);
716         p+=warning_len;
717         memcpy( p, CRLF, CRLF_LEN);
718         p+=CRLF_LEN;
719 #endif
720         /*end of message*/
721         memcpy( p, CRLF, CRLF_LEN );
722         p+=CRLF_LEN;
723         *(p) = 0;
724         *returned_len = len;
725         return buf;
726 error:
727         if (buf) local_free(buf);
728         *returned_len=0;
729         return 0;
730 }