xref: /illumos-gate/usr/src/lib/libsip/common/sip_add_hdrs.c (revision 4c28a617e3922d92a58e813a5b955eb526b9c386)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <stdio.h>
28 #include <ctype.h>
29 #include <errno.h>
30 #include <pthread.h>
31 #include <strings.h>
32 #include <stdlib.h>
33 #include <sip.h>
34 
35 #include "sip_msg.h"
36 #include "sip_miscdefs.h"
37 
38 /*
39  * Returns number of digits in the given int
40  */
41 static int
42 sip_num_of_digits(int num)
43 {
44 	int	num_of_bytes = 0;
45 
46 	do {
47 		num_of_bytes += 1;
48 		num = num / 10;
49 	} while (num > 0);
50 	return (num_of_bytes);
51 }
52 
53 /*
54  * Return the int as a string
55  */
56 static char *
57 sip_int_to_str(int i)
58 {
59 	int	count;
60 	int	t;
61 	int	x;
62 	char	*str;
63 
64 	if (i < 0)
65 		return (NULL);
66 	/*
67 	 * the following two loops convert int i to str
68 	 */
69 	count = 1;
70 	t = i;
71 	while ((t = t / 10) != 0) {
72 		count++;
73 	}
74 
75 	str = calloc(1, sizeof (char) * count + 1);
76 	if (str == NULL)
77 		return (NULL);
78 	t = i;
79 	for (x = 0; x < count; x++) {
80 		int a;
81 		a = t % 10;
82 		str[count - 1 - x] = a + '0';
83 		t = t / 10;
84 	}
85 	str[count] = '\0';
86 	return (str);
87 }
88 
89 /*
90  * Add quotes to the give str and return the quoted string
91  */
92 static char *
93 sip_add_aquot_to_str(char *str, boolean_t *alloc)
94 {
95 	char 		*new_str;
96 	char 		*tmp = str;
97 	int		size;
98 
99 	while (isspace(*tmp))
100 		tmp++;
101 
102 	*alloc = B_FALSE;
103 	if (*tmp != SIP_LAQUOT) {
104 		size = strlen(str) + 2 * sizeof (char);
105 		new_str = calloc(1, size + 1);
106 		if (new_str == NULL)
107 			return (NULL);
108 		new_str[0] = SIP_LAQUOT;
109 		new_str[1] = '\0';
110 		(void) strncat(new_str, str, strlen(str));
111 		(void) strncat(new_str, ">", 1);
112 		new_str[size] = '\0';
113 		*alloc = B_TRUE;
114 		return (new_str);
115 	}
116 
117 	return (str);
118 }
119 
120 /*
121  * Add an empty header
122  */
123 static int
124 sip_add_empty_hdr(sip_msg_t sip_msg, char *hdr_name)
125 {
126 	_sip_header_t	*new_header;
127 	int 		header_size;
128 	_sip_msg_t 	*_sip_msg;
129 	int		csize = sizeof (char);
130 
131 	if (sip_msg == NULL || hdr_name == NULL)
132 		return (EINVAL);
133 	_sip_msg = (_sip_msg_t *)sip_msg;
134 	(void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
135 	if (_sip_msg->sip_msg_cannot_be_modified) {
136 		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
137 		return (ENOTSUP);
138 	}
139 
140 	header_size = strlen(hdr_name) + SIP_SPACE_LEN + csize;
141 
142 	new_header = sip_new_header(header_size);
143 	if (new_header == NULL) {
144 		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
145 		return (ENOMEM);
146 	}
147 
148 	(void) snprintf(new_header->sip_hdr_start, header_size + 1,
149 	    "%s %c",  hdr_name, SIP_HCOLON);
150 
151 	_sip_add_header(_sip_msg, new_header, B_TRUE, B_FALSE, hdr_name);
152 	if (_sip_msg->sip_msg_buf != NULL)
153 		_sip_msg->sip_msg_modified = B_TRUE;
154 	(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
155 
156 	return (0);
157 }
158 
159 /*
160  * Generic function to add a header with two strings to message
161  */
162 static int
163 sip_add_2strs_to_msg(sip_msg_t sip_msg, char *hdr_name, char *str1,
164     boolean_t qstr1, char *str2, char *plist, char sep)
165 {
166 	_sip_header_t	*new_header;
167 	int 		header_size;
168 	_sip_msg_t 	*_sip_msg;
169 	int		csize = sizeof (char);
170 
171 	if (sip_msg == NULL || str1 == NULL || str2 == NULL ||
172 	    (str1 != NULL && str1[0] == '\0') ||
173 	    (str2 != NULL && str2[0] == '\0')) {
174 		return (EINVAL);
175 	}
176 	_sip_msg = (_sip_msg_t *)sip_msg;
177 	(void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
178 	if (_sip_msg->sip_msg_cannot_be_modified) {
179 		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
180 		return (ENOTSUP);
181 	}
182 
183 	if (plist == NULL) {
184 		header_size = strlen(hdr_name) + SIP_SPACE_LEN + csize +
185 		    SIP_SPACE_LEN + strlen(str1) + csize + strlen(str2) +
186 		    strlen(SIP_CRLF);
187 	} else {
188 		header_size = strlen(hdr_name) + SIP_SPACE_LEN + csize +
189 		    SIP_SPACE_LEN + strlen(str1) + csize + strlen(str2) +
190 		    csize + strlen(plist) + strlen(SIP_CRLF);
191 	}
192 	if (qstr1)
193 		header_size += 2 * sizeof (char);
194 
195 	new_header = sip_new_header(header_size);
196 	if (new_header == NULL) {
197 		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
198 		return (ENOMEM);
199 	}
200 
201 	if (plist == NULL) {
202 		if (qstr1) {
203 			(void) snprintf(new_header->sip_hdr_start,
204 			    header_size + 1, "%s %c \"%s\"%c%s%s",
205 			    hdr_name, SIP_HCOLON, str1, sep, str2, SIP_CRLF);
206 		} else {
207 			(void) snprintf(new_header->sip_hdr_start,
208 			    header_size + 1, "%s %c %s%c%s%s",
209 			    hdr_name, SIP_HCOLON, str1, sep, str2, SIP_CRLF);
210 		}
211 	} else {
212 		if (qstr1) {
213 			(void) snprintf(new_header->sip_hdr_start,
214 			    header_size + 1,
215 			    "%s %c \"%s\"%c%s%c%s%s", hdr_name, SIP_HCOLON,
216 			    str1, sep, str2, SIP_SEMI, plist, SIP_CRLF);
217 		} else {
218 			(void) snprintf(new_header->sip_hdr_start,
219 			    header_size + 1, "%s %c %s%c%s%c%s%s",
220 			    hdr_name, SIP_HCOLON, str1, sep, str2, SIP_SEMI,
221 			    plist, SIP_CRLF);
222 		}
223 	}
224 	_sip_add_header(_sip_msg, new_header, B_TRUE, B_FALSE, NULL);
225 	if (_sip_msg->sip_msg_buf != NULL)
226 		_sip_msg->sip_msg_modified = B_TRUE;
227 	(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
228 
229 	return (0);
230 }
231 
232 /*
233  * Generic function to add a header with a string to message
234  */
235 static int
236 sip_add_str_to_msg(sip_msg_t sip_msg, char *hdr_name, char *str, char *plist,
237     char param_sep)
238 {
239 	_sip_header_t	*new_header;
240 	int 		header_size;
241 	_sip_msg_t 	*_sip_msg;
242 	int		csize = sizeof (char);
243 
244 	if (sip_msg == NULL || str == NULL || (str != NULL && str[0] == '\0'))
245 		return (EINVAL);
246 	_sip_msg = (_sip_msg_t *)sip_msg;
247 	(void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
248 	if (_sip_msg->sip_msg_cannot_be_modified) {
249 		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
250 		return (ENOTSUP);
251 	}
252 
253 	if (plist == NULL) {
254 		header_size = strlen(hdr_name) + SIP_SPACE_LEN + csize +
255 		    SIP_SPACE_LEN + + strlen(str) + strlen(SIP_CRLF);
256 	} else {
257 		header_size = strlen(hdr_name) + SIP_SPACE_LEN + csize +
258 		    SIP_SPACE_LEN + + strlen(str) + csize + strlen(plist) +
259 		    strlen(SIP_CRLF);
260 	}
261 
262 	new_header = sip_new_header(header_size);
263 	if (new_header == NULL) {
264 		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
265 		return (ENOMEM);
266 	}
267 	if (plist == NULL) {
268 		(void) snprintf(new_header->sip_hdr_start, header_size + 1,
269 		    "%s %c %s%s", hdr_name, SIP_HCOLON, str, SIP_CRLF);
270 	} else {
271 		(void) snprintf(new_header->sip_hdr_start, header_size + 1,
272 		    "%s %c %s%c%s%s", hdr_name, SIP_HCOLON, str, param_sep,
273 		    plist, SIP_CRLF);
274 	}
275 	_sip_add_header(_sip_msg, new_header, B_TRUE, B_FALSE, NULL);
276 	if (_sip_msg->sip_msg_buf != NULL)
277 		_sip_msg->sip_msg_modified = B_TRUE;
278 	(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
279 
280 	return (0);
281 }
282 
283 /*
284  * Add an header with an int to sip_msg
285  */
286 static int
287 sip_add_int_to_msg(sip_msg_t sip_msg, char *hdr_name, int i, char *plist)
288 {
289 	_sip_header_t	*new_header;
290 	int 		header_size;
291 	_sip_msg_t 	*_sip_msg;
292 	char		*digit_str;
293 	int		csize = sizeof (char);
294 
295 	if (sip_msg == NULL || (hdr_name == NULL))
296 		return (EINVAL);
297 	_sip_msg = (_sip_msg_t *)sip_msg;
298 	(void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
299 	if (_sip_msg->sip_msg_cannot_be_modified) {
300 		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
301 		return (ENOTSUP);
302 	}
303 
304 	/*
305 	 * the following two loops convert int i to str
306 	 */
307 	digit_str = sip_int_to_str(i);
308 	if (digit_str == NULL)
309 		return (EINVAL);
310 
311 	if (plist == NULL) {
312 		header_size = strlen(hdr_name) + SIP_SPACE_LEN + csize +
313 		    SIP_SPACE_LEN + strlen(digit_str) + strlen(SIP_CRLF);
314 	} else {
315 		header_size = strlen(hdr_name) + SIP_SPACE_LEN + csize +
316 		    SIP_SPACE_LEN + strlen(digit_str) + csize +
317 		    strlen(plist) + strlen(SIP_CRLF);
318 	}
319 
320 	new_header = sip_new_header(header_size);
321 	if (new_header == NULL) {
322 		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
323 		free(digit_str);
324 		return (ENOMEM);
325 	}
326 
327 	if (plist == NULL) {
328 		(void) snprintf(new_header->sip_hdr_start, header_size + 1,
329 		    "%s %c %s%s", hdr_name, SIP_HCOLON, digit_str, SIP_CRLF);
330 	} else {
331 		(void) snprintf(new_header->sip_hdr_start, header_size + 1,
332 		    "%s %c %s%c%s%s", hdr_name, SIP_HCOLON, digit_str,
333 		    SIP_SEMI, plist, SIP_CRLF);
334 	}
335 	free(digit_str);
336 	_sip_add_header(_sip_msg, new_header, B_TRUE, B_FALSE, NULL);
337 	if (_sip_msg->sip_msg_buf != NULL)
338 		_sip_msg->sip_msg_modified = B_TRUE;
339 	(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
340 
341 	return (0);
342 }
343 
344 /*
345  * Add a header with an int and string to sip_msg
346  */
347 static int
348 sip_add_intstr_to_msg(sip_msg_t sip_msg, char *hdr_name, int i, char *s,
349     char *plist)
350 {
351 	_sip_header_t	*new_header;
352 	int 		header_size;
353 	_sip_msg_t 	*_sip_msg;
354 	char		*digit_str;
355 	int		csize = sizeof (char);
356 
357 	if (sip_msg == NULL || (hdr_name == NULL))
358 		return (EINVAL);
359 	_sip_msg = (_sip_msg_t *)sip_msg;
360 	(void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
361 	if (_sip_msg->sip_msg_cannot_be_modified) {
362 		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
363 		return (ENOTSUP);
364 	}
365 
366 	/*
367 	 * the following two loops convert int i to str
368 	 */
369 	digit_str = sip_int_to_str(i);
370 	if (digit_str == NULL) {
371 		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
372 		return (EINVAL);
373 	}
374 	if (plist == NULL) {
375 		header_size = strlen(hdr_name) + SIP_SPACE_LEN + csize +
376 		    SIP_SPACE_LEN + strlen(digit_str) + csize + strlen(s) +
377 		    strlen(SIP_CRLF);
378 	} else {
379 		header_size = strlen(hdr_name) + SIP_SPACE_LEN + csize +
380 		    SIP_SPACE_LEN + strlen(digit_str) + csize + strlen(s) +
381 		    csize + strlen(plist) + strlen(SIP_CRLF);
382 	}
383 
384 	new_header = sip_new_header(header_size);
385 	if (new_header == NULL) {
386 		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
387 		free(digit_str);
388 		return (ENOMEM);
389 	}
390 
391 	if (plist == NULL) {
392 		(void) snprintf(new_header->sip_hdr_start, header_size + 1,
393 		    "%s %c %s %s%s", hdr_name, SIP_HCOLON, digit_str, s,
394 		    SIP_CRLF);
395 	} else {
396 		(void) snprintf(new_header->sip_hdr_start, header_size + 1,
397 		    "%s %c %s %s%c%s%s", hdr_name, SIP_HCOLON, digit_str,
398 		    s, SIP_SEMI, plist, SIP_CRLF);
399 	}
400 	free(digit_str);
401 	_sip_add_header(_sip_msg, new_header, B_TRUE, B_FALSE, NULL);
402 	if (_sip_msg->sip_msg_buf != NULL)
403 		_sip_msg->sip_msg_modified = B_TRUE;
404 	(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
405 
406 	return (0);
407 }
408 
409 /*
410  * Generic function to add Contact, From,  To, Route or Record-Route header
411  */
412 static int
413 sip_add_name_aspec(sip_msg_t sip_msg, char *display_name, char *uri,
414     char *tags, boolean_t add_aquot, char *header_name, char *params)
415 {
416 	char		*t = uri;
417 	boolean_t	qalloc = B_FALSE;
418 	boolean_t	palloc = B_FALSE;
419 	int		r;
420 
421 	if (sip_msg == NULL || uri == NULL || header_name == NULL)
422 		return (EINVAL);
423 	if (display_name != NULL && !add_aquot)
424 		return (EINVAL);
425 	if (add_aquot) {
426 		t = sip_add_aquot_to_str(uri, &qalloc);
427 		if (t == NULL)
428 			return (ENOMEM);
429 	}
430 	if (tags != NULL) {
431 		int	plen;
432 
433 		if (params != NULL)
434 			return (EINVAL);
435 
436 		plen = strlen(SIP_TAG) + strlen(tags) + 1;
437 		params = malloc(plen);
438 		if (params == NULL)
439 			return (ENOMEM);
440 		(void) snprintf(params, plen, "%s%s", SIP_TAG, tags);
441 		params[plen - 1] = '\0';
442 		palloc = B_TRUE;
443 	}
444 	if (display_name == NULL) {
445 		r = sip_add_2strs_to_msg(sip_msg, header_name, " ", B_FALSE,
446 		    t, params, SIP_SP);
447 	} else {
448 		r = sip_add_2strs_to_msg(sip_msg, header_name, display_name,
449 		    B_TRUE, t, params, SIP_SP);
450 	}
451 	if (qalloc)
452 		free(t);
453 	if (palloc)
454 		free(params);
455 	return (r);
456 }
457 
458 /*
459  * Accept = "Accept" ":" (media-range [ accept-params ])
460  * media-range = ( "X/X" | (type "/" "*") | (type "/" subtype))*(";" parameter)
461  * accept-params = ";" "q" "=" qvalue *(accept-extension)
462  * accept-extension = ";" token [ "=" (token | quoted-str)
463  *
464  * function take two char ptrs - type and subtype - if any of them is NULL
465  * the corresponding value will be set to "*" in header
466  */
467 int
468 sip_add_accept(sip_msg_t sip_msg, char *type, char *subtype, char *m_par,
469     char *a_par)
470 {
471 	int		ret;
472 	char		*plist;
473 	int		size;
474 	boolean_t	alloc = B_FALSE;
475 
476 	if (type == NULL && subtype == NULL) {
477 		ret = sip_add_empty_hdr(sip_msg, SIP_ACCEPT);
478 		return (ret);
479 	}
480 
481 	if ((m_par != NULL) && (a_par != NULL)) {
482 		size = strlen(m_par) + strlen(a_par) + 2 * sizeof (char);
483 		plist = calloc(1, size * sizeof (char));
484 		(void) strncpy(plist, m_par, strlen(m_par));
485 		(void) strncat(plist, ";", 1);
486 		(void) strncat(plist, a_par, strlen(a_par));
487 		alloc = B_TRUE;
488 	} else if (m_par != NULL) {
489 		plist = m_par;
490 	} else
491 		plist = a_par;
492 
493 	if ((type != NULL) && (subtype != NULL)) {
494 		ret = sip_add_2strs_to_msg(sip_msg, SIP_ACCEPT, type, B_FALSE,
495 		    subtype, plist, SIP_SLASH);
496 	} else if (type != NULL) {
497 		ret = sip_add_2strs_to_msg(sip_msg, SIP_ACCEPT, type, B_FALSE,
498 		    "*", plist, SIP_SLASH);
499 	} else {
500 		ret = EINVAL;
501 	}
502 
503 	if (alloc == B_TRUE)
504 		free(plist);
505 
506 	return (ret);
507 }
508 
509 
510 /*
511  * Accept-Encoding = "Accept-Encoding" ":" 1#(codings [ ";" "q" "=" qval])
512  * codings = ( content-coding | "*" )
513  * content-coding   =  token
514  *
515  * function take one char ptr, if NULL value will be set to "*"
516  */
517 int
518 sip_add_accept_enc(sip_msg_t sip_msg, char *code, char *plist)
519 {
520 	int ret;
521 
522 	if (code == NULL) {
523 		ret = sip_add_str_to_msg(sip_msg, SIP_ACCEPT_ENCODE, "*", plist,
524 		    SIP_SEMI);
525 	} else {
526 		ret = sip_add_str_to_msg(sip_msg, SIP_ACCEPT_ENCODE, code,
527 		    plist, SIP_SEMI);
528 	}
529 	return (ret);
530 }
531 
532 /*
533  * Accept-Language = "Accept-Language" ":" 1#( language-range [ ";" "q""=" val])
534  * language-range = ( ( 1*8ALPHA *("-" 1*8ALPHA))|"*")
535  */
536 int
537 sip_add_accept_lang(sip_msg_t sip_msg, char *lang, char *plist)
538 {
539 	int	ret;
540 
541 	if (lang == NULL) {
542 		ret = sip_add_empty_hdr(sip_msg, SIP_ACCEPT_LANG);
543 		return (ret);
544 	}
545 	ret = sip_add_str_to_msg(sip_msg, SIP_ACCEPT_LANG, lang, plist,
546 	    SIP_SEMI);
547 	return (ret);
548 }
549 
550 /*
551  * Alert-Info = "Alert-Info" ":" "<" URI ">"
552  */
553 int
554 sip_add_alert_info(sip_msg_t sip_msg, char *alert, char *plist)
555 {
556 	int		ret;
557 	char		*tmp;
558 	boolean_t	alloc;
559 
560 	if (alert == NULL)
561 		return (EINVAL);
562 	tmp = sip_add_aquot_to_str(alert, &alloc);
563 	if (tmp == NULL)
564 		return (ENOMEM);
565 	ret = sip_add_str_to_msg(sip_msg, SIP_ALERT_INFO, tmp, plist, SIP_SEMI);
566 	if (alloc)
567 		free(tmp);
568 	return (ret);
569 }
570 
571 /*
572  * Allow = "Allow" ":" method-name1[, method-name2..]
573  * method-name = "INVITE" | "ACK" | "OPTIONS" | "CANCEL" | "BYE"
574  */
575 int
576 sip_add_allow(sip_msg_t sip_msg, sip_method_t method)
577 {
578 	int	ret;
579 
580 	if (method == 0 || method >= MAX_SIP_METHODS)
581 		return (EINVAL);
582 	ret = sip_add_str_to_msg(sip_msg, SIP_ALLOW, sip_methods[method].name,
583 	    NULL, (char)NULL);
584 	return (ret);
585 }
586 
587 /*
588  * Call-Info   =  "Call-Info" HCOLON info *(COMMA info)
589  * info        =  LAQUOT absoluteURI RAQUOT *( SEMI info-param)
590  * info-param  =  ( "purpose" EQUAL ( "icon" / "info"
591  *		/ "card" / token ) ) / generic-param
592  */
593 int
594 sip_add_call_info(sip_msg_t sip_msg, char *uri, char *plist)
595 {
596 	char		*tmp;
597 	boolean_t	alloc;
598 	int		r;
599 
600 	if (uri == NULL)
601 		return (EINVAL);
602 	tmp = sip_add_aquot_to_str(uri, &alloc);
603 	if (tmp == NULL)
604 		return (ENOMEM);
605 	r = sip_add_str_to_msg(sip_msg, SIP_CALL_INFO, tmp, plist, SIP_SEMI);
606 	if (alloc)
607 		free(tmp);
608 	return (r);
609 }
610 
611 /*
612  * Content-Disposition   =  "Content-Disposition" HCOLON
613  *				disp-type *( SEMI disp-param )
614  * disp-type             =  "render" / "session" / "icon" / "alert"
615  *				/ disp-extension-token
616  * disp-param            =  handling-param / generic-param
617  * handling-param        =  "handling" EQUAL
618  *				( "optional" / "required"
619  *				/ other-handling )
620  * other-handling        =  token
621  * disp-extension-token  =  token
622  */
623 int
624 sip_add_content_disp(sip_msg_t sip_msg, char *dis_type, char *plist)
625 {
626 	int	ret;
627 
628 	if (dis_type == NULL)
629 		return (EINVAL);
630 
631 	ret = sip_add_str_to_msg(sip_msg, SIP_CONTENT_DIS, dis_type, plist,
632 	    SIP_SEMI);
633 	return (ret);
634 }
635 
636 /*
637  * Content-Encoding  =  ( "Content-Encoding" / "e" ) HCOLON
638  *			content-coding *(COMMA content-coding)
639  * content-coding   =  token
640  */
641 int
642 sip_add_content_enc(sip_msg_t sip_msg, char *code)
643 {
644 	int	ret;
645 
646 	if (code == NULL)
647 		return (EINVAL);
648 
649 	ret = sip_add_str_to_msg(sip_msg, SIP_CONTENT_ENCODE, code, NULL,
650 	    (char)NULL);
651 	return (ret);
652 }
653 
654 /*
655  * Content-Language  =  "Content-Language" HCOLON
656  *			language-tag *(COMMA language-tag)
657  * language-tag      =  primary-tag *( "-" subtag )
658  * primary-tag       =  1*8ALPHA
659  * subtag            =  1*8ALPHA
660  */
661 int
662 sip_add_content_lang(sip_msg_t sip_msg, char *lang)
663 {
664 	int	ret;
665 
666 	if (lang == NULL)
667 		return (EINVAL);
668 	ret = sip_add_str_to_msg(sip_msg, SIP_CONTENT_LANG, lang, NULL,
669 	    (char)NULL);
670 	return (ret);
671 }
672 
673 /*
674  * Date          =  "Date" HCOLON SIP-date
675  * SIP-date      =  rfc1123-date
676  * rfc1123-date  =  wkday "," SP date1 SP time SP "GMT"
677  * date1         =  2DIGIT SP month SP 4DIGIT
678  * 			; day month year (e.g., 02 Jun 1982)
679  * time          =  2DIGIT ":" 2DIGIT ":" 2DIGIT
680  *			; 00:00:00 - 23:59:59
681  * wkday         =  "Mon" / "Tue" / "Wed"
682  *			/ "Thu" / "Fri" / "Sat" / "Sun"
683  * month         =  "Jan" / "Feb" / "Mar" / "Apr"
684  *			/ "May" / "Jun" / "Jul" / "Aug"
685  *			/ "Sep" / "Oct" / "Nov" / "Dec"
686  */
687 int
688 sip_add_date(sip_msg_t sip_msg, char *date)
689 {
690 	int	ret;
691 
692 	if (date == NULL)
693 		return (EINVAL);
694 	ret = sip_add_str_to_msg(sip_msg, SIP_DATE, date, NULL, (char)NULL);
695 	return (ret);
696 }
697 
698 /*
699  * Error-Info  =  "Error-Info" HCOLON error-uri *(COMMA error-uri)
700  * error-uri   =  LAQUOT absoluteURI RAQUOT *( SEMI generic-param )
701  */
702 int
703 sip_add_error_info(sip_msg_t sip_msg, char *uri, char *plist)
704 {
705 	char		*tmp;
706 	boolean_t	alloc;
707 	int		r;
708 
709 	if (uri == NULL)
710 		return (EINVAL);
711 	tmp = sip_add_aquot_to_str(uri, &alloc);
712 	if (tmp == NULL)
713 		return (EINVAL);
714 
715 	r = sip_add_str_to_msg(sip_msg, SIP_ERROR_INFO, tmp, plist, SIP_SEMI);
716 	if (alloc)
717 		free(tmp);
718 	return (r);
719 }
720 
721 /*
722  * Expires     =  "Expires" HCOLON delta-seconds
723  * delta-seconds      =  1*DIGIT
724  */
725 int
726 sip_add_expires(sip_msg_t sip_msg, int secs)
727 {
728 	int	ret;
729 
730 	if (sip_msg == NULL || (int)secs < 0)
731 		return (EINVAL);
732 
733 	ret = sip_add_int_to_msg(sip_msg, SIP_EXPIRE, secs, NULL);
734 	return (ret);
735 }
736 
737 /*
738  * In-Reply-To  =  "In-Reply-To" HCOLON callid *(COMMA callid)
739  * callid   =  word [ "@" word ]
740  */
741 int
742 sip_add_in_reply_to(sip_msg_t sip_msg, char *reply_id)
743 {
744 	int		r;
745 
746 	if (reply_id == NULL)
747 		return (EINVAL);
748 	r = sip_add_str_to_msg(sip_msg, SIP_IN_REPLY_TO, reply_id, NULL,
749 	    (char)NULL);
750 	return (r);
751 }
752 
753 /*
754  * RSeq          =  "RSeq" HCOLON response-num
755  */
756 int
757 sip_add_rseq(sip_msg_t sip_msg, int resp_num)
758 {
759 	int	ret;
760 
761 	if (sip_msg == NULL || resp_num <= 0)
762 		return (EINVAL);
763 	ret = sip_add_int_to_msg(sip_msg, SIP_RSEQ, resp_num, NULL);
764 	return (ret);
765 }
766 
767 /*
768  * Min-Expires  =  "Min-Expires" HCOLON delta-seconds
769  */
770 int
771 sip_add_min_expires(sip_msg_t sip_msg, int secs)
772 {
773 	int	ret;
774 
775 	if (sip_msg == NULL || (int)secs < 0)
776 		return (EINVAL);
777 	ret = sip_add_int_to_msg(sip_msg, SIP_MIN_EXPIRE, secs, NULL);
778 	return (ret);
779 }
780 
781 /*
782  * MIME-Version  =  "MIME-Version" HCOLON 1*DIGIT "." 1*DIGIT
783  */
784 int
785 sip_add_mime_version(sip_msg_t sip_msg, char *version)
786 {
787 	int	ret;
788 
789 	if (version == NULL)
790 		return (EINVAL);
791 	ret = sip_add_str_to_msg(sip_msg, SIP_MIME_VERSION, version, NULL,
792 	    (char)NULL);
793 	return (ret);
794 }
795 
796 /*
797  * Organization  =  "Organization" HCOLON [TEXT-UTF8-TRIM]
798  */
799 int
800 sip_add_org(sip_msg_t sip_msg, char *org)
801 {
802 	int	ret;
803 
804 	if (org == NULL) {
805 		ret = sip_add_empty_hdr(sip_msg, SIP_ORGANIZATION);
806 	} else {
807 		ret = sip_add_str_to_msg(sip_msg, SIP_ORGANIZATION, org, NULL,
808 		    (char)NULL);
809 	}
810 	return (ret);
811 }
812 
813 /*
814  * Priority        =  "Priority" HCOLON priority-value
815  * priority-value  =  "emergency" / "urgent" / "normal"
816  *			/ "non-urgent" / other-priority
817  * other-priority  =  token
818  */
819 int
820 sip_add_priority(sip_msg_t sip_msg, char *prio)
821 {
822 	int	ret;
823 
824 	if (prio == NULL)
825 		return (EINVAL);
826 	ret = sip_add_str_to_msg(sip_msg, SIP_PRIORITY, prio, NULL, (char)NULL);
827 
828 	return (ret);
829 }
830 
831 /*
832  * Reply-To      =  "Reply-To" HCOLON rplyto-spec
833  * rplyto-spec   =  ( name-addr / addr-spec )
834  *			*( SEMI rplyto-param )
835  * rplyto-param  =  generic-param
836  */
837 int
838 sip_add_reply_to(sip_msg_t sip_msg, char *uname, char *addr, char *plist,
839     boolean_t add_aquot)
840 {
841 	return (sip_add_name_aspec(sip_msg, uname, addr, NULL, add_aquot,
842 	    SIP_REPLYTO, plist));
843 }
844 
845 
846 /*
847  * Privacy-hdr  =  "Privacy" HCOLON priv-value *(";" priv-value)
848  * priv-value   =   "header" / "session" / "user" / "none" / "critical"
849  *			/ token
850  */
851 int
852 sip_add_privacy(sip_msg_t sip_msg, char *priv_val)
853 {
854 	int	ret;
855 
856 	if (priv_val == NULL)
857 		return (EINVAL);
858 	ret = sip_add_str_to_msg(sip_msg, SIP_PRIVACY, priv_val, NULL,
859 	    (char)NULL);
860 	return (ret);
861 }
862 
863 /*
864  * Require       =  "Require" HCOLON option-tag *(COMMA option-tag)
865  * option-tag     =  token
866  */
867 int
868 sip_add_require(sip_msg_t sip_msg, char *req)
869 {
870 	int	ret;
871 
872 	if (req == NULL)
873 		return (EINVAL);
874 	ret = sip_add_str_to_msg(sip_msg, SIP_REQUIRE, req, NULL, (char)NULL);
875 	return (ret);
876 }
877 
878 /*
879  * Retry-After  =  "Retry-After" HCOLON delta-seconds
880  *			[ comment ] *( SEMI retry-param )
881  * retry-param  =  ("duration" EQUAL delta-seconds)
882  *			/ generic-param
883  */
884 int
885 sip_add_retry_after(sip_msg_t sip_msg, int secs, char *cmt, char *plist)
886 {
887 	int	r;
888 
889 	if (secs <= 0)
890 		return (EINVAL);
891 
892 	if (cmt == NULL) {
893 		r = sip_add_int_to_msg(sip_msg, SIP_RETRY_AFTER, secs, plist);
894 		return (r);
895 	}
896 
897 	r = sip_add_intstr_to_msg(sip_msg, SIP_RETRY_AFTER, secs, cmt, plist);
898 	return (r);
899 }
900 
901 /*
902  * Server           =  "Server" HCOLON server-val *(LWS server-val)
903  * server-val       =  product / comment
904  * product          =  token [SLASH product-version]
905  * product-version  =  token
906  */
907 int
908 sip_add_server(sip_msg_t sip_msg, char *svr)
909 {
910 	int	ret;
911 
912 	if (svr == NULL)
913 		return (EINVAL);
914 	ret = sip_add_str_to_msg(sip_msg, SIP_SERVER, svr, NULL, (char)NULL);
915 	return (ret);
916 }
917 
918 /*
919  * Subject  =  ( "Subject" / "s" ) HCOLON [TEXT-UTF8-TRIM]
920  */
921 int
922 sip_add_subject(sip_msg_t sip_msg, char *subject)
923 {
924 	int	ret;
925 
926 	if (subject == NULL) {
927 		ret = sip_add_empty_hdr(sip_msg, SIP_SUBJECT);
928 	} else {
929 		ret = sip_add_str_to_msg(sip_msg, SIP_SUBJECT, subject, NULL,
930 		    (char)NULL);
931 	}
932 	return (ret);
933 }
934 
935 /*
936  * Supported  =  ( "Supported" / "k" ) HCOLON
937  *		[option-tag *(COMMA option-tag)]
938  */
939 int
940 sip_add_supported(sip_msg_t sip_msg, char *support)
941 {
942 	int	ret;
943 
944 	if (support == NULL) {
945 		ret = sip_add_empty_hdr(sip_msg, SIP_SUPPORT);
946 	} else {
947 		ret = sip_add_str_to_msg(sip_msg, SIP_SUPPORT, support, NULL,
948 		    (char)NULL);
949 	}
950 	return (ret);
951 }
952 
953 /*
954  * Timestamp  =  "Timestamp" HCOLON 1*(DIGIT)
955  *		[ "." *(DIGIT) ] [ LWS delay ]
956  * delay      =  *(DIGIT) [ "." *(DIGIT) ]
957  */
958 int
959 sip_add_tstamp(sip_msg_t sip_msg, char *time, char *delay)
960 {
961 	int	ret;
962 
963 	if (delay == NULL) {
964 		ret = sip_add_str_to_msg(sip_msg, SIP_TIMESTAMP, time, NULL,
965 		    (char)NULL);
966 	} else {
967 		ret = sip_add_2strs_to_msg(sip_msg, SIP_TIMESTAMP, time,
968 		    B_FALSE, delay, NULL, ' ');
969 	}
970 	return (ret);
971 }
972 
973 /*
974  * Unsupported  =  "Unsupported" HCOLON option-tag *(COMMA option-tag)
975  */
976 int
977 sip_add_unsupported(sip_msg_t sip_msg, char *unsupport)
978 {
979 	int	ret;
980 
981 	if (unsupport == NULL)
982 		return (EINVAL);
983 	ret = sip_add_str_to_msg(sip_msg, SIP_UNSUPPORT, unsupport, NULL,
984 	    (char)NULL);
985 	return (ret);
986 }
987 
988 /*
989  * User-Agent  =  "User-Agent" HCOLON server-val *(LWS server-val)
990  */
991 int
992 sip_add_user_agent(sip_msg_t sip_msg, char *usr)
993 {
994 	int	r;
995 
996 	if (usr == NULL)
997 		return (EINVAL);
998 	r = sip_add_str_to_msg(sip_msg, SIP_USER_AGENT, usr, NULL, (char)NULL);
999 	return (r);
1000 }
1001 
1002 /*
1003  * Warning        =  "Warning" HCOLON warning-value *(COMMA warning-value)
1004  * warning-value  =  warn-code SP warn-agent SP warn-text
1005  * warn-code      =  3DIGIT
1006  * warn-agent     =  hostport / pseudonym
1007  *			;  the name or pseudonym of the server adding
1008  *			;  the Warning header, for use in debugging
1009  * warn-text      =  quoted-string
1010  * pseudonym      =  token
1011  */
1012 int
1013 sip_add_warning(sip_msg_t sip_msg, int code, char *addr, char *msg)
1014 {
1015 	_sip_header_t	*new_header;
1016 	int 		header_size;
1017 	_sip_msg_t 	*_sip_msg;
1018 	char		*hdr_name = SIP_WARNING;
1019 
1020 	if (sip_msg == NULL || addr == NULL || msg == NULL ||
1021 	    addr[0] == '\0' || msg[0] == '\0' || code < 100 || code > 999) {
1022 		return (EINVAL);
1023 	}
1024 
1025 	_sip_msg = (_sip_msg_t *)sip_msg;
1026 	(void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
1027 	if (_sip_msg->sip_msg_cannot_be_modified) {
1028 		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
1029 		return (ENOTSUP);
1030 	}
1031 
1032 	header_size = strlen(hdr_name) + SIP_SPACE_LEN + sizeof (char) +
1033 	    SIP_SPACE_LEN + sip_num_of_digits(code) + SIP_SPACE_LEN +
1034 	    strlen(addr) + SIP_SPACE_LEN + sizeof (char) + strlen(msg) +
1035 	    sizeof (char) + strlen(SIP_CRLF);
1036 
1037 	new_header = sip_new_header(header_size);
1038 	if (new_header == NULL) {
1039 		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
1040 		return (ENOMEM);
1041 	}
1042 
1043 	(void) snprintf(new_header->sip_hdr_start, header_size + 1,
1044 	    "%s %c %d %s \"%s\"%s", hdr_name, SIP_HCOLON, code, addr,
1045 	    msg, SIP_CRLF);
1046 	_sip_add_header(_sip_msg, new_header, B_TRUE, B_FALSE, NULL);
1047 	if (_sip_msg->sip_msg_buf != NULL)
1048 		_sip_msg->sip_msg_modified = B_TRUE;
1049 	(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
1050 
1051 	return (0);
1052 }
1053 
1054 /*
1055  * RAck          =  "RAck" HCOLON response-num LWS CSeq-num LWS Method
1056  * response-num  =  1*DIGIT
1057  * CSeq-num      =  1*DIGIT
1058  */
1059 int
1060 sip_add_rack(sip_msg_t sip_msg, int resp_num, int cseq, sip_method_t method)
1061 {
1062 	_sip_header_t	*new_header;
1063 	int 		header_size;
1064 	_sip_msg_t 	*_sip_msg;
1065 	char		*hdr_name = SIP_RACK;
1066 
1067 	if (sip_msg == NULL || resp_num <= 0 || cseq < 0 || method <= 0 ||
1068 	    method >= MAX_SIP_METHODS) {
1069 		return (EINVAL);
1070 	}
1071 
1072 	_sip_msg = (_sip_msg_t *)sip_msg;
1073 	(void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
1074 	if (_sip_msg->sip_msg_cannot_be_modified) {
1075 		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
1076 		return (ENOTSUP);
1077 	}
1078 
1079 	header_size = strlen(hdr_name) + SIP_SPACE_LEN + sizeof (char) +
1080 	    SIP_SPACE_LEN + sip_num_of_digits(resp_num) + SIP_SPACE_LEN +
1081 	    sip_num_of_digits(cseq) + SIP_SPACE_LEN +
1082 	    strlen(sip_methods[method].name) + strlen(SIP_CRLF);
1083 
1084 	new_header = sip_new_header(header_size);
1085 	if (new_header == NULL) {
1086 		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
1087 		return (ENOMEM);
1088 	}
1089 
1090 	(void) snprintf(new_header->sip_hdr_start, header_size + 1,
1091 	    "%s %c %d %d %s%s", hdr_name, SIP_HCOLON, resp_num, cseq,
1092 	    sip_methods[method].name, SIP_CRLF);
1093 
1094 	_sip_add_header(_sip_msg, new_header, B_TRUE, B_FALSE, NULL);
1095 	if (_sip_msg->sip_msg_buf != NULL)
1096 		_sip_msg->sip_msg_modified = B_TRUE;
1097 	(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
1098 
1099 	return (0);
1100 
1101 }
1102 
1103 /*
1104  * Allow-Events =  ( "Allow-Events" / "u" ) HCOLON event-type
1105  *			*(COMMA event-type)
1106  */
1107 int
1108 sip_add_allow_events(sip_msg_t sip_msg, char *t_event)
1109 {
1110 	return (sip_add_str_to_msg(sip_msg, SIP_ALLOW_EVENTS, t_event, NULL,
1111 	    (char)NULL));
1112 }
1113 
1114 /*
1115  * Event             =  ( "Event" / "o" ) HCOLON event-type
1116  *			*( SEMI event-param )
1117  * event-type        =  event-package *( "." event-template )
1118  * event-package     =  token-nodot
1119  * event-template    =  token-nodot
1120  * token-nodot       =  1*( alphanum / "-"  / "!" / "%" / "*"
1121  *			/ "_" / "+" / "`" / "'" / "~" )
1122  * event-param       =  generic-param / ( "id" EQUAL token )
1123  */
1124 int
1125 sip_add_event(sip_msg_t sip_msg, char *t_event, char *plist)
1126 {
1127 	return (sip_add_str_to_msg(sip_msg, SIP_EVENT, t_event, plist,
1128 	    SIP_SEMI));
1129 }
1130 
1131 /*
1132  * Subscription-State   = "Subscription-State" HCOLON substate-value
1133  * 			*( SEMI subexp-params )
1134  * substate-value       = "active" / "pending" / "terminated"
1135  *			/ extension-substate
1136  * extension-substate   = token
1137  * subexp-params        =   ("reason" EQUAL event-reason-value)
1138  *			/ ("expires" EQUAL delta-seconds)*
1139  * 			/ ("retry-after" EQUAL delta-seconds)
1140  *			/ generic-param
1141  * event-reason-value   =   "deactivated"
1142  *				/ "probation"
1143  *				/ "rejected"
1144  *				/ "timeout"
1145  *				/ "giveup"
1146  *				/ "noresource"
1147  *				/ event-reason-extension
1148  * event-reason-extension = token
1149  */
1150 int
1151 sip_add_substate(sip_msg_t sip_msg, char *sub, char *plist)
1152 {
1153 	return (sip_add_str_to_msg(sip_msg, SIP_SUBSCRIPTION_STATE, sub, plist,
1154 	    SIP_SEMI));
1155 }
1156 
1157 /*
1158  * Authorization     =  "Authorization" HCOLON credentials
1159  * credentials       =  ("Digest" LWS digest-response)
1160  *			/ other-response
1161  * digest-response   =  dig-resp *(COMMA dig-resp)
1162  * dig-resp          =  username / realm / nonce / digest-uri
1163  *			/ dresponse / algorithm / cnonce
1164  *			/ opaque / message-qop
1165  *			/ nonce-count / auth-param
1166  * username          =  "username" EQUAL username-value
1167  * username-value    =  quoted-string
1168  * digest-uri        =  "uri" EQUAL LDQUOT digest-uri-value RDQUOT
1169  * digest-uri-value  =  rquest-uri ; Equal to request-uri as specified
1170  *			by HTTP/1.1
1171  * message-qop       =  "qop" EQUAL qop-value
1172  * cnonce            =  "cnonce" EQUAL cnonce-value
1173  * cnonce-value      =  nonce-value
1174  * nonce-count       =  "nc" EQUAL nc-value
1175  * nc-value          =  8LHEX
1176  * dresponse         =  "response" EQUAL request-digest
1177  * request-digest    =  LDQUOT 32LHEX RDQUOT
1178  * auth-param        =  auth-param-name EQUAL
1179  * 			( token / quoted-string )
1180  * auth-param-name   =  token
1181  * other-response    =  auth-scheme LWS auth-param
1182  *			*(COMMA auth-param)
1183  * auth-scheme       =  token
1184  */
1185 int
1186 sip_add_author(sip_msg_t sip_msg, char *scheme, char *param)
1187 {
1188 	return (sip_add_str_to_msg(sip_msg, SIP_AUTHOR, scheme, param, SIP_SP));
1189 }
1190 
1191 /*
1192  * Authentication-Info  =  "Authentication-Info" HCOLON ainfo
1193  *				*(COMMA ainfo)
1194  * ainfo                =  nextnonce / message-qop
1195  *				/ response-auth / cnonce
1196  *				/ nonce-count
1197  * nextnonce            =  "nextnonce" EQUAL nonce-value
1198  * response-auth        =  "rspauth" EQUAL response-digest
1199  * response-digest      =  LDQUOT *LHEX RDQUOT
1200  */
1201 int
1202 sip_add_authen_info(sip_msg_t sip_msg, char *ainfo)
1203 {
1204 	return (sip_add_str_to_msg(sip_msg, SIP_AUTHEN_INFO, ainfo, NULL,
1205 	    (char)NULL));
1206 }
1207 
1208 /*
1209  * Proxy-Authenticate  =  "Proxy-Authenticate" HCOLON challenge
1210  * challenge           =  ("Digest" LWS digest-cln *(COMMA digest-cln))
1211  *				/ other-challenge
1212  * other-challenge     =  auth-scheme LWS auth-param
1213  * 				*(COMMA auth-param)
1214  * digest-cln          =  realm / domain / nonce
1215  *				/ opaque / stale / algorithm
1216  *				/ qop-options / auth-param
1217  * realm               =  "realm" EQUAL realm-value
1218  * realm-value         =  quoted-string
1219  * domain              =  "domain" EQUAL LDQUOT URI
1220  *				*( 1*SP URI ) RDQUOT
1221  * URI                 =  absoluteURI / abs-path
1222  * nonce               =  "nonce" EQUAL nonce-value
1223  * nonce-value         =  quoted-string
1224  * opaque              =  "opaque" EQUAL quoted-string
1225  * stale               =  "stale" EQUAL ( "true" / "false" )
1226  * algorithm           =  "algorithm" EQUAL ( "MD5" / "MD5-sess"
1227  *			/ token )
1228  * qop-options         =  "qop" EQUAL LDQUOT qop-value
1229  *			*("," qop-value) RDQUOT
1230  * qop-value           =  "auth" / "auth-int" / token
1231  */
1232 int
1233 sip_add_proxy_authen(sip_msg_t sip_msg, char *pascheme, char *paparam)
1234 {
1235 	return (sip_add_str_to_msg(sip_msg, SIP_PROXY_AUTHEN, pascheme, paparam,
1236 	    SIP_SP));
1237 }
1238 
1239 /*
1240  * Proxy-Authorization  =  "Proxy-Authorization" HCOLON credentials
1241  */
1242 int
1243 sip_add_proxy_author(sip_msg_t sip_msg, char *paschem, char *paparam)
1244 {
1245 	return (sip_add_str_to_msg(sip_msg, SIP_PROXY_AUTHOR, paschem, paparam,
1246 	    SIP_SP));
1247 }
1248 
1249 /*
1250  * Proxy-Require  =  "Proxy-Require" HCOLON option-tag
1251  *			*(COMMA option-tag)
1252  * option-tag     =  token
1253  */
1254 int
1255 sip_add_proxy_require(sip_msg_t sip_msg, char *opt)
1256 {
1257 	return (sip_add_str_to_msg(sip_msg, SIP_PROXY_REQ, opt, NULL,
1258 	    (char)NULL));
1259 }
1260 
1261 /*
1262  * WWW-Authenticate  =  "WWW-Authenticate" HCOLON challenge
1263  * extension-header  =  header-name HCOLON header-value
1264  * header-name       =  token
1265  * header-value      =  *(TEXT-UTF8char / UTF8-CONT / LWS)
1266  * message-body  =  *OCTET
1267  */
1268 int
1269 sip_add_www_authen(sip_msg_t sip_msg, char *wascheme, char *waparam)
1270 {
1271 	return (sip_add_str_to_msg(sip_msg, SIP_WWW_AUTHEN, wascheme, waparam,
1272 	    SIP_SP));
1273 }
1274 
1275 /*
1276  * Call-ID  =  ( "Call-ID" / "i" ) HCOLON callid
1277  */
1278 int
1279 sip_add_callid(sip_msg_t sip_msg, char *callid)
1280 {
1281 	int		ret;
1282 	boolean_t	allocd = B_FALSE;
1283 
1284 	if (sip_msg == NULL || (callid != NULL && callid[0] == '\0'))
1285 		return (EINVAL);
1286 	if (callid == NULL) {
1287 		callid = (char *)sip_guid();
1288 		if (callid == NULL)
1289 			return (ENOMEM);
1290 		allocd = B_TRUE;
1291 	}
1292 	ret = sip_add_str_to_msg(sip_msg, SIP_CALL_ID, callid, NULL,
1293 	    (char)NULL);
1294 	if (allocd)
1295 		free(callid);
1296 	return (ret);
1297 }
1298 
1299 /*
1300  * CSeq  =  "CSeq" HCOLON 1*DIGIT LWS Method
1301  */
1302 int
1303 sip_add_cseq(sip_msg_t sip_msg, sip_method_t method, uint32_t cseq)
1304 {
1305 	int	r;
1306 
1307 	if (sip_msg == NULL || (int)cseq < 0 || method == 0 ||
1308 	    method >= MAX_SIP_METHODS) {
1309 		return (EINVAL);
1310 	}
1311 	r = sip_add_intstr_to_msg(sip_msg, SIP_CSEQ, cseq,
1312 	    sip_methods[method].name, NULL);
1313 	return (r);
1314 }
1315 
1316 /*
1317  * Via =  ( "Via" / "v" ) HCOLON via-parm *(COMMA via-parm)
1318  * via-parm          =  sent-protocol LWS sent-by *( SEMI via-params )
1319  * via-params        =  via-ttl / via-maddr
1320  *                      / via-received / via-branch
1321  *                      / via-extension
1322  * via-ttl           =  "ttl" EQUAL ttl
1323  * via-maddr         =  "maddr" EQUAL host
1324  * via-received      =  "received" EQUAL (IPv4address / IPv6address)
1325  * via-branch        =  "branch" EQUAL token
1326  * via-extension     =  generic-param
1327  * sent-protocol     =  protocol-name SLASH protocol-version
1328  *                      SLASH transport
1329  * protocol-name     =  "SIP" / token
1330  * protocol-version  =  token
1331  * transport         =  "UDP" / "TCP" / "TLS" / "SCTP"
1332  *                      / other-transport
1333  * sent-by           =  host [ COLON port ]
1334  * ttl               =  1*3DIGIT ; 0 to 255
1335  */
1336 _sip_header_t *
1337 sip_create_via_hdr(char *sent_protocol_transport, char *sent_by_host,
1338     int sent_by_port, char *via_params)
1339 {
1340 	_sip_header_t	*new_header;
1341 	int		header_size;
1342 	int		count;
1343 
1344 	header_size = strlen(SIP_VIA) + SIP_SPACE_LEN + sizeof (char) +
1345 	    SIP_SPACE_LEN + strlen(SIP_VERSION) + sizeof (char) +
1346 	    strlen(sent_protocol_transport) + SIP_SPACE_LEN +
1347 	    strlen(sent_by_host) + strlen(SIP_CRLF);
1348 
1349 	if (sent_by_port > 0) {
1350 		header_size += SIP_SPACE_LEN + sizeof (char) + SIP_SPACE_LEN +
1351 		    sip_num_of_digits(sent_by_port);
1352 	}
1353 
1354 	if (via_params != NULL) {
1355 		header_size += SIP_SPACE_LEN + sizeof (char) +
1356 		    strlen(via_params);
1357 	}
1358 	new_header = sip_new_header(header_size);
1359 	if (new_header->sip_hdr_start == NULL)
1360 		return (NULL);
1361 	count = snprintf(new_header->sip_hdr_current, header_size + 1,
1362 	    "%s %c %s/%s %s",
1363 	    SIP_VIA, SIP_HCOLON, SIP_VERSION, sent_protocol_transport,
1364 	    sent_by_host);
1365 	new_header->sip_hdr_current += count;
1366 	header_size -= count;
1367 
1368 	if (sent_by_port > 0) {
1369 		count = snprintf(new_header->sip_hdr_current, header_size + 1,
1370 		    " %c %d", SIP_HCOLON, sent_by_port);
1371 		new_header->sip_hdr_current += count;
1372 		header_size -= count;
1373 	}
1374 
1375 	if (via_params != NULL) {
1376 		count = snprintf(new_header->sip_hdr_current, header_size + 1,
1377 		    " %c%s", SIP_SEMI, via_params);
1378 		new_header->sip_hdr_current += count;
1379 		header_size -= count;
1380 	}
1381 
1382 	(void) snprintf(new_header->sip_hdr_current, header_size + 1,
1383 	    "%s", SIP_CRLF);
1384 	return (new_header);
1385 }
1386 
1387 /*
1388  * There can be multiple via headers we always append the header.
1389  * We expect the via params to be a semi-colon separated list of parameters.
1390  * We will add a semi-clone, before adding the list to the header.
1391  */
1392 int
1393 sip_add_via(sip_msg_t sip_msg, char *sent_protocol_transport,
1394     char *sent_by_host, int sent_by_port, char *via_params)
1395 {
1396 	_sip_header_t	*new_header;
1397 	_sip_msg_t	*_sip_msg;
1398 
1399 	if (sip_msg == NULL || sent_protocol_transport == NULL ||
1400 	    sent_by_host == NULL || sent_by_port < 0) {
1401 		return (EINVAL);
1402 	}
1403 
1404 	_sip_msg = (_sip_msg_t *)sip_msg;
1405 	(void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
1406 	if (_sip_msg->sip_msg_cannot_be_modified) {
1407 		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
1408 		return (ENOTSUP);
1409 	}
1410 
1411 	new_header = sip_create_via_hdr(sent_protocol_transport, sent_by_host,
1412 	    sent_by_port, via_params);
1413 	if (new_header == NULL) {
1414 		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
1415 		return (ENOMEM);
1416 	}
1417 	_sip_add_header(_sip_msg, new_header, B_TRUE, B_FALSE, NULL);
1418 	if (_sip_msg->sip_msg_buf != NULL)
1419 		_sip_msg->sip_msg_modified = B_TRUE;
1420 	(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
1421 	return (0);
1422 }
1423 
1424 /*
1425  * Max-Forwards  =  "Max-Forwards" HCOLON 1*DIGIT
1426  */
1427 int
1428 sip_add_maxforward(sip_msg_t sip_msg, uint_t maxforward)
1429 {
1430 	if (sip_msg == NULL || (int)maxforward < 0)
1431 		return (EINVAL);
1432 	return (sip_add_int_to_msg(sip_msg, SIP_MAX_FORWARDS, maxforward,
1433 	    NULL));
1434 }
1435 
1436 /*
1437  * Content-Type     =  ( "Content-Type" / "c" ) HCOLON media-type
1438  * media-type       =  m-type SLASH m-subtype *(SEMI m-parameter)
1439  * m-type           =  discrete-type / composite-type
1440  * discrete-type    =  "text" / "image" / "audio" / "video"
1441  *			/ "application" / extension-token
1442  * composite-type   =  "message" / "multipart" / extension-token
1443  * extension-token  =  ietf-token / x-token
1444  * ietf-token       =  token
1445  * x-token          =  "x-" token
1446  * m-subtype        =  extension-token / iana-token
1447  * iana-token       =  token
1448  * m-parameter      =  m-attribute EQUAL m-value
1449  * m-attribute      =  token
1450  * m-value          =  token / quoted-string
1451  */
1452 int
1453 sip_add_content_type(sip_msg_t sip_msg, char *type, char *subtype)
1454 {
1455 	if (sip_msg == NULL || type == NULL || subtype == NULL)
1456 		return (EINVAL);
1457 	return (sip_add_2strs_to_msg(sip_msg, SIP_CONTENT_TYPE, type, B_FALSE,
1458 	    subtype, NULL, SIP_SLASH));
1459 }
1460 
1461 /*
1462  * Content-Length  =  ( "Content-Length" / "l" ) HCOLON 1*DIGIT
1463  */
1464 int
1465 sip_add_content_length(_sip_msg_t *_sip_msg, int length)
1466 {
1467 	_sip_header_t	*new_header;
1468 	int 		header_size;
1469 
1470 	if (_sip_msg == NULL || length < 0)
1471 		return (EINVAL);
1472 	(void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
1473 	if (_sip_msg->sip_msg_cannot_be_modified) {
1474 		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
1475 		return (ENOTSUP);
1476 	}
1477 
1478 	header_size = strlen(SIP_CONTENT_LENGTH) + SIP_SPACE_LEN +
1479 	    sizeof (char) + SIP_SPACE_LEN + sip_num_of_digits(length) +
1480 	    strlen(SIP_CRLF) + strlen(SIP_CRLF);
1481 
1482 	new_header = sip_new_header(header_size);
1483 	if (new_header == NULL) {
1484 		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
1485 		return (ENOMEM);
1486 	}
1487 	(void) snprintf(new_header->sip_hdr_start, header_size + 1,
1488 	    "%s %c %u%s%s", SIP_CONTENT_LENGTH, SIP_HCOLON, length,
1489 	    SIP_CRLF, SIP_CRLF);
1490 
1491 	_sip_add_header(_sip_msg, new_header, B_TRUE, B_FALSE, NULL);
1492 	if (_sip_msg->sip_msg_buf != NULL)
1493 		_sip_msg->sip_msg_modified = B_TRUE;
1494 	(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
1495 	return (0);
1496 }
1497 
1498 
1499 /*
1500  * Contact = ("Contact" / "m" ) HCOLON
1501  *		( STAR / (contact-param *(COMMA contact-param)))
1502  * contact-param  =  (name-addr / addr-spec) *(SEMI contact-params)
1503  * name-addr      =  [ display-name ] LAQUOT addr-spec RAQUOT
1504  * addr-spec      =  SIP-URI / SIPS-URI / absoluteURI
1505  * display-name   =  *(token LWS)/ quoted-string
1506  * contact-params     =  c-p-q / c-p-expires
1507  *                     / contact-extension
1508  */
1509 int
1510 sip_add_contact(sip_msg_t sip_msg, char *display_name, char *contact_uri,
1511     boolean_t add_aquot, char *contact_params)
1512 {
1513 	return (sip_add_name_aspec(sip_msg, display_name, contact_uri, NULL,
1514 	    add_aquot, SIP_CONTACT, contact_params));
1515 }
1516 
1517 /*
1518  * From =  ( "From" / "f" ) HCOLON from-spec
1519  * from-spec = ( name-addr / addr-spec )
1520  *	*( SEMI from-param )
1521  * from-param  =  tag-param / generic-param
1522  * tag-param   =  "tag" EQUAL token
1523  *
1524  * Since there can be more than one tags, fromtags is a semi colon separated
1525  * list of tags.
1526  */
1527 int
1528 sip_add_from(sip_msg_t sip_msg, char *display_name, char *from_uri,
1529     char *fromtags, boolean_t add_aquot, char *from_params)
1530 {
1531 	return (sip_add_name_aspec(sip_msg, display_name, from_uri, fromtags,
1532 	    add_aquot, SIP_FROM, from_params));
1533 }
1534 
1535 /*
1536  * To =  ( "To" / "t" ) HCOLON ( name-addr
1537  *	/ addr-spec ) *( SEMI to-param )
1538  * to-param  =  tag-param / generic-param
1539  */
1540 int
1541 sip_add_to(sip_msg_t sip_msg, char *display_name, char *to_uri,
1542     char *totags, boolean_t add_aquot, char *to_params)
1543 {
1544 	return (sip_add_name_aspec(sip_msg, display_name, to_uri, totags,
1545 	    add_aquot, SIP_TO, to_params));
1546 }
1547 
1548 /*
1549  * Route        =  "Route" HCOLON route-param *(COMMA route-param)
1550  * route-param  =  name-addr *( SEMI rr-param )
1551  */
1552 int
1553 sip_add_route(sip_msg_t sip_msg, char *display_name, char *uri,
1554     char *route_params)
1555 {
1556 	return (sip_add_name_aspec(sip_msg, display_name, uri, NULL, B_TRUE,
1557 	    SIP_ROUTE, route_params));
1558 }
1559 
1560 /*
1561  * Record-Route  =  "Record-Route" HCOLON rec-route *(COMMA rec-route)
1562  * rec-route     =  name-addr *( SEMI rr-param )
1563  * rr-param      =  generic-param
1564  */
1565 int
1566 sip_add_record_route(sip_msg_t sip_msg, char *display_name, char *uri,
1567     char *route_params)
1568 {
1569 	return (sip_add_name_aspec(sip_msg, display_name, uri, NULL, B_TRUE,
1570 	    SIP_RECORD_ROUTE, route_params));
1571 }
1572 
1573 
1574 /*
1575  * PAssertedID = "P-Asserted-Identity" HCOLON PAssertedID-value
1576  *			*(COMMA PAssertedID-value)
1577  * PAssertedID-value = name-addr / addr-spec
1578  */
1579 int
1580 sip_add_passertedid(sip_msg_t sip_msg, char *display_name, char *addr,
1581     boolean_t add_aquot)
1582 {
1583 	return (sip_add_name_aspec(sip_msg, display_name, addr, NULL, add_aquot,
1584 	    SIP_PASSERTEDID, NULL));
1585 }
1586 
1587 /*
1588  * PPreferredID = "P-Preferred-Identity" HCOLON PPreferredID-value
1589  *			*(COMMA PPreferredID-value)
1590  * PPreferredID-value = name-addr / addr-spec
1591  */
1592 int
1593 sip_add_ppreferredid(sip_msg_t sip_msg, char *display_name, char *addr,
1594     boolean_t add_aquot)
1595 {
1596 	return (sip_add_name_aspec(sip_msg, display_name, addr, NULL, add_aquot,
1597 	    SIP_PPREFERREDID, NULL));
1598 }
1599