aboutsummaryrefslogtreecommitdiff
path: root/src/util
diff options
context:
space:
mode:
authorAlessio Vanni <vannilla@firemail.cc>2021-11-05 22:52:53 +0100
committerAlessio Vanni <vannilla@firemail.cc>2021-11-21 18:42:34 +0100
commitd744d49e13fa6175016e8dcfc0f9506b9f170759 (patch)
tree6d57c9744118f708f9f6bf17468e4132fffa5780 /src/util
parent48ccb35c9aea178d7103c3f198946c1bcbcc080c (diff)
downloadgnunet-d744d49e13fa6175016e8dcfc0f9506b9f170759.tar.gz
gnunet-d744d49e13fa6175016e8dcfc0f9506b9f170759.zip
Allow gnunet-qr to read codes from PNG pictures
Diffstat (limited to 'src/util')
-rw-r--r--src/util/Makefile.am3
-rw-r--r--src/util/gnunet-qr.c597
2 files changed, 411 insertions, 189 deletions
diff --git a/src/util/Makefile.am b/src/util/Makefile.am
index c3a0feccc..d21ac5e86 100644
--- a/src/util/Makefile.am
+++ b/src/util/Makefile.am
@@ -239,6 +239,9 @@ gnunet_qr_LDADD = \
239 libgnunetutil.la \ 239 libgnunetutil.la \
240 $(GN_LIBINTL) 240 $(GN_LIBINTL)
241gnunet_qr_LDFLAGS= -lzbar 241gnunet_qr_LDFLAGS= -lzbar
242if HAVE_PNG
243gnunet_qr_LDFLAGS += -lpng
244endif
242 245
243plugin_LTLIBRARIES = \ 246plugin_LTLIBRARIES = \
244 libgnunet_plugin_utiltest.la 247 libgnunet_plugin_utiltest.la
diff --git a/src/util/gnunet-qr.c b/src/util/gnunet-qr.c
index 451d61d40..5bccd3916 100644
--- a/src/util/gnunet-qr.c
+++ b/src/util/gnunet-qr.c
@@ -24,302 +24,500 @@
24 * @author Christian Grothoff (error handling) 24 * @author Christian Grothoff (error handling)
25 */ 25 */
26#include <stdio.h> 26#include <stdio.h>
27#include <zbar.h>
28#include <stdbool.h> 27#include <stdbool.h>
28#include <signal.h>
29#include <zbar.h>
30
29#include "platform.h" 31#include "platform.h"
30#include "gnunet_util_lib.h" 32#include "gnunet_util_lib.h"
31 33
32#define LOG(fmt, ...) \ 34#if HAVE_PNG
33 if (verbose) \ 35#include <png.h>
34 printf (fmt, ## __VA_ARGS__) 36#endif
35 37
36/** 38/**
37 * Video device to capture from. Sane default for GNU/Linux systems. 39 * Global exit code.
40 * Set to non-zero if an error occurs after the scheduler has started.
38 */ 41 */
39static char *device; 42static int exit_code = 0;
40 43
41/** 44/**
42 * --verbose option 45 * Video device to capture from.
46 * Used by default if PNG support is disabled or no PNG file is specified.
47 * Defaults to /dev/video0.
43 */ 48 */
44static unsigned int verbose; 49static char *device = NULL;
45 50
51#if HAVE_PNG
46/** 52/**
47 * --silent option 53 * Name of the file to read from.
54 * If the file is not a PNG-encoded image of a QR code, an error will be
55 * thrown.
48 */ 56 */
49static int silent = false; 57static char *pngfilename = NULL;
58#endif
50 59
51/** 60/**
52 * Handler exit code 61 * Requested verbosity.
53 */ 62 */
54static long unsigned int exit_code = 0; 63static unsigned int verbosity = 0;
55 64
56/** 65/**
57 * Helper process we started. 66 * Child process handle.
58 */ 67 */
59static struct GNUNET_OS_Process *p; 68struct GNUNET_OS_Process *childproc = NULL;
60 69
61/** 70/**
62 * Child signal handler. 71 * Child process handle for waiting.
63 */ 72 */
64static struct GNUNET_SIGNAL_Context *shc_chld; 73static struct GNUNET_ChildWaitHandle *waitchildproc = NULL;
65 74
66/** 75/**
67 * Pipe used to communicate child death via signal. 76 * Macro to handle verbosity when printing messages.
68 */ 77 */
69static struct GNUNET_DISK_PipeHandle *sigpipe; 78#define LOG(fmt, ...) \
79 do \
80 { \
81 if (0 < verbosity) \
82 { \
83 GNUNET_log (GNUNET_ERROR_TYPE_INFO, fmt, ##__VA_ARGS__); \
84 if (verbosity > 1) \
85 { \
86 fprintf (stdout, fmt, ##__VA_ARGS__); \
87 } \
88 } \
89 } \
90 while (0)
70 91
71/** 92/**
72 * Process ID of this process at the time we installed the various 93 * Executed when program is terminating.
73 * signal handlers.
74 */ 94 */
75static pid_t my_pid; 95static void
96shutdown_program (void *cls)
97{
98 if (NULL != waitchildproc)
99 {
100 GNUNET_wait_child_cancel (waitchildproc);
101 }
102 if (NULL != childproc)
103 {
104 /* A bit brutal, but this process is terminating so we're out of time */
105 GNUNET_OS_process_kill (childproc, SIGKILL);
106 }
107}
76 108
77/** 109/**
78 * Task triggered whenever we receive a SIGCHLD (child 110 * Callback executed when the child process terminates.
79 * process died) or when user presses CTRL-C.
80 * 111 *
81 * @param cls closure, NULL 112 * @param cls closure
113 * @param type status of the child process
114 * @param code the exit code of the child process
82 */ 115 */
83static void 116static void
84maint_child_death (void *cls) 117wait_child (void *cls,
118 enum GNUNET_OS_ProcessStatusType type,
119 long unsigned int code)
85{ 120{
86 enum GNUNET_OS_ProcessStatusType type; 121 GNUNET_OS_process_destroy (childproc);
122 childproc = NULL;
123 waitchildproc = NULL;
124
125 char *uri = cls;
87 126
88 if ((GNUNET_OK != GNUNET_OS_process_status (p, &type, &exit_code)) || 127 if (0 != exit_code)
89 (type != GNUNET_OS_PROCESS_EXITED))
90 GNUNET_break (0 == GNUNET_OS_process_kill (p, GNUNET_TERM_SIG));
91 GNUNET_SIGNAL_handler_uninstall (shc_chld);
92 shc_chld = NULL;
93 if (NULL != sigpipe)
94 { 128 {
95 GNUNET_DISK_pipe_close (sigpipe); 129 fprintf (stdout, _("Failed to add URI %s\n"), uri);
96 sigpipe = NULL; 130 }
131 else
132 {
133 fprintf (stdout, _("Added URI %s\n"), uri);
97 } 134 }
98 GNUNET_OS_process_destroy (p);
99}
100 135
136 GNUNET_free (uri);
101 137
102/** 138 GNUNET_SCHEDULER_shutdown ();
103 * Signal handler called for signals that causes us to wait for the child process.
104 */
105static void
106sighandler_chld ()
107{
108 static char c;
109 int old_errno = errno; /* backup errno */
110
111 if (getpid () != my_pid)
112 _exit (1); /* we have fork'ed since the signal handler was created,
113 * ignore the signal, see https://gnunet.org/vfork discussion */
114 GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle
115 (sigpipe, GNUNET_DISK_PIPE_END_WRITE),
116 &c, sizeof(c));
117 errno = old_errno;
118} 139}
119 140
120
121/** 141/**
122 * Dispatch URIs to the appropriate GNUnet helper process 142 * Dispatch URIs to the appropriate GNUnet helper process.
123 * 143 *
124 * @param cls closure 144 * @param cls closure
125 * @param uri uri to dispatch 145 * @param uri URI to dispatch
126 * @param cfgfile name of the configuration file used (for saving, can be NULL!) 146 * @param cfgfile name of the configuration file in use
127 * @param cfg configuration 147 * @param cfg the configuration in use
128 */ 148 */
129static void 149static void
130gnunet_uri (void *cls, 150handle_uri (void *cls,
131 const char *uri, 151 const char *uri,
132 const char *cfgfile, 152 const char *cfgfile,
133 const struct GNUNET_CONFIGURATION_Handle *cfg) 153 const struct GNUNET_CONFIGURATION_Handle *cfg)
134{ 154{
135 const char *orig_uri; 155 const char *cursor = uri;
136 const char *slash;
137 char *subsystem;
138 char *program;
139 struct GNUNET_SCHEDULER_Task *rt;
140 156
141 orig_uri = uri;
142 if (0 != strncasecmp ("gnunet://", uri, strlen ("gnunet://"))) 157 if (0 != strncasecmp ("gnunet://", uri, strlen ("gnunet://")))
143 { 158 {
144 fprintf (stderr, 159 fprintf (stderr,
145 _ ("Invalid URI: does not start with `%s'\n"), 160 _("Invalid URI: does not start with `gnunet://'\n"));
146 "gnunet://"); 161 exit_code = 1;
147 return; 162 return;
148 } 163 }
149 uri += strlen ("gnunet://"); 164
150 if (NULL == (slash = strchr (uri, '/'))) 165 cursor += strlen ("gnunet://");
166
167 const char *slash = strchr (cursor, '/');
168 if (NULL == slash)
151 { 169 {
152 fprintf (stderr, _ ("Invalid URI: fails to specify subsystem\n")); 170 fprintf (stderr, _("Invalid URI: fails to specify a subsystem\n"));
171 exit_code = 1;
153 return; 172 return;
154 } 173 }
155 subsystem = GNUNET_strndup (uri, slash - uri); 174
175 char *subsystem = GNUNET_strndup (cursor, slash - cursor);
176 char *program = NULL;
177
156 if (GNUNET_OK != 178 if (GNUNET_OK !=
157 GNUNET_CONFIGURATION_get_value_string (cfg, "uri", subsystem, &program)) 179 GNUNET_CONFIGURATION_get_value_string (cfg, "uri", subsystem, &program))
158 { 180 {
159 fprintf (stderr, _ ("No handler known for subsystem `%s'\n"), subsystem); 181 fprintf (stderr, _("No known handler for subsystem `%s'\n"), subsystem);
160 GNUNET_free (subsystem); 182 GNUNET_free (subsystem);
183 exit_code = 1;
161 return; 184 return;
162 } 185 }
186
163 GNUNET_free (subsystem); 187 GNUNET_free (subsystem);
164 sigpipe = GNUNET_DISK_pipe (GNUNET_DISK_PF_NONE);
165 GNUNET_assert (NULL != sigpipe);
166 rt = GNUNET_SCHEDULER_add_read_file (
167 GNUNET_TIME_UNIT_FOREVER_REL,
168 GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ),
169 &maint_child_death,
170 NULL);
171 my_pid = getpid ();
172 shc_chld = GNUNET_SIGNAL_handler_install (SIGCHLD,
173 &sighandler_chld);
174
175 {
176 char **argv = NULL;
177 unsigned int argc = 0;
178 char *u = GNUNET_strdup (program);
179
180 for (const char *tok = strtok (u, " ");
181 NULL != tok;
182 tok = strtok (NULL, " "))
183 GNUNET_array_append (argv,
184 argc,
185 GNUNET_strdup (tok));
186 GNUNET_array_append (argv,
187 argc,
188 GNUNET_strdup (orig_uri));
189 GNUNET_array_append (argv,
190 argc,
191 NULL);
192 p = GNUNET_OS_start_process_vap (GNUNET_OS_INHERIT_STD_ALL,
193 NULL,
194 NULL,
195 NULL,
196 argv[0],
197 argv);
198 for (unsigned int i = 0; i<argc - 1; i++)
199 GNUNET_free (argv[i]);
200 GNUNET_array_grow (argv,
201 argc,
202 0);
203 GNUNET_free (u);
204 }
205 if (NULL == p)
206 GNUNET_SCHEDULER_cancel (rt);
207 GNUNET_free (program);
208}
209 188
189 char **childargv = NULL;
190 unsigned int childargc = 0;
191
192 for (const char *token=strtok (program, " ");
193 NULL!=token;
194 token=strtok(NULL, " "))
195 {
196 GNUNET_array_append (childargv, childargc, GNUNET_strdup (token));
197 }
198 GNUNET_array_append (childargv, childargc, GNUNET_strdup (uri));
199 GNUNET_array_append (childargv, childargc, NULL);
200
201 childproc = GNUNET_OS_start_process_vap (GNUNET_OS_INHERIT_STD_ALL,
202 NULL,
203 NULL,
204 NULL,
205 childargv[0],
206 childargv);
207 for (size_t i=0; i<childargc-1; ++i)
208 {
209 GNUNET_free (childargv[i]);
210 }
211
212 GNUNET_array_grow (childargv, childargc, 0);
213
214 if (NULL == childproc)
215 {
216 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
217 _("Unable to start child process `%s'\n"),
218 program);
219 GNUNET_free (program);
220 exit_code = 1;
221 return;
222 }
223
224 waitchildproc = GNUNET_wait_child (childproc, &wait_child, (void *)uri);
225}
210 226
211/** 227/**
212 * Obtain QR code 'symbol' from @a proc. 228 * Obtain a QR code symbol from @a proc.
213 * 229 *
214 * @param proc zbar processor to use 230 * @param proc the zbar processor to use
215 * @return NULL on error 231 * @return NULL on error
216 */ 232 */
217static const zbar_symbol_t * 233static const zbar_symbol_t *
218get_symbol (zbar_processor_t *proc) 234get_symbol (zbar_processor_t *proc)
219{ 235{
220 const zbar_symbol_set_t *symbols;
221 int rc;
222 int n;
223
224 if (0 != zbar_processor_parse_config (proc, "enable")) 236 if (0 != zbar_processor_parse_config (proc, "enable"))
225 { 237 {
226 GNUNET_break (0); 238 GNUNET_break (0);
227 return NULL; 239 return NULL;
228 } 240 }
229 241
230 /* initialize the Processor */ 242 int r = zbar_processor_init (proc, device, 1);
231 if (NULL == device) 243 if (0 != r)
232 device = GNUNET_strdup ("/dev/video0");
233 if (0 != (rc = zbar_processor_init (proc, device, 1)))
234 { 244 {
235 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 245 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
236 "Failed to open device `%s': %d\n", 246 _("Failed to open device: `%s': %d\n"),
237 device, 247 device,
238 rc); 248 r);
239 return NULL; 249 return NULL;
240 } 250 }
241 251
242 /* enable the preview window */ 252 r = zbar_processor_set_visible (proc, 1);
243 if ((0 != (rc = zbar_processor_set_visible (proc, 1))) || 253 r += zbar_processor_set_active (proc, 1);
244 (0 != (rc = zbar_processor_set_active (proc, 1)))) 254 if (0 != r)
245 { 255 {
246 GNUNET_break (0); 256 GNUNET_break (0);
247 return NULL; 257 return NULL;
248 } 258 }
249 259
250 /* read at least one barcode (or until window closed) */ 260 LOG (_("Capturing...\n"));
251 LOG ("Capturing\n"); 261
252 n = zbar_process_one (proc, -1); 262 int n = zbar_process_one (proc, -1);
263
264 zbar_processor_set_active (proc, 0);
265 zbar_processor_set_visible (proc, 0);
253 266
254 /* hide the preview window */
255 (void) zbar_processor_set_active (proc, 0);
256 (void) zbar_processor_set_visible (proc, 0);
257 if (-1 == n) 267 if (-1 == n)
258 return NULL; /* likely user closed the window */ 268 {
259 LOG ("Got %i images\n", n); 269 LOG (_("No captured images\n"));
260 /* extract results */ 270 return NULL;
261 symbols = zbar_processor_get_results (proc); 271 }
272
273 LOG(_("Got %d images\n"), n);
274
275 const zbar_symbol_set_t *symbols = zbar_processor_get_results (proc);
262 if (NULL == symbols) 276 if (NULL == symbols)
263 { 277 {
264 GNUNET_break (0); 278 GNUNET_break (0);
265 return NULL; 279 return NULL;
266 } 280 }
281
267 return zbar_symbol_set_first_symbol (symbols); 282 return zbar_symbol_set_first_symbol (symbols);
268} 283}
269 284
270
271/** 285/**
272 * Run zbar QR code parser. 286 * Run the zbar QR code parser.
273 * 287 *
274 * @return NULL on error, otherwise the URI that we found 288 * @return NULL on error
275 */ 289 */
276static char * 290static char *
277run_zbar () 291run_zbar (void)
278{ 292{
279 zbar_processor_t *proc; 293 zbar_processor_t *proc = zbar_processor_create (1);
280 const char *data;
281 char *ret;
282 const zbar_symbol_t *symbol;
283
284 /* configure the Processor */
285 proc = zbar_processor_create (1);
286 if (NULL == proc) 294 if (NULL == proc)
287 { 295 {
288 GNUNET_break (0); 296 GNUNET_break (0);
289 return NULL; 297 return NULL;
290 } 298 }
291 299
292 symbol = get_symbol (proc); 300 if (NULL == device)
301 {
302 device = GNUNET_strdup ("/dev/video0");
303 }
304
305 const zbar_symbol_t *symbol = get_symbol (proc);
293 if (NULL == symbol) 306 if (NULL == symbol)
294 { 307 {
295 zbar_processor_destroy (proc); 308 zbar_processor_destroy (proc);
296 return NULL; 309 return NULL;
297 } 310 }
298 data = zbar_symbol_get_data (symbol); 311
312 const char *data = zbar_symbol_get_data (symbol);
299 if (NULL == data) 313 if (NULL == data)
300 { 314 {
301 GNUNET_break (0); 315 GNUNET_break (0);
302 zbar_processor_destroy (proc); 316 zbar_processor_destroy (proc);
303 return NULL; 317 return NULL;
304 } 318 }
305 LOG ("Found %s \"%s\"\n", 319
320 LOG (_("Found %s: \"%s\"\n"),
306 zbar_get_symbol_name (zbar_symbol_get_type (symbol)), 321 zbar_get_symbol_name (zbar_symbol_get_type (symbol)),
307 data); 322 data);
308 ret = GNUNET_strdup (data); 323
309 /* clean up */ 324 char *copy = GNUNET_strdup (data);
325
310 zbar_processor_destroy (proc); 326 zbar_processor_destroy (proc);
311 GNUNET_free (device); 327 GNUNET_free (device);
312 return ret; 328
329 return copy;
313} 330}
314 331
332#if HAVE_PNG
333/**
334 * Decode the PNG-encoded file to a raw byte buffer.
335 *
336 * @param width[out] where to store the image width
337 * @param height[out] where to store the image height
338 */
339static char *
340png_parse (uint32_t *width, uint32_t *height)
341{
342 if (NULL == width || NULL == height)
343 {
344 return NULL;
345 }
346
347 FILE *pngfile = fopen (pngfilename, "rb");
348 if (NULL == pngfile)
349 {
350 return NULL;
351 }
352
353 unsigned char header[8];
354 if (8 != fread (header, 1, 8, pngfile))
355 {
356 fclose (pngfile);
357 return NULL;
358 }
359
360 if (png_sig_cmp (header, 0, 8))
361 {
362 fclose (pngfile);
363 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
364 _("%s is not a PNG file\n"),
365 pngfilename);
366 fprintf (stderr, _("%s is not a PNG file\n"), pngfilename);
367 return NULL;
368 }
369
370 /* libpng's default error handling might or might not conflict with GNUnet's
371 scheduler and event loop. Beware of strange interactions. */
372 png_structp png = png_create_read_struct (PNG_LIBPNG_VER_STRING,
373 NULL,
374 NULL,
375 NULL);
376 if (NULL == png)
377 {
378 GNUNET_break (0);
379 fclose (pngfile);
380 return NULL;
381 }
382
383 png_infop pnginfo = png_create_info_struct (png);
384 if (NULL == pnginfo)
385 {
386 GNUNET_break (0);
387 png_destroy_read_struct (&png, NULL, NULL);
388 fclose (pngfile);
389 return NULL;
390 }
391
392 if (setjmp (png_jmpbuf (png)))
393 {
394 GNUNET_break (0);
395 png_destroy_read_struct (&png, &pnginfo, NULL);
396 fclose (pngfile);
397 return NULL;
398 }
399
400 png_init_io (png, pngfile);
401 png_set_sig_bytes (png, 8);
402
403 png_read_info (png, pnginfo);
404
405 png_byte pngcolor = png_get_color_type (png, pnginfo);
406 png_byte pngdepth = png_get_bit_depth (png, pnginfo);
407
408 /* Normalize picture --- based on a zbar example */
409 if (0 != (pngcolor & PNG_COLOR_TYPE_PALETTE))
410 {
411 png_set_palette_to_rgb (png);
412 }
413
414 if (pngcolor == PNG_COLOR_TYPE_GRAY && pngdepth < 8)
415 {
416 png_set_expand_gray_1_2_4_to_8 (png);
417 }
418
419 if (16 == pngdepth)
420 {
421 png_set_strip_16 (png);
422 }
423
424 if (0 != (pngcolor & PNG_COLOR_MASK_ALPHA))
425 {
426 png_set_strip_alpha (png);
427 }
428
429 if (0 != (pngcolor & PNG_COLOR_MASK_COLOR))
430 {
431 png_set_rgb_to_gray_fixed (png, 1, -1, -1);
432 }
433
434 png_uint_32 pngwidth = png_get_image_width (png, pnginfo);
435 png_uint_32 pngheight = png_get_image_height (png, pnginfo);
436
437 char *buffer = GNUNET_new_array (pngwidth * pngheight, char);
438 png_bytepp rows = GNUNET_new_array (pngheight, png_bytep);
439
440 for (png_uint_32 i=0; i<pngheight; ++i)
441 {
442 rows[i] = (unsigned char *)buffer + (pngwidth * i);
443 }
444
445 png_read_image (png, rows);
446
447 GNUNET_free (rows);
448 fclose (pngfile);
449
450 *width = pngwidth;
451 *height = pngheight;
452
453 return buffer;
454}
455
456/**
457 * Parse a PNG-encoded file for a QR code.
458 *
459 * @return NULL on error
460 */
461static char *
462run_png_reader (void)
463{
464 uint32_t width = 0;
465 uint32_t height = 0;
466 char *buffer = png_parse (&width, &height);
467 if (NULL == buffer)
468 {
469 return NULL;
470 }
471
472 zbar_image_scanner_t *scanner = zbar_image_scanner_create ();
473 zbar_image_scanner_set_config (scanner,0, ZBAR_CFG_ENABLE, 1);
474
475 zbar_image_t *zimage = zbar_image_create ();
476 zbar_image_set_format (zimage, zbar_fourcc ('Y', '8', '0', '0'));
477 zbar_image_set_size (zimage, width, height);
478 zbar_image_set_data (zimage, buffer, width * height, &zbar_image_free_data);
479
480 int n = zbar_scan_image (scanner, zimage);
481
482 if (-1 == n)
483 {
484 LOG (_("No captured images\n"));
485 return NULL;
486 }
487
488 LOG(_("Got %d images\n"), n);
489
490 const zbar_symbol_t *symbol = zbar_image_first_symbol (zimage);
491
492 const char *data = zbar_symbol_get_data (symbol);
493 if (NULL == data)
494 {
495 GNUNET_break (0);
496 zbar_image_destroy (zimage);
497 zbar_image_scanner_destroy (scanner);
498 return NULL;
499 }
500
501 LOG (_("Found %s: \"%s\"\n"),
502 zbar_get_symbol_name (zbar_symbol_get_type (symbol)),
503 data);
504
505 char *copy = GNUNET_strdup (data);
506
507 zbar_image_destroy (zimage);
508 zbar_image_scanner_destroy (scanner);
509
510 return copy;
511}
512#endif
315 513
316/** 514/**
317 * Main function that will be run by the scheduler. 515 * Main function executed by the scheduler.
318 * 516 *
319 * @param cls closure 517 * @param cls closure
320 * @param args remaining command-line arguments 518 * @param args remaining command line arguments
321 * @param cfgfile name of the configuration file used (for saving, can be NULL!) 519 * @param cfgfile name of the configuration file being used
322 * @param cfg configuration 520 * @param cfg the used configuration
323 */ 521 */
324static void 522static void
325run (void *cls, 523run (void *cls,
@@ -327,51 +525,72 @@ run (void *cls,
327 const char *cfgfile, 525 const char *cfgfile,
328 const struct GNUNET_CONFIGURATION_Handle *cfg) 526 const struct GNUNET_CONFIGURATION_Handle *cfg)
329{ 527{
330 char *data; 528 char *data = NULL;
331 529
332 data = run_zbar (); 530 GNUNET_SCHEDULER_add_shutdown (&shutdown_program, NULL);
333 if (NULL == data) 531
334 return; 532#if HAVE_PNG
335 gnunet_uri (cls, data, cfgfile, cfg); 533 if (NULL != pngfilename)
336 if (exit_code != 0)
337 { 534 {
338 printf ("Failed to add URI %s\n", data); 535 data = run_png_reader ();
339 } 536 }
340 else 537 else
538#endif
539 {
540 data = run_zbar ();
541 }
542
543 if (NULL == data)
341 { 544 {
342 printf ("Added URI %s\n", data); 545 LOG (_("No data found\n"));
546 exit_code = 1;
547 GNUNET_SCHEDULER_shutdown ();
548 return;
343 } 549 }
344 GNUNET_free (data);
345};
346 550
551 handle_uri (cls, data, cfgfile, cfg);
552
553 if (0 != exit_code)
554 {
555 fprintf (stdout, _("Failed to add URI %s\n"), data);
556 GNUNET_free (data);
557 GNUNET_SCHEDULER_shutdown ();
558 return;
559 }
560
561 LOG (_("Dispatching the URI\n"));
562}
347 563
348int 564int
349main (int argc, char *const *argv) 565main (int argc, char *const *argv)
350{ 566{
351 int ret;
352 struct GNUNET_GETOPT_CommandLineOption options[] = { 567 struct GNUNET_GETOPT_CommandLineOption options[] = {
353 GNUNET_GETOPT_option_string ( 568 GNUNET_GETOPT_option_string (
354 'd', 569 'd',
355 "device", 570 "device",
356 "DEVICE", 571 "DEVICE",
357 gettext_noop ("use video-device DEVICE (default: /dev/video0"), 572 gettext_noop ("use the video device DEVICE (defaults to /dev/video0)"),
358 &device), 573 &device),
359 GNUNET_GETOPT_option_verbose (&verbose), 574#if HAVE_PNG
360 GNUNET_GETOPT_option_flag ('s', 575 GNUNET_GETOPT_option_string (
361 "silent", 576 'f',
362 gettext_noop ("do not show preview windows"), 577 "file",
363 &silent), 578 "FILE",
364 GNUNET_GETOPT_OPTION_END 579 gettext_noop ("read from the PNG-encoded file FILE"),
580 &pngfilename),
581#endif
582 GNUNET_GETOPT_option_verbose (&verbosity),
583 GNUNET_GETOPT_OPTION_END,
365 }; 584 };
366 585
367 ret = GNUNET_PROGRAM_run ( 586 enum GNUNET_GenericReturnValue ret =
368 argc, 587 GNUNET_PROGRAM_run (argc,
369 argv, 588 argv,
370 "gnunet-qr", 589 "gnunet-qr",
371 gettext_noop ( 590 gettext_noop ("Scan a QR code and import the URI read"),
372 "Scan a QR code using a video device and import the uri read"), 591 options,
373 options, 592 &run,
374 &run, 593 NULL);
375 NULL); 594
376 return ((GNUNET_OK == ret) && (0 == exit_code)) ? 0 : 1; 595 return ((GNUNET_OK == ret) && (0 == exit_code)) ? 0 : 1;
377} 596}