1 /*
2  * This file is part of the Sofia-SIP package
3  *
4  * Copyright (C) 2005 Nokia Corporation.
5  *
6  * Contact: Pekka Pessi <pekka.pessi@nokia.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation; either version 2.1 of
11  * the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21  * 02110-1301 USA
22  *
23  */
24 
25 /**@ingroup msg_headers
26  * @CFILE msg_header_make.c
27  *
28  * Creating message headers from strings.
29  *
30  * @author Pekka Pessi <Pekka.Pessi@nokia.com>
31  *
32  * @date Created: Fri Feb 23 14:06:34 2001 ppessi
33  *
34  */
35 
36 #include "config.h"
37 
38 #include <sofia-sip/su_alloc.h>
39 
40 #include "sofia-sip/msg.h"
41 #include "sofia-sip/bnf.h"
42 #include "sofia-sip/msg_parser.h"
43 #include "sofia-sip/msg_header.h"
44 
45 #include <stddef.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <stdio.h>
49 #include <stdarg.h>
50 #include <limits.h>
51 #include <errno.h>
52 
53 #if defined(va_copy)
54 /* Xyzzy */
55 #elif defined(__va_copy)
56 #define va_copy(dst, src) __va_copy((dst), (src))
57 #else
58 #define va_copy(dst, src) (memcpy(&(dst), &(src), sizeof (va_list)))
59 #endif
60 
61 #include <assert.h>
62 
63 /** Make a header from a value string. */
msg_header_make(su_home_t * home,msg_hclass_t * hc,char const * s)64 msg_header_t *msg_header_make(su_home_t *home,
65 			      msg_hclass_t *hc,
66 			      char const *s)
67 {
68   size_t xtra;
69   msg_header_t *h;
70   int normal = hc->hc_name ||
71     (hc->hc_hash != msg_payload_hash &&
72      hc->hc_hash != msg_separator_hash &&
73      hc->hc_hash != msg_error_hash);
74 
75   if (s == NULL)
76     return NULL;
77 
78   /* For normal headers, strip LWS from both ends */
79   if (normal)
80     skip_lws(&s);
81   xtra = strlen(s);
82   if (normal)
83     while (xtra > 0 && IS_LWS(s[xtra - 1]))
84       xtra--;
85 
86   h = msg_header_alloc(home, hc, xtra + 1);
87 
88   if (h) {
89     char *b = MSG_HEADER_DATA(h);
90 
91     strncpy(b, s, xtra)[xtra] = 0;
92 
93     if (hc->hc_parse(home, h, b, xtra) == -1) {
94       /* Note: parsing function is responsible to free
95 	 everything it has allocated (like parameter lists) */
96       /* XXX - except header structures */
97       su_free(home, h), h = NULL;
98     }
99   }
100 
101   return h;
102 }
103 
104 /** Make a MSG header with formatting provided. */
msg_header_vformat(su_home_t * home,msg_hclass_t * hc,char const * fmt,va_list ap)105 msg_header_t *msg_header_vformat(su_home_t *home,
106 				msg_hclass_t *hc,
107 				char const *fmt,
108 				va_list ap)
109 {
110   msg_header_t *h;
111 
112   int n;
113   size_t xtra = 64;		/* reasonable default */
114 
115   /* Quick path */
116   if (!fmt || !strchr(fmt, '%'))
117     return msg_header_make(home, hc, fmt);
118 
119   /* Another quickie */
120   if (strcmp(fmt, "%s") == 0) {
121     fmt = va_arg(ap, char const *);
122     return msg_header_make(home, hc, fmt);
123   }
124 
125   if (!(h = msg_header_alloc(home, hc, xtra)))
126     return NULL;
127 
128   for (;;) {
129     va_list aq;
130 
131     va_copy(aq, ap);
132     n = vsnprintf(MSG_HEADER_DATA(h), xtra, fmt, aq);
133     va_end(aq);
134 
135     if (n >= 0 && (size_t)n < xtra)
136       break;
137 
138     /* Try again with more space */
139     su_free(home, h);
140 
141     if (xtra >= INT_MAX)
142       return NULL;
143 
144     if (n >= 0)
145       xtra = n + 1; /* precisely what is needed */
146     else
147       xtra *= 2;    /* glibc 2.0 - twice the old size */
148 
149     if (xtra > INT_MAX)
150       xtra = INT_MAX;
151 
152     if (!(h = msg_header_alloc(home, hc, xtra)))
153       return NULL;
154   }
155 
156   if (hc->hc_parse(home, h, MSG_HEADER_DATA(h), (size_t)n) == -1) {
157     /* Note: parsing function is responsible to free
158        everything it has allocated (like parameter lists) */
159     su_free(home, h), h = NULL;
160   }
161 
162   return h;
163 }
164 
msg_header_format(su_home_t * home,msg_hclass_t * hc,char const * fmt,...)165 msg_header_t *msg_header_format(su_home_t *home,
166 				msg_hclass_t *hc,
167 				char const *fmt,
168 				...)
169 {
170   msg_header_t *h;
171   va_list ap;
172 
173   va_start(ap, fmt);
174 
175   h = msg_header_vformat(home, hc, fmt, ap);
176 
177   va_end(ap);
178 
179   return h;
180 }
181