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