⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sip_pref_util.c

📁 this is simple sip stack.
💻 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 <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>/** Parse a single preference */int sip_prefs_parse(union sip_pref *sp, 		    char const **in_out_s, 		    int *return_negation){  char const *s;  unsigned 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 = strtod(s = s + 1, &e);    else if (s0 == '<' && s[1] == '=')      sp->sp_type = sp_range, n1 = DBL_MIN, n2 = strtod(s = s + 2, &e);    else if (s0 == '>' && s[1] == '=')      sp->sp_type = sp_range, n1 = strtod(s = s + 2, &e), n2 = DBL_MAX;    else if (((n1 = strtod(s, &e)) != 0.0 || s != e) && e[0] == ':')      sp->sp_type = sp_range, n2 = strtod(s = e + 1, &e);    else      /* Error in conversion */      sp->sp_type = sp_error, n1 = DBL_MAX, n2 = DBL_MIN;    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;}/** 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. * * The function sip_prefs_matching() checks 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) * * @return * The function sip_prefs_match() returns 1, if given feature parameters * match. The function sip_prefs_match() returns 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. */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. */int sip_is_callerpref(char const *param){#define MATCH(s) \  (strncasecmp(param + 1, s + 1, strlen(s) - 1) == 0 && \   (param[strlen(s)] == '=' || param[strlen(s)] == '\0'))  int xor = 0, base = 0;  if (!param || !param[0])    return 0;  if (param[0] == '+')    param++, xor = 1;  switch (param[0]) {  case 'a': case 'A':    base = MATCH("audio") || MATCH("automata") || MATCH("application") ||      MATCH("actor");    break;  case 'c': case 'C':    base = MATCH("class") || MATCH("control");    break;  case 'd': case 'D':    base = MATCH("duplex") || MATCH("data") || MATCH("description");    break;  case 'e': case 'E':    base = MATCH("events");    break;  case 'i': case 'I':    base = MATCH("isfocus");    break;  case 'l': case 'L':    base = MATCH("language");    break;  case 'm': case 'M':    base = MATCH("mobility") || MATCH("methods");    break;  case 'p': case 'P':    base = MATCH("priority");    break;  case 's': case 'S':    base = MATCH("schemes");    break;  case 't': case 'T':    base = MATCH("type");    break;  case 'v': case 'V':    base = MATCH("video");    break;  default:    base = 0;    break;  }#undef MATCH  return base ^ xor;}/** Check if @b Contact is immune to callerprefs. */int sip_contact_immune(sip_contact_t const *m){  unsigned i;  if (m->m_params)    for (i = 0; m->m_params[i]; i++) {      if (sip_is_callerpref(m->m_params[i]))	return 0;    }  return 1;}/** Check if @b Contact matches by @b Accept-Contact. * *  * * @retval 1 if successful * @retval 0 if an error occurs */int sip_contact_accept(sip_contact_t const *m, 		       sip_accept_contact_t const *cp,		       unsigned *return_S,		       unsigned *return_N,		       int *return_error){  char const *cap, *acc;  unsigned i, S, N, eq;  if (!return_N) return_N = &N;  if (!return_S) return_S = &S;  *return_S = 0, *return_N = 0;  if (!m || !cp || !m->m_params || !cp->cp_params)    return 1;  for (i = 0, S = 0, N = 0; cp->cp_params[i]; i++) {    acc = cp->cp_params[i];    if (!sip_is_callerpref(acc))      continue;    N++;    cap = msg_params_find(m->m_params, acc);    if (cap) {      eq = strcspn(acc, "=");      acc += eq + (acc[eq] == '=');      if (!sip_prefs_matching(cap, acc, return_error)) 	return 0;            S++;    }  }  *return_S = S; /* Matched feature tags */  *return_N = N; /* Number of feature tags in Accept-Contact */  return 1; }/** Check if Contact can be rejected by Reject-Contact. */int sip_contact_reject(sip_contact_t const *m, 		       sip_reject_contact_t const *reject){  unsigned S, N;  int error;  if (!m || !m->m_params || !reject || !reject->cp_params)    return 0;  return sip_contact_accept(m, reject, &S, &N, &error) && S == N && N > 0;}/** Immunize Contact is to callerprefs. */sip_contact_t *sip_contact_immunize(su_home_t *home, sip_contact_t const *m){  unsigned i, j;  sip_contact_t m0[1], *m1;  msg_param_t *params;  if (!m)    return NULL;  *m0 = *m, m0->m_next = NULL;  m1 = sip_contact_copy(home, m0);  if (m1 == NULL || !m1->m_params)    return m1;  params = (msg_param_t *)m1->m_params;  for (i = 0, j = 0; params[i]; i++) {    if (!sip_is_callerpref(params[i]))      params[j++] = params[i];  }  params[j] = NULL;  return m1;}/** Calculate score for contact */int sip_contact_score(sip_contact_t const *m,		      sip_accept_contact_t const *ac,		      sip_reject_contact_t const *rc){  unsigned long S_total = 0;  unsigned M = 0, scale = 1000;  int error = 0;  if (sip_contact_immune(m))    return 1000;		/* Immune */  for (; rc; rc = rc->cp_next)    if (sip_contact_reject(m, rc))       break;  if (rc)    return -1;			/* Rejected */  for (; ac; ac = ac->cp_next) {    unsigned S, N;	    if (!sip_contact_accept(m, ac, &S, &N, &error)) {      if (ac->cp_require)	return 0;		/* Discarded */      continue;    }    M++;    /* Apply score */    if (S < N && ac->cp_explicit) {      S = 0;      if (ac->cp_require)	return 0;		/* Dropped */    }    if (S > 0 && N > 0)       S_total += sip_q_value(ac->cp_q) * (scale * S / N + (2 * S >= N));  }  if (!M)     return 0;  S_total /= M;  if (S_total < scale * 1000)    return S_total / scale;  else    return 1000;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -