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