OSDN Git Service

2013.10.24
[uclinux-h8/uClinux-dist.git] / user / ser / parser / parse_methods.c
1 /*
2  * $Id: parse_methods.c,v 1.2.2.1 2005/07/20 17:11:52 andrei Exp $
3  *
4  * Copyright (c) 2004 Juha Heinanen
5  *
6  * This file is part of ser, a free SIP server.
7  *
8  * ser 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  * For a license to use the ser software under conditions
14  * other than those described here, or to purchase support for this
15  * software, please contact iptel.org by e-mail at the following addresses:
16  *    info@iptel.org
17  *
18  * ser is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License 
24  * along with this program; if not, write to the Free Software 
25  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26  */
27
28 #include <strings.h>
29 #include "../dprint.h"
30 #include "../trim.h"
31 #include "parse_methods.h"
32
33
34 /*
35  * Check if argument is valid RFC3261 token character.
36  */
37 static int token_char(char _c)
38 {
39         return  (_c >= 65 && _c <= 90) ||        /* upper alpha */
40                 (_c >= 97 && _c <= 122) ||       /* lower aplha */
41                 (_c >= 48 && _c <= 57) ||        /* digits */
42                 (_c == '-') || (_c == '.') || (_c == '!') || (_c == '%') ||
43                 (_c == '*') || (_c == '_') || (_c == '+') || (_c == '`') ||
44                 (_c == '\'') || (_c == '~') || (_c == '+') || (_c == '`');
45  }
46  
47  
48  /*
49   * Parse a method pointed by _next, assign its enum bit to _method, and update
50   * _next past the method. Returns 1 if parse succeeded and 0 otherwise.
51   */
52 static int parse_method(str* _next, unsigned int* _method) 
53  {
54          if (!_next || !_method) {
55                  LOG(L_ERR, "parse_method: Invalid parameter value\n");
56                  return 0;
57          }
58          
59          if (!_next->len || !_next->s) {
60                  DBG("parse_method: No input\n");
61                  return 1;
62          }
63
64          switch ((_next->s)[0]) {
65          case 'A':
66          case 'a':
67                  if ((_next->len > 2) && !strncasecmp(_next->s + 1, "ck", 2)) {
68                         *_method = METH_ACK;
69                         _next->len -= 3;
70                         _next->s += 3;
71                         return 1;
72                 } else {
73                         goto unknown;
74                 }
75
76         case 'B':
77         case 'b':
78                 if ((_next->len > 2) && !strncasecmp(_next->s + 1, "ye", 2)) {
79                         *_method = METH_BYE;
80                         _next->len -= 3;
81                         _next->s += 3;
82                         return 1;
83                 } else {
84                         goto unknown;
85                 }
86
87         case 'C':
88         case 'c':
89                 if ((_next->len > 5) && !strncasecmp(_next->s + 1, "ancel", 5)) {
90                         *_method = METH_CANCEL;
91                         _next->len -= 6;
92                         _next->s += 6;
93                         return 1;
94                 } else {
95                         goto unknown;
96                 }
97
98         case 'I':
99         case 'i':
100                 if ((_next->len > 3) &&
101                     ((*(_next->s + 1) == 'N') || (*(_next->s + 1) == 'n'))) {
102                         if (!strncasecmp(_next->s + 2, "fo", 2)) {
103                                 *_method = METH_INFO;
104                                 _next->len -= 4;
105                                 _next->s += 4;
106                                 return 1;
107                         }
108
109                         if ((_next->len > 5) && !strncasecmp(_next->s + 2, "vite", 4)) {
110                                 *_method = METH_INVITE;
111                                 _next->len -= 6;
112                                 _next->s += 6;
113                                 return 1;
114                         }
115                 }
116                 goto unknown;
117
118         case 'M':
119         case 'm':
120                 if ((_next->len > 6) && !strncasecmp(_next->s + 1, "essage", 6)) {
121                         *_method = METH_MESSAGE;
122                         _next->len -= 7;
123                         _next->s += 7;
124                         return 1;
125                 } else {
126                         goto unknown;
127                 }
128
129         case 'N':
130         case 'n':
131                 if ((_next->len > 5) && !strncasecmp(_next->s + 1, "otify", 5)) {
132                         *_method = METH_NOTIFY;
133                         _next->len -= 6;
134                         _next->s += 6;
135                         return 1;
136                 } else {
137                         goto unknown;
138                 }
139
140         case 'O':
141         case 'o':
142                 if ((_next->len > 6) && !strncasecmp(_next->s + 1, "ptions", 6)) {
143                         *_method = METH_OPTIONS;
144                         _next->len -= 7;
145                         _next->s += 7;
146                         return 1;
147                 } else {
148                         goto unknown;
149                 }
150
151         case 'P':
152         case 'p':
153                 if ((_next->len > 4) && !strncasecmp(_next->s + 1, "rack", 4)) {
154                         *_method = METH_PRACK;
155                         _next->len -= 5;
156                         _next->s += 5;
157                         return 1;
158                 } else {
159                         goto unknown;
160                 }
161
162         case 'R':
163         case 'r':
164                 if ((_next->len > 4) &&
165                     ((*(_next->s + 1) == 'E') || (*(_next->s + 1) == 'e'))) {
166                         if (!strncasecmp(_next->s + 2, "fer", 3)) {
167                                 *_method = METH_REFER;
168                                 _next->len -= 5;
169                                 _next->s += 5;
170                                 return 1;
171                         }
172
173                         if ((_next->len > 7) && !strncasecmp(_next->s + 2, "gister", 6)) {
174                                 *_method = METH_REGISTER;
175                                 _next->len -= 8;
176                                 _next->s += 8;
177                                 return 1;
178                         }
179                 }
180                 goto unknown;
181
182         case 'S':
183         case 's':
184                 if ((_next->len > 8) && !strncasecmp(_next->s + 1, "ubscribe", 8)) {
185                         *_method = METH_SUBSCRIBE;
186                         _next->len -= 9;
187                         _next->s += 9;
188                         return 1;
189                 } else {
190                         goto unknown;
191                 }
192
193         case 'U':
194         case 'u':
195                 if ((_next->len > 5) && !strncasecmp(_next->s + 1, "pdate", 5)) {
196                         *_method = METH_UPDATE;
197                         _next->len -= 6;
198                         _next->s += 6;
199                         return 1;
200                 } else {
201                         goto unknown;
202                 }
203
204         default:
205                 goto unknown;
206         }
207  
208  unknown:
209         if (token_char(*(_next->s))) {
210                 do { 
211                         _next->s++;
212                         _next->len--;
213                 } while (_next->len && token_char(*(_next->s)));
214                 *_method = METH_UNKNOWN;
215                 return 1;
216         } else {
217                 return 0;
218         }
219  }
220  
221  
222  /* 
223   * Parse comma separated list of methods pointed by _body and assign their
224   * enum bits to _methods.  Returns 1 on success and 0 on failure.
225   */
226  int parse_methods(str* _body, unsigned int* _methods)
227  {
228         str next;
229         unsigned int method;
230         
231         method=0; /* fixes silly gcc 4.x warning */
232  
233         if (!_body || !_methods) {
234                 LOG(L_ERR, "parse_methods: Invalid parameter value\n");
235                 return 0;
236         }
237
238         next.len = _body->len;
239         next.s = _body->s;
240  
241         trim_leading(&next);
242  
243         if (next.len == 0) {
244                 LOG(L_ERR, "ERROR: parse_methods: Empty body\n");
245                 return 0;
246         }
247
248         *_methods = 0;
249  
250         while (1) {
251                 if (parse_method(&next, &method)) {
252                         *_methods |= method;
253                 } else {
254                         LOG(L_ERR, "ERROR: parse_methods: Invalid method\n");
255                         return 0;
256                 }
257                 
258                 trim_leading(&next);
259                 if (next.len) {
260                         if (next.s[0] == ',') {
261                                 next.len--;
262                                 next.s++;
263                                 trim_leading(&next);
264                                 if (next.len == 0) {
265                                         LOG(L_ERR, "ERROR: parse_methods: Method expected\n");
266                                         return 0;
267                                 }
268                         } else {
269                                 LOG(L_ERR, "ERROR: parse_methods: Comma expected\n");
270                                 return 0;
271                         }
272                 } else {
273                         break;
274                 }
275         }
276
277         return 1;
278  }