Fix a potential leak.
[evas_quartz.git] / proto / ecore_dbus / ecore_dbus_address.c
blob16f00190fe72cdbf08dc2138d9cd87c1746a78dd
1 /*
2 * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
3 */
4 #include "config.h"
5 #include "ecore_private.h"
6 #include "Ecore_DBus.h"
7 #include "ecore_dbus_private.h"
8 #include <string.h>
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <ctype.h>
13 static void _ecore_dbus_address_list_free_cb(void *data);
15 static int _ecore_dbus_address_value_char_optional_encode(char c);
16 static char * _ecore_dbus_address_value_decode(const char *value);
17 static char * _ecore_dbus_address_value_encode(const char *value);
19 static void
20 _ecore_dbus_address_list_free_cb(void *data)
22 if (data) free(data);
25 Ecore_DBus_Address *
26 ecore_dbus_address_new()
28 Ecore_DBus_Address *a;
29 a = calloc(1, sizeof(Ecore_DBus_Address));
30 if (!a) return NULL;
32 a->keys = ecore_list_new();
33 ecore_list_free_cb_set(a->keys, _ecore_dbus_address_list_free_cb);
34 a->vals = ecore_list_new();
35 ecore_list_free_cb_set(a->vals, _ecore_dbus_address_list_free_cb);
37 return a;
40 void
41 ecore_dbus_address_free(Ecore_DBus_Address *address)
43 if (!address) return;
44 ecore_list_destroy(address->keys);
45 ecore_list_destroy(address->vals);
46 if (address->transport) free(address->transport);
47 free(address);
51 /**
52 * Parse an address into an array of Ecore_DBus_Address structs
54 Ecore_List *
55 ecore_dbus_address_parse(const char *address)
57 Ecore_List *alist = NULL;
59 Ecore_DBus_Address *a = NULL;
60 char *addcpy;
61 char *p;
63 addcpy = strdup(address);
64 p = addcpy;
65 char *start = NULL;
66 char *transport = p;
67 char *key = NULL;
68 char *val = NULL;
69 int error = 0;
71 alist = ecore_list_new();
72 ecore_list_free_cb_set(alist, ECORE_FREE_CB(ecore_dbus_address_free));
74 while(1)
76 if (!a)
78 start = p;
79 a = ecore_dbus_address_new();
80 if (!a) { error = 1; break; }
83 if (!*p || *p == ';' || *p == ',')
85 /* append value */
86 char sep = *p;
88 if (!val)
90 if (p != start) error = 1;
91 break;
93 *p = '\0';
94 ecore_list_append(a->vals, _ecore_dbus_address_value_decode(val));
95 val = NULL;
97 if (sep == ',')
99 key = p + 1;
101 else
103 /* append address to list */
104 ecore_list_append(alist, a);
105 a = NULL;
106 if (!sep) break; /* end of string */
107 transport = p + 1;
110 else if (*p == '=')
112 /* append key */
113 if (!key) { error = 1; break; }
114 *p = '\0';
115 ecore_list_append(a->keys, strdup(key));
116 key = NULL;
117 val = p + 1;
119 else if (*p == ':')
121 /* append transport */
122 if (!transport) { error = 1; break; }
123 *p = '\0';
124 a->transport = strdup(transport);
125 transport = NULL;
126 key = p + 1;
128 p++;
131 if (error)
133 ecore_list_destroy(alist);
134 alist = NULL;
136 free(addcpy);
137 return alist;
140 const char *
141 ecore_dbus_address_value_get(Ecore_DBus_Address *address, const char *key)
143 int i;
144 char *s;
145 if (!key) return NULL;
147 ecore_list_first_goto(address->keys);
148 i = 0;
149 while((s = ecore_list_next(address->keys)))
151 if (!strcmp(key, s))
153 return ecore_list_index_goto(address->vals, i);
155 i++;
157 return NULL;
160 EAPI char *
161 ecore_dbus_address_string(Ecore_DBus_Address *address)
163 char buf[PATH_MAX];
164 char *key, *val;
165 int left = PATH_MAX - 1; /* space left in the buffer, leaving room for a final null */
167 if (!address) return NULL;
169 snprintf(buf, PATH_MAX, "%s:", address->transport);
170 left -= strlen(address->transport) + 1;
171 ecore_list_first_goto(address->keys);
172 ecore_list_first_goto(address->vals);
173 while ((key = ecore_list_next(address->keys)) && (val = ecore_list_next(address->vals)))
175 char *encval;
176 strncat(buf, key, left);
177 left -= strlen(key);
178 strncat(buf, "=", left);
179 left -= 1;
180 encval = _ecore_dbus_address_value_encode(val);
181 strncat(buf, encval, left);
182 left -= strlen(encval);
183 free(encval);
185 return strdup(buf);
189 * Connect to the first successful server in a list of addresses.
191 EAPI Ecore_DBus_Server *
192 ecore_dbus_address_list_connect(Ecore_List *addrs, const void *data)
194 Ecore_DBus_Address *addr;
195 ecore_list_first_goto(addrs);
196 /* try each listed address in turn */
197 while ((addr = ecore_list_next(addrs)))
199 Ecore_DBus_Server *svr;
200 svr = ecore_dbus_address_connect(addr, data);
201 if (svr) return svr;
203 return NULL;
207 * Connect to a server by its Ecore_DBus_Address
209 EAPI Ecore_DBus_Server *
210 ecore_dbus_address_connect(Ecore_DBus_Address *addr, const void *data)
212 const char *name;
213 int type;
214 int port;
216 char *addr_string;
217 addr_string = ecore_dbus_address_string(addr);
218 printf("[ecore_dbus] connecting to address: %s\n", addr_string);
219 free(addr_string);
221 if (!strcmp(addr->transport, "unix"))
223 type = ECORE_CON_LOCAL_SYSTEM;
224 name = ecore_dbus_address_value_get(addr, "path");
226 if (!name)
228 name = ecore_dbus_address_value_get(addr, "abstract");
229 type = ECORE_CON_LOCAL_ABSTRACT;
232 if (!name) return NULL;
233 port = -1;
235 else if (!strcmp(addr->transport, "tcp"))
237 /* XXX implement (and verify transport name is actually 'tcp') */
238 return NULL;
240 else
242 return NULL;
244 return ecore_dbus_server_connect(type, name, port, data);
247 void
248 ecore_dbus_print_address_list(Ecore_List *addresses)
250 Ecore_DBus_Address *a;
252 ecore_list_first_goto(addresses);
253 while((a = ecore_list_next(addresses)))
255 char *k, *v;
256 printf("Transport: %s\n", a->transport);
258 ecore_list_first_goto(a->keys);
259 ecore_list_first_goto(a->vals);
260 k = ecore_list_next(a->keys);
261 v = ecore_list_next(a->vals);
262 while (k || v)
264 printf(" %s => %s\n", k, v);
265 k = ecore_list_next(a->keys);
266 v = ecore_list_next(a->vals);
271 static int
272 _ecore_dbus_address_value_char_optional_encode(char c)
274 /* addl optional chars (other than 0-9A-Za-z) */
275 static const char OPTIONAL_CHARS[] = {'_', '-', '/', '.', '\\'};
276 unsigned int i;
278 if (isascii(c) && (isalpha(c) || isdigit(c))) return 1;
279 for (i = 0; i < sizeof(OPTIONAL_CHARS); i++)
280 if (c == OPTIONAL_CHARS[i]) return 1;
282 return 0;
287 static char *
288 _ecore_dbus_address_value_encode(const char *value)
290 char *buf;
291 const char *p;
292 int i;
294 static const char hexdigits[16] = {
295 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
296 'a', 'b', 'c', 'd', 'e', 'f'
300 if (!value) return NULL;
301 buf = malloc(3 * strlen(value) + 1);
303 p = value;
304 i = 0;
305 while (*p)
307 if (_ecore_dbus_address_value_char_optional_encode(*p))
308 buf[i++] = *p;
309 else
311 buf[i++] = '%';
312 buf[i++] = hexdigits[(*p >> 4)];
313 buf[i++] = hexdigits[(*p & 0xf)];
315 p++;
318 buf[i] = '\0';
319 return buf;
322 static char *
323 _ecore_dbus_address_value_decode(const char *value)
325 char *buf;
326 const char *p;
327 int i;
329 buf = malloc(strlen(value) + 1);
331 *buf = '\0';
332 p = value;
333 i = 0;
334 while (*p)
336 if (*p == '%')
338 char c = 0;
339 int j;
340 for (j = 0; j < 2; j++)
342 p++;
343 c = c << 4;
344 if ('0' <= *p && *p <= '9')
345 c |= *p - '0';
346 else if ('A' <= *p && *p <= 'F')
347 c |= 10 + *p - 'A';
348 else if ('a' <= *p && *p <= 'f') /* a-f */
349 c |= 10 + *p - 'a';
351 buf[i++] = c;
353 else
354 buf[i++] = *p;
356 p++;
359 buf[i] = '\0';
360 return buf;