1 /*
2 The oSIP library implements the Session Initiation Protocol (SIP -rfc3261-)
3 Copyright (C) 2001-2020 Aymeric MOIZARD amoizard@antisip.com
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 #include <osipparser2/internal.h>
21
22 #include <osipparser2/osip_port.h>
23 #include <osipparser2/osip_message.h>
24 #include <osipparser2/osip_parser.h>
25 #include "parser.h"
26
27 /* adds the from header to message. */
28 /* INPUT : char *hvalue | value of header. */
29 /* OUTPUT: osip_message_t *sip | structure to save results. */
30 /* returns -1 on error. */
osip_message_set_from(osip_message_t * sip,const char * hvalue)31 int osip_message_set_from(osip_message_t *sip, const char *hvalue) {
32 int i;
33
34 if (hvalue == NULL || hvalue[0] == '\0')
35 return OSIP_SUCCESS;
36
37 if (sip->from != NULL)
38 return OSIP_SYNTAXERROR;
39
40 i = osip_from_init(&(sip->from));
41
42 if (i != 0)
43 return i;
44
45 sip->message_property = 2;
46 i = osip_from_parse(sip->from, hvalue);
47
48 if (i != 0) {
49 osip_from_free(sip->from);
50 sip->from = NULL;
51 return i;
52 }
53
54 return OSIP_SUCCESS;
55 }
56
57 #ifndef MINISIZE
58 /* returns the from header. */
59 /* INPUT : osip_message_t *sip | sip message. */
60 /* returns null on error. */
osip_message_get_from(const osip_message_t * sip)61 osip_from_t *osip_message_get_from(const osip_message_t *sip) {
62 return sip->from;
63 }
64 #endif
65
osip_from_init(osip_from_t ** from)66 int osip_from_init(osip_from_t **from) {
67 *from = (osip_from_t *) osip_malloc(sizeof(osip_from_t));
68
69 if (*from == NULL)
70 return OSIP_NOMEM;
71
72 (*from)->displayname = NULL;
73 (*from)->url = NULL;
74
75 osip_list_init(&(*from)->gen_params);
76
77 return OSIP_SUCCESS;
78 }
79
80 /* deallocates a osip_from_t structure. */
81 /* INPUT : osip_from_t *from | from. */
osip_from_free(osip_from_t * from)82 void osip_from_free(osip_from_t *from) {
83 if (from == NULL)
84 return;
85
86 if (from->url != NULL) {
87 osip_uri_free(from->url);
88 }
89
90 osip_free(from->displayname);
91
92 osip_generic_param_freelist(&from->gen_params);
93
94 osip_free(from);
95 }
96
97 /* parses the string as a from header. */
98 /* INPUT : const char *string | pointer to a from string.*/
99 /* OUTPUT: osip_from_t *from | structure to save results. */
100 /* returns -1 on error. */
osip_from_parse(osip_from_t * from,const char * hvalue)101 int osip_from_parse(osip_from_t *from, const char *hvalue) {
102 const char *displayname = NULL;
103 const char *url = NULL;
104 const char *url_end = NULL;
105 const char *gen_params;
106 const char *ptr;
107 int i;
108
109 if (from == NULL || hvalue == NULL)
110 return OSIP_BADPARAMETER;
111
112 /* How to parse:
113
114 we'll place the pointers:
115 displayname => beginning of displayname
116 url => beginning of url
117 url_end => end of url
118 gen_params => beginning of params
119
120 examples:
121
122 jack <sip:amoizard@antisip.com>;tag=34erZ
123 ^ ^ ^ ^
124
125 sip:amoizard@antisip.com;tag=34erZ
126 ^ ^^
127 */
128 /* search for first char */
129 ptr = hvalue;
130
131 while (ptr[0] != '\0') {
132 if (ptr[0] == ' ') {
133 ptr++;
134 continue;
135 }
136
137 if (ptr[0] == '"') {
138 displayname = ptr;
139 break;
140 }
141
142 break;
143 }
144
145 if (ptr[0] == '\0')
146 return OSIP_SUCCESS; /* empty header allowed? */
147
148 if (displayname != NULL) {
149 /* displayname IS A quoted-string (not a '*token') */
150 const char *second = NULL;
151
152 /* search for quotes */
153 second = __osip_quote_find(displayname + 1);
154
155 if (second == NULL)
156 return OSIP_SYNTAXERROR; /* missing quote */
157
158 if (second - displayname + 2 >= 2) {
159 from->displayname = (char *) osip_malloc(second - displayname + 2);
160
161 if (from->displayname == NULL)
162 return OSIP_NOMEM;
163
164 osip_strncpy(from->displayname, displayname, second - displayname + 1);
165 /* osip_clrspace(from->displayname); */ /*should we do that? */
166
167 /* special case: "<sip:joe@big.org>" <sip:joe@really.big.com> */
168 } /* else displayname is empty? */
169
170 ptr = second + 1;
171
172 while (ptr[0] != '\0') {
173 if (ptr[0] == ' ') {
174 ptr++;
175 continue;
176 }
177
178 if (ptr[0] == '<') {
179 url = ptr;
180 break;
181 }
182
183 break;
184 }
185
186 if (url == NULL)
187 return OSIP_SYNTAXERROR; /* '<' MUST exist */
188
189 if (ptr[1] == '\0')
190 return OSIP_SYNTAXERROR; /* '<' MUST contain something */
191
192 } else {
193 /* 1*(alphanum / "-" / "." / "!" / "%" / "*" / "_" / "+" / "`" / "'" / "~" ) */
194 /* search for URL -> continue until non allowed element is found */
195 const char *beg = ptr;
196
197 while (ptr[0] != '\0') {
198 if (ptr[0] == ' ') {
199 ptr++;
200 continue;
201 }
202
203 if (ptr[0] >= 'a' && ptr[0] <= 'z') {
204 ptr++;
205 continue;
206 }
207
208 if (ptr[0] >= 'A' && ptr[0] <= 'Z') {
209 ptr++;
210 continue;
211 }
212
213 if (ptr[0] >= '0' && ptr[0] <= '9') {
214 ptr++;
215 continue;
216 }
217
218 if (ptr[0] == '-' || ptr[0] == '.' || ptr[0] == '!' || ptr[0] == '%' || ptr[0] == '*' || ptr[0] == '_' || ptr[0] == '+' || ptr[0] == '`' || ptr[0] == '\'' || ptr[0] == '~') {
219 ptr++;
220 continue;
221 }
222
223 url = ptr;
224 break;
225 }
226
227 if (ptr[0] == '\0' || url == NULL)
228 return OSIP_SYNTAXERROR; /* not special char found? broken header? */
229
230 if (ptr[0] == '<') {
231 /* "<" found for URI */
232 if (ptr[1] == '\0')
233 return OSIP_SYNTAXERROR; /* '<' MUST contain something */
234
235 if (url - beg > 0) {
236 from->displayname = (char *) osip_malloc(url - beg + 1);
237
238 if (from->displayname == NULL)
239 return OSIP_NOMEM;
240
241 osip_clrncpy(from->displayname, hvalue, url - beg);
242 }
243
244 } else if (ptr[0] == ':') {
245 /* this was a scheme for a URL? */
246 url = beg;
247
248 } else {
249 /* this is some non URL header? */
250 url = beg;
251 }
252 }
253
254 /* define url_end and gen_params for name-addr */
255 if (url[0] == '<') {
256 url++;
257 ptr = url;
258 /* first occurence of ">" is the end of url */
259 url_end = strchr(ptr, '>');
260
261 if (url_end == NULL)
262 return OSIP_SYNTAXERROR;
263
264 url_end--;
265 gen_params = strchr(url_end, ';');
266 }
267
268 /* define url_end and gen_params for addr-spec */
269 if (url_end == NULL) {
270 /* rfc3261 // 20.10 Contact:
271 Even if the "display-name" is empty, the "name-addr" form MUST be
272 used if the "addr-spec" contains a comma, semicolon, or question
273 mark. There may or may not be LWS between the display-name and the
274 "<".
275 Conclusion: there is no semicolon (in username) before the semicolon generic param delimiter... */
276 gen_params = strchr(url, ';');
277
278 if (gen_params != NULL)
279 url_end = gen_params - 1;
280
281 else
282 url_end = url + strlen(url);
283 }
284
285 if (gen_params != NULL) { /* now we are sure a param exist */
286 i = __osip_generic_param_parseall(&from->gen_params, gen_params);
287
288 if (i != 0) {
289 return i;
290 }
291 }
292
293 /* set the url */
294 {
295 char *tmp;
296
297 if (url_end - url + 2 < 7)
298 return OSIP_SYNTAXERROR;
299
300 i = osip_uri_init(&(from->url));
301
302 if (i != 0)
303 return i;
304
305 tmp = (char *) osip_malloc(url_end - url + 2);
306
307 if (tmp == NULL)
308 return OSIP_NOMEM;
309
310 osip_strncpy(tmp, url, url_end - url + 1);
311 i = osip_uri_parse(from->url, tmp);
312 osip_free(tmp);
313
314 if (i != 0)
315 return i;
316 }
317 return OSIP_SUCCESS;
318 }
319
320 /* returns the from header as a string. */
321 /* INPUT : osip_from_t *from | from header. */
322 /* returns -1 on error. */
osip_from_to_str(const osip_from_t * from,char ** dest)323 int osip_from_to_str(const osip_from_t *from, char **dest) {
324 char *url;
325 char *buf;
326 int i;
327 size_t len;
328
329 *dest = NULL;
330
331 if ((from == NULL) || (from->url == NULL))
332 return OSIP_BADPARAMETER;
333
334 i = osip_uri_to_str(from->url, &url);
335
336 if (i != 0)
337 return i;
338
339 if (from->displayname == NULL)
340 len = strlen(url) + 5;
341
342 else
343 len = strlen(url) + strlen(from->displayname) + 5;
344
345 buf = (char *) osip_malloc(len);
346
347 if (buf == NULL) {
348 osip_free(url);
349 return OSIP_NOMEM;
350 }
351
352 if (from->displayname != NULL)
353 sprintf(buf, "%s <%s>", from->displayname, url);
354
355 else
356 /* from rfc2543bis-04: for authentication related issue!
357 "The To and From header fields always include the < and >
358 delimiters even if the display-name is empty." */
359 sprintf(buf, "<%s>", url);
360
361 osip_free(url);
362
363 {
364 size_t plen;
365 char *tmp;
366 osip_list_iterator_t it;
367 osip_generic_param_t *u_param = (osip_generic_param_t *) osip_list_get_first(&from->gen_params, &it);
368
369 while (u_param != OSIP_SUCCESS) {
370 if (u_param->gvalue == NULL)
371 plen = strlen(u_param->gname) + 2;
372
373 else
374 plen = strlen(u_param->gname) + strlen(u_param->gvalue) + 3;
375
376 len = len + plen;
377 buf = (char *) osip_realloc(buf, len);
378 tmp = buf;
379 tmp = tmp + strlen(tmp);
380
381 if (u_param->gvalue == NULL)
382 snprintf(tmp, len - (tmp - buf), ";%s", u_param->gname);
383
384 else
385 snprintf(tmp, len - (tmp - buf), ";%s=%s", u_param->gname, u_param->gvalue);
386
387 u_param = (osip_generic_param_t *) osip_list_get_next(&it);
388 }
389 }
390 *dest = buf;
391 return OSIP_SUCCESS;
392 }
393
osip_from_get_displayname(osip_from_t * from)394 char *osip_from_get_displayname(osip_from_t *from) {
395 if (from == NULL)
396 return NULL;
397
398 return from->displayname;
399 }
400
osip_from_set_displayname(osip_from_t * from,char * displayname)401 void osip_from_set_displayname(osip_from_t *from, char *displayname) {
402 from->displayname = displayname;
403 }
404
osip_from_get_url(osip_from_t * from)405 osip_uri_t *osip_from_get_url(osip_from_t *from) {
406 if (from == NULL)
407 return NULL;
408
409 return from->url;
410 }
411
osip_from_set_url(osip_from_t * from,osip_uri_t * url)412 void osip_from_set_url(osip_from_t *from, osip_uri_t *url) {
413 from->url = url;
414 }
415
osip_from_param_get(osip_from_t * from,int pos,osip_generic_param_t ** fparam)416 int osip_from_param_get(osip_from_t *from, int pos, osip_generic_param_t **fparam) {
417 *fparam = NULL;
418
419 if (from == NULL)
420 return OSIP_BADPARAMETER;
421
422 if (osip_list_size(&from->gen_params) <= pos)
423 return OSIP_UNDEFINED_ERROR; /* does not exist */
424
425 *fparam = (osip_generic_param_t *) osip_list_get(&from->gen_params, pos);
426 return pos;
427 }
428
osip_from_clone(const osip_from_t * from,osip_from_t ** dest)429 int osip_from_clone(const osip_from_t *from, osip_from_t **dest) {
430 int i;
431 osip_from_t *fr;
432
433 *dest = NULL;
434
435 if (from == NULL)
436 return OSIP_BADPARAMETER;
437
438 i = osip_from_init(&fr);
439
440 if (i != 0) /* allocation failed */
441 return i;
442
443 if (from->displayname != NULL) {
444 fr->displayname = osip_strdup(from->displayname);
445
446 if (fr->displayname == NULL) {
447 osip_from_free(fr);
448 return OSIP_NOMEM;
449 }
450 }
451
452 if (from->url != NULL) {
453 i = osip_uri_clone(from->url, &(fr->url));
454
455 if (i != 0) {
456 osip_from_free(fr);
457 return i;
458 }
459 }
460
461 i = osip_list_clone(&from->gen_params, &fr->gen_params, (int (*)(void *, void **)) & osip_generic_param_clone);
462
463 if (i != 0) {
464 osip_from_free(fr);
465 return i;
466 }
467
468 *dest = fr;
469 return OSIP_SUCCESS;
470 }
471
osip_from_compare(osip_from_t * from1,osip_from_t * from2)472 int osip_from_compare(osip_from_t *from1, osip_from_t *from2) {
473 char *tag1;
474 char *tag2;
475
476 if (from1 == NULL || from2 == NULL)
477 return OSIP_BADPARAMETER;
478
479 if (from1->url == NULL || from2->url == NULL)
480 return OSIP_BADPARAMETER;
481
482 /* we could have a sip or sips url, but if string!=NULL,
483 host part will be NULL. */
484 if (from1->url->host == NULL && from2->url->host == NULL) {
485 if (from1->url->string == NULL || from2->url->string == NULL)
486 return OSIP_UNDEFINED_ERROR;
487
488 if (0 == strcmp(from1->url->string, from2->url->string))
489 return OSIP_SUCCESS;
490 }
491
492 if (from1->url->host == NULL || from2->url->host == NULL)
493 return OSIP_UNDEFINED_ERROR;
494
495 /* compare url including tag */
496 if (0 != strcmp(from1->url->host, from2->url->host))
497 return OSIP_UNDEFINED_ERROR;
498
499 if (from1->url->username != NULL && from2->url->username != NULL)
500 if (0 != strcmp(from1->url->username, from2->url->username))
501 return OSIP_UNDEFINED_ERROR;
502
503 tag1 = NULL;
504 tag2 = NULL;
505 {
506 osip_list_iterator_t it;
507 osip_generic_param_t *u_param = (osip_generic_param_t *) osip_list_get_first(&from1->gen_params, &it);
508
509 while (u_param != OSIP_SUCCESS) {
510 if (0 == strncmp(u_param->gname, "tag", 3)) {
511 tag1 = u_param->gvalue;
512 break;
513 }
514
515 u_param = (osip_generic_param_t *) osip_list_get_next(&it);
516 }
517 }
518 {
519 osip_list_iterator_t it;
520 osip_generic_param_t *u_param = (osip_generic_param_t *) osip_list_get_first(&from2->gen_params, &it);
521
522 while (u_param != OSIP_SUCCESS) {
523 if (0 == strncmp(u_param->gname, "tag", 3)) {
524 tag2 = u_param->gvalue;
525 break;
526 }
527
528 u_param = (osip_generic_param_t *) osip_list_get_next(&it);
529 }
530 }
531
532 /* sounds like a BUG!
533 if tag2 exists and tag1 does not, then it will
534 return OSIP_SUCCESS;
535 in the first request, (INVITE) the To field does not
536 contain any tag. The response contains one! and the
537 response must match the request....
538 */
539 /* so we test the tags only when both exist! */
540 if (tag1 != NULL && tag2 != NULL)
541 if (0 != strcmp(tag1, tag2))
542 return OSIP_UNDEFINED_ERROR;
543
544 /* We could return a special case, when */
545 /* only one tag exists?? */
546
547 return OSIP_SUCCESS; /* return code changed to 0 from release 0.6.1 */
548 }
549
__osip_generic_param_parseall(osip_list_t * gen_params,const char * params)550 int __osip_generic_param_parseall(osip_list_t *gen_params, const char *params) {
551 int i;
552 char *pname;
553 char *pvalue;
554
555 const char *comma;
556 const char *equal;
557 const char *startquote;
558 const char *endquote;
559
560 /* find '=' wich is the separator for one param */
561 /* find ';' wich is the separator for multiple params */
562
563 equal = next_separator(params + 1, '=', ';');
564 comma = strchr(params + 1, ';');
565
566 /* If comma points after value start quote, move it to after end quote */
567 if (equal != NULL) {
568 const char *tmp;
569
570 startquote = NULL;
571
572 for (tmp = equal + 1; tmp[0] == ' '; tmp++) {
573 }
574
575 if (tmp[0] == '"')
576 startquote = tmp;
577
578 if (startquote != NULL && comma > startquote) {
579 comma = NULL;
580 endquote = __osip_quote_find(startquote + 1);
581
582 if (endquote)
583 comma = strchr(endquote, ';');
584 }
585 }
586
587 while (comma != NULL) {
588 if (equal == NULL) {
589 equal = comma;
590 pvalue = NULL;
591
592 } else {
593 const char *tmp;
594
595 /* check for NULL param with an '=' character */
596 tmp = equal + 1;
597 tmp += strspn(tmp, "\t ");
598 pvalue = NULL;
599
600 if (*tmp != ',' && *tmp != '\0') {
601 if (comma - equal < 2)
602 return OSIP_SYNTAXERROR;
603
604 pvalue = (char *) osip_malloc(comma - equal);
605
606 if (pvalue == NULL)
607 return OSIP_NOMEM;
608
609 osip_strncpy(pvalue, equal + 1, comma - equal - 1);
610 }
611 }
612
613 if (equal - params < 2) {
614 osip_free(pvalue);
615 return OSIP_SYNTAXERROR;
616 }
617
618 pname = (char *) osip_malloc(equal - params);
619
620 if (pname == NULL) {
621 osip_free(pvalue);
622 return OSIP_NOMEM;
623 }
624
625 osip_strncpy(pname, params + 1, equal - params - 1);
626
627 i = osip_generic_param_add(gen_params, pname, pvalue);
628
629 if (i != OSIP_SUCCESS) {
630 osip_free(pname);
631 osip_free(pvalue);
632 return OSIP_NOMEM;
633 }
634
635 params = comma;
636 equal = next_separator(params + 1, '=', ';');
637 comma = strchr(params + 1, ';');
638
639 /* If comma points after value start quote, move it to after end quote */
640 if (equal != NULL) {
641 const char *tmp;
642
643 startquote = NULL;
644
645 for (tmp = equal + 1; tmp[0] == ' '; tmp++) {
646 }
647
648 if (tmp[0] == '"')
649 startquote = tmp;
650
651 if (startquote != NULL && comma > startquote) {
652 comma = NULL;
653 endquote = __osip_quote_find(startquote + 1);
654
655 if (endquote)
656 comma = strchr(endquote, ';');
657 }
658 }
659 }
660
661 /* this is the last header (comma==NULL) */
662 comma = params + strlen(params);
663
664 if (equal == NULL) {
665 equal = comma; /* at the end */
666 pvalue = NULL;
667
668 if (equal - params < 2) {
669 osip_free(pvalue);
670 return OSIP_SUCCESS; /* empty comma? */
671 }
672
673 } else {
674 const char *tmp;
675
676 /* check for NULL param with an '=' character */
677 tmp = equal + 1;
678 tmp += strspn(tmp, "\t ");
679 pvalue = NULL;
680
681 if (*tmp != ',' && *tmp != '\0') {
682 if (comma - equal < 2)
683 return OSIP_SYNTAXERROR;
684
685 pvalue = (char *) osip_malloc(comma - equal);
686
687 if (pvalue == NULL)
688 return OSIP_NOMEM;
689
690 osip_strncpy(pvalue, equal + 1, comma - equal - 1);
691 }
692 }
693
694 if (equal - params < 2) {
695 osip_free(pvalue);
696 return OSIP_SYNTAXERROR;
697 }
698
699 pname = (char *) osip_malloc(equal - params);
700
701 if (pname == NULL) {
702 osip_free(pvalue);
703 return OSIP_NOMEM;
704 }
705
706 osip_strncpy(pname, params + 1, equal - params - 1);
707
708 i = osip_generic_param_add(gen_params, pname, pvalue);
709
710 if (i != OSIP_SUCCESS) {
711 osip_free(pname);
712 osip_free(pvalue);
713 return OSIP_NOMEM;
714 }
715
716 return OSIP_SUCCESS;
717 }
718
osip_generic_param_set_value(osip_generic_param_t * fparam,char * value)719 void osip_generic_param_set_value(osip_generic_param_t *fparam, char *value) {
720 fparam->gvalue = value;
721 }
722
osip_generic_param_get_name(const osip_generic_param_t * fparam)723 char *osip_generic_param_get_name(const osip_generic_param_t *fparam) {
724 if (fparam == NULL)
725 return NULL;
726
727 return fparam->gname;
728 }
729
osip_generic_param_set_name(osip_generic_param_t * fparam,char * name)730 void osip_generic_param_set_name(osip_generic_param_t *fparam, char *name) {
731 fparam->gname = name;
732 }
733
osip_generic_param_get_value(const osip_generic_param_t * fparam)734 char *osip_generic_param_get_value(const osip_generic_param_t *fparam) {
735 if (fparam == NULL)
736 return NULL;
737
738 if (fparam->gname == NULL)
739 return NULL; /* name is mandatory */
740
741 return fparam->gvalue;
742 }
743
osip_from_tag_match(osip_from_t * from1,osip_from_t * from2)744 int osip_from_tag_match(osip_from_t *from1, osip_from_t *from2) {
745 osip_generic_param_t *tag_from1;
746 osip_generic_param_t *tag_from2;
747
748 if (from1 == NULL || from2 == NULL)
749 return OSIP_BADPARAMETER;
750
751 osip_from_param_get_byname(from1, "tag", &tag_from1);
752 osip_from_param_get_byname(from2, "tag", &tag_from2);
753
754 if (tag_from1 == NULL && tag_from2 == NULL)
755 return OSIP_SUCCESS;
756
757 if ((tag_from1 != NULL && tag_from2 == NULL) || (tag_from1 == NULL && tag_from2 != NULL))
758 return OSIP_UNDEFINED_ERROR;
759
760 if (tag_from1->gvalue == NULL || tag_from2->gvalue == NULL)
761 return OSIP_UNDEFINED_ERROR;
762
763 if (0 != strcmp(tag_from1->gvalue, tag_from2->gvalue))
764 return OSIP_UNDEFINED_ERROR;
765
766 return OSIP_SUCCESS;
767 }
768