diff options
author | vi117747 <none@none> | 2006-10-07 14:26:26 -0700 |
---|---|---|
committer | vi117747 <none@none> | 2006-10-07 14:26:26 -0700 |
commit | 40cb5e5daa7b80bb70fcf8dadfb20f9281566331 (patch) | |
tree | dc95663e296c5dbf3cb8faa561e53416978eb4dc /usr/src/lib/libsip/common/sip_parse_hdrs.c | |
parent | 56a424cca6b3f91f31bdab72a4626c48c779fe8b (diff) | |
download | illumos-joyent-40cb5e5daa7b80bb70fcf8dadfb20f9281566331.tar.gz |
PSARC 2006/402 SIP Library Integration
6461142 Integrate SIP in Solaris
Diffstat (limited to 'usr/src/lib/libsip/common/sip_parse_hdrs.c')
-rw-r--r-- | usr/src/lib/libsip/common/sip_parse_hdrs.c | 1678 |
1 files changed, 1678 insertions, 0 deletions
diff --git a/usr/src/lib/libsip/common/sip_parse_hdrs.c b/usr/src/lib/libsip/common/sip_parse_hdrs.c new file mode 100644 index 0000000000..fc021678d8 --- /dev/null +++ b/usr/src/lib/libsip/common/sip_parse_hdrs.c @@ -0,0 +1,1678 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include "sip_parse_uri.h" +#include "sip_msg.h" +#include "sip_miscdefs.h" +#include "sip_parse_generic.h" + +/* + * Accept = "Accept" HCOLON [ accept-range *(COMMA accept-range) ] + * accept-range = media-range *(SEMI accept-param) + * media-range = ("* / *" | (m-type SLASH "*") | (m-type SLASH m-subtype)) + * *(SEMI m-param) + * accept-param = ("q" EQUAL qvalue) | generic-param + * qvalue = ("0" ["." 0*3DIGIT]) | ("1" ["." 0*3DIGIT]) + * generic-param = token [ EQUAL gen-value] + * gen-value = token | host | quoted-str + */ +int +sip_parse_acpt_header(_sip_header_t *sip_header, sip_parsed_header_t **header) +{ + if (sip_is_empty_hdr(sip_header)) + return (sip_parse_hdr_empty(sip_header, header)); + return (sip_parse_hdr_parser1(sip_header, header, SIP_SLASH)); +} + +/* + * Accept-Encoding = "Accept-Encoding" ":" 1#(codings [ ";" "q" "=" qval]) + * codings = (content-coding | "*") + * content-coding = token + */ +int +sip_parse_acpt_encode_header(_sip_header_t *sip_header, + sip_parsed_header_t **header) +{ + return (sip_parse_hdr_parser1(sip_header, header, (char)NULL)); +} + +/* + * Accept-Language = "Accept-Language" ":" [ lang * (COMMA lang) ] + * lang = lang-range *(SEMI accept-param) + * lang-range = ((1*8ALPHA * ("-" 1*8ALPHA)) | "*" + */ +int +sip_parse_acpt_lang_header(_sip_header_t *sip_header, + sip_parsed_header_t **header) +{ + if (sip_is_empty_hdr(sip_header)) + return (sip_parse_hdr_empty(sip_header, header)); + return (sip_parse_hdr_parser1(sip_header, header, (char)NULL)); +} + +/* + * Alert-Info = "Alert-Info" ":" alert-param *(COMMA alert-param) + * alert-param = LAQUOT absoluteURI RAQUOT * (SEMI generic-param) + */ +int +sip_parse_alert_header(_sip_header_t *sip_header, sip_parsed_header_t **header) +{ + return (sip_parse_hdr_parser3(sip_header, header, SIP_STR_VAL, B_TRUE)); +} + +/* + * Allow = "Allow" ":" method-name1[, method-name2..] + */ +int +sip_parse_allow_header(_sip_header_t *hdr, sip_parsed_header_t **phdr) +{ + sip_parsed_header_t *parsed_header; + sip_hdr_value_t *value = NULL; + sip_hdr_value_t *last_value = NULL; + int len; + int i; + int ret; + boolean_t multi_value = B_FALSE; + + if ((ret = sip_prim_parsers(hdr, phdr)) != 0) + return (ret); + + if (*phdr != NULL) + return (0); + + parsed_header = calloc(1, sizeof (sip_parsed_header_t)); + if (parsed_header == NULL) + return (ENOMEM); + parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1; + parsed_header->sip_header = hdr; + + while (hdr->sip_hdr_current < hdr->sip_hdr_end) { + value = calloc(1, sizeof (sip_hdr_value_t)); + if (value == NULL) { + sip_free_phdr(parsed_header); + return (ENOMEM); + } + if (last_value != NULL) + last_value->sip_next_value = value; + else + parsed_header->value = (sip_value_t *)value; + + value->sip_value_start = hdr->sip_hdr_current; + value->sip_value_header = parsed_header; + + if (sip_find_separator(hdr, SIP_COMMA, (char)NULL, + (char)NULL) == 0) { + multi_value = B_TRUE; + } + + len = hdr->sip_hdr_current - value->sip_value_start; + for (i = 1; i < MAX_SIP_METHODS; i++) { + if (strncmp(sip_methods[i].name, value->sip_value_start, + len) == 0) { + break; + } + } + if (i >= MAX_SIP_METHODS) { + value->int_val = 0; + value->sip_value_state = SIP_VALUE_BAD; + if (multi_value) + goto next_val; + else + goto end; + } + value->int_val = i; + if (!multi_value) + goto end; + next_val: + if (sip_find_token(hdr, SIP_COMMA) != 0) + break; + value->sip_value_end = hdr->sip_hdr_current - 1; + last_value = value; + (void) sip_skip_white_space(hdr); + } + +end: + *phdr = parsed_header; + return (0); +} + + +/* + * Call-Info = "Call-Info" HCOLON info * (COMMA info) + * info = LAQUOT absoluteURI RAQUOT * (SEMI info-param) + * info-param = ("purpose" EQUAL ("icon" | "info" | "card" | token)) | + * generic-param + */ +int +sip_parse_callinfo_header(_sip_header_t *sip_header, + sip_parsed_header_t **header) +{ + return (sip_parse_hdr_parser3(sip_header, header, SIP_STR_VAL, B_TRUE)); +} + +/* + * Content-Disposition = "Content-Disposition" HCOLON disp-type * + * (SEMI disp-param) + * disp-type = "render" | "session" | "icon" | "alert" | disp-ext-token + * disp-param = handling-param | generic-param + * handling-param = "handling" EQUAL("optional" | "required" | other-handling) + * other-handling = token + * disp-ext-token = token + * + */ +int +sip_parse_contentdis_header(_sip_header_t *sip_header, + sip_parsed_header_t **header) +{ + return (sip_parse_hdr_parser1(sip_header, header, (char)NULL)); +} + +/* + * Content-Encoding = ("Content-Encoding" | "e") HCOLON content-coding * + * (COMMA content-coding) + */ +int +sip_parse_contentencode_header(_sip_header_t *sip_header, + sip_parsed_header_t **header) +{ + return (sip_parse_hdr_parser1(sip_header, header, (char)NULL)); +} + +/* + * Content-Language = ("Content-Language" | "l") HCOLON lang-tag * + * (COMMA lang-tag) + * lang-tag = primary-tag *("-" subtag) + * prmary-tag = 1*8ALPHA + * subtag = 1*8ALPHA + */ +int +sip_parse_contentlang_header(_sip_header_t *sip_header, + sip_parsed_header_t **header) +{ + return (sip_parse_hdr_parser1(sip_header, header, (char)NULL)); +} + +/* + * Date = "Date" HCOLON SIPdate + * SIPdate = wkday "," SP date1 SP time SP "GMT" + * date1 = 2DIGIT SP mnth SP 4DIGIT; day month year + * time = 2DIGIT ":" 2DIGIT ":" 2DIGIT + * wkday = "Mon" | "Tue" | "Wed" | "Thu" | "Fri" | "Sat" | "Sun" + * month = "Jan" | "Feb" etc + */ +int +sip_parse_date_header(_sip_header_t *sip_header, sip_parsed_header_t **header) +{ + sip_parsed_header_t *parsed_header; + int r; + sip_hdr_value_t *value = NULL; + + if ((r = sip_prim_parsers(sip_header, header)) != 0) + return (r); + + if (*header != NULL) + return (0); + + parsed_header = calloc(1, sizeof (sip_parsed_header_t)); + if (parsed_header == NULL) + return (ENOMEM); + parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1; + parsed_header->sip_header = sip_header; + + value = calloc(1, sizeof (sip_hdr_value_t)); + if (value == NULL) { + sip_free_phdr(parsed_header); + return (ENOMEM); + } + parsed_header->value = (sip_value_t *)value; + + value->sip_value_start = sip_header->sip_hdr_current; + value->sip_value_header = parsed_header; + value->date_wd_ptr = sip_header->sip_hdr_current; + if (sip_find_token(sip_header, SIP_COMMA) == 0) { + value->date_wd_len = sip_header->sip_hdr_current - + value->date_wd_ptr - 1; + sip_header->sip_hdr_current++; + if (sip_skip_white_space(sip_header) != 0) { + value->sip_value_state = SIP_VALUE_BAD; + return (EPROTO); + } + } else { + value->sip_value_state = SIP_VALUE_BAD; + return (EPROTO); + } + + if (sip_skip_white_space(sip_header) != 0) { + value->sip_value_state = SIP_VALUE_BAD; + return (EPROTO); + } + r = sip_atoi(sip_header, &value->date_d); + if (r != 0 || value->date_d < 0 || value->date_d > 31) { + value->sip_value_state = SIP_VALUE_BAD; + return (EPROTO); + } + if (sip_skip_white_space(sip_header) != 0) { + value->sip_value_state = SIP_VALUE_BAD; + return (EPROTO); + } + value->date_m_ptr = sip_header->sip_hdr_current; + if (sip_find_token(sip_header, SIP_SP) == 0) { + value->date_m_len = sip_header->sip_hdr_current - + value->date_m_ptr - 1; + } else { + value->sip_value_state = SIP_VALUE_BAD; + return (EPROTO); + } + + r = sip_atoi(sip_header, &value->date_y); + if (r != 0 || value->date_y < 0) { + value->sip_value_state = SIP_VALUE_BAD; + return (EPROTO); + } + if (sip_skip_white_space(sip_header) != 0) { + value->sip_value_state = SIP_VALUE_BAD; + return (EPROTO); + } + value->date_t_ptr = sip_header->sip_hdr_current; + if (sip_find_token(sip_header, SIP_SP) == 0) { + value->date_t_len = sip_header->sip_hdr_current - + value->date_t_ptr - 1; + } else { + value->sip_value_state = SIP_VALUE_BAD; + return (EPROTO); + } + + value->date_tz_ptr = sip_header->sip_hdr_current; + /* + * minus 2 to get rid of the CRLF + */ + value->date_tz_len = sip_header->sip_hdr_end - + sip_header->sip_hdr_current - 2; + + *header = parsed_header; + + sip_header->sip_hdr_parsed = *header; + return (0); +} + +/* + * Error-Info = "Error-Info" HCOLON error-uri *(COMMA error-uri) + * error-uri = LAQUOT absoluteURI RAQUOT *(SEMI generic-param) + */ +int +sip_parse_errorinfo_header(_sip_header_t *sip_header, + sip_parsed_header_t **header) +{ + return (sip_parse_hdr_parser3(sip_header, header, SIP_STR_VAL, B_TRUE)); +} + +/* + * Expires = "Expires" HCOLON delta-seconds + */ +int +sip_parse_expire_header(_sip_header_t *sip_header, + sip_parsed_header_t **header) +{ + return (sip_parse_hdr_parser2(sip_header, header, SIP_INT_VAL)); +} + +/* + * In-Reply-To = "In-Reply-To" HCOLON callid *(COMMA callid) + */ +int +sip_parse_inreplyto_header(_sip_header_t *sip_header, + sip_parsed_header_t **header) +{ + return (sip_parse_hdr_parser1(sip_header, header, (char)NULL)); +} + +/* + * RSeq = "RSeq" HCOLON response-num + */ +int +sip_parse_rseq(_sip_header_t *sip_header, sip_parsed_header_t **header) +{ + int r; + sip_hdr_value_t *rseq_value; + + r = sip_parse_hdr_parser2(sip_header, header, SIP_INT_VAL); + /* + * Additionally, a value of 0 is bad_value + */ + if (sip_header->sip_hdr_parsed != NULL && + sip_header->sip_hdr_parsed->value != NULL) { + rseq_value = (sip_hdr_value_t *) + sip_header->sip_hdr_parsed->value; + if (rseq_value->int_val == 0) + rseq_value->sip_value_state = SIP_VALUE_BAD; + } + return (r); +} + +/* + * Min-Expires = "Min-Expires" HCOLON delta-seconds + */ +int +sip_parse_minexpire_header(_sip_header_t *sip_header, + sip_parsed_header_t **header) +{ + return (sip_parse_hdr_parser2(sip_header, header, SIP_INT_VAL)); +} + +/* + * MIME-Version = "MIME-Version" HCOLON 1*DIGIT "." 1*DIGIT + */ +int +sip_parse_mimeversion_header(_sip_header_t *sip_header, + sip_parsed_header_t **header) +{ + return (sip_parse_hdr_parser4(sip_header, header)); +} + +/* + * Organization = "Organization" HCOLON [TEXT-UTF8-TRIM] + */ +int +sip_parse_org_header(_sip_header_t *sip_header, + sip_parsed_header_t **header) +{ + if (sip_is_empty_hdr(sip_header)) + return (sip_parse_hdr_empty(sip_header, header)); + return (sip_parse_hdr_parser4(sip_header, header)); +} + +/* + * Priority = "Priority" HCOLON priority-val + * priority-val = "emergency" | "urgent" | "normal" | "non-urgent" | other + * other = token + */ +int +sip_parse_priority_header(_sip_header_t *sip_header, + sip_parsed_header_t **header) +{ + return (sip_parse_hdr_parser4(sip_header, header)); +} + +/* + * Reply-To = "Reply-To" HCOLON rplyto-spec + * rplyto-spec = (name-addr | addr-spec) *(SEMI rplyto-param) + * rplyto-param = generic-param + * name-addr = [ display-name ] LAQUOT addr-spec RAQUOT + * addr-spec = SIP-URI | SIPS-URI | absolute URI + */ +int +sip_parse_replyto_header(_sip_header_t *sip_header, + sip_parsed_header_t **header) +{ + return (sip_parse_hdr_parser3(sip_header, header, SIP_STRS_VAL, + B_TRUE)); +} + +/* + * PRIVACY = "Privacy" HCOLON priv-value *(COMMA priv-value) + * priv-value = "header" / "session" / "user" / "none" / "critical" + * / token / id + */ +int +sip_parse_privacy_header(_sip_header_t *sip_header, + sip_parsed_header_t **header) +{ + return (sip_parse_hdr_parser1(sip_header, header, (char)NULL)); +} + + +/* + * Require = "Require" HCOLON option-tag * (COMMA option-tag) + */ +int +sip_parse_require_header(_sip_header_t *sip_header, + sip_parsed_header_t **header) +{ + return (sip_parse_hdr_parser1(sip_header, header, (char)NULL)); +} + +/* + * Retry-After = "Retry-After" HCOLON delta-seconds [ comment ] * + * (SEMI retry-param) + * retry-param = "duration" EQUAL delta-seconds + */ +int +sip_parse_retryaft_header(_sip_header_t *sip_header, + sip_parsed_header_t **header) +{ + sip_parsed_header_t *parsed_header; + sip_hdr_value_t *value = NULL; + int ret; + + if ((ret = sip_prim_parsers(sip_header, header)) != 0) + return (ret); + + if (*header != NULL) + return (0); + + parsed_header = calloc(1, sizeof (sip_parsed_header_t)); + if (parsed_header == NULL) + return (ENOMEM); + parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1; + parsed_header->sip_header = sip_header; + + value = calloc(1, sizeof (sip_hdr_value_t)); + if (value == NULL) { + sip_free_phdr(parsed_header); + return (ENOMEM); + } + + parsed_header->value = (sip_value_t *)value; + value->sip_value_start = sip_header->sip_hdr_current; + value->sip_value_header = parsed_header; + + ret = sip_atoi(sip_header, &(value->intstr_int)); + if (ret != 0) + value->sip_value_state = SIP_VALUE_BAD; + if (sip_find_token(sip_header, SIP_LPAR) == 0) { + value->intstr_str_ptr = sip_header->sip_hdr_current; + if (sip_find_token(sip_header, SIP_RPAR) == 0) { + value->intstr_str_len = + sip_header->sip_hdr_current - + value->intstr_str_ptr - 1; + if (sip_find_token(sip_header, SIP_SEMI) == 0) { + sip_header->sip_hdr_current--; + (void) sip_parse_params(sip_header, + &(value->sip_param_list)); + } + } else { + value->sip_value_state = SIP_VALUE_BAD; + return (EPROTO); + } + } else { + value->intstr_str_ptr = NULL; + value->intstr_str_len = 0; + + /* + * from value start, search if parameter list + */ + sip_header->sip_hdr_current = value->sip_value_start; + if (sip_find_token(sip_header, SIP_SEMI) == 0) { + sip_header->sip_hdr_current--; + (void) sip_parse_params(sip_header, + &(value->sip_param_list)); + } + } + + *header = parsed_header; + sip_header->sip_hdr_parsed = *header; + return (0); +} + +/* + * Server = "Server" HCOLON servel-val *(LWS server-val) + * servel-val = product|comment + * product = token [SLASH version] + * version = token + * Treated as one single string + */ +int +sip_parse_server_header(_sip_header_t *sip_header, sip_parsed_header_t **header) +{ + return (sip_parse_hdr_parser4(sip_header, header)); +} + +/* + * Subject = ("Subject" | "s")HCOLON [TEXT-UTF8-TRIM] + */ +int +sip_parse_subject_header(_sip_header_t *sip_header, + sip_parsed_header_t **header) +{ + if (sip_is_empty_hdr(sip_header)) + return (sip_parse_hdr_empty(sip_header, header)); + return (sip_parse_hdr_parser4(sip_header, header)); +} + +/* + * Supported = ("Supported" | "k") HCOLON [option-tag * (COMMA option-tag) ] + */ +int +sip_parse_support_header(_sip_header_t *sip_header, + sip_parsed_header_t **header) +{ + if (sip_is_empty_hdr(sip_header)) + return (sip_parse_hdr_empty(sip_header, header)); + return (sip_parse_hdr_parser1(sip_header, header, (char)NULL)); +} + +/* + * Timestamp = "Timestamp" HCOLON 1*DIGIT ["." *(DIGIT)] [LWS delay] + */ +int +sip_parse_timestamp_header(_sip_header_t *sip_header, + sip_parsed_header_t **header) +{ + sip_parsed_header_t *parsed_header; + sip_hdr_value_t *value = NULL; + int ret; + + if ((ret = sip_prim_parsers(sip_header, header)) != 0) + return (ret); + + if (*header != NULL) + return (0); + + parsed_header = calloc(1, sizeof (sip_parsed_header_t)); + if (parsed_header == NULL) + return (ENOMEM); + parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1; + parsed_header->sip_header = sip_header; + + value = calloc(1, sizeof (sip_hdr_value_t)); + if (value == NULL) { + sip_free_phdr(parsed_header); + return (ENOMEM); + } + parsed_header->value = (sip_value_t *)value; + + value->sip_value_start = sip_header->sip_hdr_current; + value->sip_value_header = parsed_header; + + if (sip_skip_white_space(sip_header) != 0) { + value->sip_value_state = SIP_VALUE_BAD; + return (EPROTO); + } + value->strs1_val_ptr = sip_header->sip_hdr_current; + + if (sip_find_white_space(sip_header) == 0) { + /* + * timestamp and delay, timestamp in str1, delay in str2 + */ + value->strs1_val_len = sip_header->sip_hdr_current - + value->strs1_val_ptr; + (void) sip_skip_white_space(sip_header); + + value->strs2_val_ptr = sip_header->sip_hdr_current; + if (sip_find_cr(sip_header) != 0) { + value->sip_value_state = SIP_VALUE_BAD; + return (EPROTO); + } + if (sip_header->sip_hdr_current < value->strs2_val_ptr) { + value->strs2_val_ptr = NULL; + value->strs2_val_len = 0; + } else { + value->strs2_val_len = sip_header->sip_hdr_current - + value->strs2_val_ptr; + } + } else { + /* + * no delay information + */ + value->strs1_val_len = sip_header->sip_hdr_current + - value->strs1_val_ptr; + value->strs2_val_ptr = NULL; + value->strs2_val_len = 0; + } + + *header = parsed_header; + sip_header->sip_hdr_parsed = *header; + + return (0); +} +/* + * Unsupported = "Unsupported" HCOLON option-tag * (COMMA option-tag) + */ +int +sip_parse_usupport_header(_sip_header_t *sip_header, + sip_parsed_header_t **header) +{ + return (sip_parse_hdr_parser1(sip_header, header, (char)NULL)); +} + +/* + * User-Agent = "User-Agent" HCOLON server-val * (LWS server-val) + * servel-val = product |comment + * product = token [SLASH version] + * version = token + */ +int +sip_parse_useragt_header(_sip_header_t *sip_header, + sip_parsed_header_t **header) +{ + return (sip_parse_hdr_parser4(sip_header, header)); +} + +/* + * Warning = "Warning" HCOLON warning-value *(COMMA warning-value) + * warning-value = warn-code SP warn-agent SP warn-text + * warn-code = 3DIGIT + * warn-agent = hostport | pseudonym ; + * the name or pseudonym of the server adding; + * the Warning header, for use in debugging + * warn-text = quoted-string + * pseudonym = token + */ +int +sip_parse_warn_header(_sip_header_t *sip_header, sip_parsed_header_t **header) +{ + sip_parsed_header_t *parsed_header; + int ret; + sip_hdr_value_t *value = NULL; + sip_hdr_value_t *last_value = NULL; + + if ((ret = sip_prim_parsers(sip_header, header)) != 0) + return (ret); + + if (*header != NULL) + return (0); + + parsed_header = calloc(1, sizeof (sip_parsed_header_t)); + if (parsed_header == NULL) + return (ENOMEM); + parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1; + parsed_header->sip_header = sip_header; + + while (sip_header->sip_hdr_current < sip_header->sip_hdr_end) { + value = calloc(1, sizeof (sip_hdr_value_t)); + if (value == NULL) { + sip_free_phdr(parsed_header); + return (ENOMEM); + } + + if (last_value != NULL) + last_value->sip_next_value = value; + else + parsed_header->value = (sip_value_t *)value; + + value->sip_value_start = sip_header->sip_hdr_current; + value->sip_value_header = parsed_header; + + ret = sip_atoi(sip_header, &value->warn_code); + if (ret != 0 || value->warn_code < 100 || + value->warn_code > 999) { + value->sip_value_state = SIP_VALUE_BAD; + goto get_next_val; + } + if (sip_skip_white_space(sip_header) != 0) { + value->sip_value_state = SIP_VALUE_BAD; + goto get_next_val; + } + value->warn_agt_ptr = sip_header->sip_hdr_current; + + if (sip_find_token(sip_header, SIP_QUOTE) == 0) { + /* + * get warning agent + */ + sip_header->sip_hdr_current--; + (void) sip_reverse_skip_white_space(sip_header); + value->warn_agt_len = sip_header->sip_hdr_current - + value->warn_agt_ptr - 1; + if (value->warn_agt_len <= 0) { + value->warn_agt_ptr = NULL; + value->sip_value_state = SIP_VALUE_BAD; + } + + /* + * We will have a SIP_QUOTE here + */ + (void) sip_find_token(sip_header, SIP_QUOTE); + + value->warn_text_ptr = sip_header->sip_hdr_current; + if (sip_find_token(sip_header, SIP_QUOTE) == 0) { + value->warn_text_len = + sip_header->sip_hdr_current - + value->warn_text_ptr - 1; + } else { + value->sip_value_state = SIP_VALUE_BAD; + goto get_next_val; + } + } else + /* + * warning text must present + */ + value->sip_value_state = SIP_VALUE_BAD; + +get_next_val: + if (sip_find_token(sip_header, SIP_COMMA) != 0) + break; + value->sip_value_end = sip_header->sip_hdr_current - 1; + last_value = value; + (void) sip_skip_white_space(sip_header); + } + + *header = parsed_header; + + sip_header->sip_hdr_parsed = *header; + return (0); +} + +/* + * Parse RAck header + * "RAck" HCOLON response-num LWS CSeq-num LWS Method + * response-num = 1*DIGIT + * CSeq-num = 1*DIGIT + */ +int +sip_parse_rack(_sip_header_t *sip_header, sip_parsed_header_t **header) +{ + sip_parsed_header_t *parsed_header; + sip_hdr_value_t *rack_value; + int len; + char *tmp_ptr; + int i; + int ret; + + if ((ret = sip_prim_parsers(sip_header, header)) != 0) + return (ret); + + if (*header != NULL) + return (0); + + parsed_header = calloc(1, sizeof (sip_parsed_header_t)); + if (parsed_header == NULL) + return (ENOMEM); + parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1; + parsed_header->sip_header = sip_header; + + parsed_header->value = calloc(1, sizeof (sip_hdr_value_t)); + if (parsed_header->value == NULL) { + free(parsed_header); + return (ENOMEM); + } + rack_value = (sip_hdr_value_t *)parsed_header->value; + rack_value->sip_value_version = SIP_VALUE_VERSION_1; + rack_value->sip_value_start = sip_header->sip_hdr_current; + rack_value->sip_value_header = parsed_header; + if (sip_atoi(sip_header, &rack_value->rack_resp) || + rack_value->rack_resp == 0) { + rack_value->sip_value_state = SIP_VALUE_BAD; + rack_value->sip_value_end = sip_header->sip_hdr_end - 2; + goto rack_parse_done; + } + rack_value->sip_value_header = parsed_header; + /* + * Get cseq. + */ + if (sip_skip_white_space(sip_header) != 0) { + rack_value->sip_value_state = SIP_VALUE_BAD; + rack_value->sip_value_end = sip_header->sip_hdr_end - 2; + goto rack_parse_done; + } + if (sip_atoi(sip_header, &rack_value->rack_cseq)) { + rack_value->sip_value_state = SIP_VALUE_BAD; + rack_value->sip_value_end = sip_header->sip_hdr_end - 2; + goto rack_parse_done; + } + /* + * Get method. + */ + if (sip_skip_white_space(sip_header) != 0) { + rack_value->sip_value_state = SIP_VALUE_BAD; + rack_value->sip_value_end = sip_header->sip_hdr_end - 2; + goto rack_parse_done; + } + + tmp_ptr = sip_header->sip_hdr_current; + if (sip_find_white_space(sip_header)) { + rack_value->sip_value_state = SIP_VALUE_BAD; + rack_value->sip_value_end = sip_header->sip_hdr_end - 2; + goto rack_parse_done; + } + + len = sip_header->sip_hdr_current - tmp_ptr; + + for (i = 1; i < MAX_SIP_METHODS; i++) { + if (strncmp(sip_methods[i].name, tmp_ptr, len) == 0) + break; + } + + if (i >= MAX_SIP_METHODS) { + rack_value->sip_value_state = SIP_VALUE_BAD; + rack_value->sip_value_end = sip_header->sip_hdr_end - 2; + goto rack_parse_done; + } + + rack_value->rack_method = i; + rack_value->sip_value_end = sip_header->sip_hdr_current; + +rack_parse_done: + sip_header->sip_hdr_parsed = parsed_header; + + *header = parsed_header; + return (0); +} + +/* + * Allow = "Allow" HCOLON [Method *(COMMA Method)] + */ +int +sip_parse_allow_events_header(_sip_header_t *sip_header, + sip_parsed_header_t **header) +{ + return (sip_parse_hdr_parser1(sip_header, header, (char)NULL)); +} + +/* + * Event = ( "Event" / "o" ) HCOLON event-type + * *( SEMI event-param ) + * event-type = event-package *( "." event-template ) + * event-package = token-nodot + * event-template = token-nodot + * token-nodot = 1*( alphanum / "-" / "!" / "%" / "*" + * / "_" / "+" / "`" / "'" / "~" ) + * event-param = generic-param / ( "id" EQUAL token ) + */ +int +sip_parse_event_header(_sip_header_t *sip_header, sip_parsed_header_t **header) +{ + return (sip_parse_hdr_parser1(sip_header, header, (char)NULL)); +} + +/* + * Subscription-State = "Subscription-State" HCOLON substate-value + * *( SEMI subexp-params ) + * substate-value = "active" / "pending" / "terminated" + * / extension-substate + * extension-substate = token + * subexp-params = ("reason" EQUAL event-reason-value) + * / ("expires" EQUAL delta-seconds)* + * / ("retry-after" EQUAL delta-seconds) + * / generic-param + * event-reason-value = "deactivated" + * / "probation" + * / "rejected" + * / "timeout" + * / "giveup" + * / "noresource" + * / event-reason-extension + * event-reason-extension = token + */ +int +sip_parse_substate_header(_sip_header_t *sip_header, + sip_parsed_header_t **header) +{ + return (sip_parse_hdr_parser1(sip_header, header, (char)NULL)); +} + +/* + * Authorization = "Authorization" HCOLON credentials + * credentials = ("Digest" LWS digest-response) + * / other-response + * digest-response = dig-resp *(COMMA dig-resp) + * dig-resp = username / realm / nonce / digest-uri + * / dresponse / algorithm / cnonce + * / opaque / message-qop + * / nonce-count / auth-param + * username = "username" EQUAL username-value + * username-value = quoted-string + * digest-uri = "uri" EQUAL LDQUOT digest-uri-value RDQUOT + * digest-uri-value = rquest-uri ; Equal to request-uri as specified + * by HTTP/1.1 + * message-qop = "qop" EQUAL qop-value + * cnonce = "cnonce" EQUAL cnonce-value + * cnonce-value = nonce-value + * nonce-count = "nc" EQUAL nc-value + * nc-value = 8LHEX + * dresponse = "response" EQUAL request-digest + * request-digest = LDQUOT 32LHEX RDQUOT + * auth-param = auth-param-name EQUAL + * ( token / quoted-string ) + * auth-param-name = token + * other-response = auth-scheme LWS auth-param + * *(COMMA auth-param) + * auth-scheme = token + */ +int +sip_parse_author_header(_sip_header_t *sip_header, + sip_parsed_header_t **header) +{ + return (sip_parse_hdr_parser5(sip_header, header, B_TRUE)); +} + +/* + * Authentication-Info = "Authentication-Info" HCOLON ainfo + * *(COMMA ainfo) + * ainfo = nextnonce / message-qop + * / response-auth / cnonce + * / nonce-count + * nextnonce = "nextnonce" EQUAL nonce-value + * response-auth = "rspauth" EQUAL response-digest + * response-digest = LDQUOT *LHEX RDQUOT + * + */ +int +sip_parse_ainfo_header(_sip_header_t *sip_header, + sip_parsed_header_t **header) +{ + return (sip_parse_hdr_parser1(sip_header, header, (char)NULL)); +} + +/* + * Proxy-Authenticate = "Proxy-Authenticate" HCOLON challenge + * challenge = ("Digest" LWS digest-cln *(COMMA digest-cln)) + * / other-challenge + * other-challenge = auth-scheme LWS auth-param + * *(COMMA auth-param) + * digest-cln = realm / domain / nonce + * / opaque / stale / algorithm + * / qop-options / auth-param + * realm = "realm" EQUAL realm-value + * realm-value = quoted-string + * domain = "domain" EQUAL LDQUOT URI + * *( 1*SP URI ) RDQUOT + * URI = absoluteURI / abs-path + * nonce = "nonce" EQUAL nonce-value + * nonce-value = quoted-string + * opaque = "opaque" EQUAL quoted-string + * stale = "stale" EQUAL ( "true" / "false" ) + * algorithm = "algorithm" EQUAL ( "MD5" / "MD5-sess" + * / token ) + * qop-options = "qop" EQUAL LDQUOT qop-value + * *("," qop-value) RDQUOT + * qop-value = "auth" / "auth-int" / token + * + */ +int +sip_parse_pauthen_header(_sip_header_t *sip_header, + sip_parsed_header_t **header) +{ + return (sip_parse_hdr_parser5(sip_header, header, B_TRUE)); +} + +/* + * Proxy-Authorization = "Proxy-Authorization" HCOLON credentials + */ +int +sip_parse_pauthor_header(_sip_header_t *sip_header, + sip_parsed_header_t **header) +{ + return (sip_parse_hdr_parser5(sip_header, header, B_TRUE)); +} + +/* + * Proxy-Require = "Proxy-Require" HCOLON option-tag + * *(COMMA option-tag) + * option-tag = token + */ +int +sip_parse_preq_header(_sip_header_t *sip_header, + sip_parsed_header_t **header) +{ + return (sip_parse_hdr_parser1(sip_header, header, (char)NULL)); +} + +/* + * WWW-Authenticate = "WWW-Authenticate" HCOLON challenge + * extension-header = header-name HCOLON header-value + * header-name = token + * header-value = *(TEXT-UTF8char / UTF8-CONT / LWS) + * message-body = *OCTET + * + */ +int +sip_parse_wauthen_header(_sip_header_t *sip_header, + sip_parsed_header_t **header) +{ + return (sip_parse_hdr_parser5(sip_header, header, B_TRUE)); +} + +/* + * Call-ID = ( "Call-ID" / "i" ) HCOLON callid + */ +int +sip_parse_cid_header(_sip_header_t *sip_header, sip_parsed_header_t **header) +{ + return (sip_parse_hdr_parser4(sip_header, header)); +} + +/* + * CSeq = "CSeq" HCOLON 1*DIGIT LWS Method + */ +int +sip_parse_cseq_header(_sip_header_t *sip_header, sip_parsed_header_t **header) +{ + sip_parsed_header_t *parsed_header; + sip_hdr_value_t *cseq_value; + int len; + char *tmp_ptr; + int i; + int ret; + + if ((ret = sip_prim_parsers(sip_header, header)) != 0) + return (ret); + + if (*header != NULL) + return (0); + + parsed_header = calloc(1, sizeof (sip_parsed_header_t)); + if (parsed_header == NULL) + return (ENOMEM); + parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1; + parsed_header->sip_header = sip_header; + + parsed_header->value = calloc(1, sizeof (sip_hdr_value_t)); + if (parsed_header->value == NULL) { + free(parsed_header); + return (ENOMEM); + } + cseq_value = (sip_hdr_value_t *)parsed_header->value; + cseq_value->sip_value_version = SIP_VALUE_VERSION_1; + cseq_value->sip_value_start = sip_header->sip_hdr_current; + if (sip_atoi(sip_header, &cseq_value->cseq_num)) { + cseq_value->sip_value_state = SIP_VALUE_BAD; + cseq_value->sip_value_end = sip_header->sip_hdr_end - 2; + goto cseq_parse_done; + } + cseq_value->sip_value_header = parsed_header; + /* + * Get method. + */ + if (sip_skip_white_space(sip_header) != 0) { + cseq_value->sip_value_state = SIP_VALUE_BAD; + cseq_value->sip_value_end = sip_header->sip_hdr_end - 2; + goto cseq_parse_done; + } + + tmp_ptr = sip_header->sip_hdr_current; + + if (sip_find_white_space(sip_header)) { + cseq_value->sip_value_state = SIP_VALUE_BAD; + cseq_value->sip_value_end = sip_header->sip_hdr_current; + goto cseq_parse_done; + } + + len = sip_header->sip_hdr_current - tmp_ptr; + + for (i = 1; i < MAX_SIP_METHODS; i++) { + if (strncmp(sip_methods[i].name, tmp_ptr, len) == 0) + break; + } + + if (i >= MAX_SIP_METHODS) { + cseq_value->sip_value_state = SIP_VALUE_BAD; + cseq_value->sip_value_end = sip_header->sip_hdr_current; + goto cseq_parse_done; + } + + cseq_value->cseq_method = i; + cseq_value->sip_value_end = sip_header->sip_hdr_current; +cseq_parse_done: + + sip_header->sip_hdr_parsed = parsed_header; + + *header = parsed_header; + return (0); +} + + +/* + * Via = ( "Via" / "v" ) HCOLON via-parm *(COMMA via-parm) + * via-parm = sent-protocol LWS sent-by *( SEMI via-params ) + * via-params = via-ttl / via-maddr + * / via-received / via-branch + * / via-extension + * via-ttl = "ttl" EQUAL ttl + * via-maddr = "maddr" EQUAL host + * via-received = "received" EQUAL (IPv4address / IPv6address) + * via-branch = "branch" EQUAL token + * via-extension = generic-param + * sent-protocol = protocol-name SLASH protocol-version + * SLASH transport + * protocol-name = "SIP" / token + * protocol-version = token + * transport = "UDP" / "TCP" / "TLS" / "SCTP" + * / other-transport + * sent-by = host [ COLON port ] + * ttl = 1*3DIGIT ; 0 to 255 + * + * There can be multiple via headers we always append the header. + */ +int +sip_parse_via_header(_sip_header_t *sip_header, sip_parsed_header_t **header) +{ + sip_parsed_header_t *parsed_header; + int ret; + sip_hdr_value_t *value = NULL; + sip_hdr_value_t *last_value = NULL; + + if ((ret = sip_prim_parsers(sip_header, header)) != 0) + return (ret); + + if (*header != NULL) + return (0); + + parsed_header = calloc(1, sizeof (sip_parsed_header_t)); + if (parsed_header == NULL) + return (ENOMEM); + parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1; + parsed_header->sip_header = sip_header; + + while (sip_header->sip_hdr_current < sip_header->sip_hdr_end) { + + value = calloc(1, sizeof (sip_hdr_value_t)); + if (value == NULL) { + sip_free_phdr(parsed_header); + return (ENOMEM); + } + if (last_value != NULL) + last_value->sip_next_value = value; + else + parsed_header->value = (sip_value_t *)value; + + value->sip_value_version = SIP_VALUE_VERSION_1; + value->sip_value_start = sip_header->sip_hdr_current; + value->sip_value_header = parsed_header; + value->via_protocol_name.sip_str_ptr = + sip_header->sip_hdr_current; + + /* + * Check to see if there is a version number + */ + if (sip_get_protocol_version(sip_header, + &value->via_protocol) != 0) { + if (sip_goto_next_value(sip_header) != 0) { + sip_free_phdr(parsed_header); + return (EPROTO); + } + value->sip_value_state = SIP_VALUE_BAD; + goto get_next_via_value; + } + + if (sip_find_token(sip_header, SIP_SLASH) != 0) { + if (sip_goto_next_value(sip_header) != 0) { + sip_free_phdr(parsed_header); + return (EPROTO); + } + value->sip_value_state = SIP_VALUE_BAD; + goto get_next_via_value; + } + + if (sip_skip_white_space(sip_header) != 0) { + if (sip_goto_next_value(sip_header) != 0) { + sip_free_phdr(parsed_header); + return (EPROTO); + } + value->sip_value_state = SIP_VALUE_BAD; + goto get_next_via_value; + } + + value->via_protocol_transport.sip_str_ptr = + sip_header->sip_hdr_current; + if (sip_find_white_space(sip_header) != 0) { + if (sip_goto_next_value(sip_header) != 0) { + sip_free_phdr(parsed_header); + return (EPROTO); + } + value->sip_value_state = SIP_VALUE_BAD; + goto get_next_via_value; + } + + value->via_protocol_transport.sip_str_len = + sip_header->sip_hdr_current - + value->via_protocol_transport.sip_str_ptr; + + if (sip_skip_white_space(sip_header) != 0) { + if (sip_goto_next_value(sip_header) != 0) { + sip_free_phdr(parsed_header); + return (EPROTO); + } + value->sip_value_state = SIP_VALUE_BAD; + goto get_next_via_value; + } + + value->via_sent_by_host.sip_str_ptr = + sip_header->sip_hdr_current; + if (*sip_header->sip_hdr_current == '[') { + if (sip_find_token(sip_header, ']')) { + if (sip_goto_next_value(sip_header) != 0) { + sip_free_phdr(parsed_header); + return (EPROTO); + } + value->sip_value_state = SIP_VALUE_BAD; + goto get_next_via_value; + } + } else if (sip_find_separator(sip_header, SIP_SEMI, SIP_COMMA, + SIP_HCOLON)) { + if (sip_goto_next_value(sip_header) != 0) { + sip_free_phdr(parsed_header); + return (EPROTO); + } + value->sip_value_state = SIP_VALUE_BAD; + goto get_next_via_value; + } + value->via_sent_by_host.sip_str_len = + sip_header->sip_hdr_current - + value->via_sent_by_host.sip_str_ptr; + + if (sip_skip_white_space(sip_header) != 0) { + if (sip_goto_next_value(sip_header) != 0) { + sip_free_phdr(parsed_header); + return (EPROTO); + } + value->sip_value_state = SIP_VALUE_BAD; + goto get_next_via_value; + } + + if (*sip_header->sip_hdr_current == SIP_HCOLON) { + sip_header->sip_hdr_current++; + /* + * We have a port number + */ + if (sip_atoi(sip_header, &value->via_sent_by_port) != + 0) { + if (sip_goto_next_value(sip_header) != 0) { + sip_free_phdr(parsed_header); + return (EPROTO); + } + value->sip_value_state = SIP_VALUE_BAD; + goto get_next_via_value; + } + + } + + /* + * Do some sanity checking. + * This should be replaced by a v4/v6 address check. + */ + if (value->via_sent_by_host.sip_str_len == 0 || + (!isalnum(*value->via_sent_by_host.sip_str_ptr) && + *value->via_sent_by_host.sip_str_ptr != '[')) { + if (sip_goto_next_value(sip_header) != 0) { + sip_free_phdr(parsed_header); + return (EPROTO); + } + value->sip_value_state = SIP_VALUE_BAD; + goto get_next_via_value; + } + + ret = sip_parse_params(sip_header, &value->sip_param_list); + if (ret == EPROTO) { + value->sip_value_state = SIP_VALUE_BAD; + } else if (ret != 0) { + sip_free_phdr(parsed_header); + return (ret); + } +get_next_via_value: + value->sip_value_end = sip_header->sip_hdr_current; + + if (sip_find_token(sip_header, SIP_COMMA) != 0) + break; + last_value = value; + (void) sip_skip_white_space(sip_header); + } + + sip_header->sip_hdr_parsed = parsed_header; + + *header = parsed_header; + return (0); +} + +/* + * Max-Forwards = "Max-Forwards" HCOLON 1*DIGIT + */ +int +sip_parse_maxf_header(_sip_header_t *sip_header, sip_parsed_header_t **header) +{ + return (sip_parse_hdr_parser2(sip_header, header, SIP_INT_VAL)); +} + +/* + * Content-Type = ( "Content-Type" / "c" ) HCOLON media-type + * media-type = m-type SLASH m-subtype *(SEMI m-parameter) + * m-type = discrete-type / composite-type + * discrete-type = "text" / "image" / "audio" / "video" + * / "application" / extension-token + * composite-type = "message" / "multipart" / extension-token + * extension-token = ietf-token / x-token + * ietf-token = token + * x-token = "x-" token + * m-subtype = extension-token / iana-token + * iana-token = token + * m-parameter = m-attribute EQUAL m-value + * m-attribute = token + * m-value = token / quoted-string + */ +int +sip_parse_ctype_header(_sip_header_t *sip_header, sip_parsed_header_t **header) +{ + return (sip_parse_hdr_parser1(sip_header, header, SIP_SLASH)); +} + +/* + * Content-Length = ( "Content-Length" / "l" ) HCOLON 1*DIGIT + */ +int +sip_parse_clen_header(_sip_header_t *sip_header, sip_parsed_header_t **header) +{ + return (sip_parse_hdr_parser2(sip_header, header, SIP_INT_VAL)); +} + +/* + * Generic parser for Contact, From, To, Route and Record-Route headers + * + * Contact = ("Contact" / "m" ) HCOLON + * ( STAR / (contact-param *(COMMA contact-param))) + * contact-param = (name-addr / addr-spec) *(SEMI contact-params) + * name-addr = [ display-name ] LAQUOT addr-spec RAQUOT + * addr-spec = SIP-URI / SIPS-URI / absoluteURI + * display-name = *(token LWS)/ quoted-string + * contact-params = c-p-q / c-p-expires + * / contact-extension + * + * From = ( "From" / "f" ) HCOLON from-spec + * from-spec = ( name-addr / addr-spec ) + * *( SEMI from-param ) + * from-param = tag-param / generic-param + * tag-param = "tag" EQUAL token + * + * To = ( "To" / "t" ) HCOLON ( name-addr + * / addr-spec ) *( SEMI to-param ) + * to-param = tag-param / generic-param + * + * Route = "Route" HCOLON route-param *(COMMA route-param) + * route-param = name-addr *( SEMI rr-param ) + * + * Record-Route = "Record-Route" HCOLON rec-route *(COMMA rec-route) + * rec-route = name-addr *( SEMI rr-param ) + * rr-param = generic-param + * + * We could have multiple values for these headers. For the ones that have + * a display name we will have a LAQUOT/RAQUOT. If we encounter an error + * when parsing a value, we mark the value as bad and start paring the + * next value, if present. Before we start parsing the next value, we + * check for any parameters, if present. + */ +int +sip_parse_cftr_header(_sip_header_t *sip_header, sip_parsed_header_t **header) +{ + sip_parsed_header_t *parsed_header; + char *tmp_ptr; + char *tmp_ptr_2; + int ret; + sip_hdr_value_t *value = NULL; + sip_hdr_value_t *last_value = NULL; + + if ((ret = sip_prim_parsers(sip_header, header)) != 0) + return (ret); + + if (*header != NULL) + return (0); + + parsed_header = calloc(1, sizeof (sip_parsed_header_t)); + if (parsed_header == NULL) + return (ENOMEM); + parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1; + parsed_header->sip_header = sip_header; + while (sip_header->sip_hdr_current < sip_header->sip_hdr_end) { + boolean_t quoted_name = B_FALSE; + + value = calloc(1, sizeof (sip_hdr_value_t)); + if (value == NULL) { + sip_free_cftr_header(parsed_header); + return (ENOMEM); + } + if (last_value != NULL) + last_value->sip_next_value = value; + else + parsed_header->value = (sip_value_t *)value; + if (*sip_header->sip_hdr_current == SIP_QUOTE) { + sip_header->sip_hdr_current++; + quoted_name = B_TRUE; + } + value->sip_value_version = SIP_VALUE_VERSION_1; + value->sip_value_start = sip_header->sip_hdr_current; + value->sip_value_header = parsed_header; + /* + * let's see if there is a display name + */ + if (*sip_header->sip_hdr_current != SIP_LAQUOT) { + + tmp_ptr = sip_header->sip_hdr_current; + /* + * According to 20.10 '<' may not have a leading + * space. + */ + if (quoted_name && + sip_find_token(sip_header, SIP_QUOTE) != 0) { + if (sip_goto_next_value(sip_header) != 0) { + sip_free_cftr_header(parsed_header); + return (EPROTO); + } + value->sip_value_state = SIP_VALUE_BAD; + goto get_next_cftr_value; + } else if (sip_find_separator(sip_header, SIP_SEMI, + SIP_LAQUOT, SIP_COMMA) != 0) { + /* + * only a uri. + */ + value->cftr_uri.sip_str_ptr = tmp_ptr; + value->cftr_uri.sip_str_len = + sip_header->sip_hdr_current - tmp_ptr; + /* + * It's an error not to have a uri. + */ + if (value->cftr_uri.sip_str_len == 0) { + if (sip_goto_next_value(sip_header) != + 0) { + sip_free_cftr_header( + parsed_header); + return (EPROTO); + } + value->sip_value_state = SIP_VALUE_BAD; + goto get_next_cftr_value; + } + continue; + } + + tmp_ptr_2 = sip_header->sip_hdr_current; + if (*sip_header->sip_hdr_current == SIP_SP) { + if (sip_skip_white_space(sip_header) != 0) { + /* + * only a uri. + */ + value->cftr_uri.sip_str_ptr = tmp_ptr; + value->cftr_uri.sip_str_len = + tmp_ptr_2 - tmp_ptr; + /* + * It's an error not to have a uri. + */ + if (value->cftr_uri.sip_str_len == 0) { + if (sip_goto_next_value( + sip_header) != 0) { + sip_free_cftr_header( + parsed_header); + return (EPROTO); + } + value->sip_value_state = + SIP_VALUE_BAD; + goto get_next_cftr_value; + } + continue; + } + } + + if (*sip_header->sip_hdr_current != SIP_LAQUOT) { + /* + * No display name here. + */ + value->cftr_uri.sip_str_ptr = tmp_ptr; + value->cftr_uri.sip_str_len = tmp_ptr_2 - + tmp_ptr; + /* + * It's an error not to have a uri. + */ + if (value->cftr_uri.sip_str_len == 0) { + if (sip_goto_next_value(sip_header) != + 0) { + sip_free_cftr_header( + parsed_header); + return (EPROTO); + } + value->sip_value_state = SIP_VALUE_BAD; + goto get_next_cftr_value; + } + goto get_params; + } + + value->cftr_name = malloc(sizeof (sip_str_t)); + if (value->cftr_name == NULL) { + sip_free_cftr_header(parsed_header); + return (ENOMEM); + } + value->cftr_name->sip_str_ptr = tmp_ptr; + value->cftr_name->sip_str_len = tmp_ptr_2 - tmp_ptr; + if (quoted_name) + value->cftr_name->sip_str_len--; + } + + if (sip_find_token(sip_header, SIP_LAQUOT) != 0) { + if (sip_goto_next_value(sip_header) != 0) { + sip_free_cftr_header(parsed_header); + return (EPROTO); + } + value->sip_value_state = SIP_VALUE_BAD; + goto get_next_cftr_value; + } + + if (*sip_header->sip_hdr_current == SIP_SP) { + if (sip_skip_white_space(sip_header) != 0) { + if (sip_goto_next_value(sip_header) != 0) { + sip_free_cftr_header(parsed_header); + return (EPROTO); + } + value->sip_value_state = SIP_VALUE_BAD; + goto get_next_cftr_value; + } + } + + tmp_ptr = sip_header->sip_hdr_current; + + if (sip_find_separator(sip_header, SIP_RAQUOT, (char)NULL, + (char)NULL)) { + if (sip_goto_next_value(sip_header) != 0) { + sip_free_cftr_header(parsed_header); + return (EPROTO); + } + value->sip_value_state = SIP_VALUE_BAD; + goto get_next_cftr_value; + } + + value->cftr_uri.sip_str_ptr = tmp_ptr; + value->cftr_uri.sip_str_len = + sip_header->sip_hdr_current - tmp_ptr; + + if (sip_find_token(sip_header, SIP_RAQUOT) != 0) { + if (sip_goto_next_value(sip_header) != 0) { + sip_free_cftr_header(parsed_header); + return (EINVAL); + } + value->sip_value_state = SIP_VALUE_BAD; + goto get_next_cftr_value; + } + + if (value->cftr_uri.sip_str_len <= strlen("<>")) { + if (sip_goto_next_value(sip_header) != 0) { + sip_free_cftr_header(parsed_header); + return (EPROTO); + } + value->sip_value_state = SIP_VALUE_BAD; + goto get_next_cftr_value; + } + +get_params: + ret = sip_parse_params(sip_header, &value->sip_param_list); + if (ret == EPROTO) { + value->sip_value_state = SIP_VALUE_BAD; + } else if (ret != 0) { + sip_free_cftr_header(parsed_header); + return (ret); + } +get_next_cftr_value: + value->sip_value_end = sip_header->sip_hdr_current; + + /* + * Parse uri + */ + if (value->cftr_uri.sip_str_len > 0) { + int error; + + value->sip_value_parsed_uri = sip_parse_uri( + &value->cftr_uri, &error); + if (value->sip_value_parsed_uri == NULL) { + sip_free_cftr_header(parsed_header); + return (ENOMEM); + } + if (error != 0 || + ((_sip_uri_t *)value->sip_value_parsed_uri)-> + sip_uri_errflags != 0) { + value->sip_value_state = SIP_VALUE_BAD; + } + } + + (void) sip_find_token(sip_header, SIP_COMMA); + last_value = value; + (void) sip_skip_white_space(sip_header); + } + + sip_header->sip_hdr_parsed = parsed_header; + + *header = parsed_header; + return (0); +} + +/* + * PAssertedID = "P-Asserted-Identity" HCOLON PAssertedID-value + * *(COMMA PAssertedID-value) + * PAssertedID-value = name-addr / addr-spec + */ +int +sip_parse_passertedid(_sip_header_t *sip_header, sip_parsed_header_t **header) +{ + return (sip_parse_hdr_parser3(sip_header, header, SIP_STRS_VAL, + B_TRUE)); +} + +/* + * PPreferredID = "P-Preferred-Identity" HCOLON PPreferredID-value + * *(COMMA PAssertedID-value) + * PPreferredID-value = name-addr / addr-spec + */ +int +sip_parse_ppreferredid(_sip_header_t *sip_header, sip_parsed_header_t **header) +{ + return (sip_parse_hdr_parser3(sip_header, header, SIP_STRS_VAL, + B_TRUE)); +} + + +/* + * We don't do anything for a header we don't understand + */ +/* ARGSUSED */ +int +sip_parse_unknown_header(_sip_header_t *sip_header, + sip_parsed_header_t **header) +{ + return (EINVAL); +} |