6ec9c5bbd39ae233f173a3004f641400c1443722
[sip-router] / parser / contact / contact.c
1 /*
2  * $Id$
3  *
4  * Parses one Contact in Contact HF body
5  */
6
7 #include "contact.h"
8 #include "../../mem/mem.h" /* pkg_malloc, pkg_free */
9 #include "../../dprint.h"
10 #include <string.h>        /* memset */
11 #include "../../trim.h"    /* trim_leading, trim_trailing */
12 #include <stdio.h>         /* printf */
13
14
15 #define ST1 1 /* Basic state */
16 #define ST2 2 /* Quoted */
17 #define ST3 3 /* Angle quoted */
18 #define ST4 4 /* Angle quoted and quoted */
19 #define ST5 5 /* Escape in quoted */
20 #define ST6 6 /* Escape in angle quoted and quoted */
21
22
23 /*
24  * Skip URI, stops when , (next contact)
25  * or ; (parameter) is found
26  */
27 static inline int skip_uri(str* _s)
28 {
29         register int st = ST1;
30
31         while(_s->len) {
32                 switch(*(_s->s)) {
33                 case ',':
34                 case ';':
35                         if (st == ST1) return 0;
36                         break;
37
38                 case '\"':
39                         switch(st) {
40                         case ST1: st = ST2; break;
41                         case ST2: st = ST1; break;
42                         case ST3: st = ST4; break;
43                         case ST4: st = ST3; break;
44                         case ST5: st = ST2; break;
45                         case ST6: st = ST4; break;
46                         }
47                         break;
48
49                 case '<':
50                         switch(st) {
51                         case ST1: st = ST3; break;
52                         case ST3: 
53                                 LOG(L_ERR, "skip_uri(): Second < found\n");
54                                 return -1;
55                         case ST5: st = ST2; break;
56                         case ST6: st = ST4; break;
57                         }
58                         break;
59                         
60                 case '>':
61                         switch(st) {
62                         case ST1: 
63                                 LOG(L_ERR, "skip_uri(): > is first\n");
64                                 return -2;
65
66                         case ST3: st = ST1; break;
67                         case ST5: st = ST2; break;
68                         case ST6: st = ST4; break;
69                         }
70                         break;
71
72                 case '\\':
73                         switch(st) {
74                         case ST2: st = ST5; break;
75                         case ST4: st = ST6; break;
76                         case ST5: st = ST2; break;
77                         case ST6: st = ST4; break;
78                         }
79                         break;
80
81                 default: break;
82
83                 }
84
85                 _s->s++;
86                 _s->len--;
87         }
88
89         if (st != ST1) {
90                 LOG(L_ERR, "skip_uri(): < or \" not closed\n");
91                 return -3;
92         }
93
94         return 0;
95 }
96
97
98
99 /*
100  * Parse contacts in a Contact HF
101  */
102 int parse_contacts(str* _s, contact_t** _c)
103 {
104         contact_t* c;
105
106         while(1) {
107                      /* Allocate and clear contact stucture */
108                 c = (contact_t*)pkg_malloc(sizeof(contact_t));
109                 if (c == 0) {
110                         LOG(L_ERR, "parse_contacts(): No memory left\n");
111                         goto error;
112                 }
113                 memset(c, 0, sizeof(contact_t));
114                 
115                      /* Save beginning of URI */
116                 c->uri.s = _s->s;
117                 
118                      /* Find the end of the URI */
119                 if (skip_uri(_s) < 0) {
120                         LOG(L_ERR, "parse_contacts(): Error while skipping URI\n");
121                         goto error;
122                 }
123                 
124                 c->uri.len = _s->s - c->uri.s; /* Calculate URI length */
125                 trim_trailing(&(c->uri));      /* Remove any trailing spaces from URI */
126
127                 if (_s->len == 0) goto ok;
128                 
129                 if (_s->s[0] == ';') {         /* Contact parameter found */
130                         _s->s++;
131                         _s->len--;
132                         trim_leading(_s);
133                         
134                         if (_s->len == 0) {
135                                 LOG(L_ERR, "parse_contacts(): Error while parsing params\n");
136                                 goto error;
137                         }
138
139                         if (parse_cparams(_s, &(c->params), &(c->q), &(c->expires), &(c->method)) < 0) {
140                                 LOG(L_ERR, "parse_contacts(): Error while parsing params\n");
141                                 goto error;
142                         }
143
144                         if (_s->len == 0) goto ok;
145                 }
146
147                      /* Next character is comma */
148                 _s->s++;
149                 _s->len--;
150                 trim_leading(_s);
151
152                 if (_s->len == 0) {
153                         LOG(L_ERR, "parse_contacts(): Text after comma missing\n");
154                         goto error;
155                 }
156
157                 c->next = *_c;
158                 *_c = c;
159         }
160
161  error:
162         if (c) pkg_free(c);
163         free_contacts(_c); /* Free any contacts created so far */
164         return -1;
165
166  ok:
167         c->next = *_c;
168         *_c = c;
169         return 0;
170 }
171
172
173 /*
174  * Free list of contacts
175  * _c is head of the list
176  */
177 void free_contacts(contact_t** _c)
178 {
179         contact_t* ptr;
180
181         while(*_c) {
182                 ptr = *_c;
183                 *_c = (*_c)->next;
184                 if (ptr->params) {
185                         free_cparams(&(ptr->params));
186                 }
187                 pkg_free(ptr);
188         }
189 }
190
191
192 /*
193  * Print list of contacts, just for debugging
194  */
195 void print_contacts(contact_t* _c)
196 {
197         contact_t* ptr;
198
199         ptr = _c;
200
201         while(ptr) {
202                 printf("---Contact---\n");
203                 printf("URI    : \'%.*s\'\n", ptr->uri.len, ptr->uri.s);
204                 printf("q      : %p\n", ptr->q);
205                 printf("expires: %p\n", ptr->expires);
206                 printf("method : %p\n", ptr->method);
207                 if (ptr->params) {
208                         print_cparams(ptr->params);
209                 }
210                 printf("---/Contact---\n");
211                 ptr = ptr->next;
212         }
213 }