+void device_handler_status_download(struct device_handler *handler,
+ const struct process_info *procinfo,
+ unsigned int percentage, unsigned int size, char suffix)
+{
+ struct progress_info *p, *progress = NULL;
+ uint64_t current_converted, current = 0;
+ const char *units = " kMGTP";
+ unsigned long size_bytes;
+ char *update = NULL;
+ double total = 0;
+ unsigned int i;
+ int unit = 0;
+
+ list_for_each_entry(&handler->progress, p, list)
+ if (p->procinfo == procinfo)
+ progress = p;
+
+ if (!progress) {
+ pb_log("Registering new progress struct\n");
+ progress = talloc_zero(handler, struct progress_info);
+ if (!progress) {
+ pb_log("Failed to allocate room for progress struct\n");
+ return;
+ }
+ progress->procinfo = procinfo;
+ list_add(&handler->progress, &progress->list);
+ handler->n_progress++;
+ }
+
+ size_bytes = size;
+ for (i = 0; i < strlen(units); i++) {
+ if (units[i] == suffix)
+ break;
+ }
+
+ if (i >= strlen(units)) {
+ pb_log("Couldn't recognise suffix '%c'\n", suffix);
+ size_bytes = 0;
+ } else {
+ while (i--)
+ size_bytes <<= 10;
+ }
+
+ progress->percentage = percentage;
+ progress->size = size_bytes;
+
+ /*
+ * Aggregate the info we have and update status. If a progress struct
+ * has zero for both percentage and size we assume progress information
+ * is unavailable and fall back to a generic progress message.
+ */
+ list_for_each_entry(&handler->progress, p, list) {
+ uint64_t c;
+ double t;
+ if (!p->percentage || !p->size) {
+ update = talloc_asprintf(handler,
+ _("%u downloads in progress..."),
+ handler->n_progress);
+ current = total = 0;
+ break;
+ }
+
+ c = p->size;
+ t = (100 * c) / p->percentage;
+
+ current += c;
+ total += t;
+ }
+
+ if (total) {
+ current_converted = current;
+ while (current_converted >= 1000) {
+ current_converted >>= 10;
+ unit++;
+ }
+ update = talloc_asprintf(handler,
+ _("%u %s downloading: %.0f%% - %" PRIu64 "%cB"),
+ handler->n_progress,
+ ngettext("item", "items", handler->n_progress),
+ (current / total) * 100, current_converted,
+ units[unit]);
+ }
+
+ if (!update) {
+ pb_log_fn("failed to allocate new status\n");
+ } else {
+ device_handler_status_info(handler, "%s\n", update);
+ talloc_free(update);
+ }
+}
+
+static void device_handler_plugin_scan_device(struct device_handler *handler,
+ struct discover_device *dev)
+{
+ int rc;
+
+ pb_debug("Scanning %s for plugin files\n", dev->device->id);
+
+ rc = process_run_simple(handler, pb_system_apps.pb_plugin,
+ "scan", dev->mount_path,
+ NULL);
+ if (rc)
+ pb_log("Error from pb-plugin scan %s\n",
+ dev->mount_path);
+}
+
+void device_handler_status_download_remove(struct device_handler *handler,
+ struct process_info *procinfo)
+{
+ struct progress_info *p, *tmp;
+
+ list_for_each_entry_safe(&handler->progress, p, tmp, list)
+ if (p->procinfo == procinfo) {
+ list_remove(&p->list);
+ talloc_free(p);
+ handler->n_progress--;
+ }
+}
+