Asterisk - The Open Source Telephony Project  18.5.0
Data Structures | Functions
reqresp_parser.h File Reference

sip request response parser header file More...

This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  contact
 
struct  uriparams
 uri parameters More...
 

Functions

 AST_LIST_HEAD_NOLOCK (contactliststruct, contact)
 
void free_via (struct sip_via *v)
 
const char * get_calleridname (const char *input, char *output, size_t outputsize)
 Get caller id name from SIP headers, copy into output buffer. More...
 
int get_comma (char *parse, char **out)
 Parse all contact header contacts. More...
 
char * get_in_brackets (char *tmp)
 Pick out text in brackets from character string. More...
 
int get_in_brackets_const (const char *src, const char **start, int *length)
 Get text in brackets on a const without copy. More...
 
int get_in_brackets_full (char *tmp, char **out, char **residue)
 Get text in brackets and any trailing residue. More...
 
int get_name_and_number (const char *hdr, char **name, char **number)
 Get name and number from sip header. More...
 
int parse_contact_header (char *contactheader, struct contactliststruct *contactlist)
 
int parse_name_andor_addr (char *uri, const char *scheme, char **name, char **user, char **pass, char **domain, struct uriparams *params, char **headers, char **remander)
 Parse the ABNF structure name-andor-addr = name-addr / addr-spec into its components and return any trailing message-header parameters. More...
 
unsigned int parse_sip_options (const char *options, char *unsupported, size_t unsupported_len)
 Parse supported header in incoming packet. More...
 
int parse_uri (char *uri, const char *scheme, char **ret_name, char **pass, char **hostport, char **transport)
 parses a URI in its components. More...
 
int parse_uri_full (char *uri, const char *scheme, char **user, char **pass, char **hostport, struct uriparams *params, char **headers, char **residue)
 parses a URI in to all of its components and any trailing residue More...
 
struct sip_viaparse_via (const char *header)
 Parse a Via header. More...
 
void sip_reqresp_parser_exit (void)
 Free resources used by request and response parser. More...
 
int sip_reqresp_parser_init (void)
 initialize request and response parser data More...
 
void sip_request_parser_register_tests (void)
 register request parsing tests More...
 
void sip_request_parser_unregister_tests (void)
 unregister request parsing tests More...
 
int sip_uri_cmp (const char *input1, const char *input2)
 Compare two URIs as described in RFC 3261 Section 19.1.4. More...
 

Detailed Description

sip request response parser header file

Definition in file reqresp_parser.h.

Function Documentation

◆ AST_LIST_HEAD_NOLOCK()

AST_LIST_HEAD_NOLOCK ( contactliststruct  ,
contact   
)

◆ free_via()

void free_via ( struct sip_via v)

Definition at line 2379 of file reqresp_parser.c.

References ast_free, and sip_via::via.

Referenced by __find_call(), __sip_alloc(), AST_TEST_DEFINE(), parse_via(), and process_via().

2380 {
2381  if (!v) {
2382  return;
2383  }
2384 
2385  ast_free(v->via);
2386  ast_free(v);
2387 }
char * via
Definition: sip.h:875
#define ast_free(a)
Definition: astmm.h:182

◆ get_calleridname()

const char* get_calleridname ( const char *  input,
char *  output,
size_t  outputsize 
)

Get caller id name from SIP headers, copy into output buffer.

Return values
inputstring pointer placed after display-name field if possible

Definition at line 695 of file reqresp_parser.c.

References ast_log, ast_skip_blanks(), input(), and LOG_WARNING.

Referenced by AST_TEST_DEFINE(), check_user_full(), get_name_and_number(), parse_name_andor_addr(), and receive_message().

696 {
697  /* From RFC3261:
698  *
699  * From = ( "From" / "f" ) HCOLON from-spec
700  * from-spec = ( name-addr / addr-spec ) *( SEMI from-param )
701  * name-addr = [ display-name ] LAQUOT addr-spec RAQUOT
702  * display-name = *(token LWS)/ quoted-string
703  * token = 1*(alphanum / "-" / "." / "!" / "%" / "*"
704  * / "_" / "+" / "`" / "'" / "~" )
705  * quoted-string = SWS DQUOTE *(qdtext / quoted-pair ) DQUOTE
706  * qdtext = LWS / %x21 / %x23-5B / %x5D-7E
707  * / UTF8-NONASCII
708  * quoted-pair = "\" (%x00-09 / %x0B-0C / %x0E-7F)
709  *
710  * HCOLON = *WSP ":" SWS
711  * SWS = [LWS]
712  * LWS = *[*WSP CRLF] 1*WSP
713  * WSP = (SP / HTAB)
714  *
715  * Deviations from it:
716  * - following CRLF's in LWS is not done (here at least)
717  * - ascii NUL is never legal as it terminates the C-string
718  * - utf8-nonascii is not checked for validity
719  */
720  char *orig_output = output;
721  const char *orig_input = input;
722 
723  if (!output || !outputsize) {
724  /* Bad output parameters. Should never happen. */
725  return input;
726  }
727 
728  /* clear any empty characters in the beginning */
730 
731  /* make sure the output buffer is initilized */
732  *orig_output = '\0';
733 
734  /* make room for '\0' at the end of the output buffer */
735  --outputsize;
736 
737  /* no data at all or no display name? */
738  if (!input || *input == '<') {
739  return input;
740  }
741 
742  /* quoted-string rules */
743  if (input[0] == '"') {
744  input++; /* skip the first " */
745 
746  for (; *input; ++input) {
747  if (*input == '"') { /* end of quoted-string */
748  break;
749  } else if (*input == 0x5c) { /* quoted-pair = "\" (%x00-09 / %x0B-0C / %x0E-7F) */
750  ++input;
751  if (!*input) {
752  break;
753  }
754  if ((unsigned char) *input > 0x7f || *input == 0xa || *input == 0xd) {
755  continue; /* not a valid quoted-pair, so skip it */
756  }
757  } else if ((*input != 0x9 && (unsigned char) *input < 0x20)
758  || *input == 0x7f) {
759  continue; /* skip this invalid character. */
760  }
761 
762  if (0 < outputsize) {
763  /* We still have room for the output display-name. */
764  *output++ = *input;
765  --outputsize;
766  }
767  }
768 
769  /* if this is successful, input should be at the ending quote */
770  if (*input != '"') {
771  ast_log(LOG_WARNING, "No ending quote for display-name was found\n");
772  *orig_output = '\0';
773  return orig_input;
774  }
775 
776  /* make sure input is past the last quote */
777  ++input;
778 
779  /* terminate output */
780  *output = '\0';
781  } else { /* either an addr-spec or tokenLWS-combo */
782  for (; *input; ++input) {
783  /* token or WSP (without LWS) */
784  if ((*input >= '0' && *input <= '9') || (*input >= 'A' && *input <= 'Z')
785  || (*input >= 'a' && *input <= 'z') || *input == '-' || *input == '.'
786  || *input == '!' || *input == '%' || *input == '*' || *input == '_'
787  || *input == '+' || *input == '`' || *input == '\'' || *input == '~'
788  || *input == 0x9 || *input == ' ') {
789  if (0 < outputsize) {
790  /* We still have room for the output display-name. */
791  *output++ = *input;
792  --outputsize;
793  }
794  } else if (*input == '<') { /* end of tokenLWS-combo */
795  /* we could assert that the previous char is LWS, but we don't care */
796  break;
797  } else if (*input == ':') {
798  /* This invalid character which indicates this is addr-spec rather than display-name. */
799  *orig_output = '\0';
800  return orig_input;
801  } else { /* else, invalid character we can skip. */
802  continue; /* skip this character */
803  }
804  }
805 
806  if (*input != '<') { /* if we never found the start of addr-spec then this is invalid */
807  *orig_output = '\0';
808  return orig_input;
809  }
810 
811  /* terminate output while trimming any trailing whitespace */
812  do {
813  *output-- = '\0';
814  } while (orig_output <= output && (*output == 0x9 || *output == ' '));
815  }
816 
817  return input;
818 }
#define LOG_WARNING
Definition: logger.h:274
static int input(yyscan_t yyscanner)
Definition: ast_expr2f.c:1584
#define ast_log
Definition: astobj2.c:42
char * ast_skip_blanks(const char *str)
Gets a pointer to the first non-whitespace character in a string.
Definition: strings.h:157

◆ get_comma()

int get_comma ( char *  parse,
char **  out 
)

Parse all contact header contacts.

Return values
0success
-1failure
1all contacts (star)

Definition at line 1438 of file reqresp_parser.c.

References ast_log, c, find_closing_quote(), in, LOG_WARNING, NULL, and parse().

Referenced by parse_contact_header().

1439 {
1440  char *c;
1441  char *parse = in;
1442  if (out) {
1443  *out = in;
1444  }
1445 
1446  /* Skip any quoted text */
1447  while (*parse) {
1448  if ((c = strchr(parse, '"'))) {
1449  in = (char *)find_closing_quote((const char *)c + 1, NULL);
1450  if (!*in) {
1451  ast_log(LOG_WARNING, "No closing quote found in '%s'\n", c);
1452  return -1;
1453  } else {
1454  break;
1455  }
1456  } else {
1457  break;
1458  }
1459  parse++;
1460  }
1461  parse = in;
1462 
1463  /* Skip any userinfo components of a uri as they may contain commas */
1464  if ((c = strchr(parse,'@'))) {
1465  parse = c+1;
1466  }
1467  if ((out) && (c = strchr(parse,','))) {
1468  *c++ = '\0';
1469  *out = c;
1470  return 0;
1471  }
1472  return 1;
1473 }
#define LOG_WARNING
Definition: logger.h:274
static struct test_val c
const char * find_closing_quote(const char *start, const char *lim)
Locate closing quote in a string, skipping escaped quotes. optionally with a limit on the search...
Definition: chan_sip.c:5074
#define NULL
Definition: resample.c:96
#define ast_log
Definition: astobj2.c:42
FILE * in
Definition: utils/frame.c:33
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1872
FILE * out
Definition: utils/frame.c:33

◆ get_in_brackets()

char* get_in_brackets ( char *  tmp)

Pick out text in brackets from character string.

Returns
pointer to terminated stripped string
Parameters
tmpinput string that will be modified

Examples:

* "foo" <bar>  valid input, returns bar
*  foo returns the whole string
* < "foo ... > returns the string between brackets
* < "foo...    bogus (missing closing bracket), returns the whole string
* 

Definition at line 1173 of file reqresp_parser.c.

References get_in_brackets_full(), NULL, out, and tmp().

Referenced by AST_TEST_DEFINE(), check_user_full(), extract_uri(), get_also_info(), get_destination(), get_domain(), get_name_and_number(), get_pai(), get_rdnis(), get_refer_info(), handle_cc_notify(), parse_moved_contact(), parse_ok_contact(), parse_register_contact(), receive_message(), register_verify(), reqprep(), sip_get_cc_information(), sip_msg_send(), transmit_refer(), transmit_state_notify(), uac_sips_contact(), and uas_sips_contact().

1174 {
1175  char *out;
1176 
1177  if ((get_in_brackets_full(tmp, &out, NULL))) {
1178  return tmp;
1179  }
1180  return out;
1181 }
static int tmp()
Definition: bt_open.c:389
int get_in_brackets_full(char *tmp, char **out, char **residue)
Get text in brackets and any trailing residue.
#define NULL
Definition: resample.c:96
FILE * out
Definition: utils/frame.c:33

◆ get_in_brackets_const()

int get_in_brackets_const ( const char *  src,
const char **  start,
int *  length 
)

Get text in brackets on a const without copy.

Parameters
srcString to search
[out]startSet to first character inside left bracket.
[out]lengthSet to lenght of string inside brackets
Return values
0success
-1failure
1no brackets so got all

Definition at line 1052 of file reqresp_parser.c.

References ast_log, ast_strlen_zero, find_closing_quote(), LOG_WARNING, NULL, and parse().

Referenced by build_route(), and sip_route_process_header().

1053 {
1054  const char *parse = src;
1055  const char *first_bracket;
1056  const char *second_bracket;
1057 
1058  if (start == NULL) {
1059  return -1;
1060  }
1061  if (length == NULL) {
1062  return -1;
1063  }
1064  *start = NULL;
1065  *length = -1;
1066  if (ast_strlen_zero(src)) {
1067  return 1;
1068  }
1069 
1070  /*
1071  * Skip any quoted text until we find the part in brackets.
1072  * On any error give up and return -1
1073  */
1074  while ( (first_bracket = strchr(parse, '<')) ) {
1075  const char *first_quote = strchr(parse, '"');
1076  first_bracket++;
1077  if (!first_quote || first_quote >= first_bracket) {
1078  break; /* no need to look at quoted part */
1079  }
1080  /* the bracket is within quotes, so ignore it */
1081  parse = find_closing_quote(first_quote + 1, NULL);
1082  if (!*parse) {
1083  ast_log(LOG_WARNING, "No closing quote found in '%s'\n", src);
1084  return -1;
1085  }
1086  parse++;
1087  }
1088 
1089  /* Require a first bracket. Unlike get_in_brackets_full, this procedure is passed a const,
1090  * so it can expect a pointer to an original value */
1091  if (!first_bracket) {
1092  ast_log(LOG_WARNING, "No opening bracket found in '%s'\n", src);
1093  return 1;
1094  }
1095 
1096  if ((second_bracket = strchr(first_bracket, '>'))) {
1097  *start = first_bracket;
1098  *length = second_bracket - first_bracket;
1099  return 0;
1100  }
1101  ast_log(LOG_WARNING, "No closing bracket found in '%s'\n", src);
1102  return -1;
1103 }
#define LOG_WARNING
Definition: logger.h:274
const char * find_closing_quote(const char *start, const char *lim)
Locate closing quote in a string, skipping escaped quotes. optionally with a limit on the search...
Definition: chan_sip.c:5074
#define NULL
Definition: resample.c:96
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_log
Definition: astobj2.c:42
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1872

◆ get_in_brackets_full()

int get_in_brackets_full ( char *  tmp,
char **  out,
char **  residue 
)

Get text in brackets and any trailing residue.

Return values
0success
-1failure
1no brackets so got all

Definition at line 1105 of file reqresp_parser.c.

References ast_log, ast_strlen_zero, find_closing_quote(), LOG_WARNING, NULL, parse(), and tmp().

Referenced by get_in_brackets(), and parse_name_andor_addr().

1106 {
1107  const char *parse = tmp;
1108  char *first_bracket;
1109  char *second_bracket;
1110 
1111  if (out) {
1112  *out = "";
1113  }
1114  if (residue) {
1115  *residue = "";
1116  }
1117 
1118  if (ast_strlen_zero(tmp)) {
1119  return 1;
1120  }
1121 
1122  /*
1123  * Skip any quoted text until we find the part in brackets.
1124  * On any error give up and return -1
1125  */
1126  while ( (first_bracket = strchr(parse, '<')) ) {
1127  char *first_quote = strchr(parse, '"');
1128  first_bracket++;
1129  if (!first_quote || first_quote >= first_bracket) {
1130  break; /* no need to look at quoted part */
1131  }
1132  /* the bracket is within quotes, so ignore it */
1133  parse = find_closing_quote(first_quote + 1, NULL);
1134  if (!*parse) {
1135  ast_log(LOG_WARNING, "No closing quote found in '%s'\n", tmp);
1136  return -1;
1137  }
1138  parse++;
1139  }
1140 
1141  /* If no first bracket then still look for a second bracket as some other parsing functions
1142  may overwrite first bracket with NULL when terminating a token based display-name. As this
1143  only affects token based display-names there is no danger of brackets being in quotes */
1144  if (first_bracket) {
1145  parse = first_bracket;
1146  } else {
1147  parse = tmp;
1148  }
1149 
1150  if ((second_bracket = strchr(parse, '>'))) {
1151  *second_bracket++ = '\0';
1152  if (out) {
1153  *out = (char *) parse;
1154  }
1155  if (residue) {
1156  *residue = second_bracket;
1157  }
1158  return 0;
1159  }
1160 
1161  if ((first_bracket)) {
1162  ast_log(LOG_WARNING, "No closing bracket found in '%s'\n", tmp);
1163  return -1;
1164  }
1165 
1166  if (out) {
1167  *out = tmp;
1168  }
1169 
1170  return 1;
1171 }
#define LOG_WARNING
Definition: logger.h:274
static int tmp()
Definition: bt_open.c:389
const char * find_closing_quote(const char *start, const char *lim)
Locate closing quote in a string, skipping escaped quotes. optionally with a limit on the search...
Definition: chan_sip.c:5074
#define NULL
Definition: resample.c:96
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_log
Definition: astobj2.c:42
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1872
FILE * out
Definition: utils/frame.c:33

◆ get_name_and_number()

int get_name_and_number ( const char *  hdr,
char **  name,
char **  number 
)

Get name and number from sip header.

Note
name and number point to malloced memory on return and must be freed. If name or number is not found, they will be returned as NULL.
Return values
0success
-1failure

Definition at line 905 of file reqresp_parser.c.

References ast_copy_string(), ast_log, ast_strdup, ast_strlen_zero, ast_uri_decode(), ast_uri_sip_user, dummy(), get_calleridname(), get_in_brackets(), LOG_ERROR, NULL, and parse_uri().

Referenced by AST_TEST_DEFINE(), change_redirecting_information(), and get_pai().

906 {
907  char header[256];
908  char tmp_name[256];
909  char *tmp_number = NULL;
910  char *hostport = NULL;
911  char *dummy = NULL;
912 
913  if (!name || !number || ast_strlen_zero(hdr)) {
914  return -1;
915  }
916 
917  *number = NULL;
918  *name = NULL;
919  ast_copy_string(header, hdr, sizeof(header));
920 
921  /* strip the display-name portion off the beginning of the header. */
922  get_calleridname(header, tmp_name, sizeof(tmp_name));
923 
924  /* get uri within < > brackets */
925  tmp_number = get_in_brackets(header);
926 
927  /* parse out the number here */
928  if (parse_uri(tmp_number, "sip:,sips:", &tmp_number, &dummy, &hostport, NULL) || ast_strlen_zero(tmp_number)) {
929  ast_log(LOG_ERROR, "can not parse name and number from sip header.\n");
930  return -1;
931  }
932 
933  /* number is not option, and must be present at this point */
934  *number = ast_strdup(tmp_number);
936 
937  /* name is optional and may not be present at this point */
938  if (!ast_strlen_zero(tmp_name)) {
939  *name = ast_strdup(tmp_name);
940  }
941 
942  return 0;
943 }
void ast_uri_decode(char *s, struct ast_flags spec)
Decode URI, URN, URL (overwrite string)
Definition: main/utils.c:616
static void dummy(char *unused,...)
Definition: chan_unistim.c:220
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
#define NULL
Definition: resample.c:96
#define ast_strlen_zero(foo)
Definition: strings.h:52
Number structure.
Definition: app_followme.c:154
int parse_uri(char *uri, const char *scheme, char **user, char **pass, char **hostport, char **transport)
parses a URI in its components.
#define ast_log
Definition: astobj2.c:42
char * get_in_brackets(char *tmp)
Pick out text in brackets from character string.
const char * get_calleridname(const char *input, char *output, size_t outputsize)
Get caller id name from SIP headers, copy into output buffer.
#define LOG_ERROR
Definition: logger.h:285
static const char name[]
Definition: cdr_mysql.c:74
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
const struct ast_flags ast_uri_sip_user
Definition: main/utils.c:575

◆ parse_contact_header()

int parse_contact_header ( char *  contactheader,
struct contactliststruct *  contactlist 
)

Definition at line 1475 of file reqresp_parser.c.

References ast_calloc, AST_LIST_HEAD_SET_NOLOCK, AST_LIST_INSERT_TAIL, contact::expires, get_comma(), contact::headers, contact::hostport, last, contact::name, NULL, contact::params, parse_name_andor_addr(), contact::pass, contact::q, contact::user, and value.

Referenced by AST_TEST_DEFINE().

1476 {
1477  int res;
1478  int last;
1479  char *comma;
1480  char *residue;
1481  char *param;
1482  char *value;
1483  struct contact *split_contact = NULL;
1484 
1485  if (*contactheader == '*') {
1486  return 1;
1487  }
1488 
1489  split_contact = ast_calloc(1, sizeof(*split_contact));
1490 
1491  AST_LIST_HEAD_SET_NOLOCK(contactlist, split_contact);
1492  while ((last = get_comma(contactheader, &comma)) != -1) {
1493  res = parse_name_andor_addr(contactheader, "sip:,sips:",
1494  &split_contact->name, &split_contact->user,
1495  &split_contact->pass, &split_contact->hostport,
1496  &split_contact->params, &split_contact->headers,
1497  &residue);
1498  if (res == -1) {
1499  return res;
1500  }
1501 
1502  /* parse contact params */
1503  split_contact->expires = split_contact->q = "";
1504 
1505  while ((value = strchr(residue,'='))) {
1506  *value++ = '\0';
1507 
1508  param = residue;
1509  if ((residue = strchr(value,';'))) {
1510  *residue++ = '\0';
1511  } else {
1512  residue = "";
1513  }
1514 
1515  if (!strcmp(param,"expires")) {
1516  split_contact->expires = value;
1517  } else if (!strcmp(param,"q")) {
1518  split_contact->q = value;
1519  }
1520  }
1521 
1522  if (last) {
1523  return 0;
1524  }
1525  contactheader = comma;
1526 
1527  split_contact = ast_calloc(1, sizeof(*split_contact));
1528  AST_LIST_INSERT_TAIL(contactlist, split_contact, list);
1529  }
1530  return last;
1531 }
char * user
struct uriparams params
char * headers
char * expires
#define NULL
Definition: resample.c:96
int value
Definition: syslog.c:37
char * hostport
struct sla_ringing_trunk * last
Definition: app_meetme.c:1092
char * pass
char * name
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:730
int parse_name_andor_addr(char *uri, const char *scheme, char **name, char **user, char **pass, char **hostport, struct uriparams *params, char **headers, char **residue)
Parse the ABNF structure name-andor-addr = name-addr / addr-spec into its components and return any t...
int get_comma(char *in, char **out)
Parse all contact header contacts.
#define AST_LIST_HEAD_SET_NOLOCK(head, entry)
Initializes a list head structure with a specified first entry.
Definition: linkedlists.h:387
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
char * q

◆ parse_name_andor_addr()

int parse_name_andor_addr ( char *  uri,
const char *  scheme,
char **  name,
char **  user,
char **  pass,
char **  domain,
struct uriparams params,
char **  headers,
char **  remander 
)

Parse the ABNF structure name-andor-addr = name-addr / addr-spec into its components and return any trailing message-header parameters.

Return values
0success
-1failure

Definition at line 1262 of file reqresp_parser.c.

References buf, get_calleridname(), get_in_brackets_full(), NULL, and parse_uri_full().

Referenced by AST_TEST_DEFINE(), and parse_contact_header().

1266 {
1267  char buf[1024];
1268  char **residue2 = residue;
1269  char *orig_uri = uri;
1270  int ret;
1271 
1272  buf[0] = '\0';
1273  if (name) {
1274  uri = (char *) get_calleridname(uri, buf, sizeof(buf));
1275  }
1276  ret = get_in_brackets_full(uri, &uri, residue);
1277  if (ret == 0) {
1278  /*
1279  * The uri is in brackets so do not treat unknown trailing uri
1280  * parameters as potential message header parameters.
1281  */
1282  if (residue && **residue) {
1283  /* step over the first semicolon as per parse_uri_full residue */
1284  *residue = *residue + 1;
1285  }
1286  residue2 = NULL;
1287  }
1288 
1289  if (name) {
1290  if (buf[0]) {
1291  /*
1292  * There is always room at orig_uri for the display-name because
1293  * at least one character has always been removed. A '"' or '<'
1294  * has been removed.
1295  */
1296  strcpy(orig_uri, buf);
1297  *name = orig_uri;
1298  } else {
1299  *name = "";
1300  }
1301  }
1302 
1303  return parse_uri_full(uri, scheme, user, pass, hostport, params, headers, residue2);
1304 }
static char pass[512]
char * headers
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
int get_in_brackets_full(char *tmp, char **out, char **residue)
Get text in brackets and any trailing residue.
#define NULL
Definition: resample.c:96
int parse_uri_full(char *uri, const char *scheme, char **user, char **pass, char **hostport, struct uriparams *params, char **headers, char **residue)
parses a URI in its components.
char * hostport
const char * get_calleridname(const char *input, char *output, size_t outputsize)
Get caller id name from SIP headers, copy into output buffer.
static const char name[]
Definition: cdr_mysql.c:74
structure to hold users read from users.conf

◆ parse_sip_options()

unsigned int parse_sip_options ( const char *  options,
char *  unsupported,
size_t  unsupported_len 
)

Parse supported header in incoming packet.

This function parses through the options parameters and builds a bit field representing all the SIP options in that field. When an item is found that is not supported, it is copied to the unsupported out buffer.

Parameters
optionlist
unsupportedout buffer (optional)
unsupportedout buffer length (optional)
Note
Because this function can be called multiple times, it will append whatever options are specified in options to unsupported. Callers of this function should make sure the unsupported buffer is clear before calling this function.

This function parses through the options parameters and builds a bit field representing all the SIP options in that field. When an item is found that is not supported, it is copied to the unsupported out buffer.

Parameters
optionslist
unsupportedout buffer (optional)
unsupported_lenout buffer length (optional)

Definition at line 1693 of file reqresp_parser.c.

References ARRAY_LEN, ast_copy_string(), ast_debug, ast_strdupa, ast_strip(), ast_strlen_zero, FALSE, cfsip_options::id, NULL, out, SIP_OPT_UNKNOWN, sip_options, SUPPORTED, text, and TRUE.

Referenced by AST_TEST_DEFINE(), handle_request_bye(), and handle_request_invite().

1694 {
1695  char *next, *sep;
1696  char *temp;
1697  int i, found, supported;
1698  unsigned int profile = 0;
1699 
1700  char *out = unsupported;
1701  size_t outlen = unsupported_len;
1702  char *cur_out = out;
1703 
1704  if (ast_strlen_zero(options) )
1705  return 0;
1706 
1707  temp = ast_strdupa(options);
1708 
1709  ast_debug(3, "Begin: parsing SIP \"Supported: %s\"\n", options);
1710  for (next = temp; next; next = sep) {
1711  found = FALSE;
1712  supported = FALSE;
1713  if ((sep = strchr(next, ',')) != NULL) {
1714  *sep++ = '\0';
1715  }
1716 
1717  /* trim leading and trailing whitespace */
1718  next = ast_strip(next);
1719 
1720  if (ast_strlen_zero(next)) {
1721  continue; /* if there is a blank argument in there just skip it */
1722  }
1723 
1724  ast_debug(3, "Found SIP option: -%s-\n", next);
1725  for (i = 0; i < ARRAY_LEN(sip_options); i++) {
1726  if (!strcasecmp(next, sip_options[i].text)) {
1727  profile |= sip_options[i].id;
1728  if (sip_options[i].supported == SUPPORTED) {
1729  supported = TRUE;
1730  }
1731  found = TRUE;
1732  ast_debug(3, "Matched SIP option: %s\n", next);
1733  break;
1734  }
1735  }
1736 
1737  /* If option is not supported, add to unsupported out buffer */
1738  if (!supported && out && outlen) {
1739  size_t copylen = strlen(next);
1740  size_t cur_outlen = strlen(out);
1741  /* Check to see if there is enough room to store this option.
1742  * Copy length is string length plus 2 for the ',' and '\0' */
1743  if ((cur_outlen + copylen + 2) < outlen) {
1744  /* if this isn't the first item, add the ',' */
1745  if (cur_outlen) {
1746  *cur_out = ',';
1747  cur_out++;
1748  cur_outlen++;
1749  }
1750  ast_copy_string(cur_out, next, (outlen - cur_outlen));
1751  cur_out += copylen;
1752  }
1753  }
1754 
1755  if (!found) {
1756  profile |= SIP_OPT_UNKNOWN;
1757  if (!strncasecmp(next, "x-", 2))
1758  ast_debug(3, "Found private SIP option, not supported: %s\n", next);
1759  else
1760  ast_debug(3, "Found no match for SIP option: %s (Please file bug report!)\n", next);
1761  }
1762  }
1763 
1764  return profile;
1765 }
#define FALSE
Definition: app_minivm.c:521
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
#define SIP_OPT_UNKNOWN
Definition: sip.h:167
char * text
Definition: app_queue.c:1508
#define NULL
Definition: resample.c:96
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:219
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
int id
Definition: sip.h:1828
static const struct cfsip_options sip_options[]
#define SUPPORTED
Definition: sip.h:142
FILE * out
Definition: utils/frame.c:33
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
#define TRUE
Definition: app_minivm.c:518
static struct test_options options

◆ parse_uri()

int parse_uri ( char *  uri,
const char *  scheme,
char **  ret_name,
char **  pass,
char **  hostport,
char **  transport 
)

parses a URI in its components.

Note
  • Multiple scheme's can be specified ',' delimited. ex: "sip:,sips:"
  • If a component is not requested, do not split around it. This means that if we don't have domain, we cannot split name:pass.
  • It is safe to call with ret_name, pass, hostport pointing all to the same place.
  • If no secret parameter is provided, ret_name will return with both parts, user:secret.
  • If the URI contains a port number, hostport will return with both parts, host:port.
  • This function overwrites the URI string.
Return values
0on success
-1on error.
* general form we are expecting is sip:user:password;user-parameters@host:port;uri-parameters?headers
* 

Definition at line 517 of file reqresp_parser.c.

References NULL, parse_uri_full(), and uriparams::transport.

Referenced by AST_TEST_DEFINE(), check_peer_ok(), get_name_and_number(), parse_uri_legacy_check(), and sip_msg_send().

518  {
519  int ret;
520  char *headers;
521  struct uriparams params;
522 
523  headers = NULL;
524  ret = parse_uri_full(uri, scheme, user, pass, hostport, &params, &headers, NULL);
525  if (transport) {
526  *transport=params.transport;
527  }
528  return ret;
529 }
static char pass[512]
char * headers
#define NULL
Definition: resample.c:96
int parse_uri_full(char *uri, const char *scheme, char **user, char **pass, char **hostport, struct uriparams *params, char **headers, char **residue)
parses a URI in its components.
char * transport
uri parameters
structure to hold users read from users.conf

◆ parse_uri_full()

int parse_uri_full ( char *  uri,
const char *  scheme,
char **  user,
char **  pass,
char **  hostport,
struct uriparams params,
char **  headers,
char **  residue 
)

parses a URI in to all of its components and any trailing residue

Return values
0on success
-1on error.

parses a URI in to all of its components and any trailing residue

Definition at line 37 of file reqresp_parser.c.

References ast_debug, ast_strdupa, ast_strlen_zero, c, error(), uriparams::lr, uriparams::maddr, uriparams::method, NULL, strsep(), uriparams::transport, uriparams::ttl, uriparams::user, and value.

Referenced by AST_TEST_DEFINE(), parse_name_andor_addr(), and parse_uri().

40 {
41  char *userinfo = NULL;
42  char *parameters = NULL;
43  char *endparams = NULL;
44  char *c = NULL;
45  int error = 0;
46  int teluri_scheme = 0;
47 
48  /*
49  * Initialize requested strings - some functions don't care if parse_uri fails
50  * and will attempt to use string pointers passed into parse_uri even after a
51  * parse_uri failure
52  */
53  if (user) {
54  *user = "";
55  }
56  if (pass) {
57  *pass = "";
58  }
59  if (hostport) {
60  *hostport = "";
61  }
62  if (headers) {
63  *headers = "";
64  }
65  if (residue) {
66  *residue = "";
67  }
68 
69  /* check for valid input */
70  if (ast_strlen_zero(uri)) {
71  return -1;
72  }
73 
74  if (scheme) {
75  int l;
76  char *scheme2 = ast_strdupa(scheme);
77  char *cur = strsep(&scheme2, ",");
78  for (; !ast_strlen_zero(cur); cur = strsep(&scheme2, ",")) {
79  l = strlen(cur);
80  if (!strncasecmp(uri, cur, l)) {
81  teluri_scheme = !strncasecmp(uri, "tel:", 4); /* TEL URI */
82  uri += l;
83  break;
84  }
85  }
86  if (ast_strlen_zero(cur)) {
87  ast_debug(1, "No supported scheme found in '%s' using the scheme[s] %s\n", uri, scheme);
88  error = -1;
89  }
90  }
91 
92  if (!hostport) {
93  /* if we don't want to split around hostport, keep everything as a
94  * userinfo - cos thats how old parse_uri operated*/
95  userinfo = uri;
96  } else if (teluri_scheme) {
97  /*
98  * tel: TEL URI INVITE RFC 3966 patch
99  * See http://www.ietf.org/rfc/rfc3966.txt
100  *
101  * Once the full RFC 3966 parsing is implemented,
102  * the ext= or isub= parameters would be extracted from userinfo.
103  * When this kind of subaddressing would be implemented, the userinfo must be further parsed.
104  * Those parameters would be used for ISDN or PSTN local extensions.
105  *
106  * Current restrictions:
107  * We currently consider the ";isub=" or the ";ext=" as part of the userinfo (unparsed).
108  */
109 
110  if ((c = strstr(uri, ";phone-context="))) {
111  /*
112  * Local number with context or domain.
113  * ext= or isub= TEL URI parameters should be upfront.
114  * All other parameters should come after the ";phone-context=" parameter.
115  * If other parameters would occur before ";phone-context=" they will be ignored.
116  */
117 
118  *c = '\0';
119  userinfo = uri;
120  uri = c + 15;
121  *hostport = uri;
122  } else if ('+' == uri[0]) {
123  /* Global number without context or domain; possibly followed by RFC 3966 and optional other parameters. */
124 
125  userinfo = uri;
126  *hostport = uri;
127  } else {
128  ast_debug(1, "No RFC 3966 global number or context found in '%s'; returning local number anyway\n", uri);
129  userinfo = uri; /* Return local number anyway */
130  error = -1;
131  }
132  } else {
133  char *dom = "";
134  if ((c = strchr(uri, '@'))) {
135  *c++ = '\0';
136  dom = c;
137  userinfo = uri;
138  uri = c; /* userinfo can contain ? and ; chars so step forward before looking for params and headers */
139  } else {
140  /* domain-only URI, according to the SIP RFC. */
141  dom = uri;
142  userinfo = "";
143  }
144 
145  *hostport = dom;
146  }
147 
148  if (pass && (c = strchr(userinfo, ':'))) { /* user:password */
149  *c++ = '\0';
150  *pass = c;
151  } else if (pass) {
152  *pass = "";
153  }
154 
155  if (user) {
156  *user = userinfo;
157  }
158 
159  parameters = uri;
160  /* strip [?headers] from end of uri - even if no header pointer exists*/
161  if ((c = strrchr(uri, '?'))) {
162  *c++ = '\0';
163  uri = c;
164  if (headers) {
165  *headers = c;
166  }
167  if ((c = strrchr(uri, ';'))) {
168  *c++ = '\0';
169  } else {
170  c = strrchr(uri, '\0');
171  }
172  uri = c; /* residue */
173 
174 
175  } else if (headers) {
176  *headers = "";
177  }
178 
179  /* parse parameters */
180  endparams = strchr(parameters,'\0');
181  if ((c = strchr(parameters, ';'))) {
182  *c++ = '\0';
183  parameters = c;
184  } else {
185  parameters = endparams;
186  }
187 
188  if (params) {
189  char *rem = parameters; /* unparsed or unrecognised remainder */
190  char *label;
191  char *value;
192  int lr = 0;
193 
194  params->transport = "";
195  params->user = "";
196  params->method = "";
197  params->ttl = "";
198  params->maddr = "";
199  params->lr = 0;
200 
201  rem = parameters;
202 
203  while ((value = strchr(parameters, '=')) || (lr = !strncmp(parameters, "lr", 2))) {
204  /* The while condition will not continue evaluation to set lr if it matches "lr=" */
205  if (lr) {
206  value = parameters;
207  } else {
208  *value++ = '\0';
209  }
210  label = parameters;
211  if ((c = strchr(value, ';'))) {
212  *c++ = '\0';
213  parameters = c;
214  } else {
215  parameters = endparams;
216  }
217 
218  if (!strcmp(label, "transport")) {
219  params->transport = value;
220  rem = parameters;
221  } else if (!strcmp(label, "user")) {
222  params->user = value;
223  rem = parameters;
224  } else if (!strcmp(label, "method")) {
225  params->method = value;
226  rem = parameters;
227  } else if (!strcmp(label, "ttl")) {
228  params->ttl = value;
229  rem = parameters;
230  } else if (!strcmp(label, "maddr")) {
231  params->maddr = value;
232  rem = parameters;
233  /* Treat "lr", "lr=yes", "lr=on", "lr=1", "lr=almostanything" as lr enabled and "", "lr=no", "lr=off", "lr=0", "lr=" and "lranything" as lr disabled */
234  } else if ((!strcmp(label, "lr") && strcmp(value, "no") && strcmp(value, "off") && strcmp(value, "0") && strcmp(value, "")) || ((lr) && strcmp(value, "lr"))) {
235  params->lr = 1;
236  rem = parameters;
237  } else {
238  value--;
239  *value = '=';
240  if (c) {
241  c--;
242  *c = ';';
243  }
244  }
245  }
246  if (rem > uri) { /* no headers */
247  uri = rem;
248  }
249 
250  }
251 
252  if (residue) {
253  *residue = uri;
254  }
255 
256  return error;
257 }
static char pass[512]
char * method
static struct test_val c
#define NULL
Definition: resample.c:96
int value
Definition: syslog.c:37
#define ast_strlen_zero(foo)
Definition: strings.h:52
char * transport
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
char * user
char * maddr
char * ttl
structure to hold users read from users.conf
char * strsep(char **str, const char *delims)
int error(const char *format,...)
Definition: utils/frame.c:999

◆ parse_via()

struct sip_via* parse_via ( const char *  header)

Parse a Via header.

This function parses the Via header and processes it according to section 18.2 of RFC 3261 and RFC 3581. Since we don't have a transport layer, we only care about the maddr and ttl parms. The received and rport params are not parsed.

Note
This function fails to parse some odd combinations of SWS in parameter lists.
VIA syntax. RFC 3261 section 25.1
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

Definition at line 2389 of file reqresp_parser.c.

References ast_calloc, ast_log, ast_skip_blanks(), ast_strdup, ast_strlen_zero, sip_via::branch, c, free_via(), LOG_ERROR, sip_via::maddr, NULL, sip_via::port, sip_via::protocol, sip_via::sent_by, strsep(), sip_via::ttl, and sip_via::via.

Referenced by __find_call(), __sip_alloc(), AST_TEST_DEFINE(), and process_via().

2390 {
2391  struct sip_via *v = ast_calloc(1, sizeof(*v));
2392  char *via, *parm;
2393 
2394  if (!v) {
2395  return NULL;
2396  }
2397 
2398  v->via = ast_strdup(header);
2399  v->ttl = 1;
2400 
2401  via = v->via;
2402 
2403  if (ast_strlen_zero(via)) {
2404  ast_log(LOG_ERROR, "received request without a Via header\n");
2405  free_via(v);
2406  return NULL;
2407  }
2408 
2409  /* seperate the first via-parm */
2410  via = strsep(&via, ",");
2411 
2412  /* chop off sent-protocol */
2413  v->protocol = strsep(&via, " \t\r\n");
2414  if (ast_strlen_zero(v->protocol)) {
2415  ast_log(LOG_ERROR, "missing sent-protocol in Via header\n");
2416  free_via(v);
2417  return NULL;
2418  }
2420 
2421  if (via) {
2422  via = ast_skip_blanks(via);
2423  }
2424 
2425  /* chop off sent-by */
2426  v->sent_by = strsep(&via, "; \t\r\n");
2427  if (ast_strlen_zero(v->sent_by)) {
2428  ast_log(LOG_ERROR, "missing sent-by in Via header\n");
2429  free_via(v);
2430  return NULL;
2431  }
2432  v->sent_by = ast_skip_blanks(v->sent_by);
2433 
2434  /* store the port, we have to handle ipv6 addresses containing ':'
2435  * characters gracefully */
2436  if (((parm = strchr(v->sent_by, ']')) && *(++parm) == ':') || (!(parm = strchr(v->sent_by, ']')) && (parm = strchr(v->sent_by, ':')))) {
2437  char *endptr;
2438 
2439  v->port = strtol(++parm, &endptr, 10);
2440  }
2441 
2442  /* evaluate any via-parms */
2443  while ((parm = strsep(&via, "; \t\r\n"))) {
2444  char *c;
2445  if ((c = strstr(parm, "maddr="))) {
2446  v->maddr = ast_skip_blanks(c + sizeof("maddr=") - 1);
2447  } else if ((c = strstr(parm, "branch="))) {
2448  v->branch = ast_skip_blanks(c + sizeof("branch=") - 1);
2449  } else if ((c = strstr(parm, "ttl="))) {
2450  char *endptr;
2451  c = ast_skip_blanks(c + sizeof("ttl=") - 1);
2452  v->ttl = strtol(c, &endptr, 10);
2453 
2454  /* make sure we got a valid ttl value */
2455  if (c == endptr) {
2456  v->ttl = 1;
2457  }
2458  }
2459  }
2460 
2461  return v;
2462 }
const char * maddr
Definition: sip.h:879
unsigned char ttl
Definition: sip.h:881
static struct test_val c
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
#define NULL
Definition: resample.c:96
#define ast_strlen_zero(foo)
Definition: strings.h:52
Structure to store Via information.
Definition: sip.h:874
#define ast_log
Definition: astobj2.c:42
const char * branch
Definition: sip.h:878
void free_via(struct sip_via *v)
char * via
Definition: sip.h:875
#define LOG_ERROR
Definition: logger.h:285
char * ast_skip_blanks(const char *str)
Gets a pointer to the first non-whitespace character in a string.
Definition: strings.h:157
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
const char * sent_by
Definition: sip.h:877
unsigned int port
Definition: sip.h:880
char * strsep(char **str, const char *delims)
const char * protocol
Definition: sip.h:876

◆ sip_reqresp_parser_exit()

void sip_reqresp_parser_exit ( void  )

Free resources used by request and response parser.

Definition at line 2682 of file reqresp_parser.c.

References c_locale, and NULL.

Referenced by unload_module().

2683 {
2684 #ifdef HAVE_XLOCALE_H
2685  if (c_locale) {
2686  freelocale(c_locale);
2687  c_locale = NULL;
2688  }
2689 #endif
2690 }
#define NULL
Definition: resample.c:96
locale_t c_locale

◆ sip_reqresp_parser_init()

int sip_reqresp_parser_init ( void  )

initialize request and response parser data

Return values
0Success
-1Failure

Definition at line 2671 of file reqresp_parser.c.

References c_locale, and NULL.

Referenced by load_module().

2672 {
2673 #ifdef HAVE_XLOCALE_H
2674  c_locale = newlocale(LC_CTYPE_MASK, "C", NULL);
2675  if (!c_locale) {
2676  return -1;
2677  }
2678 #endif
2679  return 0;
2680 }
#define NULL
Definition: resample.c:96
locale_t c_locale

◆ sip_request_parser_register_tests()

void sip_request_parser_register_tests ( void  )

register request parsing tests

Definition at line 2644 of file reqresp_parser.c.

References AST_TEST_REGISTER.

Referenced by sip_register_tests().

2645 {
2646  AST_TEST_REGISTER(get_calleridname_test);
2647  AST_TEST_REGISTER(sip_parse_uri_test);
2648  AST_TEST_REGISTER(get_in_brackets_test);
2649  AST_TEST_REGISTER(get_name_and_number_test);
2650  AST_TEST_REGISTER(sip_parse_uri_full_test);
2651  AST_TEST_REGISTER(parse_name_andor_addr_test);
2652  AST_TEST_REGISTER(parse_contact_header_test);
2653  AST_TEST_REGISTER(sip_parse_options_test);
2654  AST_TEST_REGISTER(sip_uri_cmp_test);
2655  AST_TEST_REGISTER(parse_via_test);
2656 }
#define AST_TEST_REGISTER(cb)
Definition: test.h:127

◆ sip_request_parser_unregister_tests()

void sip_request_parser_unregister_tests ( void  )

unregister request parsing tests

Definition at line 2657 of file reqresp_parser.c.

References AST_TEST_UNREGISTER.

Referenced by sip_unregister_tests().

2658 {
2659  AST_TEST_UNREGISTER(sip_parse_uri_test);
2660  AST_TEST_UNREGISTER(get_calleridname_test);
2661  AST_TEST_UNREGISTER(get_in_brackets_test);
2662  AST_TEST_UNREGISTER(get_name_and_number_test);
2663  AST_TEST_UNREGISTER(sip_parse_uri_full_test);
2664  AST_TEST_UNREGISTER(parse_name_andor_addr_test);
2665  AST_TEST_UNREGISTER(parse_contact_header_test);
2666  AST_TEST_UNREGISTER(sip_parse_options_test);
2667  AST_TEST_UNREGISTER(sip_uri_cmp_test);
2668  AST_TEST_UNREGISTER(parse_via_test);
2669 }
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128

◆ sip_uri_cmp()

int sip_uri_cmp ( const char *  input1,
const char *  input2 
)

Compare two URIs as described in RFC 3261 Section 19.1.4.

Parameters
input1First URI
input2Second URI
Return values
0URIs match
nonzeroURIs do not match or one or both is malformed

Definition at line 2153 of file reqresp_parser.c.

References ast_strdupa, ast_strlen_zero, ast_uri_decode(), ast_uri_sip_user, S_OR, sip_uri_domain_cmp(), sip_uri_headers_cmp(), sip_uri_params_cmp(), and strsep().

Referenced by AST_TEST_DEFINE(), find_by_notify_uri_helper(), find_by_subscribe_uri_helper(), handle_request_invite(), and match_req_to_dialog().

2154 {
2155  char *uri1;
2156  char *uri2;
2157  char *uri_scheme1;
2158  char *uri_scheme2;
2159  char *host1;
2160  char *host2;
2161  char *params1;
2162  char *params2;
2163  char *headers1;
2164  char *headers2;
2165 
2166  /* XXX It would be really nice if we could just use parse_uri_full() here
2167  * to separate the components of the URI, but unfortunately it is written
2168  * in a way that can cause URI parameters to be discarded.
2169  */
2170 
2171  if (!input1 || !input2) {
2172  return 1;
2173  }
2174 
2175  uri1 = ast_strdupa(input1);
2176  uri2 = ast_strdupa(input2);
2177 
2180 
2181  uri_scheme1 = strsep(&uri1, ":");
2182  uri_scheme2 = strsep(&uri2, ":");
2183 
2184  if (strcmp(uri_scheme1, uri_scheme2)) {
2185  return 1;
2186  }
2187 
2188  /* This function is tailored for SIP and SIPS URIs. There's no
2189  * need to check uri_scheme2 since we have determined uri_scheme1
2190  * and uri_scheme2 are equivalent already.
2191  */
2192  if (strcmp(uri_scheme1, "sip") && strcmp(uri_scheme1, "sips")) {
2193  return 1;
2194  }
2195 
2196  if (ast_strlen_zero(uri1) || ast_strlen_zero(uri2)) {
2197  return 1;
2198  }
2199 
2200  if ((host1 = strchr(uri1, '@'))) {
2201  *host1++ = '\0';
2202  }
2203  if ((host2 = strchr(uri2, '@'))) {
2204  *host2++ = '\0';
2205  }
2206 
2207  /* Check for mismatched username and passwords. This is the
2208  * only case-sensitive comparison of a SIP URI
2209  */
2210  if ((host1 && !host2) ||
2211  (host2 && !host1) ||
2212  (host1 && host2 && strcmp(uri1, uri2))) {
2213  return 1;
2214  }
2215 
2216  if (!host1) {
2217  host1 = uri1;
2218  }
2219  if (!host2) {
2220  host2 = uri2;
2221  }
2222 
2223  /* Strip off the parameters and headers so we can compare
2224  * host and port
2225  */
2226 
2227  if ((params1 = strchr(host1, ';'))) {
2228  *params1++ = '\0';
2229  }
2230  if ((params2 = strchr(host2, ';'))) {
2231  *params2++ = '\0';
2232  }
2233 
2234  /* Headers come after parameters, but there may be headers without
2235  * parameters, thus the S_OR
2236  */
2237  if ((headers1 = strchr(S_OR(params1, host1), '?'))) {
2238  *headers1++ = '\0';
2239  }
2240  if ((headers2 = strchr(S_OR(params2, host2), '?'))) {
2241  *headers2++ = '\0';
2242  }
2243 
2244  if (sip_uri_domain_cmp(host1, host2)) {
2245  return 1;
2246  }
2247 
2248  /* Headers have easier rules to follow, so do those first */
2249  if (sip_uri_headers_cmp(headers1, headers2)) {
2250  return 1;
2251  }
2252 
2253  /* And now the parameters. Ugh */
2254  return sip_uri_params_cmp(params1, params2);
2255 }
void ast_uri_decode(char *s, struct ast_flags spec)
Decode URI, URN, URL (overwrite string)
Definition: main/utils.c:616
static int sip_uri_domain_cmp(const char *host1, const char *host2)
Compare domain sections of SIP URIs.
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
static int sip_uri_headers_cmp(const char *input1, const char *input2)
helper routine for sip_uri_cmp to compare URI headers
char * strsep(char **str, const char *delims)
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
const struct ast_flags ast_uri_sip_user
Definition: main/utils.c:575
static int sip_uri_params_cmp(const char *input1, const char *input2)
helper routine for sip_uri_cmp to compare URI parameters