1 /*
2   The oSIP library implements the Session Initiation Protocol (SIP -rfc3261-)
3   Copyright (C) 2001-2020 Aymeric MOIZARD amoizard@antisip.com
4 
5   This library is free software; you can redistribute it and/or
6   modify it under the terms of the GNU Lesser General Public
7   License as published by the Free Software Foundation; either
8   version 2.1 of the License, or (at your option) any later version.
9 
10   This library is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   Lesser General Public License for more details.
14 
15   You should have received a copy of the GNU Lesser General Public
16   License along with this library; if not, write to the Free Software
17   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19 
20 #include <osipparser2/internal.h>
21 
22 #include <osipparser2/osip_port.h>
23 #include <osipparser2/osip_parser.h>
24 
25 #define MIME_MAX_BOUNDARY_LEN 70
26 
27 extern const char *osip_protocol_version;
28 
29 static int strcat_simple_header(char **_string, size_t *malloc_size, char **_message, void *ptr_header, char *header_name, size_t size_of_header, int (*xxx_to_str)(void *, char **), char **next);
30 static int strcat_headers_one_per_line(char **_string, size_t *malloc_size, char **_message, osip_list_t *headers, char *header, size_t size_of_header, int (*xxx_to_str)(void *, char **), char **next);
31 
__osip_message_startline_to_strreq(osip_message_t * sip,char ** dest)32 static int __osip_message_startline_to_strreq(osip_message_t *sip, char **dest) {
33   const char *sip_version;
34   char *tmp;
35   char *rquri;
36   int i;
37 
38   *dest = NULL;
39 
40   if ((sip == NULL) || (sip->req_uri == NULL) || (sip->sip_method == NULL))
41     return OSIP_BADPARAMETER;
42 
43   i = osip_uri_to_str(sip->req_uri, &rquri);
44 
45   if (i != 0)
46     return i;
47 
48   if (sip->sip_version == NULL)
49     sip_version = osip_protocol_version;
50 
51   else
52     sip_version = sip->sip_version;
53 
54   *dest = (char *) osip_malloc(strlen(sip->sip_method) + strlen(rquri) + strlen(sip_version) + 3);
55 
56   if (*dest == NULL) {
57     osip_free(rquri);
58     return OSIP_NOMEM;
59   }
60 
61   tmp = *dest;
62 
63   tmp = osip_str_append(tmp, sip->sip_method);
64   *tmp = ' ';
65   tmp++;
66   tmp = osip_str_append(tmp, rquri);
67   *tmp = ' ';
68   tmp++;
69   strcpy(tmp, sip_version);
70 
71   osip_free(rquri);
72   return OSIP_SUCCESS;
73 }
74 
__osip_message_startline_to_strresp(osip_message_t * sip,char ** dest)75 static int __osip_message_startline_to_strresp(osip_message_t *sip, char **dest) {
76   char *tmp;
77   const char *sip_version;
78   char status_code[5];
79 
80   *dest = NULL;
81 
82   if ((sip == NULL) || (sip->reason_phrase == NULL) || (sip->status_code < 100) || (sip->status_code > 699))
83     return OSIP_BADPARAMETER;
84 
85   if (sip->sip_version == NULL)
86     sip_version = osip_protocol_version;
87 
88   else
89     sip_version = sip->sip_version;
90 
91   sprintf(status_code, "%u", sip->status_code);
92 
93   *dest = (char *) osip_malloc(strlen(sip_version) + 3 + strlen(sip->reason_phrase) + 4);
94 
95   if (*dest == NULL)
96     return OSIP_NOMEM;
97 
98   tmp = *dest;
99 
100   tmp = osip_str_append(tmp, sip_version);
101   *tmp = ' ';
102   tmp++;
103 
104   tmp = osip_strn_append(tmp, status_code, 3);
105   *tmp = ' ';
106   tmp++;
107   strcpy(tmp, sip->reason_phrase);
108 
109   return OSIP_SUCCESS;
110 }
111 
__osip_message_startline_to_str(osip_message_t * sip,char ** dest)112 static int __osip_message_startline_to_str(osip_message_t *sip, char **dest) {
113   if (sip->sip_method != NULL)
114     return __osip_message_startline_to_strreq(sip, dest);
115 
116   if (sip->status_code != 0)
117     return __osip_message_startline_to_strresp(sip, dest);
118 
119   OSIP_TRACE(osip_trace(__FILE__, __LINE__, TRACE_LEVEL1, NULL, "ERROR method has no value or status code is 0!\n"));
120   return OSIP_BADPARAMETER; /* should never come here */
121 }
122 
osip_message_get_reason_phrase(const osip_message_t * sip)123 char *osip_message_get_reason_phrase(const osip_message_t *sip) {
124   return sip->reason_phrase;
125 }
126 
osip_message_get_status_code(const osip_message_t * sip)127 int osip_message_get_status_code(const osip_message_t *sip) {
128   return sip->status_code;
129 }
130 
osip_message_get_method(const osip_message_t * sip)131 char *osip_message_get_method(const osip_message_t *sip) {
132   return sip->sip_method;
133 }
134 
osip_message_get_version(const osip_message_t * sip)135 char *osip_message_get_version(const osip_message_t *sip) {
136   return sip->sip_version;
137 }
138 
osip_message_get_uri(const osip_message_t * sip)139 osip_uri_t *osip_message_get_uri(const osip_message_t *sip) {
140   return sip->req_uri;
141 }
142 
strcat_simple_header(char ** _string,size_t * malloc_size,char ** _message,void * ptr_header,char * header_name,size_t size_of_header,int (* xxx_to_str)(void *,char **),char ** next)143 static int strcat_simple_header(char **_string, size_t *malloc_size, char **_message, void *ptr_header, char *header_name, size_t size_of_header, int (*xxx_to_str)(void *, char **), char **next) {
144   char *string;
145   char *message;
146   char *tmp;
147   int i;
148 
149   string = *_string;
150   message = *_message;
151 
152   if (ptr_header != NULL) {
153     if (*malloc_size < message - string + 100 + size_of_header) {
154       /* take some memory in order to avoid using osip_realloc too often */
155       size_t size = message - string;
156 
157       *malloc_size = message - string + size_of_header + 100;
158       string = osip_realloc(string, *malloc_size);
159 
160       if (string == NULL) {
161         osip_free(*_string); /* pointer for string */
162         *_string = NULL;
163         *_message = NULL;
164         return OSIP_NOMEM;
165       }
166 
167       *_string = string;
168       message = string + size;
169     }
170 
171     message = osip_strn_append(message, header_name, size_of_header);
172 
173     i = xxx_to_str(ptr_header, &tmp);
174 
175     if (i != 0) {
176       *_string = string;
177       *_message = message;
178       *next = NULL;
179       return i;
180     }
181 
182     if (*malloc_size < message - string + strlen(tmp) + 100) {
183       size_t size = message - string;
184 
185       *malloc_size = message - string + strlen(tmp) + 100;
186       string = osip_realloc(string, *malloc_size);
187 
188       if (string == NULL) {
189         osip_free(*_string); /* pointer for string */
190         *_string = NULL;
191         *_message = NULL;
192         return OSIP_NOMEM;
193       }
194 
195       *_string = string;
196       message = string + size;
197     }
198 
199     message = osip_str_append(message, tmp);
200     osip_free(tmp);
201     message = osip_strn_append(message, OSIP_CRLF, 2);
202   }
203 
204   *_string = string;
205   *_message = message;
206   *next = message;
207   return OSIP_SUCCESS;
208 }
209 
strcat_headers_one_per_line(char ** _string,size_t * malloc_size,char ** _message,osip_list_t * headers,char * header,size_t size_of_header,int (* xxx_to_str)(void *,char **),char ** next)210 static int strcat_headers_one_per_line(char **_string, size_t *malloc_size, char **_message, osip_list_t *headers, char *header, size_t size_of_header, int (*xxx_to_str)(void *, char **), char **next) {
211   char *string;
212   char *message;
213   char *tmp;
214   int i;
215   osip_list_iterator_t it;
216   void *elt = osip_list_get_first(headers, &it);
217 
218   string = *_string;
219   message = *_message;
220 
221   while (elt != OSIP_SUCCESS) {
222     if (*malloc_size < message - string + 100 + size_of_header)
223     /* take some memory avoid to osip_realloc too much often */
224     {
225       /* should not happen often */
226       size_t size = message - string;
227 
228       *malloc_size = message - string + size_of_header + 100;
229       string = osip_realloc(string, *malloc_size);
230 
231       if (string == NULL) {
232         osip_free(*_string); /* pointer for string */
233         *_string = NULL;
234         *_message = NULL;
235         return OSIP_NOMEM;
236       }
237 
238       *_string = string;
239       message = string + size;
240     }
241 
242     osip_strncpy(message, header, size_of_header);
243     i = xxx_to_str(elt, &tmp);
244 
245     if (i != 0) {
246       *_string = string;
247       *_message = message;
248       *next = NULL;
249       return i;
250     }
251 
252     message = message + strlen(message);
253 
254     if (*malloc_size < message - string + strlen(tmp) + 100) {
255       size_t size = message - string;
256 
257       *malloc_size = message - string + strlen(tmp) + 100;
258       string = osip_realloc(string, *malloc_size);
259 
260       if (string == NULL) {
261         osip_free(*_string); /* pointer for string */
262         *_string = NULL;
263         *_message = NULL;
264         return OSIP_NOMEM;
265       }
266 
267       *_string = string;
268       message = string + size;
269     }
270 
271     message = osip_str_append(message, tmp);
272     osip_free(tmp);
273     message = osip_strn_append(message, OSIP_CRLF, 2);
274     elt = osip_list_get_next(&it);
275   }
276 
277   *_string = string;
278   *_message = message;
279   *next = message;
280   return OSIP_SUCCESS;
281 }
282 
283 /* return values:
284    1: structure and buffer "message" are identical.
285    2: buffer "message" is not up to date with the structure info (call osip_message_to_str to update it).
286    -1 on error.
287  */
osip_message_get__property(const osip_message_t * sip)288 int osip_message_get__property(const osip_message_t *sip) {
289   if (sip == NULL)
290     return OSIP_BADPARAMETER;
291 
292   return sip->message_property;
293 }
294 
osip_message_force_update(osip_message_t * sip)295 int osip_message_force_update(osip_message_t *sip) {
296   if (sip == NULL)
297     return OSIP_BADPARAMETER;
298 
299   sip->message_property = 2;
300   return OSIP_SUCCESS;
301 }
302 
_osip_message_realloc(char ** message,char ** dest,size_t needed,size_t * malloc_size)303 static int _osip_message_realloc(char **message, char **dest, size_t needed, size_t *malloc_size) {
304   size_t size = *message - *dest;
305 
306   if (*malloc_size < (size_t)(size + needed + 100)) {
307     *malloc_size = size + needed + 100;
308     *dest = osip_realloc(*dest, *malloc_size);
309 
310     if (*dest == NULL)
311       return OSIP_NOMEM;
312 
313     *message = *dest + size;
314   }
315 
316   return OSIP_SUCCESS;
317 }
318 
_osip_message_to_str(osip_message_t * sip,char ** dest,size_t * message_length,int sipfrag)319 static int _osip_message_to_str(osip_message_t *sip, char **dest, size_t *message_length, int sipfrag) {
320   size_t malloc_size;
321   size_t total_length = 0;
322 
323   /* Added at SIPit day1 */
324   char *start_of_bodies;
325   char *content_length_to_modify = NULL;
326 
327   char *message;
328   char *next;
329   char *tmp;
330   int pos;
331   int i;
332   char *boundary = NULL;
333 
334   malloc_size = SIP_MESSAGE_MAX_LENGTH;
335 
336   *dest = NULL;
337 
338   if (sip == NULL)
339     return OSIP_BADPARAMETER;
340 
341   {
342     if (1 == osip_message_get__property(sip)) { /* message is already available in "message" */
343 
344       *dest = osip_malloc(sip->message_length + 1);
345 
346       if (*dest == NULL)
347         return OSIP_NOMEM;
348 
349       memcpy(*dest, sip->message, sip->message_length);
350       (*dest)[sip->message_length] = '\0';
351 
352       if (message_length != NULL)
353         *message_length = sip->message_length;
354 
355       return OSIP_SUCCESS;
356 
357     } else {
358       /* message should be rebuilt: delete the old one if exists. */
359       osip_free(sip->message);
360       sip->message = NULL;
361     }
362   }
363 
364   message = (char *) osip_malloc(SIP_MESSAGE_MAX_LENGTH); /* ???? message could be > 4000  */
365 
366   if (message == NULL)
367     return OSIP_NOMEM;
368 
369   *dest = message;
370 
371   /* add the first line of message */
372   i = __osip_message_startline_to_str(sip, &tmp);
373 
374   if (i != 0) {
375     if (!sipfrag) {
376       osip_free(*dest);
377       *dest = NULL;
378       return i;
379     }
380 
381     /* A start-line isn't required for message/sipfrag parts. */
382 
383   } else {
384     size_t message_len = strlen(tmp);
385 
386     if (_osip_message_realloc(&message, dest, message_len + 3, &malloc_size) < 0) {
387       osip_free(tmp);
388       *dest = NULL;
389       return OSIP_NOMEM;
390     }
391 
392     message = osip_str_append(message, tmp);
393     osip_free(tmp);
394     message = osip_strn_append(message, OSIP_CRLF, 2);
395   }
396 
397   {
398     struct to_str_table {
399       char header_name[30];
400       int header_length;
401       osip_list_t *header_list;
402       void *header_data;
403       int (*to_str)(void *, char **);
404     }
405 #ifndef MINISIZE
406     table[25] =
407 #else
408     table[16] =
409 #endif
410         {{"Via: ", 5, NULL, NULL, (int (*)(void *, char **)) & osip_via_to_str},
411          {"Record-Route: ", 14, NULL, NULL, (int (*)(void *, char **)) & osip_record_route_to_str},
412          {"Route: ", 7, NULL, NULL, (int (*)(void *, char **)) & osip_route_to_str},
413          {"From: ", 6, NULL, NULL, (int (*)(void *, char **)) & osip_from_to_str},
414          {"To: ", 4, NULL, NULL, (int (*)(void *, char **)) & osip_to_to_str},
415          {"Call-ID: ", 9, NULL, NULL, (int (*)(void *, char **)) & osip_call_id_to_str},
416          {"CSeq: ", 6, NULL, NULL, (int (*)(void *, char **)) & osip_cseq_to_str},
417          {"Contact: ", 9, NULL, NULL, (int (*)(void *, char **)) & osip_contact_to_str},
418          {"Authorization: ", 15, NULL, NULL, (int (*)(void *, char **)) & osip_authorization_to_str},
419          {"WWW-Authenticate: ", 18, NULL, NULL, (int (*)(void *, char **)) & osip_www_authenticate_to_str},
420          {"Proxy-Authenticate: ", 20, NULL, NULL, (int (*)(void *, char **)) & osip_www_authenticate_to_str},
421          {"Proxy-Authorization: ", 21, NULL, NULL, (int (*)(void *, char **)) & osip_authorization_to_str},
422          {"Call-Info: ", 11, NULL, NULL, (int (*)(void *, char **)) & osip_call_info_to_str},
423          {"Content-Type: ", 14, NULL, NULL, (int (*)(void *, char **)) & osip_content_type_to_str},
424          {"Mime-Version: ", 14, NULL, NULL, (int (*)(void *, char **)) & osip_content_length_to_str},
425 #ifndef MINISIZE
426          {"Allow: ", 7, NULL, NULL, (int (*)(void *, char **)) & osip_allow_to_str},
427          {"Content-Encoding: ", 18, NULL, NULL, (int (*)(void *, char **)) & osip_content_encoding_to_str},
428          {"Alert-Info: ", 12, NULL, NULL, (int (*)(void *, char **)) & osip_call_info_to_str},
429          {"Error-Info: ", 12, NULL, NULL, (int (*)(void *, char **)) & osip_call_info_to_str},
430          {"Accept: ", 8, NULL, NULL, (int (*)(void *, char **)) & osip_accept_to_str},
431          {"Accept-Encoding: ", 17, NULL, NULL, (int (*)(void *, char **)) & osip_accept_encoding_to_str},
432          {"Accept-Language: ", 17, NULL, NULL, (int (*)(void *, char **)) & osip_accept_language_to_str},
433          {"Authentication-Info: ", 21, NULL, NULL, (int (*)(void *, char **)) & osip_authentication_info_to_str},
434          {"Proxy-Authentication-Info: ", 27, NULL, NULL, (int (*)(void *, char **)) & osip_authentication_info_to_str},
435 #endif
436          {{'\0'}, 0, NULL, NULL, NULL}};
437     table[0].header_list = &sip->vias;
438     table[1].header_list = &sip->record_routes;
439     table[2].header_list = &sip->routes;
440     table[3].header_data = sip->from;
441     table[4].header_data = sip->to;
442     table[5].header_data = sip->call_id;
443     table[6].header_data = sip->cseq;
444     table[7].header_list = &sip->contacts;
445     table[8].header_list = &sip->authorizations;
446     table[9].header_list = &sip->www_authenticates;
447     table[10].header_list = &sip->proxy_authenticates;
448     table[11].header_list = &sip->proxy_authorizations;
449     table[12].header_list = &sip->call_infos;
450     table[13].header_data = sip->content_type;
451     table[14].header_data = sip->mime_version;
452 #ifndef MINISIZE
453     table[15].header_list = &sip->allows;
454     table[16].header_list = &sip->content_encodings;
455     table[17].header_list = &sip->alert_infos;
456     table[18].header_list = &sip->error_infos;
457     table[19].header_list = &sip->accepts;
458     table[20].header_list = &sip->accept_encodings;
459     table[21].header_list = &sip->accept_languages;
460     table[22].header_list = &sip->authentication_infos;
461     table[23].header_list = &sip->proxy_authentication_infos;
462 #endif
463 
464     pos = 0;
465 
466     while (table[pos].header_name[0] != '\0') {
467       if (table[13].header_list == NULL)
468         i = strcat_simple_header(dest, &malloc_size, &message, table[pos].header_data, table[pos].header_name, table[pos].header_length, ((int (*)(void *, char **)) table[pos].to_str), &next);
469 
470       i = strcat_headers_one_per_line(dest, &malloc_size, &message, table[pos].header_list, table[pos].header_name, table[pos].header_length, ((int (*)(void *, char **)) table[pos].to_str), &next);
471 
472       if (i != 0) {
473         osip_free(*dest);
474         *dest = NULL;
475         return i;
476       }
477 
478       message = next;
479 
480       pos++;
481     }
482   }
483 
484   {
485     osip_list_iterator_t it;
486     osip_header_t *header = (osip_header_t *) osip_list_get_first(&sip->headers, &it);
487 
488     while (header != OSIP_SUCCESS) {
489       size_t header_len = 0;
490 
491       i = osip_header_to_str(header, &tmp);
492 
493       if (i != 0) {
494         osip_free(*dest);
495         *dest = NULL;
496         return i;
497       }
498 
499       header_len = strlen(tmp);
500 
501       if (_osip_message_realloc(&message, dest, header_len + 3, &malloc_size) < 0) {
502         osip_free(tmp);
503         *dest = NULL;
504         return OSIP_NOMEM;
505       }
506 
507       message = osip_str_append(message, tmp);
508       osip_free(tmp);
509       message = osip_strn_append(message, OSIP_CRLF, 2);
510 
511       header = (osip_header_t *) osip_list_get_next(&it);
512     }
513   }
514 
515   /* we have to create the body before adding the contentlength */
516   /* add enough lenght for "Content-Length: " */
517 
518   if (_osip_message_realloc(&message, dest, 16, &malloc_size) < 0)
519     return OSIP_NOMEM;
520 
521   if (sipfrag && osip_list_eol(&sip->bodies, 0)) {
522     /* end of headers */
523     osip_strncpy(message, OSIP_CRLF, 2);
524     message = message + 2;
525 
526     /* same remark as at the beginning of the method */
527     sip->message_property = 1;
528     sip->message = osip_strdup(*dest);
529     sip->message_length = message - *dest;
530 
531     if (message_length != NULL)
532       *message_length = message - *dest;
533 
534     return OSIP_SUCCESS; /* it's all done */
535   }
536 
537   osip_strncpy(message, "Content-Length: ", 16);
538   message = message + 16;
539 
540   /* SIPit Day1
541      ALWAYS RECALCULATE?
542      if (sip->contentlength!=NULL)
543      {
544      i = osip_content_length_to_str(sip->contentlength, &tmp);
545      if (i!=0) {
546      osip_free(*dest);
547      *dest = NULL;
548      return i;
549      }
550      osip_strncpy(message,tmp,strlen(tmp));
551      osip_free(tmp);
552      }
553      else
554      { */
555   if (osip_list_eol(&sip->bodies, 0)) /* no body */
556     message = osip_strn_append(message, "0", 1);
557 
558   else {
559     /* BUG: p130 (rfc2543bis-04)
560        "No SP after last token or quoted string"
561 
562        In fact, if extra spaces exist: the stack can't be used
563        to make user-agent that wants to make authentication...
564        This should be changed...
565      */
566 
567     content_length_to_modify = message;
568     message = osip_str_append(message, "     ");
569   }
570 
571   /*  } */
572 
573   message = osip_strn_append(message, OSIP_CRLF, 2);
574 
575   /* end of headers */
576   message = osip_strn_append(message, OSIP_CRLF, 2);
577 
578   start_of_bodies = message;
579   total_length = start_of_bodies - *dest;
580 
581   if (osip_list_eol(&sip->bodies, 0)) {
582     /* same remark as at the beginning of the method */
583     sip->message_property = 1;
584     sip->message = osip_strdup(*dest);
585     sip->message_length = total_length;
586 
587     if (message_length != NULL)
588       *message_length = total_length;
589 
590     return OSIP_SUCCESS; /* it's all done */
591   }
592 
593   if (sip->content_type && sip->content_type->type && !osip_strcasecmp(sip->content_type->type, "multipart")) {
594     osip_generic_param_t *ct_param = NULL;
595 
596     /* find the boundary */
597     i = osip_generic_param_get_byname(&sip->content_type->gen_params, "boundary", &ct_param);
598 
599     if ((i >= 0) && ct_param && ct_param->gvalue) {
600       size_t len = strlen(ct_param->gvalue);
601 
602       if (len > MIME_MAX_BOUNDARY_LEN) {
603         osip_free(*dest);
604         *dest = NULL;
605         return OSIP_SYNTAXERROR;
606       }
607 
608       if (len == 1 && ct_param->gvalue[0] == '"') { /* fixed Jan 10,2020: avoid a negative length copy if boundary contains only one quote */
609         osip_free(*dest);
610         *dest = NULL;
611         return OSIP_SYNTAXERROR;
612       }
613 
614       if (len == 2 && ct_param->gvalue[0] == '"' && ct_param->gvalue[1] == '"') { /* do not accept empty boundary */
615         osip_free(*dest);
616         *dest = NULL;
617         return OSIP_SYNTAXERROR;
618       }
619 
620       boundary = osip_malloc(len + 5);
621 
622       if (boundary == NULL) {
623         osip_free(*dest);
624         *dest = NULL;
625         return OSIP_NOMEM;
626       }
627 
628       osip_strncpy(boundary, OSIP_CRLF, 2);
629       osip_strncpy(boundary + 2, "--", 2);
630 
631       if (ct_param->gvalue[0] == '"' && ct_param->gvalue[len - 1] == '"')
632         osip_strncpy(boundary + 4, ct_param->gvalue + 1, len - 2);
633 
634       else
635         osip_strncpy(boundary + 4, ct_param->gvalue, len);
636     }
637   }
638 
639   {
640     osip_list_iterator_t it;
641     osip_body_t *body = (osip_body_t *) osip_list_get_first(&sip->bodies, &it);
642 
643     while (body != OSIP_SUCCESS) {
644       size_t body_length;
645 
646       if (boundary) {
647         /* Needs at most 77 bytes,
648            last realloc allocate at least 100 bytes extra */
649         message = osip_str_append(message, boundary);
650         message = osip_strn_append(message, OSIP_CRLF, 2);
651       }
652 
653       i = osip_body_to_str(body, &tmp, &body_length);
654 
655       if (i != 0) {
656         osip_free(*dest);
657         *dest = NULL;
658 
659         if (boundary)
660           osip_free(boundary);
661 
662         return i;
663       }
664 
665       if (malloc_size < message - *dest + 100 + body_length) {
666         size_t size = message - *dest;
667         int offset_of_body;
668         int offset_content_length_to_modify = 0;
669 
670         offset_of_body = (int) (start_of_bodies - *dest);
671 
672         if (content_length_to_modify != NULL)
673           offset_content_length_to_modify = (int) (content_length_to_modify - *dest);
674 
675         malloc_size = message - *dest + body_length + 100;
676         *dest = osip_realloc(*dest, malloc_size);
677 
678         if (*dest == NULL) {
679           osip_free(tmp); /* fixed 09/Jun/2005 */
680 
681           if (boundary)
682             osip_free(boundary);
683 
684           return OSIP_NOMEM;
685         }
686 
687         start_of_bodies = *dest + offset_of_body;
688 
689         if (content_length_to_modify != NULL)
690           content_length_to_modify = *dest + offset_content_length_to_modify;
691 
692         message = *dest + size;
693       }
694 
695       memcpy(message, tmp, body_length);
696       message[body_length] = '\0';
697       osip_free(tmp);
698       message = message + body_length;
699 
700       body = (osip_body_t *) osip_list_get_next(&it);
701     }
702   }
703 
704   if (boundary) {
705     /* Needs at most 79 bytes,
706        last realloc allocate at least 100 bytes extra */
707     message = osip_str_append(message, boundary);
708     message = osip_strn_append(message, "--", 2);
709     message = osip_strn_append(message, OSIP_CRLF, 2);
710 
711     osip_free(boundary);
712     boundary = NULL;
713   }
714 
715   if (content_length_to_modify == NULL) {
716     osip_free(*dest);
717     *dest = NULL;
718     return OSIP_SYNTAXERROR;
719   }
720 
721   /* we NOW have the length of bodies: */
722   {
723     size_t size = message - start_of_bodies;
724     char tmp2[15];
725 
726     total_length += size;
727     snprintf(tmp2, 15, "%i", (int) size);
728     /* do not use osip_strncpy here! */
729     memcpy(content_length_to_modify + 5 - strlen(tmp2), tmp2, strlen(tmp2));
730   }
731 
732   /* same remark as at the beginning of the method */
733   sip->message_property = 1;
734   sip->message = osip_malloc(total_length + 1);
735 
736   if (sip->message != NULL) {
737     memcpy(sip->message, *dest, total_length);
738     sip->message[total_length] = '\0';
739     sip->message_length = total_length;
740 
741     if (message_length != NULL)
742       *message_length = total_length;
743   }
744 
745   return OSIP_SUCCESS;
746 }
747 
osip_message_to_str(osip_message_t * sip,char ** dest,size_t * message_length)748 int osip_message_to_str(osip_message_t *sip, char **dest, size_t *message_length) {
749   return _osip_message_to_str(sip, dest, message_length, 0);
750 }
751 
osip_message_to_str_sipfrag(osip_message_t * sip,char ** dest,size_t * message_length)752 int osip_message_to_str_sipfrag(osip_message_t *sip, char **dest, size_t *message_length) {
753   return _osip_message_to_str(sip, dest, message_length, 1);
754 }
755