#include "mbdesktop_module.h" #include #include #include #include #include typedef struct HalData { char* HalExecWith; char* HalMountWith; char* HalUmountWith; char* HalFolderName; char* HalFolderIcon; char* HalUnmountedIcon; char* HalMountedIcon; char* HalActionIcon; } HalData; typedef struct HalIconData { char* HalIconAction; Bool HalUpdateScreen; // For mount & umount } HalIconData; void halbrowser_open_folder(void *data1, void *data2); void halbrowser_activate_icon(void *data1, void *data2); char* get_config(MBDotDesktop *dd, char *confname, char *defaultvalue) { if (mb_dotdesktop_get(dd, confname)) return strdup(mb_dotdesktop_get(dd, confname)); else return defaultvalue; } int halbrowser_init (MBDesktop *mb, MBDesktopFolderModule *folder_module, char *arg_str) { MBDotDesktop *dd; HalData *data; MBDesktopItem *folder = NULL; /* args is the location of the configuration file */ dd = mb_dotdesktop_new_from_file(arg_str); if (!dd) { fprintf(stderr, "halbrowser: failed to open %s\n", arg_str); return -1; } /* Read config */ data = malloc(sizeof(HalData)); data->HalExecWith = get_config(dd, "ExecWith", "echo exec"); data->HalMountWith = get_config(dd, "MountWith", "echo mount"); data->HalUmountWith = get_config(dd, "UmountWith", "echo umount"); data->HalFolderName = get_config(dd, "FolderName", "Storage"); data->HalFolderIcon = get_config(dd, "FolderIcon", "mbfolder.png"); data->HalUnmountedIcon = get_config(dd, "UnmountedIcon", "mbnoapp.png"); data->HalMountedIcon = get_config(dd, "MountedIcon", "mbnoapp.png"); data->HalActionIcon = get_config(dd, "ActionIcon", "mbadd.png"); mb_dotdesktop_free(dd); folder = mbdesktop_module_folder_create(mb, data->HalFolderName, data->HalFolderIcon); mbdesktop_item_set_user_data(mb, folder, (void *) data); mbdesktop_item_set_extended_name(mb, folder, data->HalFolderName); mbdesktop_items_append_to_top_level(mb, folder); mbdesktop_item_folder_set_view(mb, folder, VIEW_LIST); mbdesktop_item_set_activate_callback(mb, folder, halbrowser_open_folder); return 1; } int hal_error_handle(DBusError *error, char *desc) { if (dbus_error_is_set(error)) { fprintf (stderr, "hal error: %s: %s: %s\n", desc, error->name, error->message); dbus_error_free (error); return 1; } return 0; } LibHalContext *get_hal_connection() { LibHalContext *hal_ctx; DBusError error; dbus_error_init (&error); if ((hal_ctx = libhal_ctx_new ()) == NULL) { fprintf (stderr, "error: libhal_ctx_new\n"); return 0; } libhal_ctx_set_dbus_connection(hal_ctx, dbus_bus_get (DBUS_BUS_SYSTEM, &error)); if (hal_error_handle(&error, "libhal_ctx_set_dbus_connection")) return 0; libhal_ctx_init(hal_ctx, &error); if (hal_error_handle(&error, "connecting to hald")) return 0; dbus_error_free (&error); return hal_ctx; } void free_string_references(MBDesktopItem *folder) { MBDesktopItem *item_cur = folder->item_child->item_next_sibling; // Skip "Back" icon HalIconData *data; while (item_cur != NULL) { data = (HalIconData *)item_cur->data; free(data->HalIconAction); free(data); item_cur = item_cur->item_next_sibling; } } /* A bit incomplete hack to check if a filesystem is mountable/unmountable by normal users. By default, assume mountability, as having a not working mount-icon is less harmful than not being able to mount a volume.*/ Bool test_mountability(char *device) { FILE *fp; struct mntent *line; Bool result = 1; fp = setmntent("/etc/fstab", "r"); if (fp == NULL) { fprintf(stderr, "halbrowser: Cannot open /etc/fstab for checking mountability\n"); return 1; } while ((line = getmntent(fp))) { if (strcmp(line->mnt_fsname, device) == 0) { if (strstr(line->mnt_opts, "user") == NULL && strstr(line->mnt_opts, "owner") == NULL) result = 0; } } fclose(fp); return result; } void halbrowser_update_folder(MBDesktop *mb, MBDesktopItem *item_folder) { HalData *mod_data; HalIconData *icon_data; MBDesktopItem *item_new = NULL; LibHalContext *hal_ctx; DBusError error; char **device_ids; int device_count, i; char buf[256]; mod_data = (HalData*)mbdesktop_item_get_user_data (mb, item_folder); if (mbdesktop_item_folder_has_contents(mb, item_folder)) { free_string_references(item_folder); mbdesktop_item_folder_contents_free(mb, item_folder); } hal_ctx = get_hal_connection(); if (hal_ctx == NULL) { fprintf(stderr, "halbrowser: failed to connect to hald\n"); return; } dbus_error_init (&error); device_ids = libhal_manager_find_device_string_match (hal_ctx, "info.category", "volume", &device_count, &error); if (hal_error_handle(&error, "getting device list")) return; for (i = 0; i < device_count; i++) { char *fsusage = libhal_device_get_property_string(hal_ctx, device_ids[i], "volume.fsusage", &error); if (hal_error_handle(&error, "get volume.fsusage")) return; if (strcmp(fsusage, "filesystem") != 0) { libhal_free_string(fsusage); /* Other than filesystem, eg. logical volume or swap */ continue; } libhal_free_string(fsusage); char *label = libhal_device_get_property_string(hal_ctx, device_ids[i], "volume.label", &error); if (hal_error_handle(&error, "get volume.label")) return; char *device = libhal_device_get_property_string(hal_ctx, device_ids[i], "block.device", &error); if (hal_error_handle(&error, "get block.device")) return; char *mount_point = libhal_device_get_property_string(hal_ctx, device_ids[i], "volume.mount_point", &error); if (hal_error_handle(&error, "get volume.mount_point")) return; Bool is_mounted = libhal_device_get_property_bool(hal_ctx, device_ids[i], "volume.is_mounted", &error); if (hal_error_handle(&error, "get volume.is_mounted")) return; /* Add the main icon */ icon_data = malloc(sizeof(HalIconData)); if (is_mounted) snprintf(buf, 255, "%s %s", mod_data->HalExecWith, mount_point); else snprintf(buf, 255, "%s %s", mod_data->HalMountWith, device); icon_data->HalIconAction = strdup(buf); if (is_mounted) snprintf(buf, 255, "%s %s mounted on %s", label, device, mount_point); else snprintf(buf, 255, "%s %s", label, device); icon_data->HalUpdateScreen = !is_mounted; // If it's mounted, action will open not mount if (is_mounted || test_mountability(device)) { item_new = mbdesktop_item_new_with_params(mb, buf, is_mounted ? mod_data->HalMountedIcon : mod_data->HalUnmountedIcon, (void *)icon_data, ITEM_TYPE_MODULE_ITEM); mbdesktop_item_set_activate_callback(mb, item_new, halbrowser_activate_icon); mbdesktop_items_append_to_folder(mb, item_folder, item_new); } /* Add unmount icon if mounted and unmountable*/ if (is_mounted && test_mountability(device)) { icon_data = malloc(sizeof(HalIconData)); snprintf(buf, 255, "%s %s", mod_data->HalUmountWith, device); icon_data->HalIconAction = strdup(buf); icon_data->HalUpdateScreen = 1; item_new = mbdesktop_item_new_with_params(mb, "Unmount", mod_data->HalActionIcon, (void *)icon_data, ITEM_TYPE_MODULE_ITEM); mbdesktop_item_set_activate_callback(mb, item_new, halbrowser_activate_icon); mbdesktop_items_append_to_folder(mb, item_folder, item_new); } libhal_free_string(label); libhal_free_string(device); libhal_free_string(mount_point); } libhal_free_string_array(device_ids); } void halbrowser_open_folder(void *data1, void *data2) { MBDesktop *mb = (MBDesktop *)data1; MBDesktopItem *item_folder = (MBDesktopItem *)data2; halbrowser_update_folder(mb, item_folder); mbdesktop_item_folder_activate_cb(data1, data2); } void halbrowser_activate_icon(void *data1, void *data2) { HalIconData *icon_data; MBDesktop *mb = (MBDesktop *)data1; MBDesktopItem *item = (MBDesktopItem *)data2; MBDesktopItem *cur; int pid, status; icon_data = (HalIconData*)mbdesktop_item_get_user_data (mb, item); if ((pid = fork()) == 0) { fprintf(stderr, "mbdesktop: attempting to exec '%s'\n", icon_data->HalIconAction); mb_exec(icon_data->HalIconAction); } if (icon_data->HalUpdateScreen) { waitpid(pid, &status, 0); // Find parent cur = item; while (cur->item_parent == NULL) { cur = cur->item_prev_sibling; } halbrowser_update_folder(mb, cur->item_parent); mbdesktop_view_paint(mb, False); } } #define MODULE_NAME "hal volume browser" #define MODULE_DESC "hal volume browser" #define MODULE_AUTHOR "Petteri Aimonen" #define MODULE_MAJOR_VER 0 #define MODULE_MINOR_VER 0 #define MODULE_MICRO_VER 2 #define MODULE_API_VERSION 0 MBDesktopModuleInfo halbrowser_info = { MODULE_NAME , MODULE_DESC , MODULE_AUTHOR , MODULE_MAJOR_VER , MODULE_MINOR_VER , MODULE_MICRO_VER , MODULE_API_VERSION }; MBDesktopFolderModule folder_module = { &halbrowser_info, halbrowser_init, NULL, NULL };