imagehlp: Use the IMAGE_FIRST_SECTION helper macro.
[wine.git] / dlls / mountmgr.sys / dbus.c
blob6fe6984c21862442cffbd2f222e14f69ce5a2730
1 /*
2 * DBus devices support
4 * Copyright 2006, 2011 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #if 0
22 #pragma makedep unix
23 #endif
25 #include "config.h"
27 #include <errno.h>
28 #include <stdarg.h>
29 #include <stdio.h>
30 #include <dlfcn.h>
31 #include <sys/socket.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
34 #ifdef SONAME_LIBDBUS_1
35 # include <dbus/dbus.h>
36 #endif
38 #include "mountmgr.h"
39 #define USE_WS_PREFIX
40 #include "winsock2.h"
41 #include "dhcpcsdk.h"
42 #include "unixlib.h"
44 #include "wine/debug.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(mountmgr);
48 #ifdef SONAME_LIBDBUS_1
50 #define DBUS_FUNCS \
51 DO_FUNC(dbus_bus_add_match); \
52 DO_FUNC(dbus_bus_get); \
53 DO_FUNC(dbus_bus_get_private); \
54 DO_FUNC(dbus_bus_remove_match); \
55 DO_FUNC(dbus_connection_add_filter); \
56 DO_FUNC(dbus_connection_read_write_dispatch); \
57 DO_FUNC(dbus_connection_remove_filter); \
58 DO_FUNC(dbus_connection_send_with_reply_and_block); \
59 DO_FUNC(dbus_error_free); \
60 DO_FUNC(dbus_error_init); \
61 DO_FUNC(dbus_error_is_set); \
62 DO_FUNC(dbus_free_string_array); \
63 DO_FUNC(dbus_message_get_args); \
64 DO_FUNC(dbus_message_get_interface); \
65 DO_FUNC(dbus_message_get_member); \
66 DO_FUNC(dbus_message_get_path); \
67 DO_FUNC(dbus_message_get_type); \
68 DO_FUNC(dbus_message_is_signal); \
69 DO_FUNC(dbus_message_iter_append_basic); \
70 DO_FUNC(dbus_message_iter_get_arg_type); \
71 DO_FUNC(dbus_message_iter_get_basic); \
72 DO_FUNC(dbus_message_iter_get_fixed_array); \
73 DO_FUNC(dbus_message_iter_init); \
74 DO_FUNC(dbus_message_iter_init_append); \
75 DO_FUNC(dbus_message_iter_next); \
76 DO_FUNC(dbus_message_iter_recurse); \
77 DO_FUNC(dbus_message_new_method_call); \
78 DO_FUNC(dbus_message_unref)
80 #define DO_FUNC(f) static typeof(f) * p_##f
81 DBUS_FUNCS;
82 #undef DO_FUNC
84 static int udisks_timeout = -1;
85 static DBusConnection *connection;
87 static inline int starts_with( const char *str, const char *prefix )
89 return !strncmp( str, prefix, strlen(prefix) );
92 static GUID *parse_uuid( GUID *guid, const char *str )
94 /* standard uuid format */
95 if (strlen(str) == 36 && str[8] == '-' && str[13] == '-' && str[18] == '-' && str[23] == '-')
97 int i;
98 unsigned char *out = guid->Data4;
100 if (sscanf( str, "%x-%hx-%hx-", (int *)&guid->Data1, &guid->Data2, &guid->Data3 ) != 3) return NULL;
101 for (i = 19; i < 36; i++)
103 unsigned char val;
105 if (i == 23) continue;
107 if (str[i] >= '0' && str[i] <= '9') val = str[i] - '0';
108 else if (str[i] >= 'a' && str[i] <= 'f') val = str[i] - 'a' + 10;
109 else if (str[i] >= 'A' && str[i] <= 'F') val = str[i] - 'A' + 10;
110 else return NULL;
111 val <<= 4;
112 i++;
114 if (str[i] >= '0' && str[i] <= '9') val += str[i] - '0';
115 else if (str[i] >= 'a' && str[i] <= 'f') val += str[i] - 'a' + 10;
116 else if (str[i] >= 'A' && str[i] <= 'F') val += str[i] - 'A' + 10;
117 else return NULL;
118 *out++ = val;
120 return guid;
123 /* check for xxxx-xxxx format (FAT serial number) */
124 if (strlen(str) == 9 && str[4] == '-')
126 memset( guid, 0, sizeof(*guid) );
127 if (sscanf( str, "%hx-%hx", &guid->Data2, &guid->Data3 ) == 2) return guid;
129 return NULL;
132 static BOOL load_dbus_functions(void)
134 void *handle;
136 if (!(handle = dlopen( SONAME_LIBDBUS_1, RTLD_NOW )))
137 goto failed;
139 #define DO_FUNC(f) if (!(p_##f = dlsym( handle, #f ))) goto failed
140 DBUS_FUNCS;
141 #undef DO_FUNC
142 return TRUE;
144 failed:
145 WARN( "failed to load DBUS support: %s\n", dlerror() );
146 return FALSE;
149 static const char *udisks_next_dict_entry( DBusMessageIter *iter, DBusMessageIter *variant )
151 DBusMessageIter sub;
152 const char *name;
154 if (p_dbus_message_iter_get_arg_type( iter ) != DBUS_TYPE_DICT_ENTRY) return NULL;
155 p_dbus_message_iter_recurse( iter, &sub );
156 p_dbus_message_iter_next( iter );
157 p_dbus_message_iter_get_basic( &sub, &name );
158 p_dbus_message_iter_next( &sub );
159 p_dbus_message_iter_recurse( &sub, variant );
160 return name;
163 static enum device_type udisks_parse_media_compatibility( DBusMessageIter *iter )
165 DBusMessageIter media;
166 enum device_type drive_type = DEVICE_UNKNOWN;
168 p_dbus_message_iter_recurse( iter, &media );
169 while (p_dbus_message_iter_get_arg_type( &media ) == DBUS_TYPE_STRING)
171 const char *media_type;
172 p_dbus_message_iter_get_basic( &media, &media_type );
173 if (starts_with( media_type, "optical_dvd" ))
174 drive_type = DEVICE_DVD;
175 if (starts_with( media_type, "floppy" ))
176 drive_type = DEVICE_FLOPPY;
177 else if (starts_with( media_type, "optical_" ) && drive_type == DEVICE_UNKNOWN)
178 drive_type = DEVICE_CDROM;
179 p_dbus_message_iter_next( &media );
181 return drive_type;
184 /* UDisks callback for new device */
185 static void udisks_new_device( const char *udi )
187 static const char *dev_name = "org.freedesktop.UDisks.Device";
188 DBusMessage *request, *reply;
189 DBusMessageIter iter, variant;
190 DBusError error;
191 const char *device = NULL;
192 const char *mount_point = NULL;
193 const char *type = NULL;
194 GUID guid, *guid_ptr = NULL;
195 int removable = FALSE;
196 enum device_type drive_type = DEVICE_UNKNOWN;
198 request = p_dbus_message_new_method_call( "org.freedesktop.UDisks", udi,
199 "org.freedesktop.DBus.Properties", "GetAll" );
200 if (!request) return;
202 p_dbus_message_iter_init_append( request, &iter );
203 p_dbus_message_iter_append_basic( &iter, DBUS_TYPE_STRING, &dev_name );
205 p_dbus_error_init( &error );
206 reply = p_dbus_connection_send_with_reply_and_block( connection, request, -1, &error );
207 p_dbus_message_unref( request );
208 if (!reply)
210 WARN( "failed: %s\n", error.message );
211 p_dbus_error_free( &error );
212 return;
214 p_dbus_error_free( &error );
216 p_dbus_message_iter_init( reply, &iter );
217 if (p_dbus_message_iter_get_arg_type( &iter ) == DBUS_TYPE_ARRAY)
219 const char *name;
221 p_dbus_message_iter_recurse( &iter, &iter );
222 while ((name = udisks_next_dict_entry( &iter, &variant )))
224 if (!strcmp( name, "DeviceFile" ))
225 p_dbus_message_iter_get_basic( &variant, &device );
226 else if (!strcmp( name, "DeviceIsRemovable" ))
227 p_dbus_message_iter_get_basic( &variant, &removable );
228 else if (!strcmp( name, "IdType" ))
229 p_dbus_message_iter_get_basic( &variant, &type );
230 else if (!strcmp( name, "DriveMediaCompatibility" ))
231 drive_type = udisks_parse_media_compatibility( &variant );
232 else if (!strcmp( name, "DeviceMountPaths" ))
234 DBusMessageIter paths;
235 p_dbus_message_iter_recurse( &variant, &paths );
236 if (p_dbus_message_iter_get_arg_type( &paths ) == DBUS_TYPE_STRING)
237 p_dbus_message_iter_get_basic( &paths, &mount_point );
239 else if (!strcmp( name, "IdUuid" ))
241 char *uuid_str;
242 p_dbus_message_iter_get_basic( &variant, &uuid_str );
243 guid_ptr = parse_uuid( &guid, uuid_str );
248 TRACE( "udi %s device %s mount point %s uuid %s type %s removable %u\n",
249 debugstr_a(udi), debugstr_a(device), debugstr_a(mount_point),
250 debugstr_guid(guid_ptr), debugstr_a(type), removable );
252 if (type)
254 if (!strcmp( type, "iso9660" ))
256 removable = TRUE;
257 drive_type = DEVICE_CDROM;
259 else if (!strcmp( type, "udf" ))
261 removable = TRUE;
262 drive_type = DEVICE_DVD;
266 if (device)
268 if (removable) queue_device_op( ADD_DOS_DEVICE, udi, device, mount_point, drive_type, guid_ptr, NULL, NULL );
269 else if (guid_ptr) queue_device_op( ADD_VOLUME, udi, device, mount_point, DEVICE_HARDDISK_VOL, guid_ptr, NULL, NULL );
272 p_dbus_message_unref( reply );
275 /* UDisks callback for removed device */
276 static void udisks_removed_device( const char *udi )
278 TRACE( "removed %s\n", wine_dbgstr_a(udi) );
279 queue_device_op( REMOVE_DEVICE, udi, NULL, NULL, 0, NULL, NULL, NULL );
282 /* UDisks callback for changed device */
283 static void udisks_changed_device( const char *udi )
285 udisks_new_device( udi );
288 static BOOL udisks_enumerate_devices(void)
290 DBusMessage *request, *reply;
291 DBusError error;
292 char **paths;
293 int i, count;
295 request = p_dbus_message_new_method_call( "org.freedesktop.UDisks", "/org/freedesktop/UDisks",
296 "org.freedesktop.UDisks", "EnumerateDevices" );
297 if (!request) return FALSE;
299 p_dbus_error_init( &error );
300 reply = p_dbus_connection_send_with_reply_and_block( connection, request, udisks_timeout, &error );
301 p_dbus_message_unref( request );
302 if (!reply)
304 WARN( "failed: %s\n", error.message );
305 p_dbus_error_free( &error );
306 return FALSE;
308 p_dbus_error_free( &error );
310 if (p_dbus_message_get_args( reply, &error, DBUS_TYPE_ARRAY,
311 DBUS_TYPE_OBJECT_PATH, &paths, &count, DBUS_TYPE_INVALID ))
313 for (i = 0; i < count; i++) udisks_new_device( paths[i] );
314 p_dbus_free_string_array( paths );
316 else WARN( "unexpected args in EnumerateDevices reply\n" );
318 p_dbus_message_unref( reply );
319 return TRUE;
322 /* to make things easier, UDisks2 stores strings as array of bytes instead of strings... */
323 static const char *udisks2_string_from_array( DBusMessageIter *iter )
325 DBusMessageIter string;
326 const char *array;
327 int size;
329 p_dbus_message_iter_recurse( iter, &string );
330 p_dbus_message_iter_get_fixed_array( &string, &array, &size );
331 return array;
334 /* find the drive entry in the dictionary and get its parameters */
335 static void udisks2_get_drive_info( const char *drive_name, DBusMessageIter *dict,
336 enum device_type *drive_type, int *removable, const char **serial )
338 DBusMessageIter iter, drive, variant;
339 const char *name;
341 p_dbus_message_iter_recurse( dict, &iter );
342 while ((name = udisks_next_dict_entry( &iter, &drive )))
344 if (strcmp( name, drive_name )) continue;
345 while ((name = udisks_next_dict_entry( &drive, &iter )))
347 if (strcmp( name, "org.freedesktop.UDisks2.Drive" )) continue;
348 while ((name = udisks_next_dict_entry( &iter, &variant )))
350 if (!strcmp( name, "Removable" ))
351 p_dbus_message_iter_get_basic( &variant, removable );
352 else if (!strcmp( name, "MediaCompatibility" ))
353 *drive_type = udisks_parse_media_compatibility( &variant );
354 else if (!strcmp( name, "Id" ))
355 p_dbus_message_iter_get_basic( &variant, serial );
361 static void udisks2_add_device( const char *udi, DBusMessageIter *dict, DBusMessageIter *block )
363 DBusMessageIter iter, variant, paths, string;
364 const char *device = NULL;
365 const char *mount_point = NULL;
366 const char *type = NULL;
367 const char *drive = NULL;
368 const char *id = NULL;
369 GUID guid, *guid_ptr = NULL;
370 const char *iface, *name;
371 int removable = FALSE;
372 enum device_type drive_type = DEVICE_UNKNOWN;
374 while ((iface = udisks_next_dict_entry( block, &iter )))
376 if (!strcmp( iface, "org.freedesktop.UDisks2.Filesystem" ))
378 while ((name = udisks_next_dict_entry( &iter, &variant )))
380 if (!strcmp( name, "MountPoints" ))
382 p_dbus_message_iter_recurse( &variant, &paths );
383 if (p_dbus_message_iter_get_arg_type( &paths ) == DBUS_TYPE_ARRAY)
385 p_dbus_message_iter_recurse( &variant, &string );
386 mount_point = udisks2_string_from_array( &string );
391 if (!strcmp( iface, "org.freedesktop.UDisks2.Block" ))
393 while ((name = udisks_next_dict_entry( &iter, &variant )))
395 if (!strcmp( name, "Device" ))
396 device = udisks2_string_from_array( &variant );
397 else if (!strcmp( name, "IdType" ))
398 p_dbus_message_iter_get_basic( &variant, &type );
399 else if (!strcmp( name, "Drive" ))
401 p_dbus_message_iter_get_basic( &variant, &drive );
402 udisks2_get_drive_info( drive, dict, &drive_type, &removable, &id );
404 else if (!strcmp( name, "IdUUID" ))
406 const char *uuid_str;
407 if (p_dbus_message_iter_get_arg_type( &variant ) == DBUS_TYPE_ARRAY)
408 uuid_str = udisks2_string_from_array( &variant );
409 else
410 p_dbus_message_iter_get_basic( &variant, &uuid_str );
411 guid_ptr = parse_uuid( &guid, uuid_str );
417 TRACE( "udi %s device %s mount point %s uuid %s type %s removable %u\n",
418 debugstr_a(udi), debugstr_a(device), debugstr_a(mount_point),
419 debugstr_guid(guid_ptr), debugstr_a(type), removable );
421 if (type)
423 if (!strcmp( type, "iso9660" ))
425 removable = TRUE;
426 drive_type = DEVICE_CDROM;
428 else if (!strcmp( type, "udf" ))
430 removable = TRUE;
431 drive_type = DEVICE_DVD;
434 if (device)
436 if (removable) queue_device_op( ADD_DOS_DEVICE, udi, device, mount_point, drive_type, guid_ptr, id, NULL );
437 else if (guid_ptr) queue_device_op( ADD_VOLUME, udi, device, mount_point, DEVICE_HARDDISK_VOL, guid_ptr, id, NULL );
441 /* UDisks2 is almost, but not quite, entirely unlike UDisks.
442 * It would have been easy to make it backwards compatible, but where would be the fun in that?
444 static BOOL udisks2_add_devices( const char *changed )
446 DBusMessage *request, *reply;
447 DBusMessageIter dict, iter, block;
448 DBusError error;
449 const char *udi;
451 request = p_dbus_message_new_method_call( "org.freedesktop.UDisks2", "/org/freedesktop/UDisks2",
452 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects" );
453 if (!request) return FALSE;
455 p_dbus_error_init( &error );
456 reply = p_dbus_connection_send_with_reply_and_block( connection, request, udisks_timeout, &error );
457 p_dbus_message_unref( request );
458 if (!reply)
460 WARN( "failed: %s\n", error.message );
461 p_dbus_error_free( &error );
462 return FALSE;
464 p_dbus_error_free( &error );
466 p_dbus_message_iter_init( reply, &dict );
467 if (p_dbus_message_iter_get_arg_type( &dict ) == DBUS_TYPE_ARRAY)
469 p_dbus_message_iter_recurse( &dict, &iter );
470 while ((udi = udisks_next_dict_entry( &iter, &block )))
472 if (!starts_with( udi, "/org/freedesktop/UDisks2/block_devices/" )) continue;
473 if (changed && strcmp( changed, udi )) continue;
474 udisks2_add_device( udi, &dict, &block );
477 else WARN( "unexpected args in GetManagedObjects reply\n" );
479 p_dbus_message_unref( reply );
480 return TRUE;
483 static DBusHandlerResult udisks_filter( DBusConnection *ctx, DBusMessage *msg, void *user_data )
485 char *path;
486 DBusError error;
488 p_dbus_error_init( &error );
490 /* udisks signals */
491 if (p_dbus_message_is_signal( msg, "org.freedesktop.UDisks", "DeviceAdded" ) &&
492 p_dbus_message_get_args( msg, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID ))
494 udisks_new_device( path );
496 else if (p_dbus_message_is_signal( msg, "org.freedesktop.UDisks", "DeviceRemoved" ) &&
497 p_dbus_message_get_args( msg, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID ))
499 udisks_removed_device( path );
501 else if (p_dbus_message_is_signal( msg, "org.freedesktop.UDisks", "DeviceChanged" ) &&
502 p_dbus_message_get_args( msg, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID ))
504 udisks_changed_device( path );
506 /* udisks2 signals */
507 else if (p_dbus_message_is_signal( msg, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded" ) &&
508 p_dbus_message_get_args( msg, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID ))
510 TRACE( "added %s\n", wine_dbgstr_a(path) );
511 udisks2_add_devices( path );
513 else if (p_dbus_message_is_signal( msg, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved" ) &&
514 p_dbus_message_get_args( msg, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID ))
516 udisks_removed_device( path );
518 else if (p_dbus_message_is_signal( msg, "org.freedesktop.DBus.Properties", "PropertiesChanged" ))
520 const char *udi = p_dbus_message_get_path( msg );
521 TRACE( "changed %s\n", wine_dbgstr_a(udi) );
522 udisks2_add_devices( udi );
524 else TRACE( "ignoring message type=%d path=%s interface=%s method=%s\n",
525 p_dbus_message_get_type( msg ), p_dbus_message_get_path( msg ),
526 p_dbus_message_get_interface( msg ), p_dbus_message_get_member( msg ) );
528 p_dbus_error_free( &error );
529 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
532 void run_dbus_loop(void)
534 static const char udisks_match[] = "type='signal',"
535 "interface='org.freedesktop.UDisks',"
536 "sender='org.freedesktop.UDisks'";
537 static const char udisks2_match_interfaces[] = "type='signal',"
538 "interface='org.freedesktop.DBus.ObjectManager',"
539 "path='/org/freedesktop/UDisks2'";
540 static const char udisks2_match_properties[] = "type='signal',"
541 "interface='org.freedesktop.DBus.Properties'";
544 DBusError error;
546 if (!load_dbus_functions()) return;
548 p_dbus_error_init( &error );
549 if (!(connection = p_dbus_bus_get( DBUS_BUS_SYSTEM, &error )))
551 WARN( "failed to get system dbus connection: %s\n", error.message );
552 p_dbus_error_free( &error );
553 return;
556 /* first try UDisks2 */
558 p_dbus_connection_add_filter( connection, udisks_filter, NULL, NULL );
559 p_dbus_bus_add_match( connection, udisks2_match_interfaces, &error );
560 p_dbus_bus_add_match( connection, udisks2_match_properties, &error );
561 if (udisks2_add_devices( NULL )) goto found;
562 p_dbus_bus_remove_match( connection, udisks2_match_interfaces, &error );
563 p_dbus_bus_remove_match( connection, udisks2_match_properties, &error );
565 /* then try UDisks */
567 p_dbus_bus_add_match( connection, udisks_match, &error );
568 if (udisks_enumerate_devices()) goto found;
569 p_dbus_bus_remove_match( connection, udisks_match, &error );
570 p_dbus_connection_remove_filter( connection, udisks_filter, NULL );
572 found:
573 while (p_dbus_connection_read_write_dispatch( connection, -1 )) /* nothing */ ;
576 #if !defined(__APPLE__)
578 /* The udisks dispatch loop will block all threads using the same connection, so we'll
579 use a private connection. Multiple threads can make methods calls at the same time
580 on the same connection, according to the documentation.
582 static DBusConnection *dhcp_connection;
583 static DBusConnection *get_dhcp_connection(void)
585 if (!dhcp_connection)
587 DBusError error;
588 p_dbus_error_init( &error );
589 if (!(dhcp_connection = p_dbus_bus_get_private( DBUS_BUS_SYSTEM, &error )))
591 WARN( "failed to get system dbus connection: %s\n", error.message );
592 p_dbus_error_free( &error );
595 return dhcp_connection;
598 static DBusMessage *device_by_iface_request( const char *iface )
600 DBusMessage *request, *reply;
601 DBusMessageIter iter;
602 DBusError error;
603 DBusConnection *connection = get_dhcp_connection();
605 if (!connection) return NULL;
607 request = p_dbus_message_new_method_call( "org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager",
608 "org.freedesktop.NetworkManager", "GetDeviceByIpIface" );
609 if (!request) return NULL;
611 p_dbus_message_iter_init_append( request, &iter );
612 p_dbus_message_iter_append_basic( &iter, DBUS_TYPE_STRING, &iface );
614 p_dbus_error_init( &error );
615 reply = p_dbus_connection_send_with_reply_and_block( connection, request, -1, &error );
616 p_dbus_message_unref( request );
617 if (!reply)
619 WARN( "failed: %s\n", error.message );
620 p_dbus_error_free( &error );
621 return NULL;
624 p_dbus_error_free( &error );
625 return reply;
628 static DBusMessage *dhcp4_config_request( const char *iface )
630 static const char *device = "org.freedesktop.NetworkManager.Device";
631 static const char *dhcp4_config = "Dhcp4Config";
632 DBusMessage *request, *reply;
633 DBusMessageIter iter;
634 DBusError error;
635 const char *path = NULL;
637 if (!(reply = device_by_iface_request( iface ))) return NULL;
639 p_dbus_message_iter_init( reply, &iter );
640 if (p_dbus_message_iter_get_arg_type( &iter ) == DBUS_TYPE_OBJECT_PATH) p_dbus_message_iter_get_basic( &iter, &path );
641 if (!path)
643 p_dbus_message_unref( reply );
644 return NULL;
647 request = p_dbus_message_new_method_call( "org.freedesktop.NetworkManager", path,
648 "org.freedesktop.DBus.Properties", "Get" );
649 p_dbus_message_unref( reply );
650 if (!request) return NULL;
652 p_dbus_message_iter_init_append( request, &iter );
653 p_dbus_message_iter_append_basic( &iter, DBUS_TYPE_STRING, &device );
654 p_dbus_message_iter_append_basic( &iter, DBUS_TYPE_STRING, &dhcp4_config );
656 p_dbus_error_init( &error );
657 reply = p_dbus_connection_send_with_reply_and_block( get_dhcp_connection(), request, -1, &error );
658 p_dbus_message_unref( request );
659 if (!reply)
661 WARN( "failed: %s\n", error.message );
662 p_dbus_error_free( &error );
663 return NULL;
666 p_dbus_error_free( &error );
667 return reply;
670 static DBusMessage *dhcp4_config_options_request( const char *unix_name )
672 static const char *dhcp4_config = "org.freedesktop.NetworkManager.DHCP4Config";
673 static const char *options = "Options";
674 DBusMessage *request, *reply;
675 DBusMessageIter iter, sub;
676 DBusError error;
677 const char *path = NULL;
679 if (!(reply = dhcp4_config_request( unix_name ))) return NULL;
681 p_dbus_message_iter_init( reply, &iter );
682 if (p_dbus_message_iter_get_arg_type( &iter ) == DBUS_TYPE_VARIANT)
684 p_dbus_message_iter_recurse( &iter, &sub );
685 p_dbus_message_iter_get_basic( &sub, &path );
687 if (!path)
689 p_dbus_message_unref( reply );
690 return NULL;
693 request = p_dbus_message_new_method_call( "org.freedesktop.NetworkManager", path,
694 "org.freedesktop.DBus.Properties", "Get" );
695 p_dbus_message_unref( reply );
696 if (!request) return NULL;
698 p_dbus_message_iter_init_append( request, &iter );
699 p_dbus_message_iter_append_basic( &iter, DBUS_TYPE_STRING, &dhcp4_config );
700 p_dbus_message_iter_append_basic( &iter, DBUS_TYPE_STRING, &options );
702 p_dbus_error_init( &error );
703 reply = p_dbus_connection_send_with_reply_and_block( get_dhcp_connection(), request, -1, &error );
704 p_dbus_message_unref( request );
705 if (!reply)
707 p_dbus_error_free( &error );
708 return NULL;
711 p_dbus_error_free( &error );
712 return reply;
715 static const char *dhcp4_config_option_next_dict_entry( DBusMessageIter *iter, DBusMessageIter *variant )
717 DBusMessageIter sub;
718 const char *name;
720 if (p_dbus_message_iter_get_arg_type( iter ) != DBUS_TYPE_DICT_ENTRY) return NULL;
721 p_dbus_message_iter_recurse( iter, &sub );
722 p_dbus_message_iter_next( iter );
723 p_dbus_message_iter_get_basic( &sub, &name );
724 p_dbus_message_iter_next( &sub );
725 p_dbus_message_iter_recurse( &sub, variant );
726 return name;
729 static DBusMessage *dhcp4_config_option_request( const char *unix_name, const char *option, const char **value )
731 DBusMessage *reply;
732 DBusMessageIter iter, variant;
733 const char *name;
735 if (!(reply = dhcp4_config_options_request( unix_name ))) return NULL;
737 *value = NULL;
738 p_dbus_message_iter_init( reply, &iter );
739 if (p_dbus_message_iter_get_arg_type( &iter ) == DBUS_TYPE_VARIANT)
741 p_dbus_message_iter_recurse( &iter, &iter );
742 if (p_dbus_message_iter_get_arg_type( &iter ) == DBUS_TYPE_ARRAY)
744 p_dbus_message_iter_recurse( &iter, &iter );
745 while ((name = dhcp4_config_option_next_dict_entry( &iter, &variant )))
747 if (!strcmp( name, option ))
749 p_dbus_message_iter_get_basic( &variant, value );
750 break;
756 return reply;
759 static const char *map_option( unsigned option )
761 switch (option)
763 case OPTION_SUBNET_MASK: return "subnet_mask";
764 case OPTION_ROUTER_ADDRESS: return "next_server";
765 case OPTION_HOST_NAME: return "host_name";
766 case OPTION_DOMAIN_NAME: return "domain_name";
767 case OPTION_BROADCAST_ADDRESS: return "broadcast_address";
768 case OPTION_MSFT_IE_PROXY: return "wpad";
769 default:
770 FIXME( "unhandled option %u\n", option );
771 return "";
775 NTSTATUS dhcp_request( void *args )
777 const struct dhcp_request_params *params = args;
778 DBusMessage *reply;
779 const char *value;
780 ULONG ret = 0;
782 params->req->offset = params->req->size = 0;
783 *params->ret_size = 0;
785 if (!(reply = dhcp4_config_option_request( params->unix_name, map_option(params->req->id), &value ))) return STATUS_SUCCESS;
787 switch (params->req->id)
789 case OPTION_SUBNET_MASK:
790 case OPTION_ROUTER_ADDRESS:
791 case OPTION_BROADCAST_ADDRESS:
793 IN_ADDR *ptr = (IN_ADDR *)(params->buffer + params->offset);
794 if (value && params->size >= sizeof(IN_ADDR))
796 ptr->S_un.S_addr = inet_addr( value );
797 params->req->offset = params->offset;
798 params->req->size = sizeof(*ptr);
799 TRACE( "returning %08x\n", *(unsigned int*)ptr );
801 ret = sizeof(*ptr);
802 break;
804 case OPTION_HOST_NAME:
805 case OPTION_DOMAIN_NAME:
806 case OPTION_MSFT_IE_PROXY:
808 char *ptr = params->buffer + params->offset;
809 int len = value ? strlen( value ) : 0;
810 if (len && params->size >= len)
812 memcpy( ptr, value, len );
813 params->req->offset = params->offset;
814 params->req->size = len;
815 TRACE( "returning %s\n", debugstr_an(ptr, len) );
817 ret = len;
818 break;
820 default:
821 FIXME( "option %u not supported\n", (unsigned int)params->req->id );
822 break;
825 p_dbus_message_unref( reply );
826 *params->ret_size = ret;
827 return STATUS_SUCCESS;
829 #endif
831 #else /* SONAME_LIBDBUS_1 */
833 void run_dbus_loop(void)
835 TRACE( "Skipping, DBUS support not compiled in\n" );
838 #endif /* SONAME_LIBDBUS_1 */