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=%"G_GUINT64_FORMAT", "
279 "processed=%"G_GUINT64_FORMAT", deleted=%"G_GUINT64_FORMAT", "
280 "skipped=%"G_GUINT64_FORMAT", errors=%"G_GUINT64_FORMAT"\n",
281 category, path, uptodate, processed, deleted, skipped, errors);
286 populate_scan_params(gpointer key, gpointer value, gpointer user_data)
288 const char *category = key;
289 const GArray *paths = value;
290 GVariantBuilder *builder = user_data;
291 GVariantBuilder *sub;
294 sub = g_variant_builder_new(G_VARIANT_TYPE("as"));
295 for (itr = (char **)paths->data; *itr != NULL; itr++)
296 g_variant_builder_add(sub, "s", *itr);
298 g_variant_builder_add(builder, "{sv}", category, g_variant_builder_end(sub));
299 g_variant_builder_unref(sub);
303 do_free_array(gpointer data)
305 g_array_free(data, TRUE);
309 do_scan(struct app *app)
311 GVariantBuilder *builder;
313 GError *error = NULL;
316 GHashTable *categories;
318 nameowner = g_dbus_proxy_get_name_owner(app->proxy);
320 fputs("Server is not running, cannot start scan!\n", stderr);
321 app->ret = EXIT_FAILURE;
322 g_main_loop_quit(app->loop);
326 printf("Server at %s, try to start scan\n", nameowner);
329 g_signal_connect(app->proxy, "g-properties-changed",
330 G_CALLBACK(on_properties_changed_check_scan),
332 g_signal_connect(app->proxy, "g-signal",
333 G_CALLBACK(on_signal),
336 categories = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, do_free_array);
337 for (i = 0; i < app->argc; i++) {
339 char *arg = app->argv[i];
340 char *sep = strchr(arg, ':');
345 fprintf(stderr, "Ignored scan parameter: invalid format '%s'\n",
353 arr = g_hash_table_lookup(categories, arg);
355 arr = g_array_new(TRUE, FALSE, sizeof(char *));
356 g_hash_table_insert(categories, arg, arr);
360 g_array_append_val(arr, path);
363 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
364 g_hash_table_foreach(categories, populate_scan_params, builder);
366 ret = g_dbus_proxy_call_sync(app->proxy, "Scan",
367 g_variant_new("(a{sv})", builder),
368 G_DBUS_CALL_FLAGS_NONE, -1, NULL,
370 g_variant_builder_unref(builder);
371 g_hash_table_destroy(categories);
374 fprintf(stderr, "Could not start scan: %s\n", error->message);
376 app->ret = EXIT_FAILURE;
377 g_main_loop_quit(app->loop);
381 g_variant_unref(ret);
385 do_stop(struct app *app)
388 GError *error = NULL;
391 nameowner = g_dbus_proxy_get_name_owner(app->proxy);
393 fputs("Server is not running, cannot stop scan!\n", stderr);
394 app->ret = EXIT_FAILURE;
395 g_main_loop_quit(app->loop);
399 printf("Server at %s, try to stop scan\n", nameowner);
402 ret = g_dbus_proxy_call_sync(app->proxy, "Stop",
404 G_DBUS_CALL_FLAGS_NONE, -1, NULL,
408 fprintf(stderr, "Could not stop scan: %s\n", error->message);
410 app->ret = EXIT_FAILURE;
411 g_main_loop_quit(app->loop);
415 app->ret = EXIT_SUCCESS;
416 g_main_loop_quit(app->loop);
417 g_variant_unref(ret);
421 do_action(gpointer data)
423 struct app *app = data;
429 print_help(const char *prog)
434 "Action is one of:\n"
435 "\tstatus print server properties and exit.\n"
436 "\tmonitor monitor server and its properties.\n"
437 "\twrite-lock try to get a write-lock and keep it while running.\n"
438 "\tscan [params] start scan. May receive parameters as a series of \n"
439 "\t CATEGORY:PATH to limit scan.\n"
440 "\tstop stop ongoing scan.\n"
441 "\thelp this message.\n"
447 main(int argc, char *argv[])
449 GError *error = NULL;
454 fprintf(stderr, "Missing action, see --help.\n");
458 for (i = 1; i < argc; i++) {
459 if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
465 if (strcmp(argv[1], "status") == 0)
466 app.action = do_status;
467 else if (strcmp(argv[1], "monitor") == 0)
468 app.action = do_monitor;
469 else if (strcmp(argv[1], "write-lock") == 0)
470 app.action = do_write_lock;
471 else if (strcmp(argv[1], "scan") == 0)
472 app.action = do_scan;
473 else if (strcmp(argv[1], "stop") == 0)
474 app.action = do_stop;
475 else if (strcmp(argv[1], "help") == 0) {
479 fprintf(stderr, "Unknown action '%s', see --help.\n", argv[1]);
484 app.loop = g_main_loop_new(NULL, FALSE);
485 app.proxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SESSION,
486 G_DBUS_PROXY_FLAGS_NONE,
488 "org.lightmediascanner",
489 "/org/lightmediascanner/Scanner1",
490 "org.lightmediascanner.Scanner1",
494 g_error("Could not create proxy: %s", error->message);
501 app.ret = EXIT_SUCCESS;
503 g_idle_add(do_action, &app);
505 g_main_loop_run(app.loop);
506 g_object_unref(app.proxy);
507 g_main_loop_unref(app.loop);
510 printf("Elapsed time: %0.3f seconds\n",
511 g_timer_elapsed(app.timer, NULL));
512 g_timer_destroy(app.timer);