/src/opensips/parser/contact/contact.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Parses one Contact in Contact HF body |
3 | | * |
4 | | * Copyright (C) 2001-2003 FhG Fokus |
5 | | * |
6 | | * This file is part of opensips, a free SIP server. |
7 | | * |
8 | | * opensips is free software; you can redistribute it and/or modify |
9 | | * it under the terms of the GNU General Public License as published by |
10 | | * the Free Software Foundation; either version 2 of the License, or |
11 | | * (at your option) any later version |
12 | | * |
13 | | * opensips is distributed in the hope that it will be useful, |
14 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | | * GNU General Public License for more details. |
17 | | * |
18 | | * You should have received a copy of the GNU General Public License |
19 | | * along with this program; if not, write to the Free Software |
20 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
21 | | * |
22 | | * History: |
23 | | * ------- |
24 | | * 2003-03-25 Adapted to use new parameter parser (janakj) |
25 | | */ |
26 | | |
27 | | #include <string.h> /* memset */ |
28 | | #include "../../mem/mem.h" /* pkg_malloc, pkg_free */ |
29 | | #include "../../dprint.h" |
30 | | #include "../../trim.h" /* trim_leading, trim_trailing */ |
31 | | #include "contact.h" |
32 | | |
33 | | |
34 | 0 | #define ST1 1 /* Basic state */ |
35 | 0 | #define ST2 2 /* Quoted */ |
36 | 0 | #define ST3 3 /* Angle quoted */ |
37 | 0 | #define ST4 4 /* Angle quoted and quoted */ |
38 | 0 | #define ST5 5 /* Escape in quoted */ |
39 | 0 | #define ST6 6 /* Escape in angle quoted and quoted */ |
40 | | |
41 | | |
42 | | /* |
43 | | * Skip URI, stops when , (next contact) |
44 | | * or ; (parameter) is found |
45 | | */ |
46 | | static inline int skip_uri(str* _s) |
47 | 0 | { |
48 | 0 | register int st = ST1; |
49 | |
|
50 | 0 | while(_s->len) { |
51 | 0 | switch(*(_s->s)) { |
52 | 0 | case ',': |
53 | 0 | case ';': |
54 | 0 | if (st == ST1) return 0; |
55 | 0 | break; |
56 | | |
57 | 0 | case '\"': |
58 | 0 | switch(st) { |
59 | 0 | case ST1: st = ST2; break; |
60 | 0 | case ST2: st = ST1; break; |
61 | 0 | case ST3: st = ST4; break; |
62 | 0 | case ST4: st = ST3; break; |
63 | 0 | case ST5: st = ST2; break; |
64 | 0 | case ST6: st = ST4; break; |
65 | 0 | } |
66 | 0 | break; |
67 | | |
68 | 0 | case '<': |
69 | 0 | switch(st) { |
70 | 0 | case ST1: st = ST3; break; |
71 | 0 | case ST3: |
72 | 0 | LM_ERR("second < found\n"); |
73 | 0 | return -1; |
74 | 0 | case ST5: st = ST2; break; |
75 | 0 | case ST6: st = ST4; break; |
76 | 0 | } |
77 | 0 | break; |
78 | | |
79 | 0 | case '>': |
80 | 0 | switch(st) { |
81 | 0 | case ST1: |
82 | 0 | LM_ERR("> is first\n"); |
83 | 0 | return -2; |
84 | | |
85 | 0 | case ST3: st = ST1; break; |
86 | 0 | case ST5: st = ST2; break; |
87 | 0 | case ST6: st = ST4; break; |
88 | 0 | } |
89 | 0 | break; |
90 | | |
91 | 0 | case '\\': |
92 | 0 | switch(st) { |
93 | 0 | case ST2: st = ST5; break; |
94 | 0 | case ST4: st = ST6; break; |
95 | 0 | case ST5: st = ST2; break; |
96 | 0 | case ST6: st = ST4; break; |
97 | 0 | } |
98 | 0 | break; |
99 | | |
100 | 0 | default: break; |
101 | |
|
102 | 0 | } |
103 | | |
104 | 0 | _s->s++; |
105 | 0 | _s->len--; |
106 | 0 | } |
107 | | |
108 | 0 | if (st != ST1) { |
109 | 0 | LM_ERR("< or \" not closed\n"); |
110 | 0 | return -3; |
111 | 0 | } |
112 | | |
113 | 0 | return 0; |
114 | 0 | } |
115 | | |
116 | | |
117 | | /* |
118 | | * Skip name part |
119 | | * |
120 | | * _s will be adjusted to point at the beginning |
121 | | * of URI |
122 | | */ |
123 | | static inline int skip_name(str* _s) |
124 | 0 | { |
125 | 0 | char* last_wsp, *p; |
126 | 0 | int i, quoted = 0; |
127 | | |
128 | |
|
129 | 0 | if (!_s) { |
130 | 0 | LM_ERR("invalid parameter value\n"); |
131 | 0 | return -1; |
132 | 0 | } |
133 | | |
134 | 0 | p = _s->s; |
135 | |
|
136 | 0 | last_wsp = 0; |
137 | |
|
138 | 0 | for(i = 0; i < _s->len; i++) { |
139 | 0 | if (!quoted) { |
140 | 0 | if ((*p == ' ') || (*p == '\t')) { |
141 | 0 | last_wsp = p; |
142 | 0 | } else { |
143 | 0 | if (*p == '<') { |
144 | 0 | _s->s = p; |
145 | 0 | _s->len -= i; |
146 | 0 | return 0; |
147 | 0 | } |
148 | | |
149 | 0 | if (*p == ':') { |
150 | 0 | if (last_wsp) { |
151 | 0 | _s->len -= last_wsp - _s->s + 1; |
152 | 0 | _s->s = last_wsp; |
153 | 0 | } |
154 | 0 | return 0; |
155 | 0 | } |
156 | | |
157 | 0 | if (*p == '\"') { |
158 | 0 | quoted = 1; |
159 | 0 | } |
160 | 0 | } |
161 | 0 | } else { |
162 | 0 | if ((*p == '\"') && (*(p-1) != '\\')) quoted = 0; |
163 | 0 | } |
164 | 0 | p++; |
165 | 0 | } |
166 | | |
167 | 0 | if (quoted) { |
168 | 0 | LM_ERR("closing quote missing in name part of Contact\n"); |
169 | 0 | } else { |
170 | 0 | LM_ERR("error in contact, scheme separator not found\n"); |
171 | 0 | } |
172 | |
|
173 | 0 | return -1; |
174 | 0 | } |
175 | | |
176 | | |
177 | | /* |
178 | | * Parse contacts in a Contact HF |
179 | | */ |
180 | | int parse_contacts(str* _s, contact_t** _c) |
181 | 0 | { |
182 | 0 | contact_t* c; |
183 | 0 | contact_t* last; |
184 | 0 | param_hooks_t hooks; |
185 | |
|
186 | 0 | last = NULL; |
187 | |
|
188 | 0 | while(1) { |
189 | | /* Allocate and clear contact structure */ |
190 | 0 | c = (contact_t*)pkg_malloc(sizeof(contact_t)); |
191 | 0 | if (c == 0) { |
192 | 0 | LM_ERR("no pkg memory left\n"); |
193 | 0 | goto error; |
194 | 0 | } |
195 | 0 | memset(c, 0, sizeof(contact_t)); |
196 | |
|
197 | 0 | c->name.s = _s->s; |
198 | |
|
199 | 0 | if (skip_name(_s) < 0) { |
200 | 0 | LM_ERR("failed to skip name part\n"); |
201 | 0 | goto error; |
202 | 0 | } |
203 | | |
204 | 0 | c->uri.s = _s->s; |
205 | 0 | c->name.len = _s->s - c->name.s; |
206 | 0 | trim_trailing(&c->name); |
207 | | |
208 | | /* Find the end of the URI */ |
209 | 0 | if (skip_uri(_s) < 0) { |
210 | 0 | LM_ERR("failed to skip URI\n"); |
211 | 0 | goto error; |
212 | 0 | } |
213 | | |
214 | 0 | c->uri.len = _s->s - c->uri.s; /* Calculate URI length */ |
215 | 0 | trim_trailing(&(c->uri)); /* Remove any trailing spaces from URI */ |
216 | | |
217 | | /* Remove <> if any */ |
218 | 0 | if ((c->uri.len >= 2) && (c->uri.s[0] == '<') && |
219 | 0 | (c->uri.s[c->uri.len - 1] == '>')) { |
220 | 0 | c->uri.s++; |
221 | 0 | c->uri.len -= 2; |
222 | 0 | } |
223 | |
|
224 | 0 | trim(&c->uri); |
225 | | |
226 | | /* RFC3261 grammar enforces the existence of an URI */ |
227 | 0 | if (c->uri.len==0) { |
228 | 0 | LM_ERR("Empty URI found in contact body\n"); |
229 | 0 | goto error; |
230 | 0 | } |
231 | | |
232 | 0 | if (_s->len == 0) goto ok; |
233 | | |
234 | 0 | if (_s->s[0] == ';') { /* Contact parameter found */ |
235 | 0 | _s->s++; |
236 | 0 | _s->len--; |
237 | 0 | trim_leading(_s); |
238 | |
|
239 | 0 | if (_s->len == 0) { |
240 | 0 | LM_ERR("failed to parse params\n"); |
241 | 0 | goto error; |
242 | 0 | } |
243 | | |
244 | 0 | if (parse_params(_s, CLASS_CONTACT, &hooks, &c->params) < 0) { |
245 | 0 | LM_ERR("failed to parse contact parameters\n"); |
246 | 0 | goto error; |
247 | 0 | } |
248 | | |
249 | 0 | c->q = hooks.contact.q; |
250 | 0 | c->expires = hooks.contact.expires; |
251 | 0 | c->received = hooks.contact.received; |
252 | 0 | c->methods = hooks.contact.methods; |
253 | 0 | c->instance = hooks.contact.instance; |
254 | |
|
255 | 0 | if (_s->len == 0) goto ok; |
256 | 0 | } |
257 | | |
258 | | /* Next character is comma */ |
259 | 0 | c->len = _s->s - c->name.s; |
260 | 0 | _s->s++; |
261 | 0 | _s->len--; |
262 | 0 | trim_leading(_s); |
263 | |
|
264 | 0 | if (_s->len == 0) { |
265 | 0 | LM_ERR("text after comma missing\n"); |
266 | 0 | goto error; |
267 | 0 | } |
268 | | |
269 | 0 | if (last) {last->next=c;} else {*_c = c;} |
270 | 0 | last = c; |
271 | 0 | } |
272 | | |
273 | 0 | error: |
274 | 0 | if (c) free_contacts(&c); |
275 | 0 | free_contacts(_c); /* Free any contacts created so far */ |
276 | 0 | return -1; |
277 | | |
278 | 0 | ok: |
279 | 0 | c->len = _s->s - c->name.s; |
280 | 0 | if (last) {last->next=c;} else {*_c = c;} |
281 | 0 | return 0; |
282 | 0 | } |
283 | | |
284 | | |
285 | | /* |
286 | | * Free list of contacts |
287 | | * _c is head of the list |
288 | | */ |
289 | | void free_contacts(contact_t** _c) |
290 | 0 | { |
291 | 0 | contact_t* ptr; |
292 | |
|
293 | 0 | while(*_c) { |
294 | 0 | ptr = *_c; |
295 | 0 | *_c = (*_c)->next; |
296 | 0 | if (ptr->params) { |
297 | 0 | free_params(ptr->params); |
298 | 0 | } |
299 | 0 | pkg_free(ptr); |
300 | 0 | } |
301 | 0 | } |
302 | | |
303 | | |
304 | | /* |
305 | | * Print list of contacts, just for debugging |
306 | | */ |
307 | | void log_contacts(contact_t* _c) |
308 | 0 | { |
309 | 0 | contact_t* ptr; |
310 | |
|
311 | 0 | ptr = _c; |
312 | |
|
313 | 0 | while(ptr) { |
314 | 0 | LM_DBG("---Contact---\n"); |
315 | 0 | LM_DBG("name : '%.*s'\n", ptr->name.len, ptr->name.s); |
316 | 0 | LM_DBG("URI : '%.*s'\n", ptr->uri.len, ptr->uri.s); |
317 | 0 | LM_DBG("instance: %p\n", ptr->instance); |
318 | 0 | LM_DBG("q : %p\n", ptr->q); |
319 | 0 | LM_DBG("expires : %p\n", ptr->expires); |
320 | 0 | LM_DBG("received: %p\n", ptr->received); |
321 | 0 | LM_DBG("method : %p\n", ptr->methods); |
322 | 0 | LM_DBG("len : %d\n", ptr->len); |
323 | 0 | if (ptr->params) { |
324 | 0 | print_params(ptr->params); |
325 | 0 | } |
326 | 0 | LM_DBG("---/Contact---\n"); |
327 | 0 | ptr = ptr->next; |
328 | 0 | } |
329 | 0 | } |