11 void (*action)(struct app *app);
18 print_server(GDBusProxy *proxy)
23 nameowner = g_dbus_proxy_get_name_owner(proxy);
25 puts("Server is not running.");
29 printf("Server at %s\n", nameowner);
30 props = g_dbus_proxy_get_cached_property_names(proxy);
34 for (itr = props; *itr != NULL; itr++) {
35 GVariant *value = g_dbus_proxy_get_cached_property(proxy, *itr);
36 char *str = g_variant_print(value, TRUE);
37 printf("\t%s = %s\n", *itr, str);
38 g_variant_unref(value);
47 do_status(struct app *app)
49 print_server(app->proxy);
50 g_main_loop_quit(app->loop);
51 app->ret = EXIT_SUCCESS;
55 on_properties_changed(GDBusProxy *proxy, GVariant *changed, const char *const *invalidated, gpointer user_data)
57 struct app *app = user_data;
59 printf("%015.3f --- Properties Changed ---\n",
60 g_timer_elapsed(app->timer, NULL));
62 if (g_variant_n_children(changed) > 0) {
67 printf("Changed Properties:");
68 g_variant_get(changed, "a{sv}", &itr);
69 while (g_variant_iter_loop(itr, "{&sv}", &prop, &value)) {
71 str = g_variant_print(value, TRUE);
72 printf(" %s=%s", prop, str);
75 g_variant_iter_free(itr);
79 if (invalidated[0] != NULL) {
80 const char * const *itr;
81 printf("Invalidated Properties:");
82 for (itr = invalidated; *itr != NULL; itr++)
91 do_delayed_print_server(gpointer data)
93 GDBusProxy *proxy = data;
97 nameowner = g_dbus_proxy_get_name_owner(proxy);
104 props = g_dbus_proxy_get_cached_property_names(proxy);
106 g_timeout_add(1000, do_delayed_print_server, proxy);
116 on_name_owner_notify(GObject *object, GParamSpec *pspec, gpointer user_data)
118 GDBusProxy *proxy = G_DBUS_PROXY(object);
119 struct app *app = user_data;
121 printf("%015.3f --- Name Owner Changed ---\n",
122 g_timer_elapsed(app->timer, NULL));
123 do_delayed_print_server(proxy);
127 do_monitor(struct app *app)
129 app->timer = g_timer_new();
130 g_timer_start(app->timer);
132 print_server(app->proxy);
133 g_signal_connect(app->proxy, "g-properties-changed",
134 G_CALLBACK(on_properties_changed),
136 g_signal_connect(app->proxy, "notify::g-name-owner",
137 G_CALLBACK(on_name_owner_notify),
142 on_properties_changed_check_lock(GDBusProxy *proxy, GVariant *changed, const char *const *invalidated, gpointer user_data)
144 struct app *app = user_data;
145 gboolean lost_lock = FALSE;
147 if (g_variant_n_children(changed) > 0) {
152 g_variant_get(changed, "a{sv}", &itr);
153 while (g_variant_iter_loop(itr, "{&sv}", &prop, &value)) {
154 if (strcmp(prop, "WriteLocked") == 0) {
155 if (!g_variant_get_boolean(value))
160 g_variant_iter_free(itr);
163 if (invalidated[0] != NULL) {
164 const char * const *itr;
165 for (itr = invalidated; *itr != NULL; itr++) {
166 if (strcmp(*itr, "WriteLocked") == 0) {
174 fputs("Lost lock, exit.\n", stderr);
175 app->ret = EXIT_FAILURE;
176 g_main_loop_quit(app->loop);
181 do_write_lock(struct app *app)
184 GError *error = NULL;
187 nameowner = g_dbus_proxy_get_name_owner(app->proxy);
189 fputs("Server is not running, cannot get write lock!\n", stderr);
190 app->ret = EXIT_FAILURE;
191 g_main_loop_quit(app->loop);
195 printf("Server at %s, try to get write lock\n", nameowner);
198 g_signal_connect(app->proxy, "g-properties-changed",
199 G_CALLBACK(on_properties_changed_check_lock),
202 ret = g_dbus_proxy_call_sync(app->proxy, "RequestWriteLock",
204 G_DBUS_CALL_FLAGS_NONE, -1, NULL,
208 fprintf(stderr, "Could not get write lock: %s\n", error->message);
210 app->ret = EXIT_FAILURE;
211 g_main_loop_quit(app->loop);
215 g_variant_unref(ret);
216 puts("Got write lock, close program to release it.");
220 on_properties_changed_check_scan(GDBusProxy *proxy, GVariant *changed, const char *const *invalidated, gpointer user_data)
222 struct app *app = user_data;
224 if (g_variant_n_children(changed) > 0) {
229 g_variant_get(changed, "a{sv}", &itr);
230 while (g_variant_iter_loop(itr, "{&sv}", &prop, &value)) {
231 if (strcmp(prop, "IsScanning") == 0) {
232 if (g_variant_get_boolean(value) && !app->timer) {
233 app->timer = g_timer_new();
234 g_timer_start(app->timer);
235 } else if (!g_variant_get_boolean(value) && app->timer) {
236 g_timer_stop(app->timer);
237 app->ret = EXIT_SUCCESS;
238 g_main_loop_quit(app->loop);
240 g_variant_unref(value);
243 g_variant_unref(value);
245 g_variant_iter_free(itr);
248 if (invalidated[0] != NULL) {
249 const char * const *itr;
250 for (itr = invalidated; *itr != NULL; itr++) {
251 if (strcmp(*itr, "IsScanning") == 0) {
252 fputs("Lost server, exit.\n", stderr);
253 app->ret = EXIT_FAILURE;
254 g_main_loop_quit(app->loop);
262 on_signal(GDBusProxy *proxy, gchar *sender, gchar *signal, GVariant *params, gpointer user_data)
264 if (g_str_equal(signal, "ScanProgress")) {
265 const gchar *category = NULL, *path = NULL;
266 guint64 uptodate = 0, processed = 0, deleted = 0,
267 skipped = 0, errors = 0;
269 g_variant_get(params, "(&s&sttttt)",
278 printf("Scan Progress %s:%s uptodate=%llu, processed=%llu, "
279 "deleted=%llu, skipped=%llu, errors=%llu\n",
280 category, path, uptodate, processed, deleted, skipped, errors);
285 populate_scan_params(gpointer key, gpointer value, gpointer user_data)
287 const char *category = key;
288 const GArray *paths = value;
289 GVariantBuilder *builder = user_data;
290 GVariantBuilder *sub;
293 sub = g_variant_builder_new(G_VARIANT_TYPE("as"));
294 for (itr = (char **)paths->data; *itr != NULL; itr++)
295 g_variant_builder_add(sub, "s", *itr);
297 g_variant_builder_add(builder, "{sv}", category, g_variant_builder_end(sub));
298 g_variant_builder_unref(sub);
302 do_free_array(gpointer data)
304 g_array_free(data, TRUE);
308 do_scan(struct app *app)
310 GVariantBuilder *builder;
312 GError *error = NULL;
315 GHashTable *categories;
317 nameowner = g_dbus_proxy_get_name_owner(app->proxy);
319 fputs("Server is not running, cannot start scan!\n", stderr);
320 app->ret = EXIT_FAILURE;
321 g_main_loop_quit(app->loop);
325 printf("Server at %s, try to start scan\n", nameowner);
328 g_signal_connect(app->proxy, "g-properties-changed",
329 G_CALLBACK(on_properties_changed_check_scan),
331 g_signal_connect(app->proxy, "g-signal",
332 G_CALLBACK(on_signal),
335 categories = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, do_free_array);
336 for (i = 0; i < app->argc; i++) {
338 char *arg = app->argv[i];
339 char *sep = strchr(arg, ':');
344 fprintf(stderr, "Ignored scan parameter: invalid format '%s'\n",
352 arr = g_hash_table_lookup(categories, arg);
354 arr = g_array_new(TRUE, FALSE, sizeof(char *));
355 g_hash_table_insert(categories, arg, arr);
359 g_array_append_val(arr, path);
362 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
363 g_hash_table_foreach(categories, populate_scan_params, builder);
365 ret = g_dbus_proxy_call_sync(app->proxy, "Scan",
366 g_variant_new("(a{sv})", builder),
367 G_DBUS_CALL_FLAGS_NONE, -1, NULL,
369 g_variant_builder_unref(builder);
370 g_hash_table_destroy(categories);
373 fprintf(stderr, "Could not start scan: %s\n", error->message);
375 app->ret = EXIT_FAILURE;
376 g_main_loop_quit(app->loop);
380 g_variant_unref(ret);
384 do_stop(struct app *app)
387 GError *error = NULL;
390 nameowner = g_dbus_proxy_get_name_owner(app->proxy);
392 fputs("Server is not running, cannot stop scan!\n", stderr);
393 app->ret = EXIT_FAILURE;
394 g_main_loop_quit(app->loop);
398 printf("Server at %s, try to stop scan\n", nameowner);
401 ret = g_dbus_proxy_call_sync(app->proxy, "Stop",
403 G_DBUS_CALL_FLAGS_NONE, -1, NULL,
407 fprintf(stderr, "Could not stop scan: %s\n", error->message);
409 app->ret = EXIT_FAILURE;
410 g_main_loop_quit(app->loop);
414 app->ret = EXIT_SUCCESS;
415 g_main_loop_quit(app->loop);
416 g_variant_unref(ret);
420 do_action(gpointer data)
422 struct app *app = data;
428 print_help(const char *prog)
433 "Action is one of:\n"
434 "\tstatus print server properties and exit.\n"
435 "\tmonitor monitor server and its properties.\n"
436 "\twrite-lock try to get a write-lock and keep it while running.\n"
437 "\tscan [params] start scan. May receive parameters as a series of \n"
438 "\t CATEGORY:PATH to limit scan.\n"
439 "\tstop stop ongoing scan.\n"
440 "\thelp this message.\n"
446 main(int argc, char *argv[])
448 GError *error = NULL;
453 fprintf(stderr, "Missing action, see --help.\n");
457 for (i = 1; i < argc; i++) {
458 if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
464 if (strcmp(argv[1], "status") == 0)
465 app.action = do_status;
466 else if (strcmp(argv[1], "monitor") == 0)
467 app.action = do_monitor;
468 else if (strcmp(argv[1], "write-lock") == 0)
469 app.action = do_write_lock;
470 else if (strcmp(argv[1], "scan") == 0)
471 app.action = do_scan;
472 else if (strcmp(argv[1], "stop") == 0)
473 app.action = do_stop;
474 else if (strcmp(argv[1], "help") == 0) {
478 fprintf(stderr, "Unknown action '%s', see --help.\n", argv[1]);
483 app.loop = g_main_loop_new(NULL, FALSE);
484 app.proxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SESSION,
485 G_DBUS_PROXY_FLAGS_NONE,
487 "org.lightmediascanner",
488 "/org/lightmediascanner/Scanner1",
489 "org.lightmediascanner.Scanner1",
493 g_error("Could not create proxy: %s", error->message);
500 app.ret = EXIT_SUCCESS;
502 g_idle_add(do_action, &app);
504 g_main_loop_run(app.loop);
505 g_object_unref(app.proxy);
506 g_main_loop_unref(app.loop);
509 printf("Elapsed time: %0.3f seconds\n",
510 g_timer_elapsed(app.timer, NULL));
511 g_timer_destroy(app.timer);