diff options
Diffstat (limited to 'src/udev-mgr.c')
-rw-r--r-- | src/udev-mgr.c | 420 |
1 files changed, 415 insertions, 5 deletions
diff --git a/src/udev-mgr.c b/src/udev-mgr.c index 6575ca5..e3328ec 100644 --- a/src/udev-mgr.c +++ b/src/udev-mgr.c @@ -17,22 +17,120 @@ You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <gudev/gudev.h> + +// TEMP +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdarg.h> + #include "udev-mgr.h" +#include "sane-rules.h" + +static void udevice_mgr_device_list_iterator (gpointer data, + gpointer userdata); +static void udev_mgr_uevent_cb (GUdevClient *client, + gchar *action, + GUdevDevice *device, + gpointer user_data); +static void udev_mgr_update_menuitems (UdevMgr* self); +static void udev_mgr_check_if_usb_device_is_supported (UdevMgr* self, + GUdevDevice *device, + UdevMgrDeviceAction action); +static void udev_mgr_handle_webcam (UdevMgr* self, + GUdevDevice* device, + UdevMgrDeviceAction action); +static void udev_mgr_handle_scsi_device (UdevMgr* self, + GUdevDevice* device, + UdevMgrDeviceAction action); + +static void udev_mgr_cleanup_lists(gpointer data, gpointer self); +static void udev_mgr_cleanup_entries(gpointer data, gpointer self); + + +static void debug_device (UdevMgr* self, + GUdevDevice* device, + UdevMgrDeviceAction action); + + +struct _UdevMgr +{ + GObject parent_instance; + DbusmenuMenuitem* scanner_item; + DbusmenuMenuitem* webcam_item; + GUdevClient* client; + GHashTable* supported_usb_scanners; + GHashTable* supported_scsi_scanners; + GHashTable* scanners_present; + GHashTable* webcams_present; +}; + +const char *subsystems[3] = {"usb", "scsi", "video4linux"}; +const gchar* usb_subsystem = "usb"; +const gchar* scsi_subsystem = "scsi"; +const gchar* video4linux_subsystem = "video4linux"; G_DEFINE_TYPE (UdevMgr, udev_mgr, G_TYPE_OBJECT); static void -udev_mgr_init (UdevMgr *object) +udev_mgr_init (UdevMgr* self) { - /* TODO: Add initialization code here */ + self->client = NULL; + self->supported_usb_scanners = NULL; + self->scanners_present = NULL; + self->webcams_present = NULL; + self->client = g_udev_client_new (subsystems); + self->supported_usb_scanners = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + (GDestroyNotify)udev_mgr_cleanup_lists); + self->supported_scsi_scanners = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + (GDestroyNotify)udev_mgr_cleanup_lists); + self->scanners_present = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + g_free); + self->webcams_present = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + g_free); + + // load into memory all supported scanners ... + populate_usb_scanners (self->supported_usb_scanners); + populate_scsi_scanners (self->supported_scsi_scanners); + g_signal_connect (G_OBJECT (self->client), + "uevent", + G_CALLBACK (udev_mgr_uevent_cb), + self); } static void -udev_mgr_finalize (GObject *object) +udev_mgr_cleanup_lists(gpointer data, gpointer self) { - /* TODO: Add deinitalization code here */ + GList* scanners = (GList*)data; + g_list_foreach (scanners, udev_mgr_cleanup_entries, NULL); + g_list_free(scanners); +} + +static void +udev_mgr_cleanup_entries(gpointer data, gpointer self) +{ + gchar* entry = (gchar*)data; + g_free(entry); +} +static void +udev_mgr_finalize (GObject *object) +{ + UdevMgr* self = UDEV_MGR (object); + g_hash_table_destroy (self->supported_scsi_scanners); + g_hash_table_destroy (self->supported_usb_scanners); + g_hash_table_destroy (self->scanners_present); + g_hash_table_destroy (self->webcams_present); G_OBJECT_CLASS (udev_mgr_parent_class)->finalize (object); } @@ -40,7 +138,319 @@ static void udev_mgr_class_init (UdevMgrClass *klass) { GObjectClass* object_class = G_OBJECT_CLASS (klass); - object_class->finalize = udev_mgr_finalize; } +static void +udevice_mgr_device_list_iterator (gpointer data, gpointer userdata) +{ + g_return_if_fail (G_UDEV_IS_DEVICE (data)); + g_return_if_fail (UDEV_IS_MGR (userdata)); + + UdevMgr* self = UDEV_MGR (userdata); + + GUdevDevice* device = G_UDEV_DEVICE (data); + + const gchar* subsystem = NULL; + subsystem = g_udev_device_get_subsystem (device); + + if (g_strcmp0 (subsystem, "usb") == 0){ + udev_mgr_check_if_usb_device_is_supported (self, device, ADD); + } + else if (g_strcmp0 (subsystem, "video4linux") == 0){ + udev_mgr_handle_webcam (self, device, ADD); + } + else if (g_strcmp0 (subsystem, "scsi") == 0){ + udev_mgr_handle_scsi_device (self, device, ADD); + } + + g_object_unref (device); +} + + +static void udev_mgr_update_menuitems (UdevMgr* self) +{ + dbusmenu_menuitem_property_set_bool (self->scanner_item, + DBUSMENU_MENUITEM_PROP_VISIBLE, + g_hash_table_size (self->scanners_present) > 0); + + dbusmenu_menuitem_property_set_bool (self->webcam_item, + DBUSMENU_MENUITEM_PROP_VISIBLE, + g_hash_table_size (self->webcams_present) > 0); + +} + +static void udev_mgr_uevent_cb (GUdevClient *client, + gchar *action, + GUdevDevice *device, + gpointer user_data) +{ + g_return_if_fail (UDEV_IS_MGR (user_data)); + UdevMgr* self = UDEV_MGR (user_data); + g_return_if_fail (device != NULL); + + g_debug ("just received a UEVENT with an action : %s", action); + + UdevMgrDeviceAction udev_mgr_action = ADD; + + if (g_strcmp0 (action, "remove") == 0){ + udev_mgr_action = REMOVE; + } + + const gchar* subsystem = NULL; + subsystem = g_udev_device_get_subsystem (device); + + if (g_strcmp0 (subsystem, "usb") == 0){ + udev_mgr_check_if_usb_device_is_supported (self, + device, + udev_mgr_action); + } + else if (g_strcmp0 (subsystem, "video4linux") == 0){ + udev_mgr_handle_webcam (self, device, udev_mgr_action); + } + else if (g_strcmp0 (subsystem, "scsi") == 0){ + udev_mgr_handle_scsi_device (self, device, udev_mgr_action); + } +} + + +static void +udev_mgr_handle_webcam (UdevMgr* self, + GUdevDevice* device, + UdevMgrDeviceAction action) +{ + if (FALSE) + debug_device (self, device, action); + + const gchar* vendor; + const gchar* product; + + vendor = g_udev_device_get_property (device, "ID_VENDOR_ID"); + product = g_udev_device_get_property (device, "ID_MODEL_ID"); + + if (action == REMOVE){ + if (g_hash_table_lookup (self->webcams_present, product) == NULL){ + g_warning ("Got a remove event on a webcam device but we don't have that device in our webcam cache"); + return; + } + g_hash_table_remove (self->webcams_present, + product); + + } + else { + if (g_hash_table_lookup (self->webcams_present, product) != NULL){ + g_warning ("Got an ADD event on a webcam device but we already have that device in our webcam cache"); + return; + } + g_hash_table_insert (self->webcams_present, + g_strdup (product), + g_strdup (vendor)); + } + udev_mgr_update_menuitems (self); +} + +static void +debug_device (UdevMgr* self, + GUdevDevice* device, + UdevMgrDeviceAction action) +{ + const gchar* vendor; + const gchar* product; + const gchar* number; + const gchar* name; + + vendor = g_udev_device_get_property (device, "ID_VENDOR_ID"); + product = g_udev_device_get_property (device, "ID_MODEL_ID"); + number = g_udev_device_get_number (device); + name = g_udev_device_get_name (device); + + g_debug ("device vendor id %s , product id of %s , number of %s and name of %s", + g_strdup(vendor), + g_strdup(product), + g_strdup(number), + g_strdup(name)); + + const gchar *const *list; + const gchar *const *iter; + char propstr[500]; + guint32 namelen = 0, i; + + list = g_udev_device_get_property_keys(device); + + for (iter = list; iter && *iter; iter++) { + if (strlen(*iter) > namelen) + namelen = strlen(*iter); + } + namelen++; + + for (iter = list; iter && *iter; iter++) { + strcpy(propstr, *iter); + strcat(propstr, ":"); + for (i = 0; i < namelen - strlen(*iter); i++) + strcat(propstr, " "); + strcat(propstr, g_udev_device_get_property(device, *iter)); + g_debug("%s", propstr); + } +} + +static void udev_mgr_handle_scsi_device (UdevMgr* self, + GUdevDevice* device, + UdevMgrDeviceAction action) +{ + const gchar* type = NULL; + type = g_udev_device_get_property (device, "TYPE"); + // apparently anything thats type 3 and SCSI is a Scanner + if (g_strcmp0 (type, "6") == 0){ + gchar* random_scanner_name = g_strdup_printf("%p--scanner", self); + g_hash_table_insert (self->scanners_present, + random_scanner_name, + g_strdup("Scanner")); + udev_mgr_update_menuitems (self); + return; + } + + // We only care about type 3 for the special cases below + if (g_strcmp0 (type, "3") != 0){ + return; + } + + const gchar* vendor = NULL; + vendor = g_udev_device_get_property (device, "VENDOR"); + + if (vendor == NULL) + return; + + GList* vendor_list = NULL; + vendor_list = g_hash_table_lookup (self->supported_scsi_scanners, + (gpointer)vendor); + if (vendor_list == NULL) + return; + + const gchar* model_id = NULL; + model_id = g_udev_device_get_property (device, "MODEL"); + + if (model_id == NULL) + return; + + GList* model_entry = NULL; + model_entry = g_list_find_custom (vendor_list, + model_id, + (GCompareFunc)g_strcmp0); + + if (model_entry != NULL){ + if (action == REMOVE){ + if (g_hash_table_lookup (self->scanners_present, g_strdup(vendor)) == NULL){ + g_warning ("Got an REMOVE event on a scanner device but we dont have that device in our scanners cache"); + } + else{ + g_hash_table_remove (self->scanners_present, vendor); + } + } + else{ + if (g_hash_table_lookup (self->scanners_present, g_strdup(vendor)) != NULL){ + g_warning ("Got an ADD event on a scanner device but we already have that device in our scanners cache"); + } + else{ + g_hash_table_insert (self->scanners_present, + g_strdup(vendor), + g_strdup(model_id)); + } + } + udev_mgr_update_menuitems (self); + } +} + +static void +udev_mgr_check_if_usb_device_is_supported (UdevMgr* self, + GUdevDevice *device, + UdevMgrDeviceAction action) +{ + const gchar* vendor = NULL; + debug_device (self, device, action); + + vendor = g_udev_device_get_property (device, "ID_VENDOR_ID"); + + if (vendor == NULL) + return; + + //g_debug ("vendor = %s", vendor); + + GList* vendor_list = NULL; + vendor_list = g_hash_table_lookup (self->supported_usb_scanners, + (gpointer)vendor); + if (vendor_list == NULL) + return; + + const gchar* model_id = NULL; + model_id = g_udev_device_get_property (device, "ID_MODEL_ID"); + + if (model_id == NULL) + return; + + GList* model_entry = NULL; + model_entry = g_list_find_custom(vendor_list, model_id, (GCompareFunc)g_strcmp0); + + if (model_entry != NULL){ + if (action == REMOVE){ + if (g_hash_table_lookup (self->scanners_present, g_strdup(vendor)) == NULL){ + g_warning ("Got an REMOVE event on a scanner device but we dont have that device in our scanners cache"); + } + else{ + g_hash_table_remove (self->scanners_present, vendor); + } + } + else{ + if (g_hash_table_lookup (self->scanners_present, g_strdup(vendor)) != NULL){ + g_warning ("Got an ADD event on a scanner device but we already have that device in our scanners cache"); + } + else{ + g_hash_table_insert (self->scanners_present, + g_strdup(vendor), + g_strdup(model_id)); + } + } + udev_mgr_update_menuitems (self); + } +} + +UdevMgr* udev_mgr_new (DbusmenuMenuitem* scanner, + DbusmenuMenuitem* webcam) +{ + UdevMgr* mgr = g_object_new (UDEV_TYPE_MGR, NULL); + mgr->scanner_item = scanner; + mgr->webcam_item = webcam; + + // Check for USB devices + GList* usb_devices_available = NULL; + usb_devices_available = g_udev_client_query_by_subsystem (mgr->client, + usb_subsystem); + if (usb_devices_available != NULL){ + g_list_foreach (usb_devices_available, + udevice_mgr_device_list_iterator, + mgr); + + g_list_free (usb_devices_available); + } + // Check for webcams + GList* video_devices_available = NULL; + video_devices_available = g_udev_client_query_by_subsystem (mgr->client, + video4linux_subsystem); + if (video_devices_available != NULL){ + g_list_foreach (video_devices_available, + udevice_mgr_device_list_iterator, + mgr); + + g_list_free (video_devices_available); + } + // Check for SCSI devices + GList* scsi_devices_available = NULL; + scsi_devices_available = g_udev_client_query_by_subsystem (mgr->client, + scsi_subsystem); + if (scsi_devices_available != NULL){ + g_list_foreach (scsi_devices_available, + udevice_mgr_device_list_iterator, + mgr); + g_list_free (scsi_devices_available); + } + return mgr; +} |