Bug 621213 – GDBusProxy and well-known names
[platform/upstream/glib.git] / gio / gdbusutils.c
1 /* GDBus - GLib D-Bus Library
2  *
3  * Copyright (C) 2008-2010 Red Hat, Inc.
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 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
16  * Public License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * Author: David Zeuthen <davidz@redhat.com>
21  */
22
23 #include "config.h"
24
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "gdbusutils.h"
29
30 #include "glibintl.h"
31 #include "gioalias.h"
32
33 /**
34  * SECTION:gdbusutils
35  * @title: D-Bus Utilities
36  * @short_description: Various utilities related to D-Bus.
37  * @include: gio/gio.h
38  *
39  * Various utility routines related to D-Bus.
40  */
41
42 static gboolean
43 is_valid_bus_name_character (gint c,
44                              gboolean allow_hyphen)
45 {
46   return
47     (c >= '0' && c <= '9') ||
48     (c >= 'A' && c <= 'Z') ||
49     (c >= 'a' && c <= 'z') ||
50     (c == '_') ||
51     (allow_hyphen && c == '-');
52 }
53
54 static gboolean
55 is_valid_initial_bus_name_character (gint c,
56                                      gboolean allow_initial_digit,
57                                      gboolean allow_hyphen)
58 {
59   if (allow_initial_digit)
60     return is_valid_bus_name_character (c, allow_hyphen);
61   else
62     return
63       (c >= 'A' && c <= 'Z') ||
64       (c >= 'a' && c <= 'z') ||
65       (c == '_') ||
66       (allow_hyphen && c == '-');
67 }
68
69 static gboolean
70 is_valid_name (const gchar *start,
71                guint len,
72                gboolean allow_initial_digit,
73                gboolean allow_hyphen)
74 {
75   gboolean ret;
76   const gchar *s;
77   const gchar *end;
78   gboolean has_dot;
79
80   ret = FALSE;
81
82   if (len == 0)
83     goto out;
84
85   s = start;
86   end = s + len;
87   has_dot = FALSE;
88   while (s != end)
89     {
90       if (*s == '.')
91         {
92           s += 1;
93           if (G_UNLIKELY (!is_valid_initial_bus_name_character (*s, allow_initial_digit, allow_hyphen)))
94             goto out;
95           has_dot = TRUE;
96         }
97       else if (G_UNLIKELY (!is_valid_bus_name_character (*s, allow_hyphen)))
98         {
99           goto out;
100         }
101       s += 1;
102     }
103
104   if (G_UNLIKELY (!has_dot))
105     goto out;
106
107   ret = TRUE;
108
109  out:
110   return ret;
111 }
112
113 /**
114  * g_dbus_is_name:
115  * @string: The string to check.
116  *
117  * Checks if @string is a valid D-Bus bus name (either unique or well-known).
118  *
119  * Returns: %TRUE if valid, %FALSE otherwise.
120  *
121  * Since: 2.26
122  */
123 gboolean
124 g_dbus_is_name (const gchar *string)
125 {
126   guint len;
127   gboolean ret;
128   const gchar *s;
129   const gchar *end;
130
131   g_return_val_if_fail (string != NULL, FALSE);
132
133   ret = FALSE;
134
135   len = strlen (string);
136   if (G_UNLIKELY (len == 0 || len > 255))
137     goto out;
138
139   s = string;
140   end = s + len;
141   if (*s == ':')
142     {
143       /* handle unique name */
144       if (!is_valid_name (s + 1, len - 1, TRUE, TRUE))
145         goto out;
146       ret = TRUE;
147       goto out;
148     }
149   else if (G_UNLIKELY (*s == '.'))
150     {
151       /* can't start with a . */
152       goto out;
153     }
154   else if (G_UNLIKELY (!is_valid_initial_bus_name_character (*s, FALSE, TRUE)))
155     goto out;
156
157   ret = is_valid_name (s + 1, len - 1, FALSE, TRUE);
158
159  out:
160   return ret;
161 }
162
163 /**
164  * g_dbus_is_unique_name:
165  * @string: The string to check.
166  *
167  * Checks if @string is a valid D-Bus unique bus name.
168  *
169  * Returns: %TRUE if valid, %FALSE otherwise.
170  *
171  * Since: 2.26
172  */
173 gboolean
174 g_dbus_is_unique_name (const gchar *string)
175 {
176   gboolean ret;
177   guint len;
178
179   g_return_val_if_fail (string != NULL, FALSE);
180
181   ret = FALSE;
182
183   len = strlen (string);
184   if (G_UNLIKELY (len == 0 || len > 255))
185     goto out;
186
187   if (G_UNLIKELY (*string != ':'))
188     goto out;
189
190   if (G_UNLIKELY (!is_valid_name (string + 1, len - 1, TRUE, TRUE)))
191     goto out;
192
193   ret = TRUE;
194
195  out:
196   return ret;
197 }
198
199 /**
200  * g_dbus_is_member_name:
201  * @string: The string to check.
202  *
203  * Checks if @string is a valid D-Bus member (e.g. signal or method) name.
204  *
205  * Returns: %TRUE if valid, %FALSE otherwise.
206  *
207  * Since: 2.26
208  */
209 gboolean
210 g_dbus_is_member_name (const gchar *string)
211 {
212   gboolean ret;
213   guint n;
214
215   ret = FALSE;
216   if (G_UNLIKELY (string == NULL))
217     goto out;
218
219   if (G_UNLIKELY (!is_valid_initial_bus_name_character (string[0], FALSE, FALSE)))
220     goto out;
221
222   for (n = 1; string[n] != '\0'; n++)
223     {
224       if (G_UNLIKELY (!is_valid_bus_name_character (string[n], FALSE)))
225         {
226           goto out;
227         }
228     }
229
230   ret = TRUE;
231
232  out:
233   return ret;
234 }
235
236 /**
237  * g_dbus_is_interface_name:
238  * @string: The string to check.
239  *
240  * Checks if @string is a valid D-Bus interface name.
241  *
242  * Returns: %TRUE if valid, %FALSE otherwise.
243  *
244  * Since: 2.26
245  */
246 gboolean
247 g_dbus_is_interface_name (const gchar *string)
248 {
249   guint len;
250   gboolean ret;
251   const gchar *s;
252   const gchar *end;
253
254   g_return_val_if_fail (string != NULL, FALSE);
255
256   ret = FALSE;
257
258   len = strlen (string);
259   if (G_UNLIKELY (len == 0 || len > 255))
260     goto out;
261
262   s = string;
263   end = s + len;
264   if (G_UNLIKELY (*s == '.'))
265     {
266       /* can't start with a . */
267       goto out;
268     }
269   else if (G_UNLIKELY (!is_valid_initial_bus_name_character (*s, FALSE, FALSE)))
270     goto out;
271
272   ret = is_valid_name (s + 1, len - 1, FALSE, FALSE);
273
274  out:
275   return ret;
276 }
277
278 /* ---------------------------------------------------------------------------------------------------- */
279
280 /* TODO: maybe move to glib? if so, it should conform to http://en.wikipedia.org/wiki/Guid and/or
281  *       http://tools.ietf.org/html/rfc4122 - specifically it should have hyphens then.
282  */
283
284 /**
285  * g_dbus_generate_guid:
286  *
287  * Generate a D-Bus GUID that can be used with
288  * e.g. g_dbus_connection_new().
289  *
290  * See the D-Bus specification regarding what strings are valid D-Bus
291  * GUID (for example, D-Bus GUIDs are not RFC-4122 compliant).
292  *
293  * Returns: A valid D-Bus GUID. Free with g_free().
294  *
295  * Since: 2.26
296  */
297 gchar *
298 g_dbus_generate_guid (void)
299 {
300   GString *s;
301   GTimeVal now;
302   guint32 r1;
303   guint32 r2;
304   guint32 r3;
305
306   s = g_string_new (NULL);
307
308   r1 = g_random_int ();
309   r2 = g_random_int ();
310   r3 = g_random_int ();
311   g_get_current_time (&now);
312
313   g_string_append_printf (s, "%08x", r1);
314   g_string_append_printf (s, "%08x", r2);
315   g_string_append_printf (s, "%08x", r3);
316   g_string_append_printf (s, "%08x", (guint32) now.tv_sec);
317
318   return g_string_free (s, FALSE);
319 }
320
321 /**
322  * g_dbus_is_guid:
323  * @string: The string to check.
324  *
325  * Checks if @string is a D-Bus GUID.
326  *
327  * See the D-Bus specification regarding what strings are valid D-Bus
328  * GUID (for example, D-Bus GUIDs are not RFC-4122 compliant).
329  *
330  * Returns: %TRUE if @string is a guid, %FALSE otherwise.
331  *
332  * Since: 2.26
333  */
334 gboolean
335 g_dbus_is_guid (const gchar *string)
336 {
337   gboolean ret;
338   guint n;
339
340   g_return_val_if_fail (string != NULL, FALSE);
341
342   ret = FALSE;
343
344   for (n = 0; n < 32; n++)
345     {
346       if (!g_ascii_isxdigit (string[n]))
347         goto out;
348     }
349   if (string[32] != '\0')
350     goto out;
351
352   ret = TRUE;
353
354  out:
355   return ret;
356 }
357
358 /* ---------------------------------------------------------------------------------------------------- */
359
360 #define __G_DBUS_UTILS_C__
361 #include "gioaliasdef.c"