📄 sip_pref_util.c
字号:
/* * This file is part of the Sofia-SIP package * * Copyright (C) 2005 Nokia Corporation. * * Contact: Pekka Pessi <pekka.pessi@nokia.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * *//**@CFILE sip_pref_util.c * * SIP callercaps and callerprefs utility functions. * * @author Pekka Pessi <Pekka.Pessi@nokia.com>. * * @date Created: Tue Nov 2 16:39:33 EET 2004 ppessi */#include "config.h"#include <stdio.h>#include <stddef.h>#include <stdlib.h>#include <string.h>#include <assert.h>#include <float.h>#include "sofia-sip/sip_parser.h"#include <sofia-sip/sip_header.h>#include <sofia-sip/sip_util.h>#include <sofia-sip/sip_status.h>static double parse_number(char const *str, char **return_end);/** Parse a single preference */int sip_prefs_parse(union sip_pref *sp, char const **in_out_s, int *return_negation){ char const *s; size_t n; enum sp_type old_type; assert(sp && in_out_s && *in_out_s && return_negation); old_type = sp->sp_type; sp->sp_type = sp_error; s = *in_out_s; if (!s) return 0; if (old_type == sp_init) { if (s[0] == '\0' || strcasecmp(s, "TRUE") == 0 || strcasecmp(s, "\"TRUE\"") == 0) { /* Boolean */ sp->sp_type = sp_literal; sp->sp_literal.spl_value = "TRUE"; sp->sp_literal.spl_length = 4; *return_negation = 0; *in_out_s = s + strlen(s); return 1; } else if (strcasecmp(s, "FALSE") == 0 || strcasecmp(s, "\"FALSE\"") == 0) { /* Boolean */ sp->sp_type = sp_literal; sp->sp_literal.spl_value = "FALSE"; sp->sp_literal.spl_length = 5; *return_negation = 0; *in_out_s = s + strlen(s); return 1; } else if (s[0] == '"' && s[1] != '\0') { for (s++; IS_LWS(s[0]); s++); } else old_type = sp_error; } else if (!s[0]) { sp->sp_type = sp_init; return 0; } if (old_type == sp_error) return 0; if ((*return_negation = s[0] == '!')) for (s++; IS_LWS(s[0]); s++); if (*s == '#') { /* Numeric */ double n1, n2; char s0, *e; for (s++; IS_LWS(s[0]); s++); s0 = s[0]; if (s0 == '=') sp->sp_type = sp_range, n1 = n2 = parse_number(s = s + 1, &e); else if (s0 == '<' && s[1] == '=') sp->sp_type = sp_range, n1 = -DBL_MAX, n2 = parse_number(s = s + 2, &e); else if (s0 == '>' && s[1] == '=') sp->sp_type = sp_range, n1 = parse_number(s = s + 2, &e), n2 = DBL_MAX; else if (((n1 = parse_number(s, &e)) != 0.0 || s != e) && e[0] == ':') sp->sp_type = sp_range, n2 = parse_number(s = e + 1, &e); else /* Error in conversion */ sp->sp_type = sp_error, n1 = DBL_MAX, n2 = -DBL_MAX; if (s == e && (n1 == 0.0 || n2 == 0.0)) sp->sp_type = sp_error; /* Error in conversion */ sp->sp_range.spr_lower = n1; sp->sp_range.spr_upper = n2; s = e; } else if (*s == '<') { /* Quoted string */ n = strcspn(++s, ">"); sp->sp_type = sp_string; sp->sp_string.sps_value = s; sp->sp_string.sps_length = n; s += n + 1; } else if ((n = span_token(s))) { /* Literal */ sp->sp_type = sp_literal; sp->sp_literal.spl_value = s; sp->sp_literal.spl_length = n; s += n; } for (; IS_LWS(s[0]); s++); if (s[0] == ',' || (s[0] == '"' && s[1] == '\0')) for (s++; IS_LWS(s[0]); s++); else old_type = sp_error; if (old_type != sp_init && old_type != sp->sp_type) sp->sp_type = sp_error; *in_out_s = s; return sp->sp_type != sp_error;}/** Parse number: * number = [ "+" / "-" ] 1*DIGIT ["." 0*DIGIT] */static double parse_number(char const *str, char **return_end){ double value = 0.0; double decimal = 0.1; char d, sign = '+'; if (return_end) *return_end = (char *)str; d = *str; if (d == '+' || d == '-') sign = d, d = *++str; if (!('0' <= d && d <= '9')) return value; for (; '0' <= d && d <= '9'; d = *++str) value = value * 10 + (d - '0'); if (d == '.') for (d = *++str; '0' <= d && d <= '9'; d = *++str) { value += (d - '0') * decimal; decimal *= 0.1; } if (value > DBL_MAX) value = DBL_MAX; if (sign == '-') value = -value; if (return_end) *return_end = (char *)str; return value;}/** Return true if preferences match */int sip_prefs_match(union sip_pref const *a, union sip_pref const *b){ if (!a || !b) return 0; if (a->sp_type != b->sp_type) return 0; switch (a->sp_type) { default: case sp_error: return 0; case sp_literal: return a->sp_literal.spl_length == b->sp_literal.spl_length && strncasecmp(a->sp_literal.spl_value, b->sp_literal.spl_value, a->sp_literal.spl_length) == 0; case sp_string: return a->sp_string.sps_length == b->sp_string.sps_length && strncmp(a->sp_string.sps_value, b->sp_string.sps_value, a->sp_string.sps_length) == 0; case sp_range: return a->sp_range.spr_lower <= b->sp_range.spr_upper && a->sp_range.spr_upper >= b->sp_range.spr_lower; }}/**Find a matching parameter-value pair from a parameter list. * * Check if the given feature values match with each other. * * @param pvalue first feature parameter * @param nvalue second feature parameter * @param return_parse_error return-value parameter for error (may be NULL) * * @retval 1 if given feature parameters match * @retval 0 if there is no match or a parse or type error occurred. * * If there is a parsing or type error, 0 is returned and @a * *return_parse_error is set to -1. * * @sa sip_prefs_parse(), sip_prefs_match(), union #sip_pref. */int sip_prefs_matching(char const *pvalue, char const *nvalue, int *return_parse_error){ int error; char const *p; union sip_pref np[1], pp[1]; int n_negated, p_negated; if (!return_parse_error) return_parse_error = &error; if (!pvalue || !nvalue) return 0; memset(np, 0, sizeof np); /* Usually nvalue is from Accept/Reject-Contact, pvalue is from Contact */ while (sip_prefs_parse(np, &nvalue, &n_negated)) { memset(pp, 0, sizeof pp); p = pvalue; while (sip_prefs_parse(pp, &p, &p_negated)) { if (pp->sp_type != np->sp_type) /* Types do not match */ return 0; if (sip_prefs_match(np, pp) /* We found matching value */ ? !p_negated /* without negative */ : p_negated) /* Negative did not match */ break; } if (pp->sp_type == sp_error) return *return_parse_error = -1, 0; if (pp->sp_type != sp_init /* We found matching value */ ? !n_negated /* and we expected one */ : n_negated) /* We found none and expected none */ return 1; } if (np->sp_type == sp_error) *return_parse_error = -1; return 0;}/** Check if the parameter is a valid feature tag. * * A feature tag is a parameter starting with a single plus, or a well-known * feature tag listed in @RFC3841: "audio", "automata", "application", * "class", "control", "duplex", "data", "description", "events", "isfocus", * "language", "mobility", "methods", "priority", "schemes", "type", or * "video". However, well-known feature tag can not start with plus. So, * "+alarm" or "audio" is a feature tag, "alarm", "++alarm", or "+audio" are * not.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -