windows.gaming.input: Fake empty IGamepadStatics::Gamepads vector.
[wine/zf.git] / dlls / mountmgr.sys / dbus.c
blob98b2a47ba6d7f17f5da78f2cfeb5de4d27f6d224
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 #include "config.h"
22 #include "wine/port.h"
24 #include <assert.h>
25 #include <errno.h>
26 #include <stdarg.h>
27 #include <stdio.h>
28 #ifdef SONAME_LIBDBUS_1
29 # include <dbus/dbus.h>
30 #endif
31 #ifdef SONAME_LIBHAL
32 # include <hal/libhal.h>
33 #endif
35 #include "mountmgr.h"
36 #include "winnls.h"
37 #include "excpt.h"
38 #define USE_WS_PREFIX
39 #include "winsock2.h"
40 #include "ws2ipdef.h"
41 #include "nldef.h"
42 #include "netioapi.h"
43 #include "inaddr.h"
44 #include "ip2string.h"
45 #include "dhcpcsdk.h"
47 #include "wine/exception.h"
48 #include "wine/debug.h"
50 WINE_DEFAULT_DEBUG_CHANNEL(mountmgr);
52 #ifdef SONAME_LIBDBUS_1
54 #define DBUS_FUNCS \
55 DO_FUNC(dbus_bus_add_match); \
56 DO_FUNC(dbus_bus_get); \
57 DO_FUNC(dbus_bus_get_private); \
58 DO_FUNC(dbus_bus_remove_match); \
59 DO_FUNC(dbus_connection_add_filter); \
60 DO_FUNC(dbus_connection_read_write_dispatch); \
61 DO_FUNC(dbus_connection_remove_filter); \
62 DO_FUNC(dbus_connection_send_with_reply_and_block); \
63 DO_FUNC(dbus_error_free); \
64 DO_FUNC(dbus_error_init); \
65 DO_FUNC(dbus_error_is_set); \
66 DO_FUNC(dbus_free_string_array); \
67 DO_FUNC(dbus_message_get_args); \
68 DO_FUNC(dbus_message_get_interface); \
69 DO_FUNC(dbus_message_get_member); \
70 DO_FUNC(dbus_message_get_path); \
71 DO_FUNC(dbus_message_get_type); \
72 DO_FUNC(dbus_message_is_signal); \
73 DO_FUNC(dbus_message_iter_append_basic); \
74 DO_FUNC(dbus_message_iter_get_arg_type); \
75 DO_FUNC(dbus_message_iter_get_basic); \
76 DO_FUNC(dbus_message_iter_get_fixed_array); \
77 DO_FUNC(dbus_message_iter_init); \
78 DO_FUNC(dbus_message_iter_init_append); \
79 DO_FUNC(dbus_message_iter_next); \
80 DO_FUNC(dbus_message_iter_recurse); \
81 DO_FUNC(dbus_message_new_method_call); \
82 DO_FUNC(dbus_message_unref)
84 #define DO_FUNC(f) static typeof(f) * p_##f
85 DBUS_FUNCS;
86 #undef DO_FUNC
88 static int udisks_timeout = -1;
89 static DBusConnection *connection;
91 #ifdef SONAME_LIBHAL
93 #define HAL_FUNCS \
94 DO_FUNC(libhal_ctx_free); \
95 DO_FUNC(libhal_ctx_init); \
96 DO_FUNC(libhal_ctx_new); \
97 DO_FUNC(libhal_ctx_set_dbus_connection); \
98 DO_FUNC(libhal_ctx_set_device_added); \
99 DO_FUNC(libhal_ctx_set_device_property_modified); \
100 DO_FUNC(libhal_ctx_set_device_removed); \
101 DO_FUNC(libhal_ctx_shutdown); \
102 DO_FUNC(libhal_device_get_property_bool); \
103 DO_FUNC(libhal_device_get_property_int); \
104 DO_FUNC(libhal_device_get_property_string); \
105 DO_FUNC(libhal_device_add_property_watch); \
106 DO_FUNC(libhal_device_remove_property_watch); \
107 DO_FUNC(libhal_free_string); \
108 DO_FUNC(libhal_free_string_array); \
109 DO_FUNC(libhal_get_all_devices)
111 #define DO_FUNC(f) static typeof(f) * p_##f
112 HAL_FUNCS;
113 #undef DO_FUNC
115 static BOOL load_hal_functions(void)
117 void *hal_handle;
119 /* Load libhal with RTLD_GLOBAL so that the dbus symbols are available.
120 * We can't load libdbus directly since libhal may have been built against a
121 * different version but with the same soname. Binary compatibility is for wimps. */
123 if (!(hal_handle = dlopen( SONAME_LIBHAL, RTLD_NOW | RTLD_GLOBAL )))
124 goto failed;
126 #define DO_FUNC(f) if (!(p_##f = dlsym( RTLD_DEFAULT, #f ))) goto failed
127 DBUS_FUNCS;
128 #undef DO_FUNC
130 #define DO_FUNC(f) if (!(p_##f = dlsym( hal_handle, #f ))) goto failed
131 HAL_FUNCS;
132 #undef DO_FUNC
134 udisks_timeout = 3000; /* don't try for too long if we can fall back to HAL */
135 return TRUE;
137 failed:
138 WARN( "failed to load HAL support: %s\n", dlerror() );
139 return FALSE;
142 #endif /* SONAME_LIBHAL */
144 static LONG WINAPI assert_fault(EXCEPTION_POINTERS *eptr)
146 if (eptr->ExceptionRecord->ExceptionCode == EXCEPTION_WINE_ASSERTION)
147 return EXCEPTION_EXECUTE_HANDLER;
148 return EXCEPTION_CONTINUE_SEARCH;
151 static inline int starts_with( const char *str, const char *prefix )
153 return !strncmp( str, prefix, strlen(prefix) );
156 static GUID *parse_uuid( GUID *guid, const char *str )
158 /* standard uuid format */
159 if (strlen(str) == 36)
161 UNICODE_STRING strW;
162 WCHAR buffer[39];
164 if (MultiByteToWideChar( CP_UNIXCP, 0, str, 36, buffer + 1, 36 ))
166 buffer[0] = '{';
167 buffer[37] = '}';
168 buffer[38] = 0;
169 RtlInitUnicodeString( &strW, buffer );
170 if (!RtlGUIDFromString( &strW, guid )) return guid;
174 /* check for xxxx-xxxx format (FAT serial number) */
175 if (strlen(str) == 9 && str[4] == '-')
177 memset( guid, 0, sizeof(*guid) );
178 if (sscanf( str, "%hx-%hx", &guid->Data2, &guid->Data3 ) == 2) return guid;
180 return NULL;
183 static BOOL load_dbus_functions(void)
185 void *handle;
187 if (!(handle = dlopen( SONAME_LIBDBUS_1, RTLD_NOW )))
188 goto failed;
190 #define DO_FUNC(f) if (!(p_##f = dlsym( handle, #f ))) goto failed
191 DBUS_FUNCS;
192 #undef DO_FUNC
193 return TRUE;
195 failed:
196 WARN( "failed to load DBUS support: %s\n", dlerror() );
197 return FALSE;
200 static const char *udisks_next_dict_entry( DBusMessageIter *iter, DBusMessageIter *variant )
202 DBusMessageIter sub;
203 const char *name;
205 if (p_dbus_message_iter_get_arg_type( iter ) != DBUS_TYPE_DICT_ENTRY) return NULL;
206 p_dbus_message_iter_recurse( iter, &sub );
207 p_dbus_message_iter_next( iter );
208 p_dbus_message_iter_get_basic( &sub, &name );
209 p_dbus_message_iter_next( &sub );
210 p_dbus_message_iter_recurse( &sub, variant );
211 return name;
214 static enum device_type udisks_parse_media_compatibility( DBusMessageIter *iter )
216 DBusMessageIter media;
217 enum device_type drive_type = DEVICE_UNKNOWN;
219 p_dbus_message_iter_recurse( iter, &media );
220 while (p_dbus_message_iter_get_arg_type( &media ) == DBUS_TYPE_STRING)
222 const char *media_type;
223 p_dbus_message_iter_get_basic( &media, &media_type );
224 if (starts_with( media_type, "optical_dvd" ))
225 drive_type = DEVICE_DVD;
226 if (starts_with( media_type, "floppy" ))
227 drive_type = DEVICE_FLOPPY;
228 else if (starts_with( media_type, "optical_" ) && drive_type == DEVICE_UNKNOWN)
229 drive_type = DEVICE_CDROM;
230 p_dbus_message_iter_next( &media );
232 return drive_type;
235 /* UDisks callback for new device */
236 static void udisks_new_device( const char *udi )
238 static const char *dev_name = "org.freedesktop.UDisks.Device";
239 DBusMessage *request, *reply;
240 DBusMessageIter iter, variant;
241 DBusError error;
242 const char *device = NULL;
243 const char *mount_point = NULL;
244 const char *type = NULL;
245 GUID guid, *guid_ptr = NULL;
246 int removable = FALSE;
247 enum device_type drive_type = DEVICE_UNKNOWN;
249 request = p_dbus_message_new_method_call( "org.freedesktop.UDisks", udi,
250 "org.freedesktop.DBus.Properties", "GetAll" );
251 if (!request) return;
253 p_dbus_message_iter_init_append( request, &iter );
254 p_dbus_message_iter_append_basic( &iter, DBUS_TYPE_STRING, &dev_name );
256 p_dbus_error_init( &error );
257 reply = p_dbus_connection_send_with_reply_and_block( connection, request, -1, &error );
258 p_dbus_message_unref( request );
259 if (!reply)
261 WARN( "failed: %s\n", error.message );
262 p_dbus_error_free( &error );
263 return;
265 p_dbus_error_free( &error );
267 p_dbus_message_iter_init( reply, &iter );
268 if (p_dbus_message_iter_get_arg_type( &iter ) == DBUS_TYPE_ARRAY)
270 const char *name;
272 p_dbus_message_iter_recurse( &iter, &iter );
273 while ((name = udisks_next_dict_entry( &iter, &variant )))
275 if (!strcmp( name, "DeviceFile" ))
276 p_dbus_message_iter_get_basic( &variant, &device );
277 else if (!strcmp( name, "DeviceIsRemovable" ))
278 p_dbus_message_iter_get_basic( &variant, &removable );
279 else if (!strcmp( name, "IdType" ))
280 p_dbus_message_iter_get_basic( &variant, &type );
281 else if (!strcmp( name, "DriveMediaCompatibility" ))
282 drive_type = udisks_parse_media_compatibility( &variant );
283 else if (!strcmp( name, "DeviceMountPaths" ))
285 DBusMessageIter paths;
286 p_dbus_message_iter_recurse( &variant, &paths );
287 if (p_dbus_message_iter_get_arg_type( &paths ) == DBUS_TYPE_STRING)
288 p_dbus_message_iter_get_basic( &paths, &mount_point );
290 else if (!strcmp( name, "IdUuid" ))
292 char *uuid_str;
293 p_dbus_message_iter_get_basic( &variant, &uuid_str );
294 guid_ptr = parse_uuid( &guid, uuid_str );
299 TRACE( "udi %s device %s mount point %s uuid %s type %s removable %u\n",
300 debugstr_a(udi), debugstr_a(device), debugstr_a(mount_point),
301 debugstr_guid(guid_ptr), debugstr_a(type), removable );
303 if (type)
305 if (!strcmp( type, "iso9660" ))
307 removable = TRUE;
308 drive_type = DEVICE_CDROM;
310 else if (!strcmp( type, "udf" ))
312 removable = TRUE;
313 drive_type = DEVICE_DVD;
317 if (device)
319 if (removable) add_dos_device( -1, udi, device, mount_point, drive_type, guid_ptr, NULL );
320 else if (guid_ptr) add_volume( udi, device, mount_point, DEVICE_HARDDISK_VOL, guid_ptr, NULL );
323 p_dbus_message_unref( reply );
326 /* UDisks callback for removed device */
327 static void udisks_removed_device( const char *udi )
329 TRACE( "removed %s\n", wine_dbgstr_a(udi) );
331 if (!remove_dos_device( -1, udi )) remove_volume( udi );
334 /* UDisks callback for changed device */
335 static void udisks_changed_device( const char *udi )
337 udisks_new_device( udi );
340 static BOOL udisks_enumerate_devices(void)
342 DBusMessage *request, *reply;
343 DBusError error;
344 char **paths;
345 int i, count;
347 request = p_dbus_message_new_method_call( "org.freedesktop.UDisks", "/org/freedesktop/UDisks",
348 "org.freedesktop.UDisks", "EnumerateDevices" );
349 if (!request) return FALSE;
351 p_dbus_error_init( &error );
352 reply = p_dbus_connection_send_with_reply_and_block( connection, request, udisks_timeout, &error );
353 p_dbus_message_unref( request );
354 if (!reply)
356 WARN( "failed: %s\n", error.message );
357 p_dbus_error_free( &error );
358 return FALSE;
360 p_dbus_error_free( &error );
362 if (p_dbus_message_get_args( reply, &error, DBUS_TYPE_ARRAY,
363 DBUS_TYPE_OBJECT_PATH, &paths, &count, DBUS_TYPE_INVALID ))
365 for (i = 0; i < count; i++) udisks_new_device( paths[i] );
366 p_dbus_free_string_array( paths );
368 else WARN( "unexpected args in EnumerateDevices reply\n" );
370 p_dbus_message_unref( reply );
371 return TRUE;
374 /* to make things easier, UDisks2 stores strings as array of bytes instead of strings... */
375 static const char *udisks2_string_from_array( DBusMessageIter *iter )
377 DBusMessageIter string;
378 const char *array;
379 int size;
381 p_dbus_message_iter_recurse( iter, &string );
382 p_dbus_message_iter_get_fixed_array( &string, &array, &size );
383 return array;
386 /* find the drive entry in the dictionary and get its parameters */
387 static void udisks2_get_drive_info( const char *drive_name, DBusMessageIter *dict,
388 enum device_type *drive_type, int *removable, const char **serial )
390 DBusMessageIter iter, drive, variant;
391 const char *name;
393 p_dbus_message_iter_recurse( dict, &iter );
394 while ((name = udisks_next_dict_entry( &iter, &drive )))
396 if (strcmp( name, drive_name )) continue;
397 while ((name = udisks_next_dict_entry( &drive, &iter )))
399 if (strcmp( name, "org.freedesktop.UDisks2.Drive" )) continue;
400 while ((name = udisks_next_dict_entry( &iter, &variant )))
402 if (!strcmp( name, "Removable" ))
403 p_dbus_message_iter_get_basic( &variant, removable );
404 else if (!strcmp( name, "MediaCompatibility" ))
405 *drive_type = udisks_parse_media_compatibility( &variant );
406 else if (!strcmp( name, "Id" ))
407 p_dbus_message_iter_get_basic( &variant, serial );
413 static void udisks2_add_device( const char *udi, DBusMessageIter *dict, DBusMessageIter *block )
415 DBusMessageIter iter, variant, paths, string;
416 const char *device = NULL;
417 const char *mount_point = NULL;
418 const char *type = NULL;
419 const char *drive = NULL;
420 const char *id = NULL;
421 GUID guid, *guid_ptr = NULL;
422 const char *iface, *name;
423 int removable = FALSE;
424 enum device_type drive_type = DEVICE_UNKNOWN;
426 while ((iface = udisks_next_dict_entry( block, &iter )))
428 if (!strcmp( iface, "org.freedesktop.UDisks2.Filesystem" ))
430 while ((name = udisks_next_dict_entry( &iter, &variant )))
432 if (!strcmp( name, "MountPoints" ))
434 p_dbus_message_iter_recurse( &variant, &paths );
435 if (p_dbus_message_iter_get_arg_type( &paths ) == DBUS_TYPE_ARRAY)
437 p_dbus_message_iter_recurse( &variant, &string );
438 mount_point = udisks2_string_from_array( &string );
443 if (!strcmp( iface, "org.freedesktop.UDisks2.Block" ))
445 while ((name = udisks_next_dict_entry( &iter, &variant )))
447 if (!strcmp( name, "Device" ))
448 device = udisks2_string_from_array( &variant );
449 else if (!strcmp( name, "IdType" ))
450 p_dbus_message_iter_get_basic( &variant, &type );
451 else if (!strcmp( name, "Drive" ))
453 p_dbus_message_iter_get_basic( &variant, &drive );
454 udisks2_get_drive_info( drive, dict, &drive_type, &removable, &id );
456 else if (!strcmp( name, "IdUUID" ))
458 const char *uuid_str;
459 if (p_dbus_message_iter_get_arg_type( &variant ) == DBUS_TYPE_ARRAY)
460 uuid_str = udisks2_string_from_array( &variant );
461 else
462 p_dbus_message_iter_get_basic( &variant, &uuid_str );
463 guid_ptr = parse_uuid( &guid, uuid_str );
469 TRACE( "udi %s device %s mount point %s uuid %s type %s removable %u\n",
470 debugstr_a(udi), debugstr_a(device), debugstr_a(mount_point),
471 debugstr_guid(guid_ptr), debugstr_a(type), removable );
473 if (type)
475 if (!strcmp( type, "iso9660" ))
477 removable = TRUE;
478 drive_type = DEVICE_CDROM;
480 else if (!strcmp( type, "udf" ))
482 removable = TRUE;
483 drive_type = DEVICE_DVD;
486 if (device)
488 if (removable) add_dos_device( -1, udi, device, mount_point, drive_type, guid_ptr, NULL );
489 else if (guid_ptr) add_volume( udi, device, mount_point, DEVICE_HARDDISK_VOL, guid_ptr, id );
493 /* UDisks2 is almost, but not quite, entirely unlike UDisks.
494 * It would have been easy to make it backwards compatible, but where would be the fun in that?
496 static BOOL udisks2_add_devices( const char *changed )
498 DBusMessage *request, *reply;
499 DBusMessageIter dict, iter, block;
500 DBusError error;
501 const char *udi;
503 request = p_dbus_message_new_method_call( "org.freedesktop.UDisks2", "/org/freedesktop/UDisks2",
504 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects" );
505 if (!request) return FALSE;
507 p_dbus_error_init( &error );
508 reply = p_dbus_connection_send_with_reply_and_block( connection, request, udisks_timeout, &error );
509 p_dbus_message_unref( request );
510 if (!reply)
512 WARN( "failed: %s\n", error.message );
513 p_dbus_error_free( &error );
514 return FALSE;
516 p_dbus_error_free( &error );
518 p_dbus_message_iter_init( reply, &dict );
519 if (p_dbus_message_iter_get_arg_type( &dict ) == DBUS_TYPE_ARRAY)
521 p_dbus_message_iter_recurse( &dict, &iter );
522 while ((udi = udisks_next_dict_entry( &iter, &block )))
524 if (!starts_with( udi, "/org/freedesktop/UDisks2/block_devices/" )) continue;
525 if (changed && strcmp( changed, udi )) continue;
526 udisks2_add_device( udi, &dict, &block );
529 else WARN( "unexpected args in GetManagedObjects reply\n" );
531 p_dbus_message_unref( reply );
532 return TRUE;
535 static DBusHandlerResult udisks_filter( DBusConnection *ctx, DBusMessage *msg, void *user_data )
537 char *path;
538 DBusError error;
540 p_dbus_error_init( &error );
542 /* udisks signals */
543 if (p_dbus_message_is_signal( msg, "org.freedesktop.UDisks", "DeviceAdded" ) &&
544 p_dbus_message_get_args( msg, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID ))
546 udisks_new_device( path );
548 else if (p_dbus_message_is_signal( msg, "org.freedesktop.UDisks", "DeviceRemoved" ) &&
549 p_dbus_message_get_args( msg, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID ))
551 udisks_removed_device( path );
553 else if (p_dbus_message_is_signal( msg, "org.freedesktop.UDisks", "DeviceChanged" ) &&
554 p_dbus_message_get_args( msg, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID ))
556 udisks_changed_device( path );
558 /* udisks2 signals */
559 else if (p_dbus_message_is_signal( msg, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded" ) &&
560 p_dbus_message_get_args( msg, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID ))
562 TRACE( "added %s\n", wine_dbgstr_a(path) );
563 udisks2_add_devices( path );
565 else if (p_dbus_message_is_signal( msg, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved" ) &&
566 p_dbus_message_get_args( msg, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID ))
568 udisks_removed_device( path );
570 else if (p_dbus_message_is_signal( msg, "org.freedesktop.DBus.Properties", "PropertiesChanged" ))
572 const char *udi = p_dbus_message_get_path( msg );
573 TRACE( "changed %s\n", wine_dbgstr_a(udi) );
574 udisks2_add_devices( udi );
576 else TRACE( "ignoring message type=%d path=%s interface=%s method=%s\n",
577 p_dbus_message_get_type( msg ), p_dbus_message_get_path( msg ),
578 p_dbus_message_get_interface( msg ), p_dbus_message_get_member( msg ) );
580 p_dbus_error_free( &error );
581 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
584 #ifdef SONAME_LIBHAL
586 static BOOL hal_get_ide_parameters( LibHalContext *ctx, const char *udi, SCSI_ADDRESS *scsi_addr, UCHAR *devtype, char *ident, size_t ident_size )
588 DBusError error;
589 char *parent = NULL;
590 char *type = NULL;
591 char *model = NULL;
592 int host, chan;
593 BOOL ret = FALSE;
595 p_dbus_error_init( &error );
597 if (!(parent = p_libhal_device_get_property_string( ctx, udi, "info.parent", &error )))
598 goto done;
599 if ((host = p_libhal_device_get_property_int( ctx, parent, "ide.host", &error )) < 0)
600 goto done;
601 if ((chan = p_libhal_device_get_property_int( ctx, parent, "ide.channel", &error )) < 0)
602 goto done;
604 ret = TRUE;
606 if (devtype)
608 if (!(type = p_libhal_device_get_property_string( ctx, udi, "storage.drive_type", &error )))
609 *devtype = SCSI_UNKNOWN_PERIPHERAL;
610 else if (!strcmp( type, "disk" ) || !strcmp( type, "floppy" ))
611 *devtype = SCSI_DISK_PERIPHERAL;
612 else if (!strcmp( type, "tape" ))
613 *devtype = SCSI_TAPE_PERIPHERAL;
614 else if (!strcmp( type, "cdrom" ))
615 *devtype = SCSI_CDROM_PERIPHERAL;
616 else if (!strcmp( type, "raid" ))
617 *devtype = SCSI_ARRAY_PERIPHERAL;
618 else
619 *devtype = SCSI_UNKNOWN_PERIPHERAL;
622 if (ident)
624 if (!(model = p_libhal_device_get_property_string( ctx, udi, "storage.model", &error )))
625 p_dbus_error_free( &error ); /* ignore error */
626 else
627 lstrcpynA( ident, model, ident_size );
630 scsi_addr->PortNumber = host;
631 scsi_addr->PathId = 0;
632 scsi_addr->TargetId = chan;
633 scsi_addr->Lun = 0;
635 done:
636 if (model) p_libhal_free_string( model );
637 if (type) p_libhal_free_string( type );
638 if (parent) p_libhal_free_string( parent );
639 p_dbus_error_free( &error );
640 return ret;
643 static BOOL hal_get_scsi_parameters( LibHalContext *ctx, const char *udi, SCSI_ADDRESS *scsi_addr, UCHAR *devtype, char *ident, size_t ident_size )
645 DBusError error;
646 char *type = NULL;
647 char *vendor = NULL;
648 char *model = NULL;
649 int host, bus, target, lun;
650 BOOL ret = FALSE;
652 p_dbus_error_init( &error );
654 if ((host = p_libhal_device_get_property_int( ctx, udi, "scsi.host", &error )) < 0)
655 goto done;
656 if ((bus = p_libhal_device_get_property_int( ctx, udi, "scsi.bus", &error )) < 0)
657 goto done;
658 if ((target = p_libhal_device_get_property_int( ctx, udi, "scsi.target", &error )) < 0)
659 goto done;
660 if ((lun = p_libhal_device_get_property_int( ctx, udi, "scsi.lun", &error )) < 0)
661 goto done;
663 ret = TRUE;
664 scsi_addr->PortNumber = host;
665 scsi_addr->PathId = bus;
666 scsi_addr->TargetId = target;
667 scsi_addr->Lun = lun;
669 if (ident)
671 if (!(vendor = p_libhal_device_get_property_string( ctx, udi, "scsi.vendor", &error )))
672 p_dbus_error_free( &error ); /* ignore error */
673 if (!(model = p_libhal_device_get_property_string( ctx, udi, "scsi.model", &error )))
674 p_dbus_error_free( &error ); /* ignore error */
675 snprintf( ident, ident_size, "%-8s%-16s", vendor ? vendor : "WINE", model ? model : "SCSI" );
678 if (devtype)
680 if (!(type = p_libhal_device_get_property_string( ctx, udi, "scsi.type", &error )))
682 *devtype = SCSI_UNKNOWN_PERIPHERAL;
683 goto done;
685 if (!strcmp( type, "disk" ))
686 *devtype = SCSI_DISK_PERIPHERAL;
687 else if (!strcmp( type, "tape" ))
688 *devtype = SCSI_TAPE_PERIPHERAL;
689 else if (!strcmp( type, "printer" ))
690 *devtype = SCSI_PRINTER_PERIPHERAL;
691 else if (!strcmp( type, "processor" ))
692 *devtype = SCSI_PROCESSOR_PERIPHERAL;
693 else if (!strcmp( type, "cdrom" ))
694 *devtype = SCSI_CDROM_PERIPHERAL;
695 else if (!strcmp( type, "scanner" ))
696 *devtype = SCSI_SCANNER_PERIPHERAL;
697 else if (!strcmp( type, "medium_changer" ))
698 *devtype = SCSI_MEDIUM_CHANGER_PERIPHERAL;
699 else if (!strcmp( type, "comm" ))
700 *devtype = SCSI_COMMS_PERIPHERAL;
701 else if (!strcmp( type, "raid" ))
702 *devtype = SCSI_ARRAY_PERIPHERAL;
703 else
704 *devtype = SCSI_UNKNOWN_PERIPHERAL;
707 done:
708 if (type) p_libhal_free_string( type );
709 if (vendor) p_libhal_free_string( vendor );
710 if (model) p_libhal_free_string( model );
711 p_dbus_error_free( &error );
712 return ret;
715 static void hal_new_ide_device( LibHalContext *ctx, const char *udi )
717 SCSI_ADDRESS scsi_addr;
718 UCHAR devtype;
719 char ident[40];
721 if (!hal_get_ide_parameters( ctx, udi, &scsi_addr, &devtype, ident, sizeof(ident) )) return;
722 create_scsi_entry( &scsi_addr, 255, devtype == SCSI_CDROM_PERIPHERAL ? "atapi" : "WINE SCSI", devtype, ident, NULL );
725 static void hal_set_device_name( LibHalContext *ctx, const char *udi, const UNICODE_STRING *devname )
727 DBusError error;
728 SCSI_ADDRESS scsi_addr;
729 char *parent = NULL;
731 p_dbus_error_init( &error );
733 if (!hal_get_ide_parameters( ctx, udi, &scsi_addr, NULL, NULL, 0 ))
735 if (!(parent = p_libhal_device_get_property_string( ctx, udi, "info.parent", &error )))
736 goto done;
737 if (!hal_get_scsi_parameters( ctx, parent, &scsi_addr, NULL, NULL, 0 ))
738 goto done;
740 set_scsi_device_name( &scsi_addr, devname );
742 done:
743 if (parent) p_libhal_free_string( parent );
744 p_dbus_error_free( &error );
747 static void hal_new_scsi_device( LibHalContext *ctx, const char *udi )
749 SCSI_ADDRESS scsi_addr;
750 UCHAR devtype;
751 char ident[40];
753 if (!hal_get_scsi_parameters( ctx, udi, &scsi_addr, &devtype, ident, sizeof(ident) )) return;
754 /* FIXME: get real controller Id for SCSI */
755 create_scsi_entry( &scsi_addr, 255, "WINE SCSI", devtype, ident, NULL );
758 /* HAL callback for new device */
759 static void hal_new_device( LibHalContext *ctx, const char *udi )
761 DBusError error;
762 char *parent = NULL;
763 char *mount_point = NULL;
764 char *device = NULL;
765 char *type = NULL;
766 char *uuid_str = NULL;
767 GUID guid, *guid_ptr = NULL;
768 enum device_type drive_type;
770 p_dbus_error_init( &error );
772 hal_new_scsi_device( ctx, udi );
773 hal_new_ide_device( ctx, udi );
775 if (!(device = p_libhal_device_get_property_string( ctx, udi, "block.device", &error )))
776 goto done;
778 if (!(mount_point = p_libhal_device_get_property_string( ctx, udi, "volume.mount_point", &error )))
779 goto done;
781 if (!(parent = p_libhal_device_get_property_string( ctx, udi, "info.parent", &error )))
782 goto done;
784 if (!(uuid_str = p_libhal_device_get_property_string( ctx, udi, "volume.uuid", &error )))
785 p_dbus_error_free( &error ); /* ignore error */
786 else
787 guid_ptr = parse_uuid( &guid, uuid_str );
789 if (!(type = p_libhal_device_get_property_string( ctx, parent, "storage.drive_type", &error )))
790 p_dbus_error_free( &error ); /* ignore error */
792 if (type && !strcmp( type, "cdrom" )) drive_type = DEVICE_CDROM;
793 else if (type && !strcmp( type, "floppy" )) drive_type = DEVICE_FLOPPY;
794 else drive_type = DEVICE_UNKNOWN;
796 if (p_libhal_device_get_property_bool( ctx, parent, "storage.removable", &error ))
798 UNICODE_STRING devname;
800 add_dos_device( -1, udi, device, mount_point, drive_type, guid_ptr, &devname );
801 hal_set_device_name( ctx, parent, &devname );
802 /* add property watch for mount point */
803 p_libhal_device_add_property_watch( ctx, udi, &error );
805 else if (guid_ptr) add_volume( udi, device, mount_point, DEVICE_HARDDISK_VOL, guid_ptr, NULL );
807 done:
808 if (type) p_libhal_free_string( type );
809 if (parent) p_libhal_free_string( parent );
810 if (device) p_libhal_free_string( device );
811 if (uuid_str) p_libhal_free_string( uuid_str );
812 if (mount_point) p_libhal_free_string( mount_point );
813 p_dbus_error_free( &error );
816 /* HAL callback for removed device */
817 static void hal_removed_device( LibHalContext *ctx, const char *udi )
819 DBusError error;
821 TRACE( "removed %s\n", wine_dbgstr_a(udi) );
823 if (!remove_dos_device( -1, udi ))
825 p_dbus_error_init( &error );
826 p_libhal_device_remove_property_watch( ctx, udi, &error );
827 p_dbus_error_free( &error );
829 else remove_volume( udi );
832 /* HAL callback for property changes */
833 static void hal_property_modified (LibHalContext *ctx, const char *udi,
834 const char *key, dbus_bool_t is_removed, dbus_bool_t is_added)
836 TRACE( "udi %s key %s %s\n", wine_dbgstr_a(udi), wine_dbgstr_a(key),
837 is_added ? "added" : is_removed ? "removed" : "modified" );
839 if (!strcmp( key, "volume.mount_point" )) hal_new_device( ctx, udi );
842 static BOOL hal_enumerate_devices(void)
844 LibHalContext *ctx;
845 DBusError error;
846 int i, num;
847 char **list;
849 if (!p_libhal_ctx_new) return FALSE;
850 if (!(ctx = p_libhal_ctx_new())) return FALSE;
852 p_libhal_ctx_set_dbus_connection( ctx, connection );
853 p_libhal_ctx_set_device_added( ctx, hal_new_device );
854 p_libhal_ctx_set_device_removed( ctx, hal_removed_device );
855 p_libhal_ctx_set_device_property_modified( ctx, hal_property_modified );
857 p_dbus_error_init( &error );
858 if (!p_libhal_ctx_init( ctx, &error ))
860 WARN( "HAL context init failed: %s\n", error.message );
861 p_dbus_error_free( &error );
862 return FALSE;
865 /* retrieve all existing devices */
866 if (!(list = p_libhal_get_all_devices( ctx, &num, &error ))) p_dbus_error_free( &error );
867 else
869 for (i = 0; i < num; i++) hal_new_device( ctx, list[i] );
870 p_libhal_free_string_array( list );
872 return TRUE;
875 #endif /* SONAME_LIBHAL */
877 static DWORD WINAPI dbus_thread( void *arg )
879 static const char udisks_match[] = "type='signal',"
880 "interface='org.freedesktop.UDisks',"
881 "sender='org.freedesktop.UDisks'";
882 static const char udisks2_match_interfaces[] = "type='signal',"
883 "interface='org.freedesktop.DBus.ObjectManager',"
884 "path='/org/freedesktop/UDisks2'";
885 static const char udisks2_match_properties[] = "type='signal',"
886 "interface='org.freedesktop.DBus.Properties'";
889 DBusError error;
891 p_dbus_error_init( &error );
892 if (!(connection = p_dbus_bus_get( DBUS_BUS_SYSTEM, &error )))
894 WARN( "failed to get system dbus connection: %s\n", error.message );
895 p_dbus_error_free( &error );
896 return 1;
899 /* first try UDisks2 */
901 p_dbus_connection_add_filter( connection, udisks_filter, NULL, NULL );
902 p_dbus_bus_add_match( connection, udisks2_match_interfaces, &error );
903 p_dbus_bus_add_match( connection, udisks2_match_properties, &error );
904 if (udisks2_add_devices( NULL )) goto found;
905 p_dbus_bus_remove_match( connection, udisks2_match_interfaces, &error );
906 p_dbus_bus_remove_match( connection, udisks2_match_properties, &error );
908 /* then try UDisks */
910 p_dbus_bus_add_match( connection, udisks_match, &error );
911 if (udisks_enumerate_devices()) goto found;
912 p_dbus_bus_remove_match( connection, udisks_match, &error );
913 p_dbus_connection_remove_filter( connection, udisks_filter, NULL );
915 /* then finally HAL */
917 #ifdef SONAME_LIBHAL
918 if (!hal_enumerate_devices())
920 p_dbus_error_free( &error );
921 return 1;
923 #endif
925 found:
926 __TRY
928 while (p_dbus_connection_read_write_dispatch( connection, -1 )) /* nothing */ ;
930 __EXCEPT( assert_fault )
932 WARN( "dbus assertion failure, disabling support\n" );
933 return 1;
935 __ENDTRY;
937 return 0;
940 void initialize_dbus(void)
942 HANDLE handle;
944 #ifdef SONAME_LIBHAL
945 if (!load_hal_functions())
946 #endif
947 if (!load_dbus_functions()) return;
948 if (!(handle = CreateThread( NULL, 0, dbus_thread, NULL, 0, NULL ))) return;
949 CloseHandle( handle );
952 #if !defined(HAVE_SYSTEMCONFIGURATION_SCDYNAMICSTORECOPYDHCPINFO_H) || !defined(HAVE_SYSTEMCONFIGURATION_SCNETWORKCONFIGURATION_H)
954 /* The udisks dispatch loop will block all threads using the same connection, so we'll
955 use a private connection. Multiple threads can make methods calls at the same time
956 on the same connection, according to the documentation.
958 static DBusConnection *dhcp_connection;
959 static DBusConnection *get_dhcp_connection(void)
961 if (!dhcp_connection)
963 DBusError error;
964 p_dbus_error_init( &error );
965 if (!(dhcp_connection = p_dbus_bus_get_private( DBUS_BUS_SYSTEM, &error )))
967 WARN( "failed to get system dbus connection: %s\n", error.message );
968 p_dbus_error_free( &error );
971 return dhcp_connection;
974 static DBusMessage *device_by_iface_request( const char *iface )
976 DBusMessage *request, *reply;
977 DBusMessageIter iter;
978 DBusError error;
980 request = p_dbus_message_new_method_call( "org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager",
981 "org.freedesktop.NetworkManager", "GetDeviceByIpIface" );
982 if (!request) return NULL;
984 p_dbus_message_iter_init_append( request, &iter );
985 p_dbus_message_iter_append_basic( &iter, DBUS_TYPE_STRING, &iface );
987 p_dbus_error_init( &error );
988 reply = p_dbus_connection_send_with_reply_and_block( get_dhcp_connection(), request, -1, &error );
989 p_dbus_message_unref( request );
990 if (!reply)
992 WARN( "failed: %s\n", error.message );
993 p_dbus_error_free( &error );
994 return NULL;
997 p_dbus_error_free( &error );
998 return reply;
1001 #define IF_NAMESIZE 16
1002 static BOOL map_adapter_name( const WCHAR *name, char *unix_name, DWORD len )
1004 WCHAR unix_nameW[IF_NAMESIZE];
1005 UNICODE_STRING str;
1006 GUID guid;
1008 RtlInitUnicodeString( &str, name );
1009 if (!RtlGUIDFromString( &str, &guid ))
1011 NET_LUID luid;
1012 if (ConvertInterfaceGuidToLuid( &guid, &luid ) ||
1013 ConvertInterfaceLuidToNameW( &luid, unix_nameW, ARRAY_SIZE(unix_nameW) )) return FALSE;
1015 name = unix_nameW;
1017 return WideCharToMultiByte( CP_UNIXCP, 0, name, -1, unix_name, len, NULL, NULL ) != 0;
1020 static DBusMessage *dhcp4_config_request( const WCHAR *adapter )
1022 static const char *device = "org.freedesktop.NetworkManager.Device";
1023 static const char *dhcp4_config = "Dhcp4Config";
1024 char iface[IF_NAMESIZE];
1025 DBusMessage *request, *reply;
1026 DBusMessageIter iter;
1027 DBusError error;
1028 const char *path = NULL;
1030 if (!map_adapter_name( adapter, iface, sizeof(iface) )) return NULL;
1031 if (!(reply = device_by_iface_request( iface ))) return NULL;
1033 p_dbus_message_iter_init( reply, &iter );
1034 if (p_dbus_message_iter_get_arg_type( &iter ) == DBUS_TYPE_OBJECT_PATH) p_dbus_message_iter_get_basic( &iter, &path );
1035 p_dbus_message_unref( reply );
1036 if (!path) return NULL;
1038 request = p_dbus_message_new_method_call( "org.freedesktop.NetworkManager", path,
1039 "org.freedesktop.DBus.Properties", "Get" );
1040 if (!request) return NULL;
1042 p_dbus_message_iter_init_append( request, &iter );
1043 p_dbus_message_iter_append_basic( &iter, DBUS_TYPE_STRING, &device );
1044 p_dbus_message_iter_append_basic( &iter, DBUS_TYPE_STRING, &dhcp4_config );
1046 p_dbus_error_init( &error );
1047 reply = p_dbus_connection_send_with_reply_and_block( get_dhcp_connection(), request, -1, &error );
1048 p_dbus_message_unref( request );
1049 if (!reply)
1051 WARN( "failed: %s\n", error.message );
1052 p_dbus_error_free( &error );
1053 return NULL;
1056 p_dbus_error_free( &error );
1057 return reply;
1060 static DBusMessage *dhcp4_config_options_request( const WCHAR *adapter )
1062 static const char *dhcp4_config = "org.freedesktop.NetworkManager.DHCP4Config";
1063 static const char *options = "Options";
1064 DBusMessage *request, *reply;
1065 DBusMessageIter iter, sub;
1066 DBusError error;
1067 const char *path = NULL;
1069 if (!(reply = dhcp4_config_request( adapter ))) return NULL;
1071 p_dbus_message_iter_init( reply, &iter );
1072 if (p_dbus_message_iter_get_arg_type( &iter ) == DBUS_TYPE_VARIANT)
1074 p_dbus_message_iter_recurse( &iter, &sub );
1075 p_dbus_message_iter_get_basic( &sub, &path );
1077 if (!path)
1079 p_dbus_message_unref( reply );
1080 return NULL;
1083 request = p_dbus_message_new_method_call( "org.freedesktop.NetworkManager", path,
1084 "org.freedesktop.DBus.Properties", "Get" );
1085 p_dbus_message_unref( reply );
1086 if (!request) return NULL;
1088 p_dbus_message_iter_init_append( request, &iter );
1089 p_dbus_message_iter_append_basic( &iter, DBUS_TYPE_STRING, &dhcp4_config );
1090 p_dbus_message_iter_append_basic( &iter, DBUS_TYPE_STRING, &options );
1092 p_dbus_error_init( &error );
1093 reply = p_dbus_connection_send_with_reply_and_block( get_dhcp_connection(), request, -1, &error );
1094 p_dbus_message_unref( request );
1095 if (!reply)
1097 p_dbus_error_free( &error );
1098 return NULL;
1101 p_dbus_error_free( &error );
1102 return reply;
1105 static const char *dhcp4_config_option_next_dict_entry( DBusMessageIter *iter, DBusMessageIter *variant )
1107 DBusMessageIter sub;
1108 const char *name;
1110 if (p_dbus_message_iter_get_arg_type( iter ) != DBUS_TYPE_DICT_ENTRY) return NULL;
1111 p_dbus_message_iter_recurse( iter, &sub );
1112 p_dbus_message_iter_next( iter );
1113 p_dbus_message_iter_get_basic( &sub, &name );
1114 p_dbus_message_iter_next( &sub );
1115 p_dbus_message_iter_recurse( &sub, variant );
1116 return name;
1119 static DBusMessage *dhcp4_config_option_request( const WCHAR *adapter, const char *option, const char **value )
1121 DBusMessage *reply;
1122 DBusMessageIter iter, variant;
1123 const char *name;
1125 if (!(reply = dhcp4_config_options_request( adapter ))) return NULL;
1127 *value = NULL;
1128 p_dbus_message_iter_init( reply, &iter );
1129 if (p_dbus_message_iter_get_arg_type( &iter ) == DBUS_TYPE_VARIANT)
1131 p_dbus_message_iter_recurse( &iter, &iter );
1132 if (p_dbus_message_iter_get_arg_type( &iter ) == DBUS_TYPE_ARRAY)
1134 p_dbus_message_iter_recurse( &iter, &iter );
1135 while ((name = dhcp4_config_option_next_dict_entry( &iter, &variant )))
1137 if (!strcmp( name, option ))
1139 p_dbus_message_iter_get_basic( &variant, value );
1140 break;
1146 return reply;
1149 static const char *map_option( ULONG option )
1151 switch (option)
1153 case OPTION_SUBNET_MASK: return "subnet_mask";
1154 case OPTION_ROUTER_ADDRESS: return "next_server";
1155 case OPTION_HOST_NAME: return "host_name";
1156 case OPTION_DOMAIN_NAME: return "domain_name";
1157 case OPTION_BROADCAST_ADDRESS: return "broadcast_address";
1158 case OPTION_MSFT_IE_PROXY: return "wpad";
1159 default:
1160 FIXME( "unhandled option %u\n", option );
1161 return "";
1165 ULONG get_dhcp_request_param( const WCHAR *adapter, struct mountmgr_dhcp_request_param *param, char *buf, ULONG offset,
1166 ULONG size )
1168 DBusMessage *reply;
1169 const char *value;
1170 ULONG ret = 0;
1172 param->offset = param->size = 0;
1174 if (!(reply = dhcp4_config_option_request( adapter, map_option(param->id), &value ))) return 0;
1176 switch (param->id)
1178 case OPTION_SUBNET_MASK:
1179 case OPTION_ROUTER_ADDRESS:
1180 case OPTION_BROADCAST_ADDRESS:
1182 IN_ADDR *ptr = (IN_ADDR *)(buf + offset);
1183 if (value && size >= sizeof(IN_ADDR) && !RtlIpv4StringToAddressA( value, TRUE, NULL, ptr ))
1185 param->offset = offset;
1186 param->size = sizeof(*ptr);
1187 TRACE( "returning %08x\n", *(DWORD *)ptr );
1189 ret = sizeof(*ptr);
1190 break;
1192 case OPTION_HOST_NAME:
1193 case OPTION_DOMAIN_NAME:
1194 case OPTION_MSFT_IE_PROXY:
1196 char *ptr = buf + offset;
1197 int len = value ? strlen( value ) : 0;
1198 if (len && size >= len)
1200 memcpy( ptr, value, len );
1201 param->offset = offset;
1202 param->size = len;
1203 TRACE( "returning %s\n", debugstr_an(ptr, len) );
1205 ret = len;
1206 break;
1208 default:
1209 FIXME( "option %u not supported\n", param->id );
1210 break;
1213 p_dbus_message_unref( reply );
1214 return ret;
1216 #endif
1218 #else /* SONAME_LIBDBUS_1 */
1220 void initialize_dbus(void)
1222 TRACE( "Skipping, DBUS support not compiled in\n" );
1225 #endif /* SONAME_LIBDBUS_1 */