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