99138dcaf40c139f6b00cb298e841b0938ced696
[kamailio] / src / core / parser / parse_addr_spec.c
1 /*
2  * Copyright (C) 2001-2003 Fhg Fokus
3  *
4  * This file is part of Kamailio, a free SIP server.
5  *
6  * Kamailio is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version
10  *
11  * Kamailio is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 /** Parser :: Parse To: header.
23  * @file
24  * @ingroup parser
25  */
26
27 #include "parse_to.h"
28 #include <stdlib.h>
29 #include <string.h>
30 #include "../dprint.h"
31 #include "msg_parser.h"
32 #include "parse_uri.h"
33 #include "../ut.h"
34 #include "../mem/mem.h"
35
36
37 enum
38 {
39         START_TO,
40         DISPLAY_QUOTED,
41         E_DISPLAY_QUOTED,
42         DISPLAY_TOKEN,
43         DISPLAY_TOKEN_SP,
44         S_URI_ENCLOSED,
45         URI_ENCLOSED,
46         E_URI_ENCLOSED,
47         URI_OR_TOKEN,
48         MAYBE_URI_END,
49         END,
50         F_CR,
51         F_LF,
52         F_CRLF
53 };
54
55
56 enum
57 {
58         S_PARA_NAME = 20,
59         PARA_NAME,
60         S_EQUAL,
61         S_PARA_VALUE,
62         TAG1,
63         TAG2,
64         TAG3,
65         PARA_VALUE_TOKEN,
66         PARA_VALUE_QUOTED,
67         E_PARA_VALUE
68 };
69
70
71 #define add_param(_param, _body, _newparam)                                   \
72         do {                                                                      \
73                 LM_DBG("add param: %.*s=%.*s\n", param->name.len, ZSW(param->name.s), \
74                                 param->value.len, ZSW(param->value.s));                       \
75                 if(!(_body)->param_lst)                                               \
76                         (_body)->param_lst = (_param);                                    \
77                 else                                                                  \
78                         (_body)->last_param->next = (_param);                             \
79                 (_body)->last_param = (_param);                                       \
80                 if((_param)->type == TAG_PARAM)                                       \
81                         memcpy(&((_body)->tag_value), &((_param)->value), sizeof(str));   \
82                 _newparam = 0;                                                        \
83         } while(0);
84
85
86 static char *parse_to_param(char *const buffer, const char *const end,
87                 struct to_body *const to_b, const int allow_comma_sep,
88                 int *const returned_status)
89 {
90         struct to_param *param;
91         struct to_param *newparam;
92         int status;
93         int saved_status;
94         char *tmp;
95
96         param = 0;
97         newparam = 0;
98         status = E_PARA_VALUE;
99         saved_status = E_PARA_VALUE;
100         for(tmp = buffer; tmp < end; tmp++) {
101                 switch(*tmp) {
102                         case ' ':
103                         case '\t':
104                                 switch(status) {
105                                         case TAG3:
106                                                 param->type = TAG_PARAM;
107                                         case PARA_NAME:
108                                         case TAG1:
109                                         case TAG2:
110                                                 param->name.len = tmp - param->name.s;
111                                                 status = S_EQUAL;
112                                                 break;
113                                         case PARA_VALUE_TOKEN:
114                                                 param->value.len = tmp - param->value.s;
115                                                 status = E_PARA_VALUE;
116                                                 add_param(param, to_b, newparam);
117                                                 break;
118                                         case F_CRLF:
119                                         case F_LF:
120                                         case F_CR:
121                                                 /*previous=crlf and now =' '*/
122                                                 status = saved_status;
123                                                 break;
124                                 }
125                                 break;
126                         case '\n':
127                                 switch(status) {
128                                         case S_PARA_NAME:
129                                         case S_EQUAL:
130                                         case S_PARA_VALUE:
131                                         case E_PARA_VALUE:
132                                                 saved_status = status;
133                                                 status = F_LF;
134                                                 break;
135                                         case TAG3:
136                                                 param->type = TAG_PARAM;
137                                         case PARA_NAME:
138                                         case TAG1:
139                                         case TAG2:
140                                                 param->name.len = tmp - param->name.s;
141                                                 saved_status = S_EQUAL;
142                                                 status = F_LF;
143                                                 break;
144                                         case PARA_VALUE_TOKEN:
145                                                 param->value.len = tmp - param->value.s;
146                                                 saved_status = E_PARA_VALUE;
147                                                 status = F_LF;
148                                                 add_param(param, to_b, newparam);
149                                                 break;
150                                         case F_CR:
151                                                 status = F_CRLF;
152                                                 break;
153                                         case F_CRLF:
154                                         case F_LF:
155                                                 status = saved_status;
156                                                 goto endofheader;
157                                         default:
158                                                 LM_ERR("unexpected char [%c] in status %d: [%.*s] .\n",
159                                                                 *tmp, status, (int)(tmp - buffer), ZSW(buffer));
160                                                 goto error;
161                                 }
162                                 break;
163                         case '\r':
164                                 switch(status) {
165                                         case S_PARA_NAME:
166                                         case S_EQUAL:
167                                         case S_PARA_VALUE:
168                                         case E_PARA_VALUE:
169                                                 saved_status = status;
170                                                 status = F_CR;
171                                                 break;
172                                         case TAG3:
173                                                 param->type = TAG_PARAM;
174                                         case PARA_NAME:
175                                         case TAG1:
176                                         case TAG2:
177                                                 param->name.len = tmp - param->name.s;
178                                                 saved_status = S_EQUAL;
179                                                 status = F_CR;
180                                                 break;
181                                         case PARA_VALUE_TOKEN:
182                                                 param->value.len = tmp - param->value.s;
183                                                 saved_status = E_PARA_VALUE;
184                                                 status = F_CR;
185                                                 add_param(param, to_b, newparam);
186                                                 break;
187                                         case F_CRLF:
188                                         case F_CR:
189                                         case F_LF:
190                                                 status = saved_status;
191                                                 goto endofheader;
192                                         default:
193                                                 LM_ERR("unexpected char [%c] in status %d: [%.*s] .\n",
194                                                                 *tmp, status, (int)(tmp - buffer), ZSW(buffer));
195                                                 goto error;
196                                 }
197                                 break;
198                         case 0:
199                                 switch(status) {
200                                         case TAG3:
201                                                 param->type = TAG_PARAM;
202                                         case PARA_NAME:
203                                         case TAG1:
204                                         case TAG2:
205                                                 param->name.len = tmp - param->name.s;
206                                                 status = S_EQUAL;
207                                         case S_EQUAL:
208                                         case S_PARA_VALUE:
209                                                 saved_status = status;
210                                                 goto endofheader;
211                                         case PARA_VALUE_TOKEN:
212                                                 status = E_PARA_VALUE;
213                                                 param->value.len = tmp - param->value.s;
214                                                 add_param(param, to_b, newparam);
215                                         case E_PARA_VALUE:
216                                                 saved_status = status;
217                                                 goto endofheader;
218                                                 break;
219                                         default:
220                                                 LM_ERR("unexpected char [%c] in status %d: [%.*s] .\n",
221                                                                 *tmp, status, (int)(tmp - buffer), ZSW(buffer));
222                                                 goto error;
223                                 }
224                                 break;
225                         case '\\':
226                                 switch(status) {
227                                         case PARA_VALUE_QUOTED:
228                                                 if(tmp+1>=end) {
229                                                         LM_ERR("unexpected end of data in status %d - start: %p"
230                                                                         " - end: %p - crt: %p\n",
231                                                                 status, buffer, end , tmp);
232                                                         goto error;
233                                                 }
234                                                 switch(*(tmp + 1)) {
235                                                         case '\r':
236                                                         case '\n':
237                                                                 break;
238                                                         default:
239                                                                 tmp++;
240                                                 }
241                                         default:
242                                                 LM_ERR("unexpected char [%c] in status %d: [%.*s] .\n",
243                                                                 *tmp, status, (int)(tmp - buffer), ZSW(buffer));
244                                                 goto error;
245                                 }
246                                 break;
247                         case '"':
248                                 switch(status) {
249                                         case S_PARA_VALUE:
250                                                 if(tmp+1>=end) {
251                                                         LM_ERR("unexpected end of data in status %d - start: %p"
252                                                                         " - end: %p - crt: %p\n",
253                                                                 status, buffer, end , tmp);
254                                                         goto error;
255                                                 }
256                                                 param->value.s = tmp + 1;
257                                                 status = PARA_VALUE_QUOTED;
258                                                 break;
259                                         case PARA_VALUE_QUOTED:
260                                                 param->value.len = tmp - param->value.s;
261                                                 add_param(param, to_b, newparam);
262                                                 status = E_PARA_VALUE;
263                                                 break;
264                                         case F_CRLF:
265                                         case F_LF:
266                                         case F_CR:
267                                                 /*previous=crlf and now !=' '*/
268                                                 goto endofheader;
269                                         default:
270                                                 LM_ERR("unexpected char [%c] in status %d: [%.*s] .\n",
271                                                                 *tmp, status, (int)(tmp - buffer), ZSW(buffer));
272                                                 goto error;
273                                 }
274                                 break;
275                         case ';':
276                                 switch(status) {
277                                         case PARA_VALUE_QUOTED:
278                                                 break;
279                                         case TAG3:
280                                                 param->type = TAG_PARAM;
281                                         case PARA_NAME:
282                                         case TAG1:
283                                         case TAG2:
284                                                 param->name.len = tmp - param->name.s;
285                                         case S_EQUAL:
286                                                 param->value.s = 0;
287                                                 param->value.len = 0;
288                                                 goto semicolon_add_param;
289                                         case S_PARA_VALUE:
290                                                 param->value.s = tmp;
291                                         case PARA_VALUE_TOKEN:
292                                                 param->value.len = tmp - param->value.s;
293                                         semicolon_add_param:
294                                                 add_param(param, to_b, newparam);
295                                         case E_PARA_VALUE:
296                                                 if(newparam) {
297                                                         pkg_free(newparam);
298                                                         newparam = NULL;
299                                                 }
300                                                 param = (struct to_param *)pkg_malloc(
301                                                                 sizeof(struct to_param));
302                                                 if(!param) {
303                                                         PKG_MEM_ERROR;
304                                                         goto error;
305                                                 }
306                                                 memset(param, 0, sizeof(struct to_param));
307                                                 param->type = GENERAL_PARAM;
308                                                 status = S_PARA_NAME;
309                                                 /* link to free mem if not added in to_body list */
310                                                 newparam = param;
311                                                 break;
312                                         case F_CRLF:
313                                         case F_LF:
314                                         case F_CR:
315                                                 /*previous=crlf and now !=' '*/
316                                                 goto endofheader;
317                                         default:
318                                                 LM_ERR("unexpected char [%c] in status %d: [%.*s] .\n",
319                                                                 *tmp, status, (int)(tmp - buffer), ZSW(buffer));
320                                                 goto error;
321                                 }
322                                 break;
323                         case 'T':
324                         case 't':
325                                 switch(status) {
326                                         case PARA_VALUE_QUOTED:
327                                         case PARA_VALUE_TOKEN:
328                                         case PARA_NAME:
329                                                 break;
330                                         case S_PARA_NAME:
331                                                 param->name.s = tmp;
332                                                 status = TAG1;
333                                                 break;
334                                         case S_PARA_VALUE:
335                                                 param->value.s = tmp;
336                                                 status = PARA_VALUE_TOKEN;
337                                                 break;
338                                         case TAG1:
339                                         case TAG2:
340                                         case TAG3:
341                                                 status = PARA_NAME;
342                                                 break;
343                                         case F_CRLF:
344                                         case F_LF:
345                                         case F_CR:
346                                                 /*previous=crlf and now !=' '*/
347                                                 goto endofheader;
348                                         default:
349                                                 LM_ERR("unexpected char [%c] in status %d: [%.*s] .\n",
350                                                                 *tmp, status, (int)(tmp - buffer), ZSW(buffer));
351                                                 goto error;
352                                 }
353                                 break;
354                         case 'A':
355                         case 'a':
356                                 switch(status) {
357                                         case PARA_VALUE_QUOTED:
358                                         case PARA_VALUE_TOKEN:
359                                         case PARA_NAME:
360                                                 break;
361                                         case S_PARA_NAME:
362                                                 param->name.s = tmp;
363                                                 status = PARA_NAME;
364                                                 break;
365                                         case S_PARA_VALUE:
366                                                 param->value.s = tmp;
367                                                 status = PARA_VALUE_TOKEN;
368                                                 break;
369                                         case TAG1:
370                                                 status = TAG2;
371                                                 break;
372                                         case TAG2:
373                                         case TAG3:
374                                                 status = PARA_NAME;
375                                                 break;
376                                         case F_CRLF:
377                                         case F_LF:
378                                         case F_CR:
379                                                 /*previous=crlf and now !=' '*/
380                                                 goto endofheader;
381                                         default:
382                                                 LM_ERR("unexpected char [%c] in status %d: [%.*s] .\n",
383                                                                 *tmp, status, (int)(tmp - buffer), ZSW(buffer));
384                                                 goto error;
385                                 }
386                                 break;
387                         case 'G':
388                         case 'g':
389                                 switch(status) {
390                                         case PARA_VALUE_QUOTED:
391                                         case PARA_VALUE_TOKEN:
392                                         case PARA_NAME:
393                                                 break;
394                                         case S_PARA_NAME:
395                                                 param->name.s = tmp;
396                                                 status = PARA_NAME;
397                                                 break;
398                                         case S_PARA_VALUE:
399                                                 param->value.s = tmp;
400                                                 status = PARA_VALUE_TOKEN;
401                                                 break;
402                                         case TAG1:
403                                         case TAG3:
404                                                 status = PARA_NAME;
405                                                 break;
406                                         case TAG2:
407                                                 status = TAG3;
408                                                 break;
409                                         case F_CRLF:
410                                         case F_LF:
411                                         case F_CR:
412                                                 /*previous=crlf and now !=' '*/
413                                                 goto endofheader;
414                                         default:
415                                                 LM_ERR("unexpected char [%c] in status %d: [%.*s] .\n",
416                                                                 *tmp, status, (int)(tmp - buffer), ZSW(buffer));
417                                                 goto error;
418                                 }
419                                 break;
420                         case '=':
421                                 switch(status) {
422                                         case PARA_VALUE_QUOTED:
423                                                 break;
424                                         case TAG3:
425                                                 param->type = TAG_PARAM;
426                                         case PARA_NAME:
427                                         case TAG1:
428                                         case TAG2:
429                                                 param->name.len = tmp - param->name.s;
430                                                 status = S_PARA_VALUE;
431                                                 break;
432                                         case S_EQUAL:
433                                                 status = S_PARA_VALUE;
434                                                 break;
435                                         case F_CRLF:
436                                         case F_LF:
437                                         case F_CR:
438                                                 /*previous=crlf and now !=' '*/
439                                                 goto endofheader;
440                                         default:
441                                                 LM_ERR("unexpected char [%c] in status %d: [%.*s] .\n",
442                                                                 *tmp, status, (int)(tmp - buffer), ZSW(buffer));
443                                                 goto error;
444                                 }
445                                 break;
446                         case ',':
447                                 if(status == PARA_VALUE_QUOTED) {
448                                         /* comma is allowed inside quoted values */
449                                         break;
450                                 }
451                                 if(allow_comma_sep) {
452                                         switch(status) {
453                                                 case S_PARA_NAME:
454                                                 case S_EQUAL:
455                                                 case S_PARA_VALUE:
456                                                 case E_PARA_VALUE:
457                                                         saved_status = status;
458                                                         status = E_PARA_VALUE;
459                                                         goto endofheader;
460                                                 case TAG3:
461                                                         param->type = TAG_PARAM;
462                                                 case PARA_NAME:
463                                                 case TAG1:
464                                                 case TAG2:
465                                                         param->name.len = tmp - param->name.s;
466                                                         saved_status = S_EQUAL;
467                                                         status = E_PARA_VALUE;
468                                                         goto endofheader;
469                                                 case PARA_VALUE_TOKEN:
470                                                         param->value.len = tmp - param->value.s;
471                                                         saved_status = E_PARA_VALUE;
472                                                         status = E_PARA_VALUE;
473                                                         add_param(param, to_b, newparam);
474                                                         goto endofheader;
475                                                 case F_CRLF:
476                                                 case F_CR:
477                                                 case F_LF:
478                                                         status = saved_status;
479                                                         goto endofheader;
480                                                 default:
481                                                         LM_ERR("unexpected char [%c] in status %d: [%.*s] "
482                                                                         ".\n",
483                                                                         *tmp, status, (int)(tmp - buffer),
484                                                                         ZSW(buffer));
485                                                         goto error;
486                                         }
487                                         break;
488                                 } else {
489                                         if((status == S_PARA_VALUE || status == PARA_VALUE_TOKEN)
490                                                         && param->type == TAG_PARAM) {
491                                                 /* if comma is not separator, allow it as part of value
492                                                  * - some user agents use it */
493                                                 break;
494                                         }
495                                         LM_ERR("invalid character ',' in status %d: [%.*s]\n",
496                                                         status, (int)(tmp - buffer), ZSW(buffer));
497                                 }
498                         default:
499                                 switch(status) {
500                                         case TAG1:
501                                         case TAG2:
502                                         case TAG3:
503                                                 status = PARA_NAME;
504                                                 break;
505                                         case PARA_VALUE_TOKEN:
506                                         case PARA_NAME:
507                                         case PARA_VALUE_QUOTED:
508                                                 break;
509                                         case S_PARA_NAME:
510                                                 param->name.s = tmp;
511                                                 status = PARA_NAME;
512                                                 break;
513                                         case S_PARA_VALUE:
514                                                 param->value.s = tmp;
515                                                 status = PARA_VALUE_TOKEN;
516                                                 break;
517                                         case F_CRLF:
518                                         case F_LF:
519                                         case F_CR:
520                                                 /*previous=crlf and now !=' '*/
521                                                 goto endofheader;
522                                         default:
523                                                 LM_ERR("spitting out [%c] in status %d\n", *tmp,
524                                                                 status);
525                                                 goto error;
526                                 }
527                 } /*switch*/
528         }        /*for*/
529         if(!(status == F_CR || status == F_LF || status == F_CRLF))
530                 saved_status = status;
531
532
533 endofheader:
534         switch(saved_status) {
535                 case TAG3:
536                         param->type = TAG_PARAM;        /* tag at the end */
537                                                                                 /* no break */
538                 case PARA_NAME:
539                 case TAG1:
540                 case TAG2:
541                         param->name.len = tmp - param->name.s;
542                 /* no break */
543                 case S_EQUAL:
544                         /* parameter without '=', e.g. foo */
545                         param->value.s = 0;
546                         param->value.len = 0;
547                         add_param(param, to_b, newparam);
548                         saved_status = E_PARA_VALUE;
549                         break;
550                 case S_PARA_VALUE:
551                         /* parameter with null value, e.g. foo= */
552                         if(status == F_CRLF)
553                                 param->value.s = tmp - 2;
554                         else if(status == F_CR || status == F_LF)
555                                 param->value.s = tmp - 1;
556                         else
557                                 param->value.s = tmp;
558                         param->value.len = 0;
559                         add_param(param, to_b, newparam);
560                         saved_status = E_PARA_VALUE;
561                         break;
562                 case PARA_VALUE_TOKEN:
563                         param->value.len = tmp - param->value.s;
564                         add_param(param, to_b, newparam);
565                         saved_status = E_PARA_VALUE;
566                         break;
567                 case E_PARA_VALUE:
568                         break;
569                 default:
570                         LM_ERR("unexpected end of header, status %d: [%.*s] .\n",
571                                         saved_status, (int)(tmp - buffer), ZSW(buffer));
572                         goto error;
573         }
574         if(newparam) {
575                 pkg_free(newparam);
576         }
577         *returned_status = saved_status;
578         return tmp;
579
580 error:
581         if(newparam)
582                 pkg_free(newparam);
583         to_b->error = PARSE_ERROR;
584         *returned_status = status;
585         return tmp;
586 }
587
588
589 char *parse_addr_spec(char *const buffer, const char *const end,
590                 struct to_body *const to_b, const int allow_comma_sep)
591 {
592         int status;
593         int saved_status;
594         char *tmp, *foo;
595
596         saved_status = START_TO; /* fixes gcc 4.x warning */
597         status = START_TO;
598         memset(to_b, 0, sizeof(struct to_body));
599         to_b->error = PARSE_OK;
600         foo = 0;
601
602         for(tmp = buffer; tmp < end; tmp++) {
603                 switch(*tmp) {
604                         case ' ':
605                         case '\t':
606                                 switch(status) {
607                                         case F_CRLF:
608                                         case F_LF:
609                                         case F_CR:
610                                                 /*previous=crlf and now =' '*/
611                                                 status = saved_status;
612                                                 break;
613                                         case URI_ENCLOSED:
614                                                 to_b->uri.len = tmp - to_b->uri.s;
615                                                 status = E_URI_ENCLOSED;
616                                                 break;
617                                         case URI_OR_TOKEN:
618                                                 foo = tmp;
619                                                 status = MAYBE_URI_END;
620                                                 break;
621                                         case DISPLAY_TOKEN:
622                                                 foo = tmp;
623                                                 status = DISPLAY_TOKEN_SP;
624                                                 break;
625                                 }
626                                 break;
627                         case '\n':
628                                 switch(status) {
629                                         case URI_OR_TOKEN:
630                                                 foo = tmp;
631                                                 status = MAYBE_URI_END;
632                                         case MAYBE_URI_END:
633                                         case DISPLAY_TOKEN_SP:
634                                         case E_DISPLAY_QUOTED:
635                                         case END:
636                                                 saved_status = status;
637                                                 status = F_LF;
638                                                 break;
639                                         case DISPLAY_TOKEN:
640                                                 foo = tmp;
641                                                 saved_status = DISPLAY_TOKEN_SP;
642                                                 status = F_LF;
643                                                 break;
644                                         case F_CR:
645                                                 status = F_CRLF;
646                                                 break;
647                                         case F_CRLF:
648                                         case F_LF:
649                                                 status = saved_status;
650                                                 goto endofheader;
651                                         default:
652                                                 LM_ERR("unexpected char [%c/%d] in status %d: [%.*s] .\n",
653                                                                 *tmp, *tmp, status, (int)(tmp - buffer), ZSW(buffer));
654                                                 goto error;
655                                 }
656                                 break;
657                         case '\r':
658                                 switch(status) {
659                                         case URI_OR_TOKEN:
660                                                 foo = tmp;
661                                                 status = MAYBE_URI_END;
662                                         case MAYBE_URI_END:
663                                         case DISPLAY_TOKEN_SP:
664                                         case E_DISPLAY_QUOTED:
665                                         case END:
666                                                 saved_status = status;
667                                                 status = F_CR;
668                                                 break;
669                                         case DISPLAY_TOKEN:
670                                                 foo = tmp;
671                                                 saved_status = DISPLAY_TOKEN_SP;
672                                                 status = F_CR;
673                                                 break;
674                                         case F_CRLF:
675                                         case F_CR:
676                                         case F_LF:
677                                                 status = saved_status;
678                                                 goto endofheader;
679                                         default:
680                                                 LM_ERR("unexpected char [%c/%d] in status %d: [%.*s] .\n",
681                                                                 *tmp, *tmp, status, (int)(tmp - buffer), ZSW(buffer));
682                                                 goto error;
683                                 }
684                                 break;
685                         case 0:
686                                 switch(status) {
687                                         case URI_OR_TOKEN:
688                                         case MAYBE_URI_END:
689                                                 to_b->uri.len = tmp - to_b->uri.s;
690                                         case END:
691                                                 saved_status = status = END;
692                                                 goto endofheader;
693                                         default:
694                                                 LM_ERR("unexpected char [%c/%d] in status %d: [%.*s] .\n",
695                                                                 *tmp, *tmp, status, (int)(tmp - buffer), ZSW(buffer));
696                                                 goto error;
697                                 }
698                                 break;
699                         case '\\':
700                                 switch(status) {
701                                         case DISPLAY_QUOTED:
702                                                 tmp++; /* jump over next char */
703                                                 break;
704                                         default:
705                                                 LM_ERR("unexpected char [%c/%d] in status %d: [%.*s] .\n",
706                                                                 *tmp, *tmp, status, (int)(tmp - buffer), ZSW(buffer));
707                                                 goto error;
708                                 }
709                                 break;
710                         case '<':
711                                 switch(status) {
712                                         case START_TO:
713                                                 to_b->body.s = tmp;
714                                                 status = S_URI_ENCLOSED;
715                                                 break;
716                                         case DISPLAY_QUOTED:
717                                                 break;
718                                         case E_DISPLAY_QUOTED:
719                                                 status = S_URI_ENCLOSED;
720                                                 break;
721                                         case URI_OR_TOKEN:
722                                         case DISPLAY_TOKEN:
723                                                 to_b->display.len = tmp - to_b->display.s;
724                                                 status = S_URI_ENCLOSED;
725                                                 break;
726                                         case DISPLAY_TOKEN_SP:
727                                         case MAYBE_URI_END:
728                                                 to_b->display.len = foo - to_b->display.s;
729                                                 status = S_URI_ENCLOSED;
730                                                 break;
731                                         case F_CRLF:
732                                         case F_LF:
733                                         case F_CR:
734                                                 /*previous=crlf and now !=' '*/
735                                                 goto endofheader;
736                                         default:
737                                                 LM_ERR("unexpected char [%c/%d] in status %d: [%.*s] .\n",
738                                                                 *tmp, *tmp, status, (int)(tmp - buffer), ZSW(buffer));
739                                                 goto error;
740                                 }
741                                 break;
742                         case '>':
743                                 switch(status) {
744                                         case DISPLAY_QUOTED:
745                                                 break;
746                                         case URI_ENCLOSED:
747                                                 to_b->uri.len = tmp - to_b->uri.s;
748                                         case E_URI_ENCLOSED:
749                                                 status = END;
750                                                 foo = 0;
751                                                 break;
752                                         case F_CRLF:
753                                         case F_LF:
754                                         case F_CR:
755                                                 /*previous=crlf and now !=' '*/
756                                                 goto endofheader;
757                                         default:
758                                                 LM_ERR("unexpected char [%c/%d] in status %d: [%.*s] .\n",
759                                                                 *tmp, *tmp, status, (int)(tmp - buffer), ZSW(buffer));
760                                                 goto error;
761                                 }
762                                 break;
763                         case '"':
764                                 switch(status) {
765                                         case START_TO:
766                                                 to_b->body.s = tmp;
767                                                 to_b->display.s = tmp;
768                                                 status = DISPLAY_QUOTED;
769                                                 break;
770                                         case DISPLAY_QUOTED:
771                                                 status = E_DISPLAY_QUOTED;
772                                                 to_b->display.len = tmp - to_b->display.s + 1;
773                                                 break;
774                                         case F_CRLF:
775                                         case F_LF:
776                                         case F_CR:
777                                                 /*previous=crlf and now !=' '*/
778                                                 goto endofheader;
779                                         default:
780                                                 LM_ERR("unexpected char [%c/%d] in status %d: [%.*s] .\n",
781                                                                 *tmp, *tmp, status, (int)(tmp - buffer), buffer);
782                                                 goto error;
783                                 }
784                                 break;
785                         case ';':
786                                 switch(status) {
787                                         case DISPLAY_QUOTED:
788                                         case URI_ENCLOSED:
789                                                 break;
790                                         case URI_OR_TOKEN:
791                                                 foo = tmp;
792                                         case MAYBE_URI_END:
793                                                 to_b->uri.len = foo - to_b->uri.s;
794                                         case END:
795                                                 to_b->body.len = tmp - to_b->body.s;
796                                                 tmp = parse_to_param(
797                                                                 tmp, end, to_b, allow_comma_sep, &saved_status);
798                                                 goto endofheader;
799                                         case F_CRLF:
800                                         case F_LF:
801                                         case F_CR:
802                                                 /*previous=crlf and now !=' '*/
803                                                 goto endofheader;
804                                         default:
805                                                 LM_ERR("unexpected char [%c/%d] in status %d: [%.*s] .\n",
806                                                                 *tmp, *tmp, status, (int)(tmp - buffer), buffer);
807                                                 goto error;
808                                 }
809                                 break;
810                         case ',':
811                                 if(allow_comma_sep) {
812                                         switch(status) {
813                                                 case DISPLAY_QUOTED:
814                                                 case URI_ENCLOSED:
815                                                         break;
816                                                 case URI_OR_TOKEN:
817                                                         foo = tmp;
818                                                 case MAYBE_URI_END:
819                                                         to_b->uri.len = foo - to_b->uri.s;
820                                                 case END:
821                                                         to_b->body.len = tmp - to_b->body.s;
822                                                         saved_status = END;
823                                                         goto endofheader;
824                                                 case F_CRLF:
825                                                 case F_LF:
826                                                 case F_CR:
827                                                         /*previous=crlf and now !=' '*/
828                                                         goto endofheader;
829                                                 default:
830                                                         LM_ERR("unexpected char [%c/%d] in status %d: [%.*s] "
831                                                                         ".\n",
832                                                                         *tmp, *tmp, status, (int)(tmp - buffer), buffer);
833                                                         goto error;
834                                         }
835                                         break;
836                                 }
837                         /* If commas not allowed treat as a default character */
838                         default:
839                                 switch(status) {
840                                         case START_TO:
841                                                 to_b->uri.s = to_b->body.s = tmp;
842                                                 status = URI_OR_TOKEN;
843                                                 to_b->display.s = tmp;
844                                                 break;
845                                         case S_URI_ENCLOSED:
846                                                 to_b->uri.s = tmp;
847                                                 status = URI_ENCLOSED;
848                                                 break;
849                                         case MAYBE_URI_END:
850                                         case DISPLAY_TOKEN_SP:
851                                                 status = DISPLAY_TOKEN;
852                                         case DISPLAY_QUOTED:
853                                         case DISPLAY_TOKEN:
854                                         case URI_ENCLOSED:
855                                         case URI_OR_TOKEN:
856                                                 break;
857                                         case F_CRLF:
858                                         case F_LF:
859                                         case F_CR:
860                                                 /*previous=crlf and now !=' '*/
861                                                 goto endofheader;
862                                         default:
863                                                 LM_DBG("spitting out [%c/%d] in status %d\n", *tmp,
864                                                                 *tmp, status);
865                                                 goto error;
866                                 }
867                 } /*char switch*/
868         }        /*for*/
869
870         /* Reached end of buffer */
871         switch(status) {
872                 case URI_OR_TOKEN:
873                 case MAYBE_URI_END:
874                 case END:
875                         saved_status = status;
876                         foo = tmp;
877         }
878
879 endofheader:
880         if(to_b->display.len == 0)
881                 to_b->display.s = 0;
882         status = saved_status;
883         LM_DBG("end of header reached, state=%d\n", status);
884         /* check if error*/
885         switch(status) {
886                 case URI_OR_TOKEN:
887                 case MAYBE_URI_END:
888                         to_b->uri.len = foo - to_b->uri.s;
889                 case END:
890                         to_b->body.len = tmp - to_b->body.s;
891                 case E_PARA_VALUE:
892                         break;
893                 default:
894                         LM_ERR("invalid body -  unexpected "
895                                         "end of header in state %d\n",
896                                         status);
897                         goto error;
898         }
899         return tmp;
900
901 error:
902         free_to_params(to_b);
903         to_b->error = PARSE_ERROR;
904         return tmp;
905 }
906
907
908 void free_to_params(struct to_body *const tb)
909 {
910         struct to_param *tp = tb->param_lst;
911         struct to_param *foo;
912         while(tp) {
913                 foo = tp->next;
914                 pkg_free(tp);
915                 tp = foo;
916         }
917         tb->param_lst = NULL;
918 }
919
920
921 void free_to(struct to_body *const tb)
922 {
923         free_to_params(tb);
924         pkg_free(tb);
925 }