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