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