Merge "res_pjsip: Add fax_detect_timeout endpoint option."
[asterisk/asterisk.git] / channels / sip / reqresp_parser.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2010, Digium, Inc.
5  *
6  * See http://www.asterisk.org for more information about
7  * the Asterisk project. Please do not directly contact
8  * any of the maintainers of this project for assistance;
9  * the project provides a web site, mailing lists and IRC
10  * channels for your use.
11  *
12  * This program is free software, distributed under the terms of
13  * the GNU General Public License Version 2. See the LICENSE file
14  * at the top of the source tree.
15  */
16
17 /*!
18  * \file
19  * \brief sip request parsing functions and unit tests
20  */
21
22 /*** MODULEINFO
23         <support_level>extended</support_level>
24  ***/
25
26 #include "asterisk.h"
27
28 ASTERISK_REGISTER_FILE()
29
30 #include "include/sip.h"
31 #include "include/sip_utils.h"
32 #include "include/reqresp_parser.h"
33
34 #ifdef HAVE_XLOCALE_H
35 locale_t c_locale;
36 #endif
37
38 /*! \brief * parses a URI in its components.*/
39 int parse_uri_full(char *uri, const char *scheme, char **user, char **pass,
40                    char **hostport, struct uriparams *params, char **headers,
41                    char **residue)
42 {
43         char *userinfo = NULL;
44         char *parameters = NULL;
45         char *endparams = NULL;
46         char *c = NULL;
47         int error = 0;
48         int teluri_scheme = 0;
49
50         /*
51          * Initialize requested strings - some functions don't care if parse_uri fails
52          * and will attempt to use string pointers passed into parse_uri even after a
53          * parse_uri failure
54          */
55         if (user) {
56                 *user = "";
57         }
58         if (pass) {
59                 *pass = "";
60         }
61         if (hostport) {
62                 *hostport = "";
63         }
64         if (headers) {
65                 *headers = "";
66         }
67         if (residue) {
68                 *residue = "";
69         }
70
71         /* check for valid input */
72         if (ast_strlen_zero(uri)) {
73                 return -1;
74         }
75
76         if (scheme) {
77                 int l;
78                 char *scheme2 = ast_strdupa(scheme);
79                 char *cur = strsep(&scheme2, ",");
80                 for (; !ast_strlen_zero(cur); cur = strsep(&scheme2, ",")) {
81                         l = strlen(cur);
82                         if (!strncasecmp(uri, cur, l)) {
83                                 teluri_scheme = !strncasecmp(uri, "tel:", 4);   /* TEL URI */
84                                 uri += l;
85                                 break;
86                         }
87                 }
88                 if (ast_strlen_zero(cur)) {
89                         ast_debug(1, "No supported scheme found in '%s' using the scheme[s] %s\n", uri, scheme);
90                         error = -1;
91                 }
92         }
93
94         if (!hostport) {
95                 /* if we don't want to split around hostport, keep everything as a
96                  * userinfo - cos thats how old parse_uri operated*/
97                 userinfo = uri;
98         } else if (teluri_scheme) {
99                 /*
100                  * tel: TEL URI INVITE RFC 3966 patch
101                  * See http://www.ietf.org/rfc/rfc3966.txt
102                  *
103                  * Once the full RFC 3966 parsing is implemented,
104                  * the ext= or isub= parameters would be extracted from userinfo.
105                  * When this kind of subaddressing would be implemented, the userinfo must be further parsed.
106                  * Those parameters would be used for ISDN or PSTN local extensions.
107                  *
108                  * Current restrictions:
109                  * We currently consider the ";isub=" or the ";ext=" as part of the userinfo (unparsed).
110                  */
111
112                 if ((c = strstr(uri, ";phone-context="))) {
113                         /*
114                          * Local number with context or domain.
115                          * ext= or isub= TEL URI parameters should be upfront.
116                          * All other parameters should come after the ";phone-context=" parameter.
117                          * If other parameters would occur before ";phone-context=" they will be ignored.
118                          */
119
120                         *c = '\0';
121                         userinfo = uri;
122                         uri = c + 15;
123                         *hostport = uri;
124                 } else if ('+' == uri[0]) {
125                         /* Global number without context or domain; possibly followed by RFC 3966 and optional other parameters. */
126
127                         userinfo = uri;
128                         *hostport = uri;
129                 } else {
130                         ast_debug(1, "No RFC 3966 global number or context found in '%s'; returning local number anyway\n", uri);
131                         userinfo = uri;         /* Return local number anyway */
132                         error = -1;
133                 }
134         } else {
135                 char *dom = "";
136                 if ((c = strchr(uri, '@'))) {
137                         *c++ = '\0';
138                         dom = c;
139                         userinfo = uri;
140                         uri = c; /* userinfo can contain ? and ; chars so step forward before looking for params and headers */
141                 } else {
142                         /* domain-only URI, according to the SIP RFC. */
143                         dom = uri;
144                         userinfo = "";
145                 }
146
147                 *hostport = dom;
148         }
149
150         if (pass && (c = strchr(userinfo, ':'))) {        /* user:password */
151                 *c++ = '\0';
152                 *pass = c;
153         } else if (pass) {
154                 *pass = "";
155         }
156
157         if (user) {
158                 *user = userinfo;
159         }
160
161         parameters = uri;
162         /* strip [?headers] from end of uri  - even if no header pointer exists*/
163         if ((c = strrchr(uri, '?'))) {
164                 *c++ = '\0';
165                 uri = c;
166                 if (headers) {
167                         *headers = c;
168                 }
169                 if ((c = strrchr(uri, ';'))) {
170                         *c++ = '\0';
171                 } else {
172                         c = strrchr(uri, '\0');
173                 }
174                 uri = c; /* residue */
175
176
177         } else if (headers) {
178                 *headers = "";
179         }
180
181         /* parse parameters */
182         endparams = strchr(parameters,'\0');
183         if ((c = strchr(parameters, ';'))) {
184                 *c++ = '\0';
185                 parameters = c;
186         } else {
187                 parameters = endparams;
188         }
189
190         if (params) {
191                 char *rem = parameters; /* unparsed or unrecognised remainder */
192                 char *label;
193                 char *value;
194                 int lr = 0;
195
196                 params->transport = "";
197                 params->user = "";
198                 params->method = "";
199                 params->ttl = "";
200                 params->maddr = "";
201                 params->lr = 0;
202
203                 rem = parameters;
204
205                 while ((value = strchr(parameters, '=')) || (lr = !strncmp(parameters, "lr", 2))) {
206                         /* The while condition will not continue evaluation to set lr if it matches "lr=" */
207                         if (lr) {
208                                 value = parameters;
209                         } else {
210                                 *value++ = '\0';
211                         }
212                         label = parameters;
213                         if ((c = strchr(value, ';'))) {
214                                 *c++ = '\0';
215                                 parameters = c;
216                         } else {
217                                 parameters = endparams;
218                         }
219
220                         if (!strcmp(label, "transport")) {
221                                 params->transport = value;
222                                 rem = parameters;
223                         } else if (!strcmp(label, "user")) {
224                                 params->user = value;
225                                 rem = parameters;
226                         } else if (!strcmp(label, "method")) {
227                                 params->method = value;
228                                 rem = parameters;
229                         } else if (!strcmp(label, "ttl")) {
230                                 params->ttl = value;
231                                 rem = parameters;
232                         } else if (!strcmp(label, "maddr")) {
233                                 params->maddr = value;
234                                 rem = parameters;
235                         /* 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 */
236                         } else if ((!strcmp(label, "lr") && strcmp(value, "no") && strcmp(value, "off") && strcmp(value, "0") && strcmp(value, "")) || ((lr) && strcmp(value, "lr"))) {
237                                 params->lr = 1;
238                                 rem = parameters;
239                         } else {
240                                 value--;
241                                 *value = '=';
242                                 if (c) {
243                                         c--;
244                                         *c = ';';
245                                 }
246                         }
247                 }
248                 if (rem > uri) { /* no headers */
249                         uri = rem;
250                 }
251
252         }
253
254         if (residue) {
255                 *residue = uri;
256         }
257
258         return error;
259 }
260
261 #ifdef TEST_FRAMEWORK
262 AST_TEST_DEFINE(sip_parse_uri_full_test)
263 {
264         int res = AST_TEST_PASS;
265         char uri[1024];
266         char *user, *pass, *hostport, *headers, *residue;
267         struct uriparams params;
268
269         struct testdata {
270                 char *desc;
271                 char *uri;
272                 char *user;
273                 char *pass;
274                 char *hostport;
275                 char *headers;
276                 char *residue;
277                 struct uriparams params;
278                 AST_LIST_ENTRY(testdata) list;
279         };
280
281
282         struct testdata *testdataptr;
283
284         static AST_LIST_HEAD_NOLOCK(testdataliststruct, testdata) testdatalist;
285
286         struct testdata td1 = {
287                 .desc = "no headers",
288                 .uri = "sip:user:secret@host:5060;param=discard;transport=tcp;param2=residue",
289                 .user = "user",
290                 .pass = "secret",
291                 .hostport = "host:5060",
292                 .headers = "",
293                 .residue = "param2=residue",
294                 .params.transport = "tcp",
295                 .params.lr = 0,
296                 .params.user = ""
297         };
298
299         struct testdata td2 = {
300                 .desc = "with headers",
301                 .uri = "sip:user:secret@host:5060;param=discard;transport=tcp;param2=discard2?header=blah&header2=blah2;param3=residue",
302                 .user = "user",
303                 .pass = "secret",
304                 .hostport = "host:5060",
305                 .headers = "header=blah&header2=blah2",
306                 .residue = "param3=residue",
307                 .params.transport = "tcp",
308                 .params.lr = 0,
309                 .params.user = ""
310         };
311
312         struct testdata td3 = {
313                 .desc = "difficult user",
314                 .uri = "sip:-_.!~*'()&=+$,;?/:secret@host:5060;transport=tcp",
315                 .user = "-_.!~*'()&=+$,;?/",
316                 .pass = "secret",
317                 .hostport = "host:5060",
318                 .headers = "",
319                 .residue = "",
320                 .params.transport = "tcp",
321                 .params.lr = 0,
322                 .params.user = ""
323         };
324
325         struct testdata td4 = {
326                 .desc = "difficult pass",
327                 .uri = "sip:user:-_.!~*'()&=+$,@host:5060;transport=tcp",
328                 .user = "user",
329                 .pass = "-_.!~*'()&=+$,",
330                 .hostport = "host:5060",
331                 .headers = "",
332                 .residue = "",
333                 .params.transport = "tcp",
334                 .params.lr = 0,
335                 .params.user = ""
336         };
337
338         struct testdata td5 = {
339                 .desc = "difficult host",
340                 .uri = "sip:user:secret@1-1.a-1.:5060;transport=tcp",
341                 .user = "user",
342                 .pass = "secret",
343                 .hostport = "1-1.a-1.:5060",
344                 .headers = "",
345                 .residue = "",
346                 .params.transport = "tcp",
347                 .params.lr = 0,
348                 .params.user = ""
349         };
350
351         struct testdata td6 = {
352                 .desc = "difficult params near transport",
353                 .uri = "sip:user:secret@host:5060;-_.!~*'()[]/:&+$=-_.!~*'()[]/:&+$;transport=tcp",
354                 .user = "user",
355                 .pass = "secret",
356                 .hostport = "host:5060",
357                 .headers = "",
358                 .residue = "",
359                 .params.transport = "tcp",
360                 .params.lr = 0,
361                 .params.user = ""
362         };
363
364         struct testdata td7 = {
365                 .desc = "difficult params near headers",
366                 .uri = "sip:user:secret@host:5060;-_.!~*'()[]/:&+$=-_.!~*'()[]/:&+$?header=blah&header2=blah2;-_.!~*'()[]/:&+$=residue",
367                 .user = "user",
368                 .pass = "secret",
369                 .hostport = "host:5060",
370                 .headers = "header=blah&header2=blah2",
371                 .residue = "-_.!~*'()[]/:&+$=residue",
372                 .params.transport = "",
373                 .params.lr = 0,
374                 .params.user = ""
375         };
376
377         struct testdata td8 = {
378                 .desc = "lr parameter",
379                 .uri = "sip:user:secret@host:5060;param=discard;lr?header=blah",
380                 .user = "user",
381                 .pass = "secret",
382                 .hostport = "host:5060",
383                 .headers = "header=blah",
384                 .residue = "",
385                 .params.transport = "",
386                 .params.lr = 1,
387                 .params.user = ""
388         };
389
390         struct testdata td9 = {
391                 .desc = "alternative lr parameter",
392                 .uri = "sip:user:secret@host:5060;param=discard;lr=yes?header=blah",
393                 .user = "user",
394                 .pass = "secret",
395                 .hostport = "host:5060",
396                 .headers = "header=blah",
397                 .residue = "",
398                 .params.transport = "",
399                 .params.lr = 1,
400                 .params.user = ""
401         };
402
403         struct testdata td10 = {
404                 .desc = "no lr parameter",
405                 .uri = "sip:user:secret@host:5060;paramlr=lr;lr=no;lr=off;lr=0;lr=;=lr;lrextra;lrparam2=lr?header=blah",
406                 .user = "user",
407                 .pass = "secret",
408                 .hostport = "host:5060",
409                 .headers = "header=blah",
410                 .residue = "",
411                 .params.transport = "",
412                 .params.lr = 0,
413                 .params.user = ""
414         };
415
416         /* RFC 3966 TEL URI INVITE */
417         struct testdata td11 = {
418                 .desc = "tel local number",
419                 .uri = "tel:0987654321;phone-context=+32987654321",
420                 .user = "0987654321",
421                 .pass = "",
422                 .hostport = "+32987654321",
423                 .headers = "",
424                 .residue = "",
425                 .params.transport = "",
426                 .params.lr = 0,
427                 .params.user = ""
428         };
429
430         struct testdata td12 = {
431                 .desc = "tel global number",
432                 .uri = "tel:+32987654321",
433                 .user = "+32987654321",
434                 .pass = "",
435                 .hostport = "+32987654321",
436                 .headers = "",
437                 .residue = "",
438                 .params.transport = "",
439                 .params.lr = 0,
440                 .params.user = ""
441         };
442
443         /*
444          * Once the full RFC 3966 parsing is implemented,
445          * only the ext= or isub= parameters would be extracted from .user
446          * Then the ;param=discard would be ignored,
447          * and the .user would only contain "0987654321"
448          */
449         struct testdata td13 = {
450                 .desc = "tel local number",
451                 .uri = "tel:0987654321;ext=1234;param=discard;phone-context=+32987654321;transport=udp;param2=discard2?header=blah&header2=blah2;param3=residue",
452                 .user = "0987654321;ext=1234;param=discard",
453                 .pass = "",
454                 .hostport = "+32987654321",
455                 .headers = "header=blah&header2=blah2",
456                 .residue = "param3=residue",
457                 .params.transport = "udp",
458                 .params.lr = 0,
459                 .params.user = ""
460         };
461
462         AST_LIST_HEAD_SET_NOLOCK(&testdatalist, &td1);
463         AST_LIST_INSERT_TAIL(&testdatalist, &td2, list);
464         AST_LIST_INSERT_TAIL(&testdatalist, &td3, list);
465         AST_LIST_INSERT_TAIL(&testdatalist, &td4, list);
466         AST_LIST_INSERT_TAIL(&testdatalist, &td5, list);
467         AST_LIST_INSERT_TAIL(&testdatalist, &td6, list);
468         AST_LIST_INSERT_TAIL(&testdatalist, &td7, list);
469         AST_LIST_INSERT_TAIL(&testdatalist, &td8, list);
470         AST_LIST_INSERT_TAIL(&testdatalist, &td9, list);
471         AST_LIST_INSERT_TAIL(&testdatalist, &td10, list);
472         AST_LIST_INSERT_TAIL(&testdatalist, &td11, list);
473         AST_LIST_INSERT_TAIL(&testdatalist, &td12, list);
474         AST_LIST_INSERT_TAIL(&testdatalist, &td13, list);
475
476         switch (cmd) {
477         case TEST_INIT:
478                 info->name = "sip_uri_full_parse_test";
479                 info->category = "/channels/chan_sip/";
480                 info->summary = "tests sip full uri parsing";
481                 info->description =
482                         "Tests full parsing of various URIs "
483                         "Verifies output matches expected behavior.";
484                 return AST_TEST_NOT_RUN;
485         case TEST_EXECUTE:
486                 break;
487         }
488
489         AST_LIST_TRAVERSE(&testdatalist, testdataptr, list) {
490                 user = pass = hostport = headers = residue = NULL;
491                 params.transport = params.user = params.method = params.ttl = params.maddr = NULL;
492                 params.lr = 0;
493
494                 ast_copy_string(uri,testdataptr->uri,sizeof(uri));
495                 if (parse_uri_full(uri, "sip:,sips:,tel:", &user,
496                                    &pass, &hostport,
497                                    &params,
498                                    &headers,
499                                    &residue) ||
500                         (user && strcmp(testdataptr->user, user)) ||
501                         (pass && strcmp(testdataptr->pass, pass)) ||
502                         (hostport && strcmp(testdataptr->hostport, hostport)) ||
503                         (headers && strcmp(testdataptr->headers, headers)) ||
504                         (residue && strcmp(testdataptr->residue, residue)) ||
505                         (strcmp(testdataptr->params.transport,params.transport)) ||
506                         (testdataptr->params.lr != params.lr) ||
507                         (strcmp(testdataptr->params.user,params.user))
508                 ) {
509                                 ast_test_status_update(test, "Sub-Test: %s, failed.\n", testdataptr->desc);
510                                 res = AST_TEST_FAIL;
511                 }
512         }
513
514
515         return res;
516 }
517 #endif
518
519 int parse_uri(char *uri, const char *scheme, char **user, char **pass,
520               char **hostport, char **transport) {
521         int ret;
522         char *headers;
523         struct uriparams params;
524
525         headers = NULL;
526         ret = parse_uri_full(uri, scheme, user, pass, hostport, &params, &headers, NULL);
527         if (transport) {
528                 *transport=params.transport;
529         }
530         return ret;
531 }
532
533 #ifdef TEST_FRAMEWORK
534 AST_TEST_DEFINE(sip_parse_uri_test)
535 {
536         int res = AST_TEST_PASS;
537         char *name, *pass, *hostport, *transport;
538         char uri1[] = "sip:name@host";
539         char uri2[] = "sip:name@host;transport=tcp";
540         char uri3[] = "sip:name:secret@host;transport=tcp";
541         char uri4[] = "sip:name:secret@host:port;transport=tcp?headers=%40%40testblah&headers2=blah%20blah";
542         /* test 5 is for NULL input */
543         char uri6[] = "sip:name:secret@host:port;transport=tcp?headers=%40%40testblah&headers2=blah%20blah";
544         char uri7[] = "sip:name:secret@host:port;transport=tcp?headers=%40%40testblah&headers2=blah%20blah";
545         char uri8[] = "sip:host";
546         char uri9[] = "sip:host:port;transport=tcp?headers=%40%40testblah&headers2=blah%20blah";
547         char uri10[] = "host:port;transport=tcp?headers=%40%40testblah&headers2=blah%20blah";
548         char uri11[] = "host";
549         char uri12[] = "tel:911";       /* TEL URI Local number without context or global number */
550
551         switch (cmd) {
552         case TEST_INIT:
553                 info->name = "sip_uri_parse_test";
554                 info->category = "/channels/chan_sip/";
555                 info->summary = "tests sip uri parsing";
556                 info->description =
557                                                         "Tests parsing of various URIs "
558                                                         "Verifies output matches expected behavior.";
559                 return AST_TEST_NOT_RUN;
560         case TEST_EXECUTE:
561                 break;
562         }
563
564         /* Test 1, simple URI */
565         name = pass = hostport = transport = NULL;
566         if (parse_uri(uri1, "sip:,sips:", &name, &pass, &hostport, &transport) ||
567                         strcmp(name, "name")        ||
568                         !ast_strlen_zero(pass)      ||
569                         strcmp(hostport, "host")      ||
570                         !ast_strlen_zero(transport)) {
571                 ast_test_status_update(test, "Test 1: simple uri failed. \n");
572                 res = AST_TEST_FAIL;
573         }
574
575         /* Test 2, add tcp transport */
576         name = pass = hostport = transport = NULL;
577         if (parse_uri(uri2, "sip:,sips:", &name, &pass, &hostport, &transport) ||
578                         strcmp(name, "name")        ||
579                         !ast_strlen_zero(pass)      ||
580                         strcmp(hostport, "host")    ||
581                         strcmp(transport, "tcp")) {
582                 ast_test_status_update(test, "Test 2: uri with addtion of tcp transport failed. \n");
583                 res = AST_TEST_FAIL;
584         }
585
586         /* Test 3, add secret */
587         name = pass = hostport = transport = NULL;
588         if (parse_uri(uri3, "sip:,sips:", &name, &pass, &hostport, &transport) ||
589                         strcmp(name, "name")        ||
590                         strcmp(pass, "secret")      ||
591                         strcmp(hostport, "host")    ||
592                         strcmp(transport, "tcp")) {
593                 ast_test_status_update(test, "Test 3: uri with addition of secret failed.\n");
594                 res = AST_TEST_FAIL;
595         }
596
597         /* Test 4, add port and unparsed header field*/
598         name = pass = hostport = transport = NULL;
599         if (parse_uri(uri4, "sip:,sips:", &name, &pass, &hostport, &transport) ||
600                         strcmp(name, "name")        ||
601                         strcmp(pass, "secret")      ||
602                         strcmp(hostport, "host:port") ||
603                         strcmp(transport, "tcp")) {
604                 ast_test_status_update(test, "Test 4: add port and unparsed header field failed.\n");
605                 res = AST_TEST_FAIL;
606         }
607
608         /* Test 5, verify parse_uri does not crash when given a NULL uri */
609         name = pass = hostport = transport = NULL;
610         if (!parse_uri(NULL, "sip:,sips:", &name, &pass, &hostport, &transport)) {
611                 ast_test_status_update(test, "Test 5: passing a NULL uri failed.\n");
612                 res = AST_TEST_FAIL;
613         }
614
615         /* Test 6, verify parse_uri does not crash when given a NULL output parameters */
616         name = pass = hostport = transport = NULL;
617         if (parse_uri(uri6, "sip:,sips:", NULL, NULL, NULL, NULL)) {
618                 ast_test_status_update(test, "Test 6: passing NULL output parameters failed.\n");
619                 res = AST_TEST_FAIL;
620         }
621
622         /* Test 7, verify parse_uri returns user:secret and hostport when no port or secret output parameters are supplied. */
623         name = pass = hostport = transport = NULL;
624         if (parse_uri(uri7, "sip:,sips:", &name, NULL, &hostport, NULL) ||
625                         strcmp(name, "name:secret")        ||
626                         strcmp(hostport, "host:port")) {
627
628                 ast_test_status_update(test, "Test 7: providing no port and secret output parameters failed.\n");
629                 res = AST_TEST_FAIL;
630         }
631
632         /* Test 8, verify parse_uri can handle a hostport only uri */
633         name = pass = hostport = transport = NULL;
634         if (parse_uri(uri8, "sip:,sips:", &name, &pass, &hostport, &transport) ||
635                         strcmp(hostport, "host") ||
636                         !ast_strlen_zero(name)) {
637                 ast_test_status_update(test, "Test 8: add port and unparsed header field failed.\n");
638                 res = AST_TEST_FAIL;
639         }
640
641         /* Test 9, add port and unparsed header field with hostport only uri*/
642         name = pass = hostport = transport = NULL;
643         if (parse_uri(uri9, "sip:,sips:", &name, &pass, &hostport, &transport) ||
644                         !ast_strlen_zero(name)        ||
645                         !ast_strlen_zero(pass)      ||
646                         strcmp(hostport, "host:port")    ||
647                         strcmp(transport, "tcp")) {
648                 ast_test_status_update(test, "Test 9: hostport only uri failed \n");
649                 res = AST_TEST_FAIL;
650         }
651
652         /* Test 10, handle invalid/missing "sip:,sips:" scheme
653          * we expect parse_uri to return an error, but still parse
654          * the results correctly here */
655         name = pass = hostport = transport = NULL;
656         if (!parse_uri(uri10, "sip:,sips:", &name, &pass, &hostport, &transport) ||
657                         !ast_strlen_zero(name)        ||
658                         !ast_strlen_zero(pass)      ||
659                         strcmp(hostport, "host:port")    ||
660                         strcmp(transport, "tcp")) {
661                 ast_test_status_update(test, "Test 10: missing \"sip:sips:\" scheme failed\n");
662                 res = AST_TEST_FAIL;
663         }
664
665         /* Test 11, simple hostport only URI with missing scheme
666          * we expect parse_uri to return an error, but still parse
667          * the results correctly here */
668         name = pass = hostport = transport = NULL;
669         if (!parse_uri(uri11, "sip:,sips:", &name, &pass, &hostport, &transport) ||
670                         !ast_strlen_zero(name)      ||
671                         !ast_strlen_zero(pass)      ||
672                         strcmp(hostport, "host")      ||
673                         !ast_strlen_zero(transport)) {
674                 ast_test_status_update(test, "Test 11: simple uri with missing scheme failed. \n");
675                 res = AST_TEST_FAIL;
676         }
677
678         /* Test 12, simple URI */
679         name = pass = hostport = transport = NULL;
680         if (!parse_uri(uri12, "sip:,sips:,tel:", &name, &pass, &hostport, &transport) ||
681                         strcmp(name, "911")      ||     /* We return local number anyway */
682                         !ast_strlen_zero(pass)      ||
683                         !ast_strlen_zero(hostport)      ||      /* No global number nor context */
684                         !ast_strlen_zero(transport)) {
685                 ast_test_status_update(test, "Test 12: TEL URI INVITE failed.\n");
686                 res = AST_TEST_FAIL;
687         }
688
689         return res;
690 }
691 #endif
692
693 /*! \brief  Get caller id name from SIP headers, copy into output buffer
694  *
695  *  \retval input string pointer placed after display-name field if possible
696  */
697 const char *get_calleridname(const char *input, char *output, size_t outputsize)
698 {
699         /* From RFC3261:
700          *
701          * From           =  ( "From" / "f" ) HCOLON from-spec
702          * from-spec      =  ( name-addr / addr-spec ) *( SEMI from-param )
703          * name-addr      =  [ display-name ] LAQUOT addr-spec RAQUOT
704          * display-name   =  *(token LWS)/ quoted-string
705          * token          =  1*(alphanum / "-" / "." / "!" / "%" / "*"
706          *                     / "_" / "+" / "`" / "'" / "~" )
707          * quoted-string  =  SWS DQUOTE *(qdtext / quoted-pair ) DQUOTE
708          * qdtext         =  LWS / %x21 / %x23-5B / %x5D-7E
709          *                     / UTF8-NONASCII
710          * quoted-pair    =  "\" (%x00-09 / %x0B-0C / %x0E-7F)
711          *
712          * HCOLON         = *WSP ":" SWS
713          * SWS            = [LWS]
714          * LWS            = *[*WSP CRLF] 1*WSP
715          * WSP            = (SP / HTAB)
716          *
717          * Deviations from it:
718          * - following CRLF's in LWS is not done (here at least)
719          * - ascii NUL is never legal as it terminates the C-string
720          * - utf8-nonascii is not checked for validity
721          */
722         char *orig_output = output;
723         const char *orig_input = input;
724
725         if (!output || !outputsize) {
726                 /* Bad output parameters.  Should never happen. */
727                 return input;
728         }
729
730         /* clear any empty characters in the beginning */
731         input = ast_skip_blanks(input);
732
733         /* make sure the output buffer is initilized */
734         *orig_output = '\0';
735
736         /* make room for '\0' at the end of the output buffer */
737         --outputsize;
738
739         /* no data at all or no display name? */
740         if (!input || *input == '<') {
741                 return input;
742         }
743
744         /* quoted-string rules */
745         if (input[0] == '"') {
746                 input++; /* skip the first " */
747
748                 for (; *input; ++input) {
749                         if (*input == '"') {  /* end of quoted-string */
750                                 break;
751                         } else if (*input == 0x5c) { /* quoted-pair = "\" (%x00-09 / %x0B-0C / %x0E-7F) */
752                                 ++input;
753                                 if (!*input) {
754                                         break;
755                                 }
756                                 if ((unsigned char) *input > 0x7f || *input == 0xa || *input == 0xd) {
757                                         continue;  /* not a valid quoted-pair, so skip it */
758                                 }
759                         } else if ((*input != 0x9 && (unsigned char) *input < 0x20)
760                                 || *input == 0x7f) {
761                                 continue; /* skip this invalid character. */
762                         }
763
764                         if (0 < outputsize) {
765                                 /* We still have room for the output display-name. */
766                                 *output++ = *input;
767                                 --outputsize;
768                         }
769                 }
770
771                 /* if this is successful, input should be at the ending quote */
772                 if (*input != '"') {
773                         ast_log(LOG_WARNING, "No ending quote for display-name was found\n");
774                         *orig_output = '\0';
775                         return orig_input;
776                 }
777
778                 /* make sure input is past the last quote */
779                 ++input;
780
781                 /* terminate output */
782                 *output = '\0';
783         } else {  /* either an addr-spec or tokenLWS-combo */
784                 for (; *input; ++input) {
785                         /* token or WSP (without LWS) */
786                         if ((*input >= '0' && *input <= '9') || (*input >= 'A' && *input <= 'Z')
787                                 || (*input >= 'a' && *input <= 'z') || *input == '-' || *input == '.'
788                                 || *input == '!' || *input == '%' || *input == '*' || *input == '_'
789                                 || *input == '+' || *input == '`' || *input == '\'' || *input == '~'
790                                 || *input == 0x9 || *input == ' ') {
791                                 if (0 < outputsize) {
792                                         /* We still have room for the output display-name. */
793                                         *output++ = *input;
794                                         --outputsize;
795                                 }
796                         } else if (*input == '<') {   /* end of tokenLWS-combo */
797                                 /* we could assert that the previous char is LWS, but we don't care */
798                                 break;
799                         } else if (*input == ':') {
800                                 /* This invalid character which indicates this is addr-spec rather than display-name. */
801                                 *orig_output = '\0';
802                                 return orig_input;
803                         } else {         /* else, invalid character we can skip. */
804                                 continue;    /* skip this character */
805                         }
806                 }
807
808                 if (*input != '<') {   /* if we never found the start of addr-spec then this is invalid */
809                         *orig_output = '\0';
810                         return orig_input;
811                 }
812
813                 /* terminate output while trimming any trailing whitespace */
814                 do {
815                         *output-- = '\0';
816                 } while (orig_output <= output && (*output == 0x9 || *output == ' '));
817         }
818
819         return input;
820 }
821
822 #ifdef TEST_FRAMEWORK
823 AST_TEST_DEFINE(get_calleridname_test)
824 {
825         int res = AST_TEST_PASS;
826         const char *in1 = " \" quoted-text internal \\\" quote \"<stuff>";
827         const char *in2 = " token text with no quotes <stuff>";
828         const char *overflow1 = " \"quoted-text overflow 1234567890123456789012345678901234567890\" <stuff>";
829         const char *overflow2 = " non-quoted text overflow 1234567890123456789012345678901234567890 <stuff>";
830         const char *noendquote = " \"quoted-text no end <stuff>";
831         const char *addrspec = " sip:blah@blah";
832         const char *no_quotes_no_brackets = "blah@blah";
833         const char *after_dname;
834         char dname[40];
835
836         switch (cmd) {
837         case TEST_INIT:
838                 info->name = "sip_get_calleridname_test";
839                 info->category = "/channels/chan_sip/";
840                 info->summary = "decodes callerid name from sip header";
841                 info->description = "Decodes display-name field of sip header.  Checks for valid output and expected failure cases.";
842                 return AST_TEST_NOT_RUN;
843         case TEST_EXECUTE:
844                 break;
845         }
846
847         /* quoted-text with backslash escaped quote */
848         after_dname = get_calleridname(in1, dname, sizeof(dname));
849         ast_test_status_update(test, "display-name1: %s\nafter: %s\n", dname, after_dname);
850         if (strcmp(dname, " quoted-text internal \" quote ")) {
851                 ast_test_status_update(test, "display-name1 test failed\n");
852                 res = AST_TEST_FAIL;
853         }
854
855         /* token text */
856         after_dname = get_calleridname(in2, dname, sizeof(dname));
857         ast_test_status_update(test, "display-name2: %s\nafter: %s\n", dname, after_dname);
858         if (strcmp(dname, "token text with no quotes")) {
859                 ast_test_status_update(test, "display-name2 test failed\n");
860                 res = AST_TEST_FAIL;
861         }
862
863         /* quoted-text buffer overflow */
864         after_dname = get_calleridname(overflow1, dname, sizeof(dname));
865         ast_test_status_update(test, "overflow display-name1: %s\nafter: %s\n", dname, after_dname);
866         if (strcmp(dname, "quoted-text overflow 123456789012345678")) {
867                 ast_test_status_update(test, "overflow display-name1 test failed\n");
868                 res = AST_TEST_FAIL;
869         }
870
871         /* non-quoted-text buffer overflow */
872         after_dname = get_calleridname(overflow2, dname, sizeof(dname));
873         ast_test_status_update(test, "overflow display-name2: %s\nafter: %s\n", dname, after_dname);
874         if (strcmp(dname, "non-quoted text overflow 12345678901234")) {
875                 ast_test_status_update(test, "overflow display-name2 test failed\n");
876                 res = AST_TEST_FAIL;
877         }
878
879         /* quoted-text buffer with no terminating end quote */
880         after_dname = get_calleridname(noendquote, dname, sizeof(dname));
881         ast_test_status_update(test, "noendquote display-name1: %s\nafter: %s\n", dname, after_dname);
882         if (*dname != '\0' && after_dname != noendquote) {
883                 ast_test_status_update(test, "no end quote for quoted-text display-name failed\n");
884                 res = AST_TEST_FAIL;
885         }
886
887         /* addr-spec rather than display-name. */
888         after_dname = get_calleridname(addrspec, dname, sizeof(dname));
889         ast_test_status_update(test, "addr-spec display-name1: %s\nafter: %s\n", dname, after_dname);
890         if (*dname != '\0' && after_dname != addrspec) {
891                 ast_test_status_update(test, "detection of addr-spec failed\n");
892                 res = AST_TEST_FAIL;
893         }
894
895         /* no quotes, no brackets */
896         after_dname = get_calleridname(no_quotes_no_brackets, dname, sizeof(dname));
897         ast_test_status_update(test, "no_quotes_no_brackets display-name1: %s\nafter: %s\n", dname, after_dname);
898         if (*dname != '\0' && after_dname != no_quotes_no_brackets) {
899                 ast_test_status_update(test, "detection of addr-spec failed\n");
900                 res = AST_TEST_FAIL;
901         }
902
903         return res;
904 }
905 #endif
906
907 int get_name_and_number(const char *hdr, char **name, char **number)
908 {
909         char header[256];
910         char tmp_name[256];
911         char *tmp_number = NULL;
912         char *hostport = NULL;
913         char *dummy = NULL;
914
915         if (!name || !number || ast_strlen_zero(hdr)) {
916                 return -1;
917         }
918
919         *number = NULL;
920         *name = NULL;
921         ast_copy_string(header, hdr, sizeof(header));
922
923         /* strip the display-name portion off the beginning of the header. */
924         get_calleridname(header, tmp_name, sizeof(tmp_name));
925
926         /* get uri within < > brackets */
927         tmp_number = get_in_brackets(header);
928
929         /* parse out the number here */
930         if (parse_uri(tmp_number, "sip:,sips:", &tmp_number, &dummy, &hostport, NULL) || ast_strlen_zero(tmp_number)) {
931                 ast_log(LOG_ERROR, "can not parse name and number from sip header.\n");
932                 return -1;
933         }
934
935         /* number is not option, and must be present at this point */
936         *number = ast_strdup(tmp_number);
937         ast_uri_decode(*number, ast_uri_sip_user);
938
939         /* name is optional and may not be present at this point */
940         if (!ast_strlen_zero(tmp_name)) {
941                 *name = ast_strdup(tmp_name);
942         }
943
944         return 0;
945 }
946
947 #ifdef TEST_FRAMEWORK
948 AST_TEST_DEFINE(get_name_and_number_test)
949 {
950         int res = AST_TEST_PASS;
951         char *name = NULL;
952         char *number = NULL;
953         const char *in1 = "NAME <sip:NUMBER@place>";
954         const char *in2 = "\"NA><ME\" <sip:NUMBER@place>";
955         const char *in3 = "NAME";
956         const char *in4 = "<sip:NUMBER@place>";
957         const char *in5 = "This is a screwed up string <sip:LOLCLOWNS<sip:>@place>";
958
959         switch (cmd) {
960         case TEST_INIT:
961                 info->name = "sip_get_name_and_number_test";
962                 info->category = "/channels/chan_sip/";
963                 info->summary = "Tests getting name and number from sip header";
964                 info->description =
965                                 "Runs through various test situations in which a name and "
966                                 "and number can be retrieved from a sip header.";
967                 return AST_TEST_NOT_RUN;
968         case TEST_EXECUTE:
969                 break;
970         }
971
972         /* Test 1. get name and number */
973         number = name = NULL;
974         if ((get_name_and_number(in1, &name, &number)) ||
975                 strcmp(name, "NAME") ||
976                 strcmp(number, "NUMBER")) {
977
978                 ast_test_status_update(test, "Test 1, simple get name and number failed.\n");
979                 res = AST_TEST_FAIL;
980         }
981         ast_free(name);
982         ast_free(number);
983
984         /* Test 2. get quoted name and number */
985         number = name = NULL;
986         if ((get_name_and_number(in2, &name, &number)) ||
987                 strcmp(name, "NA><ME") ||
988                 strcmp(number, "NUMBER")) {
989
990                 ast_test_status_update(test, "Test 2, get quoted name and number failed.\n");
991                 res = AST_TEST_FAIL;
992         }
993         ast_free(name);
994         ast_free(number);
995
996         /* Test 3. name only */
997         number = name = NULL;
998         if (!(get_name_and_number(in3, &name, &number))) {
999
1000                 ast_test_status_update(test, "Test 3, get name only was expected to fail but did not.\n");
1001                 res = AST_TEST_FAIL;
1002         }
1003         ast_free(name);
1004         ast_free(number);
1005
1006         /* Test 4. number only */
1007         number = name = NULL;
1008         if ((get_name_and_number(in4, &name, &number)) ||
1009                 !ast_strlen_zero(name) ||
1010                 strcmp(number, "NUMBER")) {
1011
1012                 ast_test_status_update(test, "Test 4, get number with no name present failed.\n");
1013                 res = AST_TEST_FAIL;
1014         }
1015         ast_free(name);
1016         ast_free(number);
1017
1018         /* Test 5. malformed string, since number can not be parsed, this should return an error.  */
1019         number = name = NULL;
1020         if (!(get_name_and_number(in5, &name, &number)) ||
1021                 !ast_strlen_zero(name) ||
1022                 !ast_strlen_zero(number)) {
1023
1024                 ast_test_status_update(test, "Test 5, processing malformed string failed.\n");
1025                 res = AST_TEST_FAIL;
1026         }
1027         ast_free(name);
1028         ast_free(number);
1029
1030         /* Test 6. NULL output parameters */
1031         number = name = NULL;
1032         if (!(get_name_and_number(in5, NULL, NULL))) {
1033
1034                 ast_test_status_update(test, "Test 6, NULL output parameters failed.\n");
1035                 res = AST_TEST_FAIL;
1036         }
1037
1038         /* Test 7. NULL input parameter */
1039         number = name = NULL;
1040         if (!(get_name_and_number(NULL, &name, &number)) ||
1041                 !ast_strlen_zero(name) ||
1042                 !ast_strlen_zero(number)) {
1043
1044                 ast_test_status_update(test, "Test 7, NULL input parameter failed.\n");
1045                 res = AST_TEST_FAIL;
1046         }
1047         ast_free(name);
1048         ast_free(number);
1049
1050         return res;
1051 }
1052 #endif
1053
1054 int get_in_brackets_const(const char *src,const char **start,int *length)
1055 {
1056         const char *parse = src;
1057         const char *first_bracket;
1058         const char *second_bracket;
1059
1060         if (start == NULL) {
1061                 return -1;
1062         }
1063         if (length == NULL) {
1064                 return -1;
1065         }
1066         *start = NULL;
1067         *length = -1;
1068         if (ast_strlen_zero(src)) {
1069                 return 1;
1070         }
1071
1072         /*
1073          * Skip any quoted text until we find the part in brackets.
1074          * On any error give up and return -1
1075          */
1076         while ( (first_bracket = strchr(parse, '<')) ) {
1077                 const char *first_quote = strchr(parse, '"');
1078                 first_bracket++;
1079                 if (!first_quote || first_quote >= first_bracket) {
1080                         break; /* no need to look at quoted part */
1081                 }
1082                 /* the bracket is within quotes, so ignore it */
1083                 parse = find_closing_quote(first_quote + 1, NULL);
1084                 if (!*parse) {
1085                         ast_log(LOG_WARNING, "No closing quote found in '%s'\n", src);
1086                         return  -1;
1087                 }
1088                 parse++;
1089         }
1090
1091         /* Require a first bracket.  Unlike get_in_brackets_full, this procedure is passed a const,
1092          * so it can expect a pointer to an original value */
1093         if (!first_bracket) {
1094                 ast_log(LOG_WARNING, "No opening bracket found in '%s'\n", src);
1095                 return 1;
1096         }
1097
1098         if ((second_bracket = strchr(first_bracket, '>'))) {
1099                 *start = first_bracket;
1100                 *length = second_bracket - first_bracket;
1101                 return 0;
1102         }
1103         ast_log(LOG_WARNING, "No closing bracket found in '%s'\n", src);
1104         return -1;
1105 }
1106
1107 int get_in_brackets_full(char *tmp,char **out,char **residue)
1108 {
1109         const char *parse = tmp;
1110         char *first_bracket;
1111         char *second_bracket;
1112
1113         if (out) {
1114                 *out = "";
1115         }
1116         if (residue) {
1117                 *residue = "";
1118         }
1119
1120         if (ast_strlen_zero(tmp)) {
1121                 return 1;
1122         }
1123
1124         /*
1125          * Skip any quoted text until we find the part in brackets.
1126         * On any error give up and return -1
1127         */
1128         while ( (first_bracket = strchr(parse, '<')) ) {
1129                 char *first_quote = strchr(parse, '"');
1130                 first_bracket++;
1131                 if (!first_quote || first_quote >= first_bracket) {
1132                         break; /* no need to look at quoted part */
1133                 }
1134                 /* the bracket is within quotes, so ignore it */
1135                 parse = find_closing_quote(first_quote + 1, NULL);
1136                 if (!*parse) {
1137                         ast_log(LOG_WARNING, "No closing quote found in '%s'\n", tmp);
1138                         return  -1;
1139                 }
1140                 parse++;
1141         }
1142
1143         /* If no first bracket then still look for a second bracket as some other parsing functions
1144         may overwrite first bracket with NULL when terminating a token based display-name. As this
1145         only affects token based display-names there is no danger of brackets being in quotes */
1146         if (first_bracket) {
1147                 parse = first_bracket;
1148         } else {
1149                 parse = tmp;
1150         }
1151
1152         if ((second_bracket = strchr(parse, '>'))) {
1153                 *second_bracket++ = '\0';
1154                 if (out) {
1155                         *out = (char *) parse;
1156                 }
1157                 if (residue) {
1158                         *residue = second_bracket;
1159                 }
1160                 return 0;
1161         }
1162
1163         if ((first_bracket)) {
1164                 ast_log(LOG_WARNING, "No closing bracket found in '%s'\n", tmp);
1165                 return -1;
1166         }
1167
1168         if (out) {
1169                 *out = tmp;
1170         }
1171
1172         return 1;
1173 }
1174
1175 char *get_in_brackets(char *tmp)
1176 {
1177         char *out;
1178
1179         if ((get_in_brackets_full(tmp, &out, NULL))) {
1180                 return tmp;
1181         }
1182         return out;
1183 }
1184
1185 #ifdef TEST_FRAMEWORK
1186 AST_TEST_DEFINE(get_in_brackets_test)
1187 {
1188         int res = AST_TEST_PASS;
1189         char in_brackets[] = "sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah";
1190         char no_name[] = "<sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>";
1191         char quoted_string[] = "\"I'm a quote stri><ng\" <sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>";
1192         char missing_end_quote[] = "\"I'm a quote string <sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>";
1193         char name_no_quotes[] = "name not in quotes <sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>";
1194         char no_end_bracket[] = "name not in quotes <sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah";
1195         char no_name_no_brackets[] = "sip:name@host";
1196         char missing_start_bracket[] = "sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>";
1197         char *uri = NULL;
1198
1199         switch (cmd) {
1200         case TEST_INIT:
1201                 info->name = "sip_get_in_brackets_test";
1202                 info->category = "/channels/chan_sip/";
1203                 info->summary = "Tests getting a sip uri in <> brackets within a sip header.";
1204                 info->description =
1205                                 "Runs through various test situations in which a sip uri "
1206                                 "in angle brackets needs to be retrieved";
1207                 return AST_TEST_NOT_RUN;
1208         case TEST_EXECUTE:
1209                 break;
1210         }
1211
1212         /* Test 1, simple get in brackets */
1213         if (!(uri = get_in_brackets(no_name)) || strcmp(uri, in_brackets)) {
1214                 ast_test_status_update(test, "Test 1, simple get in brackets failed. %s\n", uri);
1215                 res = AST_TEST_FAIL;
1216         }
1217
1218         /* Test 2, starts with quoted string */
1219         if (!(uri = get_in_brackets(quoted_string)) || strcmp(uri, in_brackets)) {
1220                 ast_test_status_update(test, "Test 2, get in brackets with quoted string in front failed. %s\n", uri);
1221                 res = AST_TEST_FAIL;
1222         }
1223
1224         /* Test 3, missing end quote */
1225         if (!(uri = get_in_brackets(missing_end_quote)) || !strcmp(uri, in_brackets)) {
1226                 ast_test_status_update(test, "Test 3, missing end quote failed. %s\n", uri);
1227                 res = AST_TEST_FAIL;
1228         }
1229
1230         /* Test 4, starts with a name not in quotes */
1231         if (!(uri = get_in_brackets(name_no_quotes)) || strcmp(uri, in_brackets)) {
1232                 ast_test_status_update(test, "Test 4, passing name not in quotes failed. %s\n", uri);
1233                 res = AST_TEST_FAIL;
1234         }
1235
1236         /* Test 5, no end bracket, should just return everything after the first '<'  */
1237         if (!(uri = get_in_brackets(no_end_bracket)) || !strcmp(uri, in_brackets)) {
1238                 ast_test_status_update(test, "Test 5, no end bracket failed. %s\n", uri);
1239                 res = AST_TEST_FAIL;
1240         }
1241
1242         /* Test 6, NULL input  */
1243         if (get_in_brackets(NULL)) {
1244                 ast_test_status_update(test, "Test 6, NULL input failed.\n");
1245                 res = AST_TEST_FAIL;
1246         }
1247
1248         /* Test 7, no name, and no brackets. */
1249         if (!(uri = get_in_brackets(no_name_no_brackets)) || strcmp(uri, "sip:name@host")) {
1250                 ast_test_status_update(test, "Test 7 failed. %s\n", uri);
1251                 res = AST_TEST_FAIL;
1252         }
1253
1254         /* Test 8, no start bracket, but with ending bracket. */
1255         if (!(uri = get_in_brackets(missing_start_bracket)) || strcmp(uri, in_brackets)) {
1256                 ast_test_status_update(test, "Test 8 failed. %s\n", uri);
1257                 res = AST_TEST_FAIL;
1258         }
1259
1260         return res;
1261 }
1262 #endif
1263
1264 int parse_name_andor_addr(char *uri, const char *scheme, char **name,
1265                           char **user, char **pass, char **hostport,
1266                           struct uriparams *params, char **headers,
1267                           char **residue)
1268 {
1269         char buf[1024];
1270         char **residue2 = residue;
1271         char *orig_uri = uri;
1272         int ret;
1273
1274         buf[0] = '\0';
1275         if (name) {
1276                 uri = (char *) get_calleridname(uri, buf, sizeof(buf));
1277         }
1278         ret = get_in_brackets_full(uri, &uri, residue);
1279         if (ret == 0) {
1280                 /*
1281                  * The uri is in brackets so do not treat unknown trailing uri
1282                  * parameters as potential message header parameters.
1283                  */
1284                 if (residue && **residue) {
1285                         /* step over the first semicolon as per parse_uri_full residue */
1286                         *residue = *residue + 1;
1287                 }
1288                 residue2 = NULL;
1289         }
1290
1291         if (name) {
1292                 if (buf[0]) {
1293                         /*
1294                          * There is always room at orig_uri for the display-name because
1295                          * at least one character has always been removed.  A '"' or '<'
1296                          * has been removed.
1297                          */
1298                         strcpy(orig_uri, buf);
1299                         *name = orig_uri;
1300                 } else {
1301                         *name = "";
1302                 }
1303         }
1304
1305         return parse_uri_full(uri, scheme, user, pass, hostport, params, headers, residue2);
1306 }
1307
1308 #ifdef TEST_FRAMEWORK
1309 AST_TEST_DEFINE(parse_name_andor_addr_test)
1310 {
1311         int res = AST_TEST_PASS;
1312         char uri[1024];
1313         char *name, *user, *pass, *hostport, *headers, *residue;
1314         struct uriparams params;
1315
1316         struct testdata {
1317                 char *desc;
1318                 char *uri;
1319                 char *name;
1320                 char *user;
1321                 char *pass;
1322                 char *hostport;
1323                 char *headers;
1324                 char *residue;
1325                 struct uriparams params;
1326                 AST_LIST_ENTRY(testdata) list;
1327         };
1328
1329         struct testdata *testdataptr;
1330
1331         static AST_LIST_HEAD_NOLOCK(testdataliststruct, testdata) testdatalist;
1332
1333         struct testdata td1 = {
1334                 .desc = "quotes and brackets",
1335                 .uri = "\"name :@ \" <sip:user:secret@host:5060;param=discard;transport=tcp>;tag=tag",
1336                 .name =  "name :@ ",
1337                 .user = "user",
1338                 .pass = "secret",
1339                 .hostport = "host:5060",
1340                 .headers = "",
1341                 .residue = "tag=tag",
1342                 .params.transport = "tcp",
1343                 .params.lr = 0,
1344                 .params.user = ""
1345         };
1346
1347         struct testdata td2 = {
1348                 .desc = "no quotes",
1349                 .uri = "givenname familyname <sip:user:secret@host:5060;param=discard;transport=tcp>;expires=3600",
1350                 .name = "givenname familyname",
1351                 .user = "user",
1352                 .pass = "secret",
1353                 .hostport = "host:5060",
1354                 .headers = "",
1355                 .residue = "expires=3600",
1356                 .params.transport = "tcp",
1357                 .params.lr = 0,
1358                 .params.user = ""
1359         };
1360
1361         struct testdata td3 = {
1362                 .desc = "no brackets",
1363                 .uri = "sip:user:secret@host:5060;param=discard;transport=tcp;q=1",
1364                 .name = "",
1365                 .user = "user",
1366                 .pass = "secret",
1367                 .hostport = "host:5060",
1368                 .headers = "",
1369                 .residue = "q=1",
1370                 .params.transport = "tcp",
1371                 .params.lr = 0,
1372                 .params.user = ""
1373         };
1374
1375         struct testdata td4 = {
1376                 .desc = "just host",
1377                 .uri = "sips:host",
1378                 .name = "",
1379                 .user = "",
1380                 .pass = "",
1381                 .hostport = "host",
1382                 .headers = "",
1383                 .residue = "",
1384                 .params.transport = "",
1385                 .params.lr = 0,
1386                 .params.user = ""
1387         };
1388
1389
1390         AST_LIST_HEAD_SET_NOLOCK(&testdatalist, &td1);
1391         AST_LIST_INSERT_TAIL(&testdatalist, &td2, list);
1392         AST_LIST_INSERT_TAIL(&testdatalist, &td3, list);
1393         AST_LIST_INSERT_TAIL(&testdatalist, &td4, list);
1394
1395
1396         switch (cmd) {
1397         case TEST_INIT:
1398                 info->name = "parse_name_andor_addr_test";
1399                 info->category = "/channels/chan_sip/";
1400                 info->summary = "tests parsing of name_andor_addr abnf structure";
1401                 info->description =
1402                         "Tests parsing of abnf name-andor-addr = name-addr / addr-spec "
1403                         "Verifies output matches expected behavior.";
1404                 return AST_TEST_NOT_RUN;
1405         case TEST_EXECUTE:
1406                 break;
1407         }
1408
1409         AST_LIST_TRAVERSE(&testdatalist, testdataptr, list) {
1410                 name = user = pass = hostport = headers = residue = NULL;
1411                 params.transport = params.user = params.method = params.ttl = params.maddr = NULL;
1412                 params.lr = 0;
1413                 ast_copy_string(uri,testdataptr->uri,sizeof(uri));
1414                 if (parse_name_andor_addr(uri, "sip:,sips:",
1415                                           &name,
1416                                           &user,
1417                                           &pass,
1418                                           &hostport,
1419                                           &params,
1420                                           &headers,
1421                                           &residue) ||
1422                         (name && strcmp(testdataptr->name, name)) ||
1423                         (user && strcmp(testdataptr->user, user)) ||
1424                         (pass && strcmp(testdataptr->pass, pass)) ||
1425                         (hostport && strcmp(testdataptr->hostport, hostport)) ||
1426                         (headers && strcmp(testdataptr->headers, headers)) ||
1427                         (residue && strcmp(testdataptr->residue, residue)) ||
1428                         (strcmp(testdataptr->params.transport,params.transport)) ||
1429                         (strcmp(testdataptr->params.user,params.user))
1430                         ) {
1431                         ast_test_status_update(test, "Sub-Test: %s,failed.\n", testdataptr->desc);
1432                         res = AST_TEST_FAIL;
1433                 }
1434         }
1435
1436         return res;
1437 }
1438 #endif
1439
1440 int get_comma(char *in, char **out)
1441 {
1442         char *c;
1443         char *parse = in;
1444         if (out) {
1445                 *out = in;
1446         }
1447
1448         /* Skip any quoted text */
1449         while (*parse) {
1450                 if ((c = strchr(parse, '"'))) {
1451                         in = (char *)find_closing_quote((const char *)c + 1, NULL);
1452                         if (!*in) {
1453                                 ast_log(LOG_WARNING, "No closing quote found in '%s'\n", c);
1454                                 return -1;
1455                         } else {
1456                                 break;
1457                         }
1458                 } else {
1459                         break;
1460                 }
1461                 parse++;
1462         }
1463         parse = in;
1464
1465         /* Skip any userinfo components of a uri as they may contain commas */
1466         if ((c = strchr(parse,'@'))) {
1467                 parse = c+1;
1468         }
1469         if ((out) && (c = strchr(parse,','))) {
1470                 *c++ = '\0';
1471                 *out = c;
1472                 return 0;
1473         }
1474         return 1;
1475 }
1476
1477 int parse_contact_header(char *contactheader, struct contactliststruct *contactlist)
1478 {
1479         int res;
1480         int last;
1481         char *comma;
1482         char *residue;
1483         char *param;
1484         char *value;
1485         struct contact *split_contact = NULL;
1486
1487         if (*contactheader == '*') {
1488                 return 1;
1489         }
1490
1491         split_contact = ast_calloc(1, sizeof(*split_contact));
1492
1493         AST_LIST_HEAD_SET_NOLOCK(contactlist, split_contact);
1494         while ((last = get_comma(contactheader, &comma)) != -1) {
1495                 res = parse_name_andor_addr(contactheader, "sip:,sips:",
1496                         &split_contact->name, &split_contact->user,
1497                         &split_contact->pass, &split_contact->hostport,
1498                         &split_contact->params, &split_contact->headers,
1499                         &residue);
1500                 if (res == -1) {
1501                         return res;
1502                 }
1503
1504                 /* parse contact params */
1505                 split_contact->expires = split_contact->q = "";
1506
1507                 while ((value = strchr(residue,'='))) {
1508                         *value++ = '\0';
1509
1510                         param = residue;
1511                         if ((residue = strchr(value,';'))) {
1512                                 *residue++ = '\0';
1513                         } else {
1514                                 residue = "";
1515                         }
1516
1517                         if (!strcmp(param,"expires")) {
1518                                 split_contact->expires = value;
1519                         } else if (!strcmp(param,"q")) {
1520                                 split_contact->q = value;
1521                         }
1522                 }
1523
1524                 if (last) {
1525                         return 0;
1526                 }
1527                 contactheader = comma;
1528
1529                 split_contact = ast_calloc(1, sizeof(*split_contact));
1530                 AST_LIST_INSERT_TAIL(contactlist, split_contact, list);
1531         }
1532         return last;
1533 }
1534
1535 #ifdef TEST_FRAMEWORK
1536 AST_TEST_DEFINE(parse_contact_header_test)
1537 {
1538         int res = AST_TEST_PASS;
1539         char contactheader[1024];
1540         int star;
1541         struct contactliststruct contactlist;
1542         struct contactliststruct *contactlistptr=&contactlist;
1543
1544         struct testdata {
1545                 char *desc;
1546                 char *contactheader;
1547                 int star;
1548                 struct contactliststruct *contactlist;
1549
1550                 AST_LIST_ENTRY(testdata) list;
1551         };
1552
1553         struct testdata *testdataptr;
1554         struct contact *tdcontactptr;
1555         struct contact *contactptr;
1556
1557         static AST_LIST_HEAD_NOLOCK(testdataliststruct, testdata) testdatalist;
1558         struct contactliststruct contactlist1, contactlist2;
1559
1560         struct testdata td1 = {
1561                 .desc = "single contact",
1562                 .contactheader = "\"name :@;?&,\" <sip:user:secret@host:5082;param=discard;transport=tcp>;expires=3600",
1563                 .contactlist = &contactlist1,
1564                 .star = 0
1565         };
1566         struct contact contact11 = {
1567                 .name = "name :@;?&,",
1568                 .user = "user",
1569                 .pass = "secret",
1570                 .hostport = "host:5082",
1571                 .params.transport = "tcp",
1572                 .params.ttl = "",
1573                 .params.lr = 0,
1574                 .headers = "",
1575                 .expires = "3600",
1576                 .q = ""
1577         };
1578
1579         struct testdata td2 = {
1580                 .desc = "multiple contacts",
1581                 .contactheader = "sip:,user1,:,secret1,@host1;ttl=7;q=1;expires=3600,sips:host2",
1582                 .contactlist = &contactlist2,
1583                 .star = 0,
1584         };
1585         struct contact contact21 = {
1586                 .name = "",
1587                 .user = ",user1,",
1588                 .pass = ",secret1,",
1589                 .hostport = "host1",
1590                 .params.transport = "",
1591                 .params.ttl = "7",
1592                 .params.lr = 0,
1593                 .headers = "",
1594                 .expires = "3600",
1595                 .q = "1"
1596         };
1597         struct contact contact22 = {
1598                 .name = "",
1599                 .user = "",
1600                 .pass = "",
1601                 .hostport = "host2",
1602                 .params.transport = "",
1603                 .params.ttl = "",
1604                 .params.lr = 0,
1605                 .headers = "",
1606                 .expires = "",
1607                 .q = ""
1608         };
1609
1610         struct testdata td3 = {
1611                 .desc = "star - all contacts",
1612                 .contactheader = "*",
1613                 .star = 1,
1614                 .contactlist = NULL
1615         };
1616
1617         AST_LIST_HEAD_SET_NOLOCK(&testdatalist, &td1);
1618         AST_LIST_INSERT_TAIL(&testdatalist, &td2, list);
1619         AST_LIST_INSERT_TAIL(&testdatalist, &td3, list);
1620
1621         AST_LIST_HEAD_SET_NOLOCK(&contactlist1, &contact11);
1622
1623         AST_LIST_HEAD_SET_NOLOCK(&contactlist2, &contact21);
1624         AST_LIST_INSERT_TAIL(&contactlist2, &contact22, list);
1625
1626
1627         switch (cmd) {
1628         case TEST_INIT:
1629                 info->name = "parse_contact_header_test";
1630                 info->category = "/channels/chan_sip/";
1631                 info->summary = "tests parsing of sip contact header";
1632                 info->description =
1633                         "Tests parsing of a contact header including those with multiple contacts "
1634                         "Verifies output matches expected behavior.";
1635                 return AST_TEST_NOT_RUN;
1636         case TEST_EXECUTE:
1637                 break;
1638         }
1639
1640         AST_LIST_TRAVERSE(&testdatalist, testdataptr, list) {
1641                 ast_copy_string(contactheader,testdataptr->contactheader,sizeof(contactheader));
1642                 star = parse_contact_header(contactheader,contactlistptr);
1643                 if (testdataptr->star) {
1644                         /* expecting star rather than list of contacts */
1645                         if (!star) {
1646                                 ast_test_status_update(test, "Sub-Test: %s,failed.\n", testdataptr->desc);
1647                                 res = AST_TEST_FAIL;
1648                                 break;
1649                         }
1650                 } else {
1651                         contactptr = AST_LIST_FIRST(contactlistptr);
1652                         AST_LIST_TRAVERSE(testdataptr->contactlist, tdcontactptr, list) {
1653                                 if (!contactptr ||
1654                                         strcmp(tdcontactptr->name, contactptr->name) ||
1655                                         strcmp(tdcontactptr->user, contactptr->user) ||
1656                                         strcmp(tdcontactptr->pass, contactptr->pass) ||
1657                                         strcmp(tdcontactptr->hostport, contactptr->hostport) ||
1658                                         strcmp(tdcontactptr->headers, contactptr->headers) ||
1659                                         strcmp(tdcontactptr->expires, contactptr->expires) ||
1660                                         strcmp(tdcontactptr->q, contactptr->q) ||
1661                                         strcmp(tdcontactptr->params.transport, contactptr->params.transport) ||
1662                                         strcmp(tdcontactptr->params.ttl, contactptr->params.ttl) ||
1663                                         (tdcontactptr->params.lr != contactptr->params.lr)
1664                                         ) {
1665                                         ast_test_status_update(test, "Sub-Test: %s,failed.\n", testdataptr->desc);
1666                                         res = AST_TEST_FAIL;
1667                                         break;
1668                                 }
1669
1670                                 contactptr = AST_LIST_NEXT(contactptr,list);
1671                         }
1672
1673                         while ((contactptr = AST_LIST_REMOVE_HEAD(contactlistptr,list))) {
1674                                 ast_free(contactptr);
1675                         }
1676                 }
1677         }
1678
1679         return res;
1680 }
1681 #endif
1682
1683 /*!
1684  * \brief Parse supported header in incoming packet
1685  *
1686  * \details This function parses through the options parameters and
1687  * builds a bit field representing all the SIP options in that field. When an
1688  * item is found that is not supported, it is copied to the unsupported
1689  * out buffer.
1690  *
1691  * \param options list
1692  * \param unsupported out buffer (optional)
1693  * \param unsupported_len out buffer length (optional)
1694  */
1695 unsigned int parse_sip_options(const char *options, char *unsupported, size_t unsupported_len)
1696 {
1697         char *next, *sep;
1698         char *temp;
1699         int i, found, supported;
1700         unsigned int profile = 0;
1701
1702         char *out = unsupported;
1703         size_t outlen = unsupported_len;
1704         char *cur_out = out;
1705
1706         if (ast_strlen_zero(options) )
1707                 return 0;
1708
1709         temp = ast_strdupa(options);
1710
1711         ast_debug(3, "Begin: parsing SIP \"Supported: %s\"\n", options);
1712         for (next = temp; next; next = sep) {
1713                 found = FALSE;
1714                 supported = FALSE;
1715                 if ((sep = strchr(next, ',')) != NULL) {
1716                         *sep++ = '\0';
1717                 }
1718
1719                 /* trim leading and trailing whitespace */
1720                 next = ast_strip(next);
1721
1722                 if (ast_strlen_zero(next)) {
1723                         continue; /* if there is a blank argument in there just skip it */
1724                 }
1725
1726                 ast_debug(3, "Found SIP option: -%s-\n", next);
1727                 for (i = 0; i < ARRAY_LEN(sip_options); i++) {
1728                         if (!strcasecmp(next, sip_options[i].text)) {
1729                                 profile |= sip_options[i].id;
1730                                 if (sip_options[i].supported == SUPPORTED) {
1731                                         supported = TRUE;
1732                                 }
1733                                 found = TRUE;
1734                                 ast_debug(3, "Matched SIP option: %s\n", next);
1735                                 break;
1736                         }
1737                 }
1738
1739                 /* If option is not supported, add to unsupported out buffer */
1740                 if (!supported && out && outlen) {
1741                         size_t copylen = strlen(next);
1742                         size_t cur_outlen = strlen(out);
1743                         /* Check to see if there is enough room to store this option.
1744                          * Copy length is string length plus 2 for the ',' and '\0' */
1745                         if ((cur_outlen + copylen + 2) < outlen) {
1746                                 /* if this isn't the first item, add the ',' */
1747                                 if (cur_outlen) {
1748                                         *cur_out = ',';
1749                                         cur_out++;
1750                                         cur_outlen++;
1751                                 }
1752                                 ast_copy_string(cur_out, next, (outlen - cur_outlen));
1753                                 cur_out += copylen;
1754                         }
1755                 }
1756
1757                 if (!found) {
1758                         profile |= SIP_OPT_UNKNOWN;
1759                         if (!strncasecmp(next, "x-", 2))
1760                                 ast_debug(3, "Found private SIP option, not supported: %s\n", next);
1761                         else
1762                                 ast_debug(3, "Found no match for SIP option: %s (Please file bug report!)\n", next);
1763                 }
1764         }
1765
1766         return profile;
1767 }
1768
1769 #ifdef TEST_FRAMEWORK
1770 AST_TEST_DEFINE(sip_parse_options_test)
1771 {
1772         int res = AST_TEST_PASS;
1773         char unsupported[64];
1774         unsigned int option_profile = 0;
1775         struct testdata {
1776                 char *name;
1777                 char *input_options;
1778                 char *expected_unsupported;
1779                 unsigned int expected_profile;
1780                 AST_LIST_ENTRY(testdata) list;
1781         };
1782
1783         struct testdata *testdataptr;
1784         static AST_LIST_HEAD_NOLOCK(testdataliststruct, testdata) testdatalist;
1785
1786         struct testdata test1 = {
1787                 .name = "test_all_unsupported",
1788                 .input_options = "unsupported1,,, ,unsupported2,unsupported3,unsupported4",
1789                 .expected_unsupported = "unsupported1,unsupported2,unsupported3,unsupported4",
1790                 .expected_profile = SIP_OPT_UNKNOWN,
1791         };
1792         struct testdata test2 = {
1793                 .name = "test_all_unsupported_one_supported",
1794                 .input_options = "  unsupported1, replaces,   unsupported3  , , , ,unsupported4",
1795                 .expected_unsupported = "unsupported1,unsupported3,unsupported4",
1796                 .expected_profile = SIP_OPT_UNKNOWN | SIP_OPT_REPLACES
1797         };
1798         struct testdata test3 = {
1799                 .name = "test_two_supported_two_unsupported",
1800                 .input_options = ",,  timer  ,replaces     ,unsupported3,unsupported4",
1801                 .expected_unsupported = "unsupported3,unsupported4",
1802                 .expected_profile = SIP_OPT_UNKNOWN | SIP_OPT_REPLACES | SIP_OPT_TIMER,
1803         };
1804
1805         struct testdata test4 = {
1806                 .name = "test_all_supported",
1807                 .input_options = "timer,replaces",
1808                 .expected_unsupported = "",
1809                 .expected_profile = SIP_OPT_REPLACES | SIP_OPT_TIMER,
1810         };
1811
1812         struct testdata test5 = {
1813                 .name = "test_all_supported_redundant",
1814                 .input_options = "timer,replaces,timer,replace,timer,replaces",
1815                 .expected_unsupported = "",
1816                 .expected_profile = SIP_OPT_REPLACES | SIP_OPT_TIMER,
1817         };
1818         struct testdata test6 = {
1819                 .name = "test_buffer_overflow",
1820                 .input_options = "unsupported1,replaces,timer,unsupported4,unsupported_huge____"
1821                 "____________________________________,__________________________________________"
1822                 "________________________________________________",
1823                 .expected_unsupported = "unsupported1,unsupported4",
1824                 .expected_profile = SIP_OPT_UNKNOWN | SIP_OPT_REPLACES | SIP_OPT_TIMER,
1825         };
1826         struct testdata test7 = {
1827                 .name = "test_null_input",
1828                 .input_options = NULL,
1829                 .expected_unsupported = "",
1830                 .expected_profile = 0,
1831         };
1832         struct testdata test8 = {
1833                 .name = "test_whitespace_input",
1834                 .input_options = "         ",
1835                 .expected_unsupported = "",
1836                 .expected_profile = 0,
1837         };
1838         struct testdata test9 = {
1839                 .name = "test_whitespace_plus_option_input",
1840                 .input_options = " , , ,timer , ,  , ,        ,    ",
1841                 .expected_unsupported = "",
1842                 .expected_profile = SIP_OPT_TIMER,
1843         };
1844
1845         switch (cmd) {
1846         case TEST_INIT:
1847                 info->name = "sip_parse_options_test";
1848                 info->category = "/channels/chan_sip/";
1849                 info->summary = "Tests parsing of sip options";
1850                 info->description =
1851                                                         "Tests parsing of SIP options from supported and required "
1852                                                         "header fields.  Verifies when unsupported options are encountered "
1853                                                         "that they are appended to the unsupported out buffer and that the "
1854                                                         "correct bit field representnig the option profile is returned.";
1855                 return AST_TEST_NOT_RUN;
1856         case TEST_EXECUTE:
1857                 break;
1858         }
1859
1860         AST_LIST_HEAD_SET_NOLOCK(&testdatalist, &test1);
1861         AST_LIST_INSERT_TAIL(&testdatalist, &test2, list);
1862         AST_LIST_INSERT_TAIL(&testdatalist, &test3, list);
1863         AST_LIST_INSERT_TAIL(&testdatalist, &test4, list);
1864         AST_LIST_INSERT_TAIL(&testdatalist, &test5, list);
1865         AST_LIST_INSERT_TAIL(&testdatalist, &test6, list);
1866         AST_LIST_INSERT_TAIL(&testdatalist, &test7, list);
1867         AST_LIST_INSERT_TAIL(&testdatalist, &test8, list);
1868         AST_LIST_INSERT_TAIL(&testdatalist, &test9, list);
1869
1870         /* Test with unsupported char buffer */
1871         AST_LIST_TRAVERSE(&testdatalist, testdataptr, list) {
1872                 memset(unsupported, 0, sizeof(unsupported));
1873                 option_profile = parse_sip_options(testdataptr->input_options, unsupported, ARRAY_LEN(unsupported));
1874                 if (option_profile != testdataptr->expected_profile ||
1875                         strcmp(unsupported, testdataptr->expected_unsupported)) {
1876                         ast_test_status_update(test, "Test with output buffer \"%s\", expected unsupported: %s actual unsupported:"
1877                                 "%s expected bit profile: %x actual bit profile: %x\n",
1878                                 testdataptr->name,
1879                                 testdataptr->expected_unsupported,
1880                                 unsupported,
1881                                 testdataptr->expected_profile,
1882                                 option_profile);
1883                         res = AST_TEST_FAIL;
1884                 } else {
1885                         ast_test_status_update(test, "\"%s\" passed got expected unsupported: %s and bit profile: %x\n",
1886                                 testdataptr->name,
1887                                 unsupported,
1888                                 option_profile);
1889                 }
1890
1891                 option_profile = parse_sip_options(testdataptr->input_options, NULL, 0);
1892                 if (option_profile != testdataptr->expected_profile) {
1893                         ast_test_status_update(test, "NULL output test \"%s\", expected bit profile: %x actual bit profile: %x\n",
1894                                 testdataptr->name,
1895                                 testdataptr->expected_profile,
1896                                 option_profile);
1897                         res = AST_TEST_FAIL;
1898                 } else {
1899                         ast_test_status_update(test, "\"%s\" with NULL output buf passed, bit profile: %x\n",
1900                                 testdataptr->name,
1901                                 option_profile);
1902                 }
1903         }
1904
1905         return res;
1906 }
1907 #endif
1908
1909 /*! \brief helper routine for sip_uri_cmp to compare URI parameters
1910  *
1911  * This takes the parameters from two SIP URIs and determines
1912  * if the URIs match. The rules for parameters *suck*. Here's a breakdown
1913  * 1. If a parameter appears in both URIs, then they must have the same value
1914  *    in order for the URIs to match
1915  * 2. If one URI has a user, maddr, ttl, or method parameter, then the other
1916  *    URI must also have that parameter and must have the same value
1917  *    in order for the URIs to match
1918  * 3. All other headers appearing in only one URI are not considered when
1919  *    determining if URIs match
1920  *
1921  * \param input1 Parameters from URI 1
1922  * \param input2 Parameters from URI 2
1923  * \retval 0 URIs' parameters match
1924  * \retval nonzero URIs' parameters do not match
1925  */
1926 static int sip_uri_params_cmp(const char *input1, const char *input2)
1927 {
1928         char *params1 = NULL;
1929         char *params2 = NULL;
1930         char *pos1;
1931         char *pos2;
1932         int zerolength1 = 0;
1933         int zerolength2 = 0;
1934         int maddrmatch = 0;
1935         int ttlmatch = 0;
1936         int usermatch = 0;
1937         int methodmatch = 0;
1938
1939         if (ast_strlen_zero(input1)) {
1940                 zerolength1 = 1;
1941         } else {
1942                 params1 = ast_strdupa(input1);
1943         }
1944         if (ast_strlen_zero(input2)) {
1945                 zerolength2 = 1;
1946         } else {
1947                 params2 = ast_strdupa(input2);
1948         }
1949
1950         /* Quick optimization. If both params are zero-length, then
1951          * they match
1952          */
1953         if (zerolength1 && zerolength2) {
1954                 return 0;
1955         }
1956
1957         for (pos1 = strsep(&params1, ";"); pos1; pos1 = strsep(&params1, ";")) {
1958                 char *value1 = pos1;
1959                 char *name1 = strsep(&value1, "=");
1960                 char *params2dup = NULL;
1961                 int matched = 0;
1962                 if (!value1) {
1963                         value1 = "";
1964                 }
1965                 /* Checkpoint reached. We have the name and value parsed for param1
1966                  * We have to duplicate params2 each time through this loop
1967                  * or else the inner loop below will not work properly.
1968                  */
1969                 if (!zerolength2) {
1970                         params2dup = ast_strdupa(params2);
1971                 }
1972                 for (pos2 = strsep(&params2dup, ";"); pos2; pos2 = strsep(&params2dup, ";")) {
1973                         char *name2 = pos2;
1974                         char *value2 = strchr(pos2, '=');
1975                         if (!value2) {
1976                                 value2 = "";
1977                         } else {
1978                                 *value2++ = '\0';
1979                         }
1980                         if (!strcasecmp(name1, name2)) {
1981                                 if (strcasecmp(value1, value2)) {
1982                                         goto fail;
1983                                 } else {
1984                                         matched = 1;
1985                                         break;
1986                                 }
1987                         }
1988                 }
1989                 /* Check to see if the parameter is one of the 'must-match' parameters */
1990                 if (!strcasecmp(name1, "maddr")) {
1991                         if (matched) {
1992                                 maddrmatch = 1;
1993                         } else {
1994                                 goto fail;
1995                         }
1996                 } else if (!strcasecmp(name1, "ttl")) {
1997                         if (matched) {
1998                                 ttlmatch = 1;
1999                         } else {
2000                                 goto fail;
2001                         }
2002                 } else if (!strcasecmp(name1, "user")) {
2003                         if (matched) {
2004                                 usermatch = 1;
2005                         } else {
2006                                 goto fail;
2007                         }
2008                 } else if (!strcasecmp(name1, "method")) {
2009                         if (matched) {
2010                                 methodmatch = 1;
2011                         } else {
2012                                 goto fail;
2013                         }
2014                 }
2015         }
2016
2017         /* We've made it out of that horrible O(m*n) construct and there are no
2018          * failures yet. We're not done yet, though, because params2 could have
2019          * an maddr, ttl, user, or method header and params1 did not.
2020          */
2021         for (pos2 = strsep(&params2, ";"); pos2; pos2 = strsep(&params2, ";")) {
2022                 char *value2 = pos2;
2023                 char *name2 = strsep(&value2, "=");
2024                 if (!value2) {
2025                         value2 = "";
2026                 }
2027                 if ((!strcasecmp(name2, "maddr") && !maddrmatch) ||
2028                                 (!strcasecmp(name2, "ttl") && !ttlmatch) ||
2029                                 (!strcasecmp(name2, "user") && !usermatch) ||
2030                                 (!strcasecmp(name2, "method") && !methodmatch)) {
2031                         goto fail;
2032                 }
2033         }
2034         return 0;
2035
2036 fail:
2037         return 1;
2038 }
2039
2040 /*! \brief helper routine for sip_uri_cmp to compare URI headers
2041  *
2042  * This takes the headers from two SIP URIs and determines
2043  * if the URIs match. The rules for headers is simple. If a header
2044  * appears in one URI, then it must also appear in the other URI. The
2045  * order in which the headers appear does not matter.
2046  *
2047  * \param input1 Headers from URI 1
2048  * \param input2 Headers from URI 2
2049  * \retval 0 URI headers match
2050  * \retval nonzero URI headers do not match
2051  */
2052 static int sip_uri_headers_cmp(const char *input1, const char *input2)
2053 {
2054         char *headers1 = NULL;
2055         char *headers2 = NULL;
2056         int zerolength1 = 0;
2057         int zerolength2 = 0;
2058         int different = 0;
2059         char *header1;
2060
2061         if (ast_strlen_zero(input1)) {
2062                 zerolength1 = 1;
2063         } else {
2064                 headers1 = ast_strdupa(input1);
2065         }
2066
2067         if (ast_strlen_zero(input2)) {
2068                 zerolength2 = 1;
2069         } else {
2070                 headers2 = ast_strdupa(input2);
2071         }
2072
2073         /* If one URI contains no headers and the other
2074          * does, then they cannot possibly match
2075          */
2076         if (zerolength1 != zerolength2) {
2077                 return 1;
2078         }
2079
2080         if (zerolength1 && zerolength2)
2081                 return 0;
2082
2083         /* At this point, we can definitively state that both inputs are
2084          * not zero-length. First, one more optimization. If the length
2085          * of the headers is not equal, then we definitely have no match
2086          */
2087         if (strlen(headers1) != strlen(headers2)) {
2088                 return 1;
2089         }
2090
2091         for (header1 = strsep(&headers1, "&"); header1; header1 = strsep(&headers1, "&")) {
2092                 if (!strcasestr(headers2, header1)) {
2093                         different = 1;
2094                         break;
2095                 }
2096         }
2097
2098         return different;
2099 }
2100
2101 /*!
2102  * \brief Compare domain sections of SIP URIs
2103  *
2104  * For hostnames, a case insensitive string comparison is
2105  * used. For IP addresses, a binary comparison is used. This
2106  * is mainly because IPv6 addresses have many ways of writing
2107  * the same address.
2108  *
2109  * For specifics about IP address comparison, see the following
2110  * document: http://tools.ietf.org/html/draft-ietf-sip-ipv6-abnf-fix-05
2111  *
2112  * \param host1 The domain from the first URI
2113  * \param host2 THe domain from the second URI
2114  * \retval 0 The domains match
2115  * \retval nonzero The domains do not match
2116  */
2117 static int sip_uri_domain_cmp(const char *host1, const char *host2)
2118 {
2119         struct ast_sockaddr addr1;
2120         struct ast_sockaddr addr2;
2121         int addr1_parsed;
2122         int addr2_parsed;
2123
2124         addr1_parsed = ast_sockaddr_parse(&addr1, host1, 0);
2125         addr2_parsed = ast_sockaddr_parse(&addr2, host2, 0);
2126
2127         if (addr1_parsed != addr2_parsed) {
2128                 /* One domain was an IP address and the other had
2129                  * a host name. FAIL!
2130                  */
2131                 return 1;
2132         }
2133
2134         /* Both are host names. A string comparison will work
2135          * perfectly here. Specifying the "C" locale ensures that
2136          * The LC_CTYPE conventions use those defined in ANSI C,
2137          * i.e. ASCII.
2138          */
2139         if (!addr1_parsed) {
2140 #ifdef HAVE_XLOCALE_H
2141                 if(!c_locale) {
2142                         return strcasecmp(host1, host2);
2143                 } else {
2144                         return strcasecmp_l(host1, host2, c_locale);
2145                 }
2146 #else
2147                 return strcasecmp(host1, host2);
2148 #endif
2149         }
2150
2151         /* Both contain IP addresses */
2152         return ast_sockaddr_cmp(&addr1, &addr2);
2153 }
2154
2155 int sip_uri_cmp(const char *input1, const char *input2)
2156 {
2157         char *uri1;
2158         char *uri2;
2159         char *uri_scheme1;
2160         char *uri_scheme2;
2161         char *host1;
2162         char *host2;
2163         char *params1;
2164         char *params2;
2165         char *headers1;
2166         char *headers2;
2167
2168         /* XXX It would be really nice if we could just use parse_uri_full() here
2169          * to separate the components of the URI, but unfortunately it is written
2170          * in a way that can cause URI parameters to be discarded.
2171          */
2172
2173         if (!input1 || !input2) {
2174                 return 1;
2175         }
2176
2177         uri1 = ast_strdupa(input1);
2178         uri2 = ast_strdupa(input2);
2179
2180         ast_uri_decode(uri1, ast_uri_sip_user);
2181         ast_uri_decode(uri2, ast_uri_sip_user);
2182
2183         uri_scheme1 = strsep(&uri1, ":");
2184         uri_scheme2 = strsep(&uri2, ":");
2185
2186         if (strcmp(uri_scheme1, uri_scheme2)) {
2187                 return 1;
2188         }
2189
2190         /* This function is tailored for SIP and SIPS URIs. There's no
2191          * need to check uri_scheme2 since we have determined uri_scheme1
2192          * and uri_scheme2 are equivalent already.
2193          */
2194         if (strcmp(uri_scheme1, "sip") && strcmp(uri_scheme1, "sips")) {
2195                 return 1;
2196         }
2197
2198         if (ast_strlen_zero(uri1) || ast_strlen_zero(uri2)) {
2199                 return 1;
2200         }
2201
2202         if ((host1 = strchr(uri1, '@'))) {
2203                 *host1++ = '\0';
2204         }
2205         if ((host2 = strchr(uri2, '@'))) {
2206                 *host2++ = '\0';
2207         }
2208
2209         /* Check for mismatched username and passwords. This is the
2210          * only case-sensitive comparison of a SIP URI
2211          */
2212         if ((host1 && !host2) ||
2213                         (host2 && !host1) ||
2214                         (host1 && host2 && strcmp(uri1, uri2))) {
2215                 return 1;
2216         }
2217
2218         if (!host1) {
2219                 host1 = uri1;
2220         }
2221         if (!host2) {
2222                 host2 = uri2;
2223         }
2224
2225         /* Strip off the parameters and headers so we can compare
2226          * host and port
2227          */
2228
2229         if ((params1 = strchr(host1, ';'))) {
2230                 *params1++ = '\0';
2231         }
2232         if ((params2 = strchr(host2, ';'))) {
2233                 *params2++ = '\0';
2234         }
2235
2236         /* Headers come after parameters, but there may be headers without
2237          * parameters, thus the S_OR
2238          */
2239         if ((headers1 = strchr(S_OR(params1, host1), '?'))) {
2240                 *headers1++ = '\0';
2241         }
2242         if ((headers2 = strchr(S_OR(params2, host2), '?'))) {
2243                 *headers2++ = '\0';
2244         }
2245
2246         if (sip_uri_domain_cmp(host1, host2)) {
2247                 return 1;
2248         }
2249
2250         /* Headers have easier rules to follow, so do those first */
2251         if (sip_uri_headers_cmp(headers1, headers2)) {
2252                 return 1;
2253         }
2254
2255         /* And now the parameters. Ugh */
2256         return sip_uri_params_cmp(params1, params2);
2257 }
2258
2259 #define URI_CMP_MATCH 0
2260 #define URI_CMP_NOMATCH 1
2261
2262 #ifdef TEST_FRAMEWORK
2263 AST_TEST_DEFINE(sip_uri_cmp_test)
2264 {
2265         static const struct {
2266                 const char *uri1;
2267                 const char *uri2;
2268                 int expected_result;
2269         } uri_cmp_tests [] = {
2270                 /* These are identical, so they match */
2271                 { "sip:bob@example.com", "sip:bob@example.com", URI_CMP_MATCH },
2272                 /* Different usernames. No match */
2273                 { "sip:alice@example.com", "sip:bob@example.com", URI_CMP_NOMATCH },
2274                 /* Different hosts. No match */
2275                 { "sip:bob@example.com", "sip:bob@examplez.com", URI_CMP_NOMATCH },
2276                 /* Now start using IP addresses. Identical, so they match */
2277                 { "sip:bob@1.2.3.4", "sip:bob@1.2.3.4", URI_CMP_MATCH },
2278                 /* Two identical IPv4 addresses represented differently. Match */
2279                 { "sip:bob@1.2.3.4", "sip:bob@001.002.003.004", URI_CMP_MATCH },
2280                 /* Logically equivalent IPv4 Address and hostname. No Match */
2281                 { "sip:bob@127.0.0.1", "sip:bob@localhost", URI_CMP_NOMATCH },
2282                 /* Logically equivalent IPv6 address and hostname. No Match */
2283                 { "sip:bob@[::1]", "sip:bob@localhost", URI_CMP_NOMATCH },
2284                 /* Try an IPv6 one as well */
2285                 { "sip:bob@[2001:db8::1234]", "sip:bob@[2001:db8::1234]", URI_CMP_MATCH },
2286                 /* Two identical IPv6 addresses represented differently. Match */
2287                 { "sip:bob@[2001:db8::1234]", "sip:bob@[2001:0db8::1234]", URI_CMP_MATCH },
2288                 /* Different ports. No match */
2289                 { "sip:bob@1.2.3.4:5060", "sip:bob@1.2.3.4:5061", URI_CMP_NOMATCH },
2290                 /* Same port logically, but only one address specifies it. No match */
2291                 { "sip:bob@1.2.3.4:5060", "sip:bob@1.2.3.4", URI_CMP_NOMATCH },
2292                 /* And for safety, try with IPv6 */
2293                 { "sip:bob@[2001:db8:1234]:5060", "sip:bob@[2001:db8:1234]", URI_CMP_NOMATCH },
2294                 /* User comparison is case sensitive. No match */
2295                 { "sip:bob@example.com", "sip:BOB@example.com", URI_CMP_NOMATCH },
2296                 /* Host comparison is case insensitive. Match */
2297                 { "sip:bob@example.com", "sip:bob@EXAMPLE.COM", URI_CMP_MATCH },
2298                 /* Add headers to the URI. Identical, so they match */
2299                 { "sip:bob@example.com?header1=value1&header2=value2", "sip:bob@example.com?header1=value1&header2=value2", URI_CMP_MATCH },
2300                 /* Headers in URI 1 are not in URI 2. No Match */
2301                 { "sip:bob@example.com?header1=value1&header2=value2", "sip:bob@example.com", URI_CMP_NOMATCH },
2302                 /* Header present in both URIs does not have matching values. No match */
2303                 { "sip:bob@example.com?header1=value1&header2=value2", "sip:bob@example.com?header1=value1&header2=value3", URI_CMP_NOMATCH },
2304                 /* Add parameters to the URI. Identical so they match */
2305                 { "sip:bob@example.com;param1=value1;param2=value2", "sip:bob@example.com;param1=value1;param2=value2", URI_CMP_MATCH },
2306                 /* Same parameters in both URIs but appear in different order. Match */
2307                 { "sip:bob@example.com;param2=value2;param1=value1", "sip:bob@example.com;param1=value1;param2=value2", URI_CMP_MATCH },
2308                 /* params in URI 1 are not in URI 2. Match */
2309                 { "sip:bob@example.com;param1=value1;param2=value2", "sip:bob@example.com", URI_CMP_MATCH },
2310                 /* param present in both URIs does not have matching values. No match */
2311                 { "sip:bob@example.com;param1=value1;param2=value2", "sip:bob@example.com;param1=value1;param2=value3", URI_CMP_NOMATCH },
2312                 /* URI 1 has a maddr param but URI 2 does not. No match */
2313                 { "sip:bob@example.com;param1=value1;maddr=192.168.0.1", "sip:bob@example.com;param1=value1", URI_CMP_NOMATCH },
2314                 /* URI 1 and URI 2 both have identical maddr params. Match */
2315                 { "sip:bob@example.com;param1=value1;maddr=192.168.0.1", "sip:bob@example.com;param1=value1;maddr=192.168.0.1", URI_CMP_MATCH },
2316                 /* URI 1 is a SIPS URI and URI 2 is a SIP URI. No Match */
2317                 { "sips:bob@example.com", "sip:bob@example.com", URI_CMP_NOMATCH },
2318                 /* No URI schemes. No match */
2319                 { "bob@example.com", "bob@example.com", URI_CMP_NOMATCH },
2320                 /* Crashiness tests. Just an address scheme. No match */
2321                 { "sip", "sips", URI_CMP_NOMATCH },
2322                 /* Still just an address scheme. Even though they're the same, No match */
2323                 { "sip", "sip", URI_CMP_NOMATCH },
2324                 /* Empty strings. No match */
2325                 { "", "", URI_CMP_NOMATCH },
2326                 /* An empty string and a NULL. No match */
2327                 { "", NULL, URI_CMP_NOMATCH },
2328         };
2329         int i;
2330         int test_res = AST_TEST_PASS;
2331         switch (cmd) {
2332         case TEST_INIT:
2333                 info->name = "sip_uri_cmp_test";
2334                 info->category = "/channels/chan_sip/";
2335                 info->summary = "Tests comparison of SIP URIs";
2336                 info->description = "Several would-be tricky URI comparisons are performed";
2337                 return AST_TEST_NOT_RUN;
2338         case TEST_EXECUTE:
2339                 break;
2340         }
2341
2342         for (i = 0; i < ARRAY_LEN(uri_cmp_tests); ++i) {
2343                 int cmp_res1;
2344                 int cmp_res2;
2345                 if ((cmp_res1 = sip_uri_cmp(uri_cmp_tests[i].uri1, uri_cmp_tests[i].uri2))) {
2346                         /* URI comparison may return -1 or +1 depending on the failure. Standardize
2347                          * the return value to be URI_CMP_NOMATCH on any failure
2348                          */
2349                         cmp_res1 = URI_CMP_NOMATCH;
2350                 }
2351                 if (cmp_res1 != uri_cmp_tests[i].expected_result) {
2352                         ast_test_status_update(test, "Unexpected comparison result for URIs %s and %s. "
2353                                         "Expected %s but got %s\n", uri_cmp_tests[i].uri1, uri_cmp_tests[i].uri2,
2354                                         uri_cmp_tests[i].expected_result == URI_CMP_MATCH ? "Match" : "No Match",
2355                                         cmp_res1 == URI_CMP_MATCH ? "Match" : "No Match");
2356                         test_res = AST_TEST_FAIL;
2357                 }
2358
2359                 /* All URI comparisons are commutative, so for the sake of being thorough, we'll
2360                  * rerun the comparison with the parameters reversed
2361                  */
2362                 if ((cmp_res2 = sip_uri_cmp(uri_cmp_tests[i].uri2, uri_cmp_tests[i].uri1))) {
2363                         /* URI comparison may return -1 or +1 depending on the failure. Standardize
2364                          * the return value to be URI_CMP_NOMATCH on any failure
2365                          */
2366                         cmp_res2 = URI_CMP_NOMATCH;
2367                 }
2368                 if (cmp_res2 != uri_cmp_tests[i].expected_result) {
2369                         ast_test_status_update(test, "Unexpected comparison result for URIs %s and %s. "
2370                                         "Expected %s but got %s\n", uri_cmp_tests[i].uri2, uri_cmp_tests[i].uri1,
2371                                         uri_cmp_tests[i].expected_result == URI_CMP_MATCH ? "Match" : "No Match",
2372                                         cmp_res2 == URI_CMP_MATCH ? "Match" : "No Match");
2373                         test_res = AST_TEST_FAIL;
2374                 }
2375         }
2376
2377         return test_res;
2378 }
2379 #endif
2380
2381 void free_via(struct sip_via *v)
2382 {
2383         if (!v) {
2384                 return;
2385         }
2386
2387         ast_free(v->via);
2388         ast_free(v);
2389 }
2390
2391 struct sip_via *parse_via(const char *header)
2392 {
2393         struct sip_via *v = ast_calloc(1, sizeof(*v));
2394         char *via, *parm;
2395
2396         if (!v) {
2397                 return NULL;
2398         }
2399
2400         v->via = ast_strdup(header);
2401         v->ttl = 1;
2402
2403         via = v->via;
2404
2405         if (ast_strlen_zero(via)) {
2406                 ast_log(LOG_ERROR, "received request without a Via header\n");
2407                 free_via(v);
2408                 return NULL;
2409         }
2410
2411         /* seperate the first via-parm */
2412         via = strsep(&via, ",");
2413
2414         /* chop off sent-protocol */
2415         v->protocol = strsep(&via, " \t\r\n");
2416         if (ast_strlen_zero(v->protocol)) {
2417                 ast_log(LOG_ERROR, "missing sent-protocol in Via header\n");
2418                 free_via(v);
2419                 return NULL;
2420         }
2421         v->protocol = ast_skip_blanks(v->protocol);
2422
2423         if (via) {
2424                 via = ast_skip_blanks(via);
2425         }
2426
2427         /* chop off sent-by */
2428         v->sent_by = strsep(&via, "; \t\r\n");
2429         if (ast_strlen_zero(v->sent_by)) {
2430                 ast_log(LOG_ERROR, "missing sent-by in Via header\n");
2431                 free_via(v);
2432                 return NULL;
2433         }
2434         v->sent_by = ast_skip_blanks(v->sent_by);
2435
2436         /* store the port, we have to handle ipv6 addresses containing ':'
2437          * characters gracefully */
2438         if (((parm = strchr(v->sent_by, ']')) && *(++parm) == ':') || (!(parm = strchr(v->sent_by, ']')) && (parm = strchr(v->sent_by, ':')))) {
2439                 char *endptr;
2440
2441                 v->port = strtol(++parm, &endptr, 10);
2442         }
2443
2444         /* evaluate any via-parms */
2445         while ((parm = strsep(&via, "; \t\r\n"))) {
2446                 char *c;
2447                 if ((c = strstr(parm, "maddr="))) {
2448                         v->maddr = ast_skip_blanks(c + sizeof("maddr=") - 1);
2449                 } else if ((c = strstr(parm, "branch="))) {
2450                         v->branch = ast_skip_blanks(c + sizeof("branch=") - 1);
2451                 } else if ((c = strstr(parm, "ttl="))) {
2452                         char *endptr;
2453                         c = ast_skip_blanks(c + sizeof("ttl=") - 1);
2454                         v->ttl = strtol(c, &endptr, 10);
2455
2456                         /* make sure we got a valid ttl value */
2457                         if (c == endptr) {
2458                                 v->ttl = 1;
2459                         }
2460                 }
2461         }
2462
2463         return v;
2464 }
2465
2466 #ifdef TEST_FRAMEWORK
2467 AST_TEST_DEFINE(parse_via_test)
2468 {
2469         int res = AST_TEST_PASS;
2470         int i = 1;
2471         struct sip_via *via;
2472         struct testdata {
2473                 char *in;
2474                 char *expected_protocol;
2475                 char *expected_branch;
2476                 char *expected_sent_by;
2477                 char *expected_maddr;
2478                 unsigned int expected_port;
2479                 unsigned char expected_ttl;
2480                 int expected_null;
2481                 AST_LIST_ENTRY(testdata) list;
2482         };
2483         struct testdata *testdataptr;
2484         static AST_LIST_HEAD_NOLOCK(testdataliststruct, testdata) testdatalist;
2485         struct testdata t1 = {
2486                 .in = "SIP/2.0/UDP host:port;branch=thebranch",
2487                 .expected_protocol = "SIP/2.0/UDP",
2488                 .expected_sent_by = "host:port",
2489                 .expected_branch = "thebranch",
2490         };
2491         struct testdata t2 = {
2492                 .in = "SIP/2.0/UDP host:port",
2493                 .expected_protocol = "SIP/2.0/UDP",
2494                 .expected_sent_by = "host:port",
2495                 .expected_branch = "",
2496         };
2497         struct testdata t3 = {
2498                 .in = "SIP/2.0/UDP",
2499                 .expected_null = 1,
2500         };
2501         struct testdata t4 = {
2502                 .in = "BLAH/BLAH/BLAH host:port;branch=",
2503                 .expected_protocol = "BLAH/BLAH/BLAH",
2504                 .expected_sent_by = "host:port",
2505                 .expected_branch = "",
2506         };
2507         struct testdata t5 = {
2508                 .in = "SIP/2.0/UDP host:5060;branch=thebranch;maddr=224.0.0.1;ttl=1",
2509                 .expected_protocol = "SIP/2.0/UDP",
2510                 .expected_sent_by = "host:5060",
2511                 .expected_port = 5060,
2512                 .expected_branch = "thebranch",
2513                 .expected_maddr = "224.0.0.1",
2514                 .expected_ttl = 1,
2515         };
2516         struct testdata t6 = {
2517                 .in = "SIP/2.0/UDP      host:5060;\n   branch=thebranch;\r\n  maddr=224.0.0.1;   ttl=1",
2518                 .expected_protocol = "SIP/2.0/UDP",
2519                 .expected_sent_by = "host:5060",
2520                 .expected_port = 5060,
2521                 .expected_branch = "thebranch",
2522                 .expected_maddr = "224.0.0.1",
2523                 .expected_ttl = 1,
2524         };
2525         struct testdata t7 = {
2526                 .in = "SIP/2.0/UDP [::1]:5060",
2527                 .expected_protocol = "SIP/2.0/UDP",
2528                 .expected_sent_by = "[::1]:5060",
2529                 .expected_port = 5060,
2530                 .expected_branch = "",
2531         };
2532         switch (cmd) {
2533         case TEST_INIT:
2534                 info->name = "parse_via_test";
2535                 info->category = "/channels/chan_sip/";
2536                 info->summary = "Tests parsing the Via header";
2537                 info->description =
2538                                 "Runs through various test situations in which various "
2539                                 " parameters parameter must be extracted from a VIA header";
2540                 return AST_TEST_NOT_RUN;
2541         case TEST_EXECUTE:
2542                 break;
2543         }
2544
2545         AST_LIST_HEAD_SET_NOLOCK(&testdatalist, &t1);
2546         AST_LIST_INSERT_TAIL(&testdatalist, &t2, list);
2547         AST_LIST_INSERT_TAIL(&testdatalist, &t3, list);
2548         AST_LIST_INSERT_TAIL(&testdatalist, &t4, list);
2549         AST_LIST_INSERT_TAIL(&testdatalist, &t5, list);
2550         AST_LIST_INSERT_TAIL(&testdatalist, &t6, list);
2551         AST_LIST_INSERT_TAIL(&testdatalist, &t7, list);
2552
2553
2554         AST_LIST_TRAVERSE(&testdatalist, testdataptr, list) {
2555                 via = parse_via(testdataptr->in);
2556                 if (!via) {
2557                         if (!testdataptr->expected_null) {
2558                                 ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
2559                                         "failed to parse header\n",
2560                                 i, testdataptr->in);
2561                                 res = AST_TEST_FAIL;
2562                         }
2563                         i++;
2564                         continue;
2565                 }
2566
2567                 if (testdataptr->expected_null) {
2568                         ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
2569                                 "successfully parased invalid via header\n",
2570                         i, testdataptr->in);
2571                         res = AST_TEST_FAIL;
2572                         free_via(via);
2573                         i++;
2574                         continue;
2575                 }
2576
2577                 if ((ast_strlen_zero(via->protocol) && !ast_strlen_zero(testdataptr->expected_protocol))
2578                         || (!ast_strlen_zero(via->protocol) && strcmp(via->protocol, testdataptr->expected_protocol))) {
2579
2580                         ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
2581                                 "parsed protocol = \"%s\"\n"
2582                                 "expected = \"%s\"\n"
2583                                 "failed to parse protocol\n",
2584                         i, testdataptr->in, via->protocol, testdataptr->expected_protocol);
2585                         res = AST_TEST_FAIL;
2586                 }
2587
2588                 if ((ast_strlen_zero(via->sent_by) && !ast_strlen_zero(testdataptr->expected_sent_by))
2589                         || (!ast_strlen_zero(via->sent_by) && strcmp(via->sent_by, testdataptr->expected_sent_by))) {
2590
2591                         ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
2592                                 "parsed sent_by = \"%s\"\n"
2593                                 "expected = \"%s\"\n"
2594                                 "failed to parse sent-by\n",
2595                         i, testdataptr->in, via->sent_by, testdataptr->expected_sent_by);
2596                         res = AST_TEST_FAIL;
2597                 }
2598
2599                 if (testdataptr->expected_port && testdataptr->expected_port != via->port) {
2600                         ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
2601                                 "parsed port = \"%u\"\n"
2602                                 "expected = \"%u\"\n"
2603                                 "failed to parse port\n",
2604                         i, testdataptr->in, via->port, testdataptr->expected_port);
2605                         res = AST_TEST_FAIL;
2606                 }
2607
2608                 if ((ast_strlen_zero(via->branch) && !ast_strlen_zero(testdataptr->expected_branch))
2609                         || (!ast_strlen_zero(via->branch) && strcmp(via->branch, testdataptr->expected_branch))) {
2610
2611                         ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
2612                                 "parsed branch = \"%s\"\n"
2613                                 "expected = \"%s\"\n"
2614                                 "failed to parse branch\n",
2615                         i, testdataptr->in, via->branch, testdataptr->expected_branch);
2616                         res = AST_TEST_FAIL;
2617                 }
2618
2619                 if ((ast_strlen_zero(via->maddr) && !ast_strlen_zero(testdataptr->expected_maddr))
2620                         || (!ast_strlen_zero(via->maddr) && strcmp(via->maddr, testdataptr->expected_maddr))) {
2621
2622                         ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
2623                                 "parsed maddr = \"%s\"\n"
2624                                 "expected = \"%s\"\n"
2625                                 "failed to parse maddr\n",
2626                         i, testdataptr->in, via->maddr, testdataptr->expected_maddr);
2627                         res = AST_TEST_FAIL;
2628                 }
2629
2630                 if (testdataptr->expected_ttl && testdataptr->expected_ttl != via->ttl) {
2631                         ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
2632                                 "parsed ttl = \"%d\"\n"
2633                                 "expected = \"%d\"\n"
2634                                 "failed to parse ttl\n",
2635                         i, testdataptr->in, via->ttl, testdataptr->expected_ttl);
2636                         res = AST_TEST_FAIL;
2637                 }
2638
2639                 free_via(via);
2640                 i++;
2641         }
2642         return res;
2643 }
2644 #endif
2645
2646 void sip_request_parser_register_tests(void)
2647 {
2648         AST_TEST_REGISTER(get_calleridname_test);
2649         AST_TEST_REGISTER(sip_parse_uri_test);
2650         AST_TEST_REGISTER(get_in_brackets_test);
2651         AST_TEST_REGISTER(get_name_and_number_test);
2652         AST_TEST_REGISTER(sip_parse_uri_full_test);
2653         AST_TEST_REGISTER(parse_name_andor_addr_test);
2654         AST_TEST_REGISTER(parse_contact_header_test);
2655         AST_TEST_REGISTER(sip_parse_options_test);
2656         AST_TEST_REGISTER(sip_uri_cmp_test);
2657         AST_TEST_REGISTER(parse_via_test);
2658 }
2659 void sip_request_parser_unregister_tests(void)
2660 {
2661         AST_TEST_UNREGISTER(sip_parse_uri_test);
2662         AST_TEST_UNREGISTER(get_calleridname_test);
2663         AST_TEST_UNREGISTER(get_in_brackets_test);
2664         AST_TEST_UNREGISTER(get_name_and_number_test);
2665         AST_TEST_UNREGISTER(sip_parse_uri_full_test);
2666         AST_TEST_UNREGISTER(parse_name_andor_addr_test);
2667         AST_TEST_UNREGISTER(parse_contact_header_test);
2668         AST_TEST_UNREGISTER(sip_parse_options_test);
2669         AST_TEST_UNREGISTER(sip_uri_cmp_test);
2670         AST_TEST_UNREGISTER(parse_via_test);
2671 }
2672
2673 int sip_reqresp_parser_init(void)
2674 {
2675 #ifdef HAVE_XLOCALE_H
2676         c_locale = newlocale(LC_CTYPE_MASK, "C", NULL);
2677         if (!c_locale) {
2678                 return -1;
2679         }
2680 #endif
2681         return 0;
2682 }
2683
2684 void sip_reqresp_parser_exit(void)
2685 {
2686 #ifdef HAVE_XLOCALE_H
2687         if (c_locale) {
2688                 freelocale(c_locale);
2689                 c_locale = NULL;
2690         }
2691 #endif
2692 }