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