Revert "Revert "and added files""
[bcm963xx.git] / userapps / opensource / libosip2 / src / osipparser2 / osip_via.c
1 /*
2   The oSIP library implements the Session Initiation Protocol (SIP -rfc3261-)
3   Copyright (C) 2001,2002,2003  Aymeric MOIZARD jack@atosc.org
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 <stdlib.h>
21 #include <stdio.h>
22
23 #include <osipparser2/osip_port.h>
24 #include <osipparser2/osip_message.h>
25 #include <osipparser2/osip_parser.h>
26 #include "parser.h"
27
28 /* adds the via header to message.              */
29 /* INPUT : const char *hvalue | value of header.    */
30 /* OUTPUT: osip_message_t *sip | structure to save results.  */
31 /* returns -1 on error. */
32 int
33 osip_message_set_via (osip_message_t * sip, const char *hvalue)
34 {
35   osip_via_t *via;
36   int i;
37
38   if (hvalue == NULL || hvalue[0] == '\0')
39     return 0;
40
41   i = osip_via_init (&via);
42   if (i != 0)
43     return -1;
44   i = osip_via_parse (via, hvalue);
45   if (i != 0)
46     {
47       osip_via_free (via);
48       return -1;
49     }
50   sip->message_property = 2;
51   osip_list_add (sip->vias, via, -1);
52   return 0;
53 }
54
55 /* adds the via header to message in the first position. (to be used by proxy) */
56 /* INPUT : const char *hvalue | value of header.    */
57 /* OUTPUT: osip_message_t *sip | structure to save results.  */
58 /* returns -1 on error. */
59 int
60 osip_message_append_via (osip_message_t * sip, const char *hvalue)
61 {
62   osip_via_t *via;
63   int i;
64
65   i = osip_via_init (&via);
66   if (i != 0)
67     return -1;
68   i = osip_via_parse (via, hvalue);
69   if (i != 0)
70     {
71       osip_via_free (via);
72       return -1;
73     }
74   sip->message_property = 2;
75   osip_list_add (sip->vias, via, 0);
76   return 0;
77 }
78
79 /* returns the via header.                         */
80 /* INPUT : int pos | pos of via header.            */
81 /* INPUT : osip_message_t *sip | sip message.               */
82 /* OUTPUT: osip_via_t *via | structure to save results. */
83 /* returns null on error. */
84 int
85 osip_message_get_via (const osip_message_t * sip, int pos, osip_via_t ** dest)
86 {
87   *dest = NULL;
88   if (sip == NULL)
89     return -1;
90   if (osip_list_size (sip->vias) <= pos)
91     return -1;
92   *dest = (osip_via_t *) osip_list_get (sip->vias, pos);
93
94   return pos;
95 }
96
97
98 int
99 osip_via_init (osip_via_t ** via)
100 {
101   *via = (osip_via_t *) osip_malloc (sizeof (osip_via_t));
102   if (*via == NULL)
103     return -1;
104   (*via)->version = NULL;
105   (*via)->protocol = NULL;
106   (*via)->host = NULL;
107   (*via)->port = NULL;
108   (*via)->comment = NULL;
109
110   (*via)->via_params = (osip_list_t *) osip_malloc (sizeof (osip_list_t));
111   if ((*via)->via_params == NULL)
112     {
113       osip_free (*via);
114       *via = NULL;
115       return -1;
116     }
117   osip_list_init ((*via)->via_params);
118
119   return 0;
120 }
121
122 void
123 osip_via_free (osip_via_t * via)
124 {
125   if (via == NULL)
126     return;
127   osip_free (via->version);
128   osip_free (via->protocol);
129   osip_free (via->host);
130   osip_free (via->port);
131   osip_free (via->comment);
132   osip_generic_param_freelist (via->via_params);
133
134   osip_free (via);
135 }
136
137 int
138 osip_via_parse (osip_via_t * via, const char *hvalue)
139 {
140   const char *version;
141   const char *protocol;
142   const char *host;
143   const char *ipv6host;
144   const char *port;
145   const char *via_params;
146   const char *comment;
147
148   version = strchr (hvalue, '/');
149   if (version == NULL)
150     return -1;
151
152   protocol = strchr (version + 1, '/');
153   if (protocol == NULL)
154     return -1;
155
156   /* set the version */
157   if (protocol - version < 2)
158     return -1;
159   via->version = (char *) osip_malloc (protocol - version);
160   if (via->version == NULL)
161     return -1;
162   osip_strncpy (via->version, version + 1, protocol - version - 1);
163   osip_clrspace (via->version);
164
165   /* Here: we avoid matching an additionnal space */
166   host = strchr (protocol + 1, ' ');
167   if (host == NULL)
168     return -1;                  /* fixed in 0.8.4 */
169   if (host == protocol + 1)     /* there are extra SPACE characters */
170     {
171       while (0 == strncmp (host, " ", 1))
172         {
173           host++;
174           if (strlen (host) == 1)
175             return -1;          /* via is malformed */
176         }
177       /* here, we match the real space located after the protocol name */
178       host = strchr (host + 1, ' ');
179       if (host == NULL)
180         return -1;              /* fixed in 0.8.4 */
181     }
182
183   /* set the protocol */
184   if (host - protocol < 2)
185     return -1;
186   via->protocol = (char *) osip_malloc (host - protocol);
187   if (via->protocol == NULL)
188     return -1;
189   osip_strncpy (via->protocol, protocol + 1, host - protocol - 1);
190   osip_clrspace (via->protocol);
191
192   /* comments in Via are not allowed any more in the latest draft (09) */
193   comment = strchr (host, '(');
194
195   if (comment != NULL)
196     {
197       char *end_comment;
198
199       end_comment = strchr (host, ')');
200       if (end_comment == NULL)
201         return -1;              /* if '(' exist ')' MUST exist */
202       if (end_comment - comment < 2)
203         return -1;
204       via->comment = (char *) osip_malloc (end_comment - comment);
205       if (via->comment == NULL)
206         return -1;
207       osip_strncpy (via->comment, comment + 1, end_comment - comment - 1);
208       comment--;
209     }
210   else
211     comment = host + strlen (host);
212
213   via_params = strchr (host, ';');
214
215   if ((via_params != NULL) && (via_params < comment))
216     /* via params exist */
217     {
218       char *tmp;
219
220       if (comment - via_params + 1 < 2)
221         return -1;
222       tmp = (char *) osip_malloc (comment - via_params + 1);
223       if (tmp == NULL)
224         return -1;
225       osip_strncpy (tmp, via_params, comment - via_params);
226       __osip_generic_param_parseall (via->via_params, tmp);
227       osip_free (tmp);
228     }
229
230   if (via_params == NULL)
231     via_params = comment;
232
233   /* add ipv6 support (0.8.4) */
234   /* Via: SIP/2.0/UDP [mlke::zeezf:ezfz:zef:zefzf]:port;.... */
235   ipv6host = strchr (host, '[');
236   if (ipv6host != NULL && ipv6host < via_params)
237     {
238       port = strchr (ipv6host, ']');
239       if (port == NULL || port > via_params)
240         return -1;
241
242       if (port - ipv6host < 2)
243         return -1;
244       via->host = (char *) osip_malloc (port - ipv6host);
245       if (via->host == NULL)
246         return -1;
247       osip_strncpy (via->host, ipv6host + 1, port - ipv6host - 1);
248       osip_clrspace (via->host);
249
250       port = strchr (port, ':');
251     }
252   else
253     {
254       port = strchr (host, ':');
255       ipv6host = NULL;
256     }
257
258   if ((port != NULL) && (port < via_params))
259     {
260       if (via_params - port < 2)
261         return -1;
262       via->port = (char *) osip_malloc (via_params - port);
263       if (via->port == NULL)
264         return -1;
265       osip_strncpy (via->port, port + 1, via_params - port - 1);
266       osip_clrspace (via->port);
267     }
268   else
269     port = via_params;
270
271   /* host is already set in the case of ipv6 */
272   if (ipv6host != NULL)
273     return 0;
274
275   if (port - host < 2)
276     return -1;
277   via->host = (char *) osip_malloc (port - host);
278   if (via->host == NULL)
279     return -1;
280   osip_strncpy (via->host, host + 1, port - host - 1);
281   osip_clrspace (via->host);
282
283   return 0;
284 }
285
286
287 /* returns the via header as a string. */
288 /* INPUT : osip_via_t via* | via header.    */
289 /* returns null on error. */
290 int
291 osip_via_to_str (const osip_via_t * via, char **dest)
292 {
293   char *buf;
294   size_t len;
295   size_t plen;
296   char *tmp;
297
298   *dest = NULL;
299   if ((via == NULL) || (via->host == NULL)
300       || (via->version == NULL) || (via->protocol == NULL))
301     return -1;
302
303   len = strlen (via->version) + 1 + strlen (via->protocol) + 1 + 3 + 2; /* sip/xxx/xxx */
304   len = len + strlen (via->host) + 3 + 1;
305   if (via->port != NULL)
306     len = len + strlen (via->port) + 2;
307
308   buf = (char *) osip_malloc (len);
309   if (buf == NULL)
310     return -1;
311
312   if (strchr (via->host, ':') != NULL)
313     {
314       if (via->port == NULL)
315         sprintf (buf, "SIP/%s/%s [%s]", via->version, via->protocol,
316                  via->host);
317       else
318         sprintf (buf, "SIP/%s/%s [%s]:%s", via->version, via->protocol,
319                  via->host, via->port);
320     }
321   else
322     {
323       if (via->port == NULL)
324         sprintf (buf, "SIP/%s/%s %s", via->version, via->protocol, via->host);
325       else
326         sprintf (buf, "SIP/%s/%s %s:%s", via->version, via->protocol,
327                  via->host, via->port);
328     }
329
330
331
332   {
333     int pos = 0;
334     osip_generic_param_t *u_param;
335
336     while (!osip_list_eol (via->via_params, pos))
337       {
338         u_param =
339           (osip_generic_param_t *) osip_list_get (via->via_params, pos);
340
341         if (u_param->gvalue == NULL)
342           plen = strlen (u_param->gname) + 2;
343         else
344           plen = strlen (u_param->gname) + strlen (u_param->gvalue) + 3;
345         len = len + plen;
346         buf = (char *) realloc (buf, len);
347         tmp = buf;
348         tmp = tmp + strlen (tmp);
349         if (u_param->gvalue == NULL)
350           sprintf (tmp, ";%s", u_param->gname);
351         else
352           sprintf (tmp, ";%s=%s", u_param->gname, u_param->gvalue);
353         pos++;
354       }
355   }
356
357   if (via->comment != NULL)
358     {
359       len = len + strlen (via->comment) + 4;
360       buf = (char *) realloc (buf, len);
361       tmp = buf;
362       tmp = tmp + strlen (tmp);
363       sprintf (tmp, " (%s)", via->comment);
364     }
365   *dest = buf;
366   return 0;
367 }
368
369 void
370 via_set_version (osip_via_t * via, char *version)
371 {
372   via->version = version;
373 }
374
375 char *
376 via_get_version (osip_via_t * via)
377 {
378   if (via == NULL)
379     return NULL;
380   return via->version;
381 }
382
383 void
384 via_set_protocol (osip_via_t * via, char *protocol)
385 {
386   via->protocol = protocol;
387 }
388
389 char *
390 via_get_protocol (osip_via_t * via)
391 {
392   if (via == NULL)
393     return NULL;
394   return via->protocol;
395 }
396
397 void
398 via_set_host (osip_via_t * via, char *host)
399 {
400   via->host = host;
401 }
402
403 char *
404 via_get_host (osip_via_t * via)
405 {
406   if (via == NULL)
407     return NULL;
408   return via->host;
409 }
410
411 void
412 via_set_port (osip_via_t * via, char *port)
413 {
414   via->port = port;
415 }
416
417 char *
418 via_get_port (osip_via_t * via)
419 {
420   if (via == NULL)
421     return NULL;
422   return via->port;
423 }
424
425 void
426 via_set_comment (osip_via_t * via, char *comment)
427 {
428   via->comment = comment;
429 }
430
431 char *
432 via_get_comment (osip_via_t * via)
433 {
434   if (via == NULL)
435     return NULL;
436   return via->comment;
437 }
438
439 int
440 osip_via_clone (const osip_via_t * via, osip_via_t ** dest)
441 {
442   int i;
443   osip_via_t *vi;
444
445   *dest = NULL;
446   if (via == NULL)
447     return -1;
448   if (via->version == NULL)
449     return -1;
450   if (via->protocol == NULL)
451     return -1;
452   if (via->host == NULL)
453     return -1;
454
455   i = osip_via_init (&vi);
456   if (i != 0)
457     return -1;
458   vi->version = osip_strdup (via->version);
459   vi->protocol = osip_strdup (via->protocol);
460   vi->host = osip_strdup (via->host);
461   if (via->port != NULL)
462     vi->port = osip_strdup (via->port);
463   if (via->comment != NULL)
464     vi->comment = osip_strdup (via->comment);
465
466   {
467     int pos = 0;
468     osip_generic_param_t *u_param;
469     osip_generic_param_t *dest_param;
470
471     while (!osip_list_eol (via->via_params, pos))
472       {
473         u_param =
474           (osip_generic_param_t *) osip_list_get (via->via_params, pos);
475         i = osip_generic_param_clone (u_param, &dest_param);
476         if (i != 0)
477           {
478             osip_via_free (vi);
479             return -1;
480           }
481         osip_list_add (vi->via_params, dest_param, -1);
482         pos++;
483       }
484   }
485   *dest = vi;
486   return 0;
487 }
488
489 int
490 osip_via_match (osip_via_t * via1, osip_via_t * via2)
491 {
492   /* Can I really compare it this way??
493      There exist matching rules for via header, but this method
494      should only be used to detect retransmissions so the result should
495      be exactly equivalent. (This may not be true if the retransmission
496      traverse a different set of proxy...  */
497   char *_via1;
498   char *_via2;
499   int i;
500
501   if (via1 == NULL || via2 == NULL)
502     return -1;
503   i = osip_via_to_str (via1, &_via1);
504   if (i != 0)
505     return -1;
506   i = osip_via_to_str (via2, &_via2);
507   if (i != 0)
508     {
509       osip_free (_via1);
510       return -1;
511     }
512
513   i = strcmp (_via1, _via2);
514   osip_free (_via1);
515   osip_free (_via2);
516   if (i != 0)
517     return -1;
518   return 0;
519 }