* dbus/dbus-auth.c (client_try_next_mechanism): Remove logic to
[platform/upstream/dbus.git] / dbus / dbus-address.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-address.c  Server address parser.
3  *
4  * Copyright (C) 2003  CodeFactory AB
5  *
6  * Licensed under the Academic Free License version 2.0
7  * 
8  * This program 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  * This program 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23
24 #include <config.h>
25 #include "dbus-address.h"
26 #include "dbus-internals.h"
27 #include "dbus-list.h"
28 #include "dbus-string.h"
29
30 /**
31  * @defgroup DBusAddressInternals Address parsing
32  * @ingroup  DBusInternals
33  * @brief Implementation of parsing addresses of D-BUS servers.
34  *
35  * @{
36  */
37
38 /**
39  * Internals of DBusAddressEntry 
40  */
41 struct DBusAddressEntry
42 {
43   DBusString method; /**< The address type (unix, tcp, etc.) */
44
45   DBusList *keys;    /**< List of keys */
46   DBusList *values;  /**< List of values */
47 };
48
49 /** @} */ /* End of internals */
50
51 static void
52 dbus_address_entry_free (DBusAddressEntry *entry)
53 {
54   DBusList *link;
55   
56   _dbus_string_free (&entry->method);
57
58   link = _dbus_list_get_first_link (&entry->keys);
59   while (link != NULL)
60     {
61       _dbus_string_free (link->data);
62       dbus_free (link->data);
63       
64       link = _dbus_list_get_next_link (&entry->keys, link);
65     }
66   _dbus_list_clear (&entry->keys);
67   
68   link = _dbus_list_get_first_link (&entry->values);
69   while (link != NULL)
70     {
71       _dbus_string_free (link->data);
72       dbus_free (link->data);
73       
74       link = _dbus_list_get_next_link (&entry->values, link);
75     }
76   _dbus_list_clear (&entry->values);
77   
78   dbus_free (entry);
79 }
80
81 /**
82  * @defgroup DBusAddress Address parsing
83  * @ingroup  DBus
84  * @brief Parsing addresses of D-BUS servers.
85  *
86  * @{
87  */
88
89 /**
90  * Frees a #NULL-terminated array of address entries.
91  *
92  * @param entries the array.
93  */
94 void
95 dbus_address_entries_free (DBusAddressEntry **entries)
96 {
97   int i;
98   
99   for (i = 0; entries[i] != NULL; i++)
100     dbus_address_entry_free (entries[i]);
101   dbus_free (entries);
102 }
103
104 static DBusAddressEntry *
105 create_entry (void)
106 {
107   DBusAddressEntry *entry;
108
109   entry = dbus_new0 (DBusAddressEntry, 1);
110
111   if (entry == NULL)
112     return NULL;
113
114   if (!_dbus_string_init (&entry->method))
115     {
116       dbus_free (entry);
117       return NULL;
118     }
119
120   return entry;
121 }
122
123 /**
124  * Returns the method string of an address entry.
125  *
126  * @param entry the entry.
127  * @returns a string describing the method. This string
128  * must not be freed.
129  */
130 const char *
131 dbus_address_entry_get_method (DBusAddressEntry *entry)
132 {
133   return _dbus_string_get_const_data (&entry->method);
134 }
135
136 /**
137  * Returns a value from a key of an entry.
138  *
139  * @param entry the entry.
140  * @param key the key.
141  * @returns the key value. This string must not be fred.
142  */
143 const char *
144 dbus_address_entry_get_value (DBusAddressEntry *entry,
145                               const char       *key)
146 {
147   DBusList *values, *keys;
148
149   keys = _dbus_list_get_first_link (&entry->keys);
150   values = _dbus_list_get_first_link (&entry->values);
151
152   while (keys != NULL)
153     {
154       _dbus_assert (values != NULL);
155
156       if (_dbus_string_equal_c_str (keys->data, key))
157         return _dbus_string_get_const_data (values->data);
158
159       keys = _dbus_list_get_next_link (&entry->keys, keys);
160       values = _dbus_list_get_next_link (&entry->values, values);
161     }
162   
163   return NULL;
164 }
165
166 /**
167  * Parses an address string of the form:
168  *
169  * method:key=value,key=value;method:key=value
170  *
171  * @todo document address format in the specification
172  *
173  * @todo need to be able to escape ';' and ',' in the
174  * key values, and the parsing needs to handle that.
175  * 
176  * @param address the address.
177  * @param entry return location to an array of entries.
178  * @param array_len return location for array length.
179  * @param error address where an error can be returned.
180  * @returns #TRUE on success, #FALSE otherwise.
181  */
182 dbus_bool_t
183 dbus_parse_address (const char         *address,
184                     DBusAddressEntry ***entry,
185                     int                *array_len,
186                     DBusError          *error)
187 {
188   DBusString str;
189   int pos, end_pos, len, i;
190   DBusList *entries, *link;
191   DBusAddressEntry **entry_array;
192
193   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
194   
195   _dbus_string_init_const (&str, address);
196
197   entries = NULL;
198   pos = 0;
199   len = _dbus_string_get_length (&str);
200   
201   while (pos < len)
202     {
203       DBusAddressEntry *entry;
204
205       int found_pos;
206
207       entry = create_entry ();
208       if (!entry)
209         {
210           dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
211
212           goto error;
213         }
214       
215       /* Append the entry */
216       if (!_dbus_list_append (&entries, entry))
217         {
218           dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
219           dbus_address_entry_free (entry);
220           goto error;
221         }
222       
223       /* Look for a semi-colon */
224       if (!_dbus_string_find (&str, pos, ";", &end_pos))
225         end_pos = len;
226       
227       /* Look for the colon : */
228       if (!_dbus_string_find_to (&str, pos, end_pos, ":", &found_pos))
229         {
230           dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, "Address does not contain a colon");
231           goto error;
232         }
233
234       if (!_dbus_string_copy_len (&str, pos, found_pos - pos, &entry->method, 0))
235         {
236           dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
237           goto error;
238         }
239           
240       pos = found_pos + 1;
241
242       while (pos < end_pos)
243         {
244           int comma_pos, equals_pos;
245
246           if (!_dbus_string_find_to (&str, pos, end_pos, ",", &comma_pos))
247             comma_pos = end_pos;
248           
249           if (!_dbus_string_find_to (&str, pos, comma_pos, "=", &equals_pos) ||
250               equals_pos == pos || equals_pos + 1 == comma_pos)
251             {
252               dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
253                               "'=' character not found or has no value following it");
254               goto error;
255             }
256           else
257             {
258               DBusString *key;
259               DBusString *value;
260
261               key = dbus_new0 (DBusString, 1);
262
263               if (!key)
264                 {
265                   dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);             
266                   goto error;
267                 }
268
269               value = dbus_new0 (DBusString, 1);
270               if (!value)
271                 {
272                   dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
273                   dbus_free (key);
274                   goto error;
275                 }
276               
277               if (!_dbus_string_init (key))
278                 {
279                   dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
280                   dbus_free (key);
281                   dbus_free (value);
282                   
283                   goto error;
284                 }
285               
286               if (!_dbus_string_init (value))
287                 {
288                   dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
289                   _dbus_string_free (key);
290
291                   dbus_free (key);
292                   dbus_free (value);              
293                   goto error;
294                 }
295
296               if (!_dbus_string_copy_len (&str, pos, equals_pos - pos, key, 0))
297                 {
298                   dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
299                   _dbus_string_free (key);
300                   _dbus_string_free (value);
301
302                   dbus_free (key);
303                   dbus_free (value);              
304                   goto error;
305                 }
306
307               if (!_dbus_string_copy_len (&str, equals_pos + 1, comma_pos - equals_pos - 1, value, 0))
308                 {
309                   dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);             
310                   _dbus_string_free (key);
311                   _dbus_string_free (value);
312
313                   dbus_free (key);
314                   dbus_free (value);              
315                   goto error;
316                 }
317
318               if (!_dbus_list_append (&entry->keys, key))
319                 {
320                   dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);             
321                   _dbus_string_free (key);
322                   _dbus_string_free (value);
323
324                   dbus_free (key);
325                   dbus_free (value);              
326                   goto error;
327                 }
328
329               if (!_dbus_list_append (&entry->values, value))
330                 {
331                   dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);             
332                   _dbus_string_free (value);
333
334                   dbus_free (value);
335                   goto error;             
336                 }
337             }
338
339           pos = comma_pos + 1;
340         }
341
342       pos = end_pos + 1;
343     }
344
345   *array_len = _dbus_list_get_length (&entries);
346   
347   entry_array = dbus_new (DBusAddressEntry *, *array_len + 1);
348
349   if (!entry_array)
350     {
351       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
352       
353       goto error;
354     }
355   
356   entry_array [*array_len] = NULL;
357
358   link = _dbus_list_get_first_link (&entries);
359   i = 0;
360   while (link != NULL)
361     {
362       entry_array[i] = link->data;
363       i++;
364       link = _dbus_list_get_next_link (&entries, link);
365     }
366
367   _dbus_list_clear (&entries);
368   *entry = entry_array;
369
370   return TRUE;
371
372  error:
373   
374   link = _dbus_list_get_first_link (&entries);
375   while (link != NULL)
376     {
377       dbus_address_entry_free (link->data);
378       link = _dbus_list_get_next_link (&entries, link);
379     }
380
381   _dbus_list_clear (&entries);
382   
383   return FALSE;
384   
385 }
386
387
388 /** @} */ /* End of public API */
389
390 #ifdef DBUS_BUILD_TESTS
391 #include "dbus-test.h"
392
393 dbus_bool_t
394 _dbus_address_test (void)
395 {
396   DBusAddressEntry **entries;
397   int len;  
398   DBusError error;
399
400   dbus_error_init (&error);
401   
402   if (!dbus_parse_address ("unix:path=/tmp/foo;debug:name=test,sliff=sloff;",
403                            &entries, &len, &error))
404     _dbus_assert_not_reached ("could not parse address");
405   _dbus_assert (len == 2);
406   _dbus_assert (strcmp (dbus_address_entry_get_value (entries[0], "path"), "/tmp/foo") == 0);
407   _dbus_assert (strcmp (dbus_address_entry_get_value (entries[1], "name"), "test") == 0);
408   _dbus_assert (strcmp (dbus_address_entry_get_value (entries[1], "sliff"), "sloff") == 0);
409   
410   dbus_address_entries_free (entries);
411
412   /* Different possible errors */
413   if (dbus_parse_address ("foo", &entries, &len, &error))
414     _dbus_assert_not_reached ("Parsed incorrect address.");
415   else
416     dbus_error_free (&error);
417   
418   if (dbus_parse_address ("foo:bar", &entries, &len, &error))
419     _dbus_assert_not_reached ("Parsed incorrect address.");
420   else
421     dbus_error_free (&error);
422   
423   if (dbus_parse_address ("foo:bar,baz", &entries, &len, &error))
424     _dbus_assert_not_reached ("Parsed incorrect address.");
425   else
426     dbus_error_free (&error);
427   
428   if (dbus_parse_address ("foo:bar=foo,baz", &entries, &len, &error))
429     _dbus_assert_not_reached ("Parsed incorrect address.");
430   else
431     dbus_error_free (&error);
432   
433   if (dbus_parse_address ("foo:bar=foo;baz", &entries, &len, &error))
434     _dbus_assert_not_reached ("Parsed incorrect address.");
435   else
436     dbus_error_free (&error);
437   
438   if (dbus_parse_address ("foo:=foo", &entries, &len, &error))
439     _dbus_assert_not_reached ("Parsed incorrect address.");
440   else
441     dbus_error_free (&error);
442   
443   if (dbus_parse_address ("foo:foo=", &entries, &len, &error))
444     _dbus_assert_not_reached ("Parsed incorrect address.");
445   else
446     dbus_error_free (&error);
447
448   if (dbus_parse_address ("foo:foo,bar=baz", &entries, &len, &error))
449     _dbus_assert_not_reached ("Parsed incorrect address.");
450   else
451     dbus_error_free (&error);
452
453   return TRUE;
454 }
455
456 #endif