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 <assert.h>
29#include <errno.h>
30#include <pthread.h>
31#include <stdlib.h>
32#include <string.h>
33#include <sip.h>
34
35#include "sip_msg.h"
36#include "sip_miscdefs.h"
37#include "sip_parse_generic.h"
38
39sip_methods_t sip_methods[MAX_SIP_METHODS] = {
40	{"UNKNOWN", 7},
41	{"INVITE", 6},
42	{"ACK", 3},
43	{"OPTIONS", 7},
44	{"BYE", 3},
45	{"CANCEL", 6},
46	{"REGISTER", 8},
47	{"REFER", 5},
48	{"INFO", 4},
49	{"SUBSCRIBE", 9},
50	{"NOTIFY", 6},
51	{"PRACK", 5}
52};
53
54/*
55 * Built-In Header function table
56 */
57sip_header_function_t sip_header_function_table[] = {
58	{"Unknown", NULL, sip_parse_unknown_header, NULL, NULL, NULL},
59	{"CONTACT", "m", sip_parse_cftr_header, NULL, NULL,
60	sip_free_cftr_header},
61	{"FROM", "F", sip_parse_cftr_header, NULL, NULL, sip_free_cftr_header},
62	{"TO", "T", sip_parse_cftr_header, NULL, NULL, sip_free_cftr_header},
63	{"CONTENT-LENGTH", "l", sip_parse_clen_header, NULL, NULL,
64	sip_free_phdr},
65	{"CONTENT-TYPE", "c", sip_parse_ctype_header, NULL, NULL,
66	sip_free_phdr},
67	{"CALL-ID", "i", sip_parse_cid_header, NULL, NULL, sip_free_phdr},
68	{"CSEQ", NULL, sip_parse_cseq_header, NULL, NULL, sip_free_phdr},
69	{"VIA", "v", sip_parse_via_header, NULL, NULL, sip_free_phdr},
70	{"Max-Forwards", NULL, sip_parse_maxf_header, NULL, NULL,
71	sip_free_phdr},
72	{"RECORD-ROUTE", NULL, sip_parse_cftr_header, NULL, NULL,
73	sip_free_cftr_header},
74	{"ROUTE", NULL, sip_parse_cftr_header, NULL, NULL,
75	sip_free_cftr_header},
76	{"ACCEPT", NULL, sip_parse_acpt_header, NULL, NULL, sip_free_phdr},
77	{"ACCEPT-ENCODING", NULL, sip_parse_acpt_encode_header, NULL, NULL,
78	sip_free_phdr},
79	{"ACCEPT-LANGUAGE", NULL, sip_parse_acpt_lang_header, NULL, NULL,
80	sip_free_phdr},
81	{"ALERT-INFO", NULL, sip_parse_alert_header, NULL, NULL, sip_free_phdr},
82	{"ALLOW", NULL, sip_parse_allow_header, NULL, NULL, sip_free_phdr},
83	{"CALL-INFO", NULL, sip_parse_callinfo_header, NULL, NULL,
84	sip_free_phdr},
85	{"CONTENT-DISPOSITION", NULL, sip_parse_contentdis_header, NULL, NULL,
86	sip_free_phdr},
87	{"CONTENT-ENCODING", "e", sip_parse_contentencode_header, NULL, NULL,
88	sip_free_phdr},
89	{"CONTENT-LANGUAGE", NULL, sip_parse_contentlang_header, NULL, NULL,
90	sip_free_phdr},
91	{"DATE", NULL, sip_parse_date_header, NULL, NULL, sip_free_phdr},
92	{"ERROR-INFO", NULL, sip_parse_errorinfo_header, NULL, NULL,
93	sip_free_phdr},
94	{"EXPIRES", NULL, sip_parse_expire_header, NULL, NULL, sip_free_phdr},
95	{"IN-REPLY-TO", NULL, sip_parse_inreplyto_header, NULL, NULL,
96	sip_free_phdr},
97	{"MIN-EXPIRES", NULL, sip_parse_minexpire_header, NULL, NULL,
98	sip_free_phdr},
99	{"MIME-VERSION", NULL, sip_parse_mimeversion_header, NULL, NULL,
100	sip_free_phdr},
101	{"ORGANIZATION", NULL, sip_parse_org_header, NULL, NULL, sip_free_phdr},
102	{"PRIORITY", NULL, sip_parse_priority_header, NULL, NULL,
103	sip_free_phdr},
104	{"REQUIRE", NULL, sip_parse_require_header, NULL, NULL, sip_free_phdr},
105	{"REPLY-TO", NULL, sip_parse_replyto_header, NULL, NULL, sip_free_phdr},
106	{"RETRY-AFTER", NULL, sip_parse_retryaft_header, NULL, NULL,
107	sip_free_phdr},
108	{"SERVER", NULL, sip_parse_server_header, NULL, NULL, sip_free_phdr},
109	{"SUBJECT", "s", sip_parse_subject_header, NULL, NULL, sip_free_phdr},
110	{"TIMESTAMP", NULL, sip_parse_timestamp_header, NULL, NULL,
111	sip_free_phdr},
112	{"UNSUPPORTED", NULL, sip_parse_usupport_header, NULL, NULL,
113	sip_free_phdr},
114	{"SUPPORTED", "k", sip_parse_support_header, NULL, NULL, sip_free_phdr},
115	{"USER-AGENT", NULL, sip_parse_useragt_header, NULL, NULL,
116	sip_free_phdr},
117	{"WARNING", NULL, sip_parse_warn_header, NULL, NULL, sip_free_phdr},
118	{"ALLOW-EVENTS", "u", sip_parse_allow_events_header, NULL, NULL,
119	sip_free_phdr},
120	{"EVENT", "o", sip_parse_event_header, NULL, NULL, sip_free_phdr},
121	{"SUBSCRIPTION-STATE", NULL, sip_parse_substate_header, NULL, NULL,
122	sip_free_phdr},
123	{"AUTHORIZATION", NULL, sip_parse_author_header, NULL, NULL,
124	sip_free_phdr},
125	{"AUTHENTICATION-INFO", NULL, sip_parse_ainfo_header, NULL, NULL,
126	sip_free_phdr},
127	{"PROXY-AUTHORIZATION", NULL, sip_parse_pauthor_header, NULL, NULL,
128	sip_free_phdr},
129	{"PROXY-AUTHENTICATE", NULL, sip_parse_pauthen_header, NULL, NULL,
130	sip_free_phdr},
131	{"PROXY-REQUIRE", NULL, sip_parse_preq_header, NULL, NULL,
132	sip_free_phdr},
133	{"WWW-AUTHENTICATE", NULL, sip_parse_wauthen_header, NULL, NULL,
134	sip_free_phdr},
135	{"RSEQ", NULL, sip_parse_rseq, NULL, NULL, sip_free_phdr},
136	{"RACK", NULL, sip_parse_rack, NULL, NULL, sip_free_phdr},
137	{"P-ASSERTED-IDENTITY", NULL, sip_parse_passertedid, NULL, NULL,
138	sip_free_phdr},
139	{"P-PREFERRED-IDENTITY", NULL, sip_parse_ppreferredid, NULL, NULL,
140	sip_free_phdr},
141	{"PRIVACY", NULL, sip_parse_privacy_header, NULL, NULL, sip_free_phdr},
142	{NULL, NULL, NULL, NULL, NULL, NULL},
143};
144
145#define	MAX_SIP_HEADERS	\
146	sizeof (sip_header_function_table) / sizeof (sip_header_function_t)
147
148/*
149 * External/application provided function table
150 */
151sip_header_function_t *sip_header_function_table_external = NULL;
152
153/*
154 * Free parameter list
155 */
156static void
157sip_free_params(sip_param_t *param_list)
158{
159	sip_param_t *param, *next_param;
160
161	param = param_list;
162
163	while (param != NULL) {
164		next_param = param->param_next;
165		free(param);
166		param = next_param;
167	}
168}
169
170/*
171 * Common header free routine
172 */
173void
174sip_free_phdr(sip_parsed_header_t *header)
175{
176	sip_hdr_value_t	*value;
177	sip_hdr_value_t	*next_value;
178
179	if (header == NULL)
180		return;
181	value = (sip_hdr_value_t *)header->value;
182	while (value != NULL) {
183		sip_free_params(value->sip_param_list);
184		next_value = value->sip_next_value;
185		free(value);
186		value = next_value;
187	}
188	free(header);
189}
190
191/*
192 * Free Contact/From/To header
193 */
194void
195sip_free_cftr_header(sip_parsed_header_t *header)
196{
197	sip_hdr_value_t	*value;
198	sip_hdr_value_t	*next_value;
199
200	if (header == NULL)
201		return;
202	value = (sip_hdr_value_t *)header->value;
203	while (value != NULL) {
204		next_value = value->sip_next_value;
205		sip_free_params(value->sip_param_list);
206		if (value->cftr_name != NULL)
207			free(value->cftr_name);
208		if (value->sip_value_parsed_uri != NULL) {
209			sip_free_parsed_uri(value->sip_value_parsed_uri);
210			value->sip_value_parsed_uri = NULL;
211		}
212		free(value);
213		value = next_value;
214	}
215	free(header);
216}
217
218/*
219 * Return new header
220 */
221_sip_header_t *
222sip_new_header(int header_size)
223{
224	_sip_header_t *new_header;
225
226	new_header = calloc(1, sizeof (_sip_header_t));
227	if (new_header == NULL)
228		return (NULL);
229
230	/*
231	 * We are using snprintf which adds a null character
232	 * so allocate an extra byte which is not part of
233	 * the message header
234	 */
235	new_header->sip_hdr_start = calloc(1, header_size + 1);
236	if (new_header->sip_hdr_start == NULL) {
237		free(new_header);
238		return (NULL);
239	}
240	new_header->sip_hdr_end = new_header->sip_hdr_start + header_size;
241	new_header->sip_hdr_current = new_header->sip_hdr_start;
242	new_header->sip_hdr_allocated = B_TRUE;
243	return (new_header);
244}
245
246/*
247 * Free the given header
248 */
249void
250sip_free_header(_sip_header_t *sip_header)
251{
252	if (sip_header->sip_hdr_allocated) {
253		assert(sip_header->sip_hdr_start != NULL);
254		free(sip_header->sip_hdr_start);
255	}
256	if (sip_header->sip_hdr_parsed != NULL) {
257		assert(sip_header->sip_header_functions != NULL);
258		if (sip_header->sip_header_functions->header_free != NULL) {
259			sip_header->sip_header_functions->header_free(
260			    sip_header->sip_hdr_parsed);
261		}
262	}
263	free(sip_header);
264}
265
266/*
267 * Return a copy of the header passed in.
268 */
269_sip_header_t *
270sip_dup_header(_sip_header_t *from)
271{
272	size_t		hdr_size;
273	_sip_header_t	*to;
274
275	hdr_size = from->sip_hdr_end - from->sip_hdr_start;
276	to = sip_new_header(hdr_size);
277	if (to == NULL)
278		return (NULL);
279	if (from->sip_header_state == SIP_HEADER_DELETED_VAL) {
280		to->sip_hdr_end = to->sip_hdr_start +
281		    sip_copy_values(to->sip_hdr_start, from);
282	} else {
283		(void) memcpy(to->sip_hdr_start, from->sip_hdr_start, hdr_size);
284		to->sip_hdr_end = to->sip_hdr_start + hdr_size;
285	}
286	to->sip_header_functions = from->sip_header_functions;
287	return (to);
288}
289
290/*
291 * Copy header with extra_param, if any, to sip_msg
292 */
293int
294_sip_copy_header(_sip_msg_t *sip_msg, _sip_header_t *header, char *extra_param,
295    boolean_t skip_crlf)
296{
297	_sip_header_t	*new_header;
298	int		hdrlen;
299	int		extra_len = 0;
300	int		ncrlf = 0;
301	char		*p;
302
303#ifdef	__solaris__
304	assert(mutex_held(&sip_msg->sip_msg_mutex));
305#endif
306	if (extra_param != NULL) {
307		extra_len = SIP_SPACE_LEN + sizeof (char) + SIP_SPACE_LEN +
308		    strlen(extra_param);
309	}
310	/*
311	 * Just take one if there are more, i.e. if this is the last header
312	 * before the content.
313	 */
314	if (skip_crlf) {
315		if (header->sip_hdr_end - strlen(SIP_CRLF) <=
316		    header->sip_hdr_start) {
317			goto proceed;
318		}
319		p = header->sip_hdr_end - strlen(SIP_CRLF);
320		while (strncmp(SIP_CRLF, p, strlen(SIP_CRLF)) == 0) {
321			ncrlf++;
322			if (p - strlen(SIP_CRLF) < header->sip_hdr_start)
323				break;
324			p -= strlen(SIP_CRLF);
325		}
326		/*
327		 * Take one CRLF.
328		 */
329		ncrlf = (ncrlf - 1) * strlen(SIP_CRLF);
330	}
331proceed:
332	hdrlen = header->sip_hdr_end - header->sip_hdr_start - ncrlf;
333	new_header = sip_new_header(hdrlen + extra_len);
334	if (new_header == NULL)
335		return (ENOMEM);
336	if (header->sip_header_state == SIP_HEADER_DELETED_VAL) {
337		int	len;
338
339		len = sip_copy_values(new_header->sip_hdr_start, header);
340		new_header->sip_hdr_end = new_header->sip_hdr_start + len;
341		hdrlen = hdrlen - len + extra_len;
342	} else {
343		(void) memcpy(new_header->sip_hdr_start, header->sip_hdr_start,
344		    hdrlen);
345		new_header->sip_hdr_end = new_header->sip_hdr_start + hdrlen;
346		hdrlen = extra_len;
347	}
348	if (extra_param != NULL) {
349		/*
350		 * Find CR
351		 */
352		if (sip_find_cr(new_header) != 0) {
353			sip_free_header(new_header);
354			return (EINVAL);
355		}
356		hdrlen += new_header->sip_hdr_end - new_header->sip_hdr_current;
357		(void) snprintf(new_header->sip_hdr_current, hdrlen + 1,
358		    " %c %s%s", SIP_SEMI, extra_param, SIP_CRLF);
359	}
360
361	new_header->sip_hdr_end += extra_len;
362	new_header->sip_header_functions = header->sip_header_functions;
363	_sip_add_header(sip_msg, new_header, B_TRUE, B_FALSE, NULL);
364	return (0);
365}
366
367/*
368 * Copy all "header_name" headers from _old_msg to _new_msg
369 */
370int
371_sip_find_and_copy_all_header(_sip_msg_t *_old_msg, _sip_msg_t *_new_msg,
372    char *header_name)
373{
374	_sip_header_t	*header;
375	int		ret = 0;
376
377	if (_old_msg == NULL || _new_msg == NULL)
378		return (EINVAL);
379#ifdef	__solaris__
380	assert(mutex_held(&_old_msg->sip_msg_mutex));
381#endif
382	if (_old_msg != _new_msg)
383		(void) pthread_mutex_lock(&_new_msg->sip_msg_mutex);
384	header = sip_search_for_header(_old_msg, header_name, NULL);
385	while (header != NULL) {
386		ret = _sip_copy_header(_new_msg, header, NULL, B_TRUE);
387		if (ret != 0)
388			break;
389		header = sip_search_for_header(_old_msg, header_name, header);
390	}
391	if (_old_msg != _new_msg)
392		(void) pthread_mutex_unlock(&_new_msg->sip_msg_mutex);
393	return (ret);
394}
395
396/*
397 * Copy header_name from _old_msg to _new_msg with extra_parm.
398 */
399int
400_sip_find_and_copy_header(sip_msg_t _old_msg, sip_msg_t _new_msg,
401    char *header_name, char *extra_param, boolean_t lock_newmsg)
402{
403	_sip_header_t	*header;
404	int		ret;
405
406	if (_old_msg == NULL || _new_msg == NULL)
407		return (EINVAL);
408#ifdef	__solaris__
409	assert(mutex_held(&_old_msg->sip_msg_mutex));
410#endif
411	header = sip_search_for_header(_old_msg, header_name, NULL);
412	if (header == NULL)
413		return (EINVAL);
414	if (lock_newmsg)
415		(void) pthread_mutex_lock(&_new_msg->sip_msg_mutex);
416	ret = _sip_copy_header(_new_msg, header, extra_param, B_TRUE);
417	if (lock_newmsg)
418		(void) pthread_mutex_unlock(&_new_msg->sip_msg_mutex);
419	return (ret);
420}
421
422/*
423 * Copy all headers from old_msg to new_msg
424 */
425int
426sip_copy_all_headers(sip_msg_t old_msg, sip_msg_t new_msg)
427{
428	_sip_header_t	*header;
429	_sip_msg_t	*_old_msg;
430	_sip_msg_t	*_new_msg;
431	int		ret = 0;
432
433	if (old_msg == NULL || new_msg == NULL)
434		return (EINVAL);
435	_old_msg = (_sip_msg_t *)old_msg;
436	_new_msg = (_sip_msg_t *)new_msg;
437
438	(void) pthread_mutex_lock(&_old_msg->sip_msg_mutex);
439	(void) pthread_mutex_lock(&_new_msg->sip_msg_mutex);
440	header = sip_search_for_header(_old_msg, NULL, NULL);
441	while (header != NULL) {
442		ret = _sip_copy_header(_new_msg, header, NULL, B_FALSE);
443		if (ret != 0)
444			goto done;
445		header = sip_search_for_header(_old_msg, NULL, header);
446	}
447done:
448	(void) pthread_mutex_unlock(&_new_msg->sip_msg_mutex);
449	(void) pthread_mutex_unlock(&_old_msg->sip_msg_mutex);
450	return (ret);
451}
452
453/*
454 * Copy start line from msg to sip_msg
455 */
456int
457sip_copy_start_line(sip_msg_t msg, sip_msg_t sip_msg)
458{
459	int		len;
460	_sip_header_t	*new_header;
461	_sip_msg_t	*_old_msg;
462	_sip_msg_t	*_sip_msg;
463
464	if (msg == NULL || sip_msg == NULL)
465		return (EINVAL);
466	_old_msg = (_sip_msg_t *)msg;
467	_sip_msg = (_sip_msg_t *)sip_msg;
468
469	(void) pthread_mutex_lock(&_old_msg->sip_msg_mutex);
470	if (_old_msg->sip_msg_start_line == NULL) {
471		(void) pthread_mutex_unlock(&_old_msg->sip_msg_mutex);
472		return (EINVAL);
473	}
474	len = _old_msg->sip_msg_start_line->sip_hdr_end -
475	    _old_msg->sip_msg_start_line->sip_hdr_start;
476	new_header = sip_new_header(len);
477	if (new_header == NULL) {
478		(void) pthread_mutex_unlock(&_old_msg->sip_msg_mutex);
479		return (ENOMEM);
480	}
481	new_header->sip_hdr_sipmsg = _sip_msg;
482	(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
483	_sip_msg->sip_msg_start_line = new_header;
484	_sip_msg->sip_msg_len = len;
485	(void) strncpy(_sip_msg->sip_msg_start_line->sip_hdr_start,
486	    _old_msg->sip_msg_start_line->sip_hdr_start, len);
487	(void) sip_parse_first_line(_sip_msg->sip_msg_start_line,
488	    &_sip_msg->sip_msg_req_res);
489	(void) pthread_mutex_unlock(&_old_msg->sip_msg_mutex);
490	(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
491	return (0);
492}
493
494/*
495 * Delete start line from sip_msg
496 */
497int
498sip_delete_start_line_locked(_sip_msg_t *_sip_msg)
499{
500	_sip_header_t	*header;
501	_sip_header_t	*next_header;
502
503	if (_sip_msg->sip_msg_start_line == NULL)
504		return (EINVAL);
505
506	header = _sip_msg->sip_msg_start_line;
507	while (header != NULL) {
508		next_header = header->sip_hdr_next;
509		_sip_msg->sip_msg_len -= (header->sip_hdr_end -
510		    header->sip_hdr_start);
511		sip_free_header(header);
512		header = next_header;
513	}
514	_sip_msg->sip_msg_start_line = NULL;
515
516	/*
517	 * Also delete the sip_msg_req_res info since we don't have a start
518	 * line.
519	 */
520	while (_sip_msg->sip_msg_req_res != NULL) {
521		sip_message_type_t	*sip_msg_type_ptr;
522
523		sip_msg_type_ptr = _sip_msg->sip_msg_req_res->sip_next;
524		if (_sip_msg->sip_msg_req_res->is_request) {
525			sip_request_t	*reqline;
526
527			reqline = &_sip_msg->sip_msg_req_res->U.sip_request;
528			if (reqline->sip_parse_uri != NULL) {
529				sip_free_parsed_uri(reqline->sip_parse_uri);
530				reqline->sip_parse_uri = NULL;
531			}
532		}
533		free(_sip_msg->sip_msg_req_res);
534		_sip_msg->sip_msg_req_res = sip_msg_type_ptr;
535	}
536	return (0);
537}
538
539
540/*
541 * Delete start line from sip_msg
542 */
543int
544sip_delete_start_line(sip_msg_t sip_msg)
545{
546	_sip_msg_t	*_sip_msg;
547	int		ret;
548
549	if (sip_msg == NULL)
550		return (EINVAL);
551
552	_sip_msg = (_sip_msg_t *)sip_msg;
553	(void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
554	ret = sip_delete_start_line_locked(_sip_msg);
555	(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
556
557	return (ret);
558}
559
560/*
561 * Delete all headers from _sip_msg
562 */
563void
564sip_delete_all_headers(_sip_msg_t *_sip_msg)
565{
566	_sip_header_t *header;
567
568#ifdef	__solaris__
569	assert(mutex_held(&_sip_msg->sip_msg_mutex));
570#endif
571
572	header = _sip_msg->sip_msg_headers_start;
573	while (header != NULL) {
574		_sip_header_t *next_header;
575		next_header = header->sip_hdr_next;
576		sip_free_header(header);
577		header = next_header;
578	}
579	_sip_msg->sip_msg_headers_start = NULL;
580	_sip_msg->sip_msg_headers_end = NULL;
581}
582
583/*
584 * Delete and free the named header. If header_name is null
585 * free all headers.
586 */
587void
588sip_delete_headers(sip_msg_t sip_msg, char *header_name)
589{
590	_sip_header_t *header;
591	_sip_msg_t *_sip_msg;
592
593	_sip_msg = (_sip_msg_t *)sip_msg;
594#ifdef	__solaris__
595	assert(mutex_held(&_sip_msg->sip_msg_mutex));
596#endif
597	header = sip_search_for_header(_sip_msg, header_name, NULL);
598	if (header == NULL)
599		return;
600	while (header != NULL) {
601		if (_sip_msg->sip_msg_headers_start == header) {
602			_sip_msg->sip_msg_headers_start = header->sip_hdr_next;
603		} else {
604			header->sip_hdr_prev->sip_hdr_next =
605			    header->sip_hdr_next;
606		}
607		if (_sip_msg->sip_msg_headers_end == header) {
608			_sip_msg->sip_msg_headers_end = header->sip_hdr_prev;
609		} else {
610			header->sip_hdr_next->sip_hdr_prev =
611			    header->sip_hdr_prev;
612		}
613		sip_free_header(header);
614		if (header_name != NULL)
615			return;
616		else
617			header = sip_search_for_header(_sip_msg, NULL, NULL);
618	}
619}
620
621/*
622 * Add a header to sip_msg. If header_name is provided then the new header
623 * is added before that header, if first is set, or after. If append is
624 * set, then the header is added to the end of the header list.
625 */
626void
627_sip_add_header(_sip_msg_t *sip_msg, _sip_header_t *new_header,
628    boolean_t append, boolean_t first, char *header_name)
629{
630	_sip_header_t	*header = NULL;
631
632	if (sip_msg == NULL || new_header == NULL)
633		return;
634#ifdef	__solaris__
635	assert(mutex_held(&sip_msg->sip_msg_mutex));
636#endif
637	new_header->sip_hdr_sipmsg = sip_msg;
638	if (header_name != NULL) {
639		_sip_header_t	*header_tmp;
640
641		header = sip_search_for_header(sip_msg, header_name, NULL);
642		header_tmp = header;
643		if (!first) {
644			while (header != NULL) {
645				header_tmp = header;
646				header = sip_search_for_header(sip_msg,
647				    header_name, header);
648			}
649		}
650		header = header_tmp;
651		if (header == NULL)
652			append =  B_TRUE;
653	}
654
655	if (header != NULL) {
656		if (append) {
657			new_header->sip_hdr_prev = header;
658			if (sip_msg->sip_msg_headers_end == header) {
659				sip_msg->sip_msg_headers_end = new_header;
660				new_header->sip_hdr_next = NULL;
661			} else {
662				header->sip_hdr_next->sip_hdr_prev = new_header;
663				new_header->sip_hdr_next = header->sip_hdr_next;
664			}
665			header->sip_hdr_next = new_header;
666		} else {
667			new_header->sip_hdr_next = header;
668			if (sip_msg->sip_msg_headers_start == header) {
669				sip_msg->sip_msg_headers_start = new_header;
670				new_header->sip_hdr_prev = NULL;
671			} else {
672				header->sip_hdr_prev->sip_hdr_next = new_header;
673				new_header->sip_hdr_prev = header->sip_hdr_prev;
674			}
675			header->sip_hdr_prev = new_header;
676		}
677	} else {
678		if (append) {
679			if (sip_msg->sip_msg_headers_end != NULL) {
680				sip_msg->sip_msg_headers_end->sip_hdr_next =
681				    new_header;
682			} else {
683				sip_msg->sip_msg_headers_start = new_header;
684			}
685			new_header->sip_hdr_prev =
686			    sip_msg->sip_msg_headers_end;
687			new_header->sip_hdr_next = NULL;
688			sip_msg->sip_msg_headers_end = new_header;
689		} else {
690			if (sip_msg->sip_msg_headers_start != NULL) {
691				sip_msg->sip_msg_headers_start->sip_hdr_prev =
692				    new_header;
693			} else {
694				sip_msg->sip_msg_headers_end = new_header;
695			}
696			new_header->sip_hdr_next =
697			    sip_msg->sip_msg_headers_start;
698			new_header->sip_hdr_prev = NULL;
699			sip_msg->sip_msg_headers_start = new_header;
700		}
701	}
702	sip_msg->sip_msg_len += new_header->sip_hdr_end -
703	    new_header->sip_hdr_start;
704}
705
706/*
707 * Scan through the function table and return the entry for the given header
708 * type.
709 */
710sip_header_function_t *
711_sip_get_header_functions(sip_header_function_t *sip_header_function_table,
712    _sip_header_t *sip_header, char *header_name)
713{
714	int	len;
715	int	i = 0;
716
717	if (sip_header == NULL && header_name == NULL)
718		return (NULL);
719
720	/*
721	 * If header_name is NULL we first have to locate the name
722	 */
723	if (header_name == NULL) {
724		if (sip_skip_white_space(sip_header) != 0) {
725			return (NULL);
726		}
727		header_name = sip_header->sip_hdr_current;
728		if (sip_find_separator(sip_header, SIP_HCOLON, 0,
729		    0, B_FALSE) != 0) {
730			return (NULL);
731		}
732		len = sip_header->sip_hdr_current - header_name;
733	} else {
734		len = strlen(header_name);
735	}
736
737	if (len > 0) {
738		while (sip_header_function_table[i].header_name != NULL ||
739		    sip_header_function_table[i].header_short_name != NULL) {
740			if (sip_header_function_table[i].header_name != NULL &&
741			    len ==
742			    strlen(sip_header_function_table[i].header_name)) {
743				if (strncasecmp(header_name,
744				    sip_header_function_table[i].
745				    header_name, len) == 0) {
746					break;
747				}
748			} else if (sip_header_function_table[i].
749			    header_short_name != NULL && len ==
750			    strlen(sip_header_function_table[i].
751			    header_short_name)) {
752				if (strncasecmp(header_name,
753				    sip_header_function_table[i].
754				    header_short_name, len) == 0) {
755					break;
756				}
757			}
758			i++;
759		}
760	}
761
762	if (sip_header != NULL)
763		sip_header->sip_hdr_current = sip_header->sip_hdr_start;
764	if (sip_header_function_table[i].header_name == NULL)
765		return (NULL);
766	return (&sip_header_function_table[i]);
767}
768
769/*
770 * Return the entry from the function table for the given header
771 */
772sip_header_function_t *
773sip_get_header_functions(_sip_header_t *sip_header, char *header_name)
774{
775	sip_header_function_t	*func;
776	sip_header_function_t	*header_f_table = NULL;
777
778	if (sip_header_function_table_external != NULL) {
779		header_f_table = _sip_get_header_functions(
780		    sip_header_function_table_external,
781		    sip_header, header_name);
782		if (header_f_table != NULL)
783			return (header_f_table);
784	}
785	func = _sip_get_header_functions(sip_header_function_table, sip_header,
786	    header_name);
787	return (func);
788}
789
790/*
791 * Search for the header name passed in.
792 */
793_sip_header_t *
794sip_search_for_header(_sip_msg_t *sip_msg, char *header_name,
795    _sip_header_t *old_header)
796{
797	int			len = 0;
798	int			full_len = 0;
799	int			compact_len = 0;
800	_sip_header_t		*header = NULL;
801	char			*compact_name = NULL;
802	char			*full_name = NULL;
803	sip_header_function_t	*header_f_table = NULL;
804
805	if (sip_msg == NULL)
806		return (NULL);
807#ifdef	__solaris__
808	assert(mutex_held(&sip_msg->sip_msg_mutex));
809#endif
810
811	if (header_name != NULL) {
812		header_f_table = sip_get_header_functions(NULL, header_name);
813		if (header_f_table != NULL) {
814			full_name = header_f_table->header_name;
815			compact_name = header_f_table->header_short_name;
816			if (full_name != NULL)
817				full_len = strlen(full_name);
818			if (compact_name != NULL)
819				compact_len = strlen(compact_name);
820		} else {
821			header_f_table = &sip_header_function_table[0];
822			full_name = header_name;
823			full_len  = strlen(full_name);
824		}
825	}
826
827	if (old_header != NULL)
828		header = old_header->sip_hdr_next;
829	else
830		header = sip_msg->sip_msg_headers_start;
831
832	while (header != NULL) {
833
834		if (header->sip_header_state == SIP_HEADER_DELETED) {
835			header = header->sip_hdr_next;
836			continue;
837		}
838
839		if (compact_len == 0 && full_len == 0)
840			break;
841
842		header->sip_hdr_current = header->sip_hdr_start;
843
844		if (sip_skip_white_space(header)) {
845			header = header->sip_hdr_next;
846			continue;
847		}
848
849		len = header->sip_hdr_end - header->sip_hdr_current;
850
851		if (full_name != NULL && (full_len <= len) &&
852		    strncasecmp(header->sip_hdr_current, full_name,
853		    full_len) == 0) {
854			header->sip_hdr_current += full_len;
855			if (sip_skip_white_space(header)) {
856				header = header->sip_hdr_next;
857				continue;
858			}
859
860			if (*header->sip_hdr_current == SIP_HCOLON) {
861				header_name = full_name;
862				break;
863			}
864		}
865
866		if (compact_name != NULL && (compact_len <= len) &&
867		    strncasecmp(header->sip_hdr_current, compact_name,
868		    compact_len) == 0) {
869			header->sip_hdr_current += compact_len;
870			if (sip_skip_white_space(header)) {
871				header = header->sip_hdr_next;
872				continue;
873			}
874			if (*header->sip_hdr_current == SIP_HCOLON) {
875				header_name = compact_name;
876				break;
877			}
878		}
879		header = header->sip_hdr_next;
880	}
881
882	if (header != NULL) {
883		header->sip_hdr_current = header->sip_hdr_start;
884		if (header_f_table == NULL) {
885			header_f_table =
886			    sip_get_header_functions(header, header_name);
887			if (header_f_table == NULL)
888				header_f_table = &sip_header_function_table[0];
889		}
890
891		header->sip_header_functions = header_f_table;
892	}
893	return (header);
894}
895
896/*
897 * Return the start line as a string. Caller frees string
898 */
899char *
900_sip_startline_to_str(_sip_msg_t *sip_msg, int *error)
901{
902	char		*slstr;
903	int		len;
904
905	if (error != NULL)
906		*error = 0;
907
908	if (sip_msg == NULL || sip_msg->sip_msg_start_line == NULL) {
909		if (error != NULL)
910			*error = EINVAL;
911		return (NULL);
912	}
913	(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
914	len = sip_msg->sip_msg_start_line->sip_hdr_end -
915	    sip_msg->sip_msg_start_line->sip_hdr_start - 2;
916	if ((slstr = malloc(len + 1)) == NULL) {
917		(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
918		if (error != NULL)
919			*error = ENOMEM;
920		return (NULL);
921	}
922	(void) strncpy(slstr, sip_msg->sip_msg_start_line->sip_hdr_start, len);
923	(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
924	slstr[len] = '\0';
925	return (slstr);
926}
927
928/*
929 * Return the given header as a string. Caller frees string
930 */
931char *
932sip_hdr_to_str(sip_header_t sip_header, int *error)
933{
934	char		*hdrstr;
935	char		*tmpptr;
936	_sip_header_t	*_sip_header;
937	int		len;
938
939	if (error != NULL)
940		*error = 0;
941
942	if (sip_header == NULL) {
943		if (error != NULL)
944			*error = EINVAL;
945		return (NULL);
946	}
947	_sip_header = (_sip_header_t *)sip_header;
948	if (_sip_header->sip_header_state == SIP_HEADER_DELETED) {
949		if (_sip_header->sip_hdr_sipmsg != NULL) {
950			(void) pthread_mutex_unlock(
951			    &_sip_header->sip_hdr_sipmsg->sip_msg_mutex);
952		}
953		if (error != NULL)
954			*error = EINVAL;
955		return (NULL);
956	}
957	if (_sip_header->sip_hdr_sipmsg != NULL) {
958		(void) pthread_mutex_lock(
959		    &_sip_header->sip_hdr_sipmsg->sip_msg_mutex);
960	}
961	len = _sip_header->sip_hdr_end - _sip_header->sip_hdr_start;
962	hdrstr = malloc(len);
963	if (hdrstr == NULL) {
964		if (_sip_header->sip_hdr_sipmsg != NULL) {
965			(void) pthread_mutex_unlock(
966			    &_sip_header->sip_hdr_sipmsg->sip_msg_mutex);
967		}
968		if (error != NULL)
969			*error = ENOMEM;
970		return (NULL);
971	}
972	if (_sip_header->sip_header_state == SIP_HEADER_DELETED_VAL) {
973		len = sip_copy_values(hdrstr, _sip_header);
974	} else {
975		(void) strncpy(hdrstr, _sip_header->sip_hdr_start, len);
976	}
977	if (_sip_header->sip_hdr_sipmsg != NULL) {
978		(void) pthread_mutex_unlock(
979		    &_sip_header->sip_hdr_sipmsg->sip_msg_mutex);
980	}
981	tmpptr = hdrstr + len;
982	while (*tmpptr-- != '\n') {
983		if (tmpptr == _sip_header->sip_hdr_start) {
984			free(hdrstr);
985			if (error != NULL)
986				*error = EINVAL;
987			return (NULL);
988		}
989	}
990	*tmpptr = '\0';
991	return (hdrstr);
992}
993
994/*
995 * Given a param list find the named parameter.
996 * Returns a pointer to the value or NULL.
997 */
998sip_param_t *
999sip_get_param_from_list(sip_param_t *param_list, char *param_name)
1000{
1001	while (param_list != NULL) {
1002		if (param_list->param_name.sip_str_len == strlen(param_name) &&
1003		    strncasecmp(param_list->param_name.sip_str_ptr, param_name,
1004		    strlen(param_name)) == 0) {
1005			return (param_list);
1006		}
1007		param_list = param_list->param_next;
1008	}
1009	return (NULL);
1010}
1011