GNUnet 0.26.2-98-gb402d9955
 
Loading...
Searching...
No Matches
gnunet-qr.c
Go to the documentation of this file.
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2013-2019 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
26#include "platform.h"
27#include <stdio.h>
28#include <stdbool.h>
29#include <signal.h>
30#include <zbar.h>
31
32
33#include "gnunet_util_lib.h"
34
35#if HAVE_PNG
36#include <png.h>
37#endif
38
43static int exit_code;
44
50static char *device;
51
52#if HAVE_PNG
58static char *pngfilename;
59#endif
60
64static unsigned int verbosity;
65
70
75
79#define LOG(fmt, ...) \
80 do \
81 { \
82 if (0 < verbosity) \
83 { \
84 GNUNET_log (GNUNET_ERROR_TYPE_INFO, fmt, ## __VA_ARGS__); \
85 if (verbosity > 1) \
86 { \
87 fprintf (stdout, fmt, ## __VA_ARGS__); \
88 } \
89 } \
90 } \
91 while (0)
92
96static void
98{
99 if (NULL != waitchildproc)
100 {
102 }
103 if (NULL != childproc)
104 {
105 /* A bit brutal, but this process is terminating so we're out of time */
108 SIGKILL));
109 }
110}
111
112
120static void
121wait_child (void *cls,
123 long unsigned int code)
124{
125 char *uri = cls;
126
128 childproc = NULL;
129 waitchildproc = NULL;
130 if (0 != exit_code)
131 {
132 fprintf (stdout,
133 _ ("Failed to add URI %s\n"),
134 uri);
135 }
136 else
137 {
138 fprintf (stdout,
139 _ ("Added URI %s\n"),
140 uri);
141 }
144}
145
146
155static void
156handle_uri (void *cls,
157 const char *uri,
158 const char *cfgfile,
159 const struct GNUNET_CONFIGURATION_Handle *cfg)
160{
161 const char *cursor = uri;
162 const char *slash;
163 char *program;
164
165 if (0 != strncasecmp ("gnunet://",
166 uri,
167 strlen ("gnunet://")))
168 {
169 fprintf (stderr,
170 _ ("Invalid URI: does not start with `gnunet://'\n"));
171 exit_code = 1;
172 return;
173 }
174
175 cursor += strlen ("gnunet://");
176
177 slash = strchr (cursor,
178 '/');
179 if (NULL == slash)
180 {
181 fprintf (stderr,
182 _ ("Invalid URI: fails to specify a subsystem\n"));
183 exit_code = 1;
184 return;
185 }
186
187 {
188 char *subsystem;
189
190 subsystem = GNUNET_strndup (cursor,
191 slash - cursor);
192 if (GNUNET_OK !=
194 "uri",
195 subsystem,
196 &program))
197 {
198 fprintf (stderr,
199 _ ("No known handler for subsystem `%s'\n"),
200 subsystem);
202 exit_code = 1;
203 return;
204 }
206 }
207
208 {
209 char *fullcmd;
210
211 GNUNET_asprintf (&fullcmd,
212 "%s -- %s",
213 program,
214 uri);
216 if (GNUNET_OK !=
218 fullcmd))
219 {
221 _ ("Unable to start child process `%s'\n"),
222 program);
223 }
224 GNUNET_free (fullcmd);
225 }
226 GNUNET_free (program);
227 if (NULL == childproc)
228 {
229 exit_code = 1;
230 return;
231 }
233 &wait_child,
234 (void *) uri);
235}
236
237
244static const zbar_symbol_t *
245get_symbol (zbar_processor_t *proc)
246{
247 const zbar_symbol_set_t *symbols;
248 int r, n;
249
250 if (0 != zbar_processor_parse_config (proc, "enable"))
251 {
252 GNUNET_break (0);
253 return NULL;
254 }
255
256 r = zbar_processor_init (proc, device, 1);
257 if (0 != r)
258 {
260 _ ("Failed to open device: `%s': %d\n"),
261 device,
262 r);
263 return NULL;
264 }
265
266 r = zbar_processor_set_visible (proc, 1);
267 r += zbar_processor_set_active (proc, 1);
268 if (0 != r)
269 {
270 GNUNET_break (0);
271 return NULL;
272 }
273
274 LOG (_ ("Capturing...\n"));
275
276 n = zbar_process_one (proc, -1);
277
278 zbar_processor_set_active (proc, 0);
279 zbar_processor_set_visible (proc, 0);
280
281 if (-1 == n)
282 {
283 LOG (_ ("No captured images\n"));
284 return NULL;
285 }
286
287 LOG (_ ("Got %d images\n"), n);
288
289 symbols = zbar_processor_get_results (proc);
290 if (NULL == symbols)
291 {
292 GNUNET_break (0);
293 return NULL;
294 }
295
296 return zbar_symbol_set_first_symbol (symbols);
297}
298
299
305static char *
307{
308 zbar_processor_t *proc = zbar_processor_create (1);
309 const zbar_symbol_t *symbol;
310 const char *data;
311 char *copy;
312
313 if (NULL == proc)
314 {
315 GNUNET_break (0);
316 return NULL;
317 }
318
319 if (NULL == device)
320 {
321 device = GNUNET_strdup ("/dev/video0");
322 }
323
324 symbol = get_symbol (proc);
325 if (NULL == symbol)
326 {
327 zbar_processor_destroy (proc);
328 return NULL;
329 }
330
331 data = zbar_symbol_get_data (symbol);
332 if (NULL == data)
333 {
334 GNUNET_break (0);
335 zbar_processor_destroy (proc);
336 return NULL;
337 }
338
339 LOG (_ ("Found %s: \"%s\"\n"),
340 zbar_get_symbol_name (zbar_symbol_get_type (symbol)),
341 data);
342
343 copy = GNUNET_strdup (data);
344
345 zbar_processor_destroy (proc);
347
348 return copy;
349}
350
351
352#if HAVE_PNG
359static char *
360png_parse (uint32_t *width, uint32_t *height)
361{
362 if (NULL == width || NULL == height)
363 {
364 return NULL;
365 }
366
367 FILE *pngfile = fopen (pngfilename, "rb");
368 if (NULL == pngfile)
369 {
370 return NULL;
371 }
372
373 unsigned char header[8];
374 if (8 != fread (header, 1, 8, pngfile))
375 {
376 fclose (pngfile);
377 return NULL;
378 }
379
380 if (png_sig_cmp (header, 0, 8))
381 {
382 fclose (pngfile);
384 _ ("%s is not a PNG file\n"),
385 pngfilename);
386 fprintf (stderr, _ ("%s is not a PNG file\n"), pngfilename);
387 return NULL;
388 }
389
390 /* libpng's default error handling might or might not conflict with GNUnet's
391 scheduler and event loop. Beware of strange interactions. */
392 png_structp png = png_create_read_struct (PNG_LIBPNG_VER_STRING,
393 NULL,
394 NULL,
395 NULL);
396 if (NULL == png)
397 {
398 GNUNET_break (0);
399 fclose (pngfile);
400 return NULL;
401 }
402
403 png_infop pnginfo = png_create_info_struct (png);
404 if (NULL == pnginfo)
405 {
406 GNUNET_break (0);
407 png_destroy_read_struct (&png, NULL, NULL);
408 fclose (pngfile);
409 return NULL;
410 }
411
412 if (setjmp (png_jmpbuf (png)))
413 {
414 GNUNET_break (0);
415 png_destroy_read_struct (&png, &pnginfo, NULL);
416 fclose (pngfile);
417 return NULL;
418 }
419
420 png_init_io (png, pngfile);
421 png_set_sig_bytes (png, 8);
422
423 png_read_info (png, pnginfo);
424
425 png_byte pngcolor = png_get_color_type (png, pnginfo);
426 png_byte pngdepth = png_get_bit_depth (png, pnginfo);
427
428 /* Normalize picture --- based on a zbar example */
429 if (0 != (pngcolor & PNG_COLOR_TYPE_PALETTE))
430 {
431 png_set_palette_to_rgb (png);
432 }
433
434 if (pngcolor == PNG_COLOR_TYPE_GRAY && pngdepth < 8)
435 {
436 png_set_expand_gray_1_2_4_to_8 (png);
437 }
438
439 if (16 == pngdepth)
440 {
441 png_set_strip_16 (png);
442 }
443
444 if (0 != (pngcolor & PNG_COLOR_MASK_ALPHA))
445 {
446 png_set_strip_alpha (png);
447 }
448
449 if (0 != (pngcolor & PNG_COLOR_MASK_COLOR))
450 {
451 png_set_rgb_to_gray_fixed (png, 1, -1, -1);
452 }
453
454 png_uint_32 pngwidth = png_get_image_width (png, pnginfo);
455 png_uint_32 pngheight = png_get_image_height (png, pnginfo);
456
457 char *buffer = GNUNET_new_array (pngwidth * pngheight, char);
458 png_bytepp rows = GNUNET_new_array (pngheight, png_bytep);
459
460 for (png_uint_32 i = 0; i<pngheight; ++i)
461 {
462 rows[i] = (unsigned char *) buffer + (pngwidth * i);
463 }
464
465 png_read_image (png, rows);
466
467 GNUNET_free (rows);
468 fclose (pngfile);
469
470 *width = pngwidth;
471 *height = pngheight;
472
473 return buffer;
474}
475
476
482static char *
483run_png_reader (void)
484{
485 uint32_t width = 0;
486 uint32_t height = 0;
487 char *buffer = png_parse (&width, &height);
488 if (NULL == buffer)
489 {
490 return NULL;
491 }
492
493 zbar_image_scanner_t *scanner = zbar_image_scanner_create ();
494 zbar_image_scanner_set_config (scanner,0, ZBAR_CFG_ENABLE, 1);
495
496 zbar_image_t *zimage = zbar_image_create ();
497 zbar_image_set_format (zimage, zbar_fourcc ('Y', '8', '0', '0'));
498 zbar_image_set_size (zimage, width, height);
499 zbar_image_set_data (zimage, buffer, width * height, &zbar_image_free_data);
500
501 int n = zbar_scan_image (scanner, zimage);
502
503 if (-1 == n)
504 {
505 LOG (_ ("No captured images\n"));
506 return NULL;
507 }
508
509 LOG (_ ("Got %d images\n"), n);
510
511 const zbar_symbol_t *symbol = zbar_image_first_symbol (zimage);
512
513 const char *data = zbar_symbol_get_data (symbol);
514 if (NULL == data)
515 {
516 GNUNET_break (0);
517 zbar_image_destroy (zimage);
518 zbar_image_scanner_destroy (scanner);
519 return NULL;
520 }
521
522 LOG (_ ("Found %s: \"%s\"\n"),
523 zbar_get_symbol_name (zbar_symbol_get_type (symbol)),
524 data);
525
526 char *copy = GNUNET_strdup (data);
527
528 zbar_image_destroy (zimage);
529 zbar_image_scanner_destroy (scanner);
530
531 return copy;
532}
533
534
535#endif
536
545static void
546run (void *cls,
547 char *const *args,
548 const char *cfgfile,
549 const struct GNUNET_CONFIGURATION_Handle *cfg)
550{
551 char *data = NULL;
552
554
555#if HAVE_PNG
556 if (NULL != pngfilename)
557 {
558 data = run_png_reader ();
559 }
560 else
561#endif
562 {
563 data = run_zbar ();
564 }
565
566 if (NULL == data)
567 {
568 LOG (_ ("No data found\n"));
569 exit_code = 1;
571 return;
572 }
573
574 handle_uri (cls, data, cfgfile, cfg);
575
576 if (0 != exit_code)
577 {
578 fprintf (stdout, _ ("Failed to add URI %s\n"), data);
581 return;
582 }
583
584 LOG (_ ("Dispatching the URI\n"));
585}
586
587
588int
589main (int argc, char *const *argv)
590{
593 'd',
594 "device",
595 "DEVICE",
596 gettext_noop ("use the video device DEVICE (defaults to /dev/video0)"),
597 &device),
598#if HAVE_PNG
600 'f',
601 "file",
602 "FILE",
603 gettext_noop ("read from the PNG-encoded file FILE"),
604 &pngfilename),
605#endif
608 };
609
612 argc,
613 argv,
614 "gnunet-qr",
615 gettext_noop ("Scan a QR code and import the URI read"),
616 options,
617 &run,
618 NULL);
619
620 return ((GNUNET_OK == ret) && (0 == exit_code)) ? 0 : 1;
621}
struct GNUNET_GETOPT_CommandLineOption options[]
Definition 002.c:5
int main()
Program to simulate results from GCP_get_desirability_of_path() for various plausible inputs.
#define gettext_noop(String)
Definition gettext.h:74
static int ret
Final status code.
Definition gnunet-arm.c:93
static struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
Definition gnunet-arm.c:108
static char * data
The data to insert into the dht.
static uint32_t type
Type string converted to DNS type value.
static struct GNUNET_FS_Uri * uri
Value of URI provided on command-line (when not publishing a file but just creating UBlocks to refer ...
static unsigned int verbosity
Requested verbosity.
Definition gnunet-qr.c:64
#define LOG(fmt,...)
Macro to handle verbosity when printing messages.
Definition gnunet-qr.c:79
static void shutdown_program(void *cls)
Executed when program is terminating.
Definition gnunet-qr.c:97
static void wait_child(void *cls, enum GNUNET_OS_ProcessStatusType type, long unsigned int code)
Callback executed when the child process terminates.
Definition gnunet-qr.c:121
struct GNUNET_Process * childproc
Child process handle.
Definition gnunet-qr.c:69
static int exit_code
Global exit code.
Definition gnunet-qr.c:43
static void run(void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg)
Main function executed by the scheduler.
Definition gnunet-qr.c:546
static void handle_uri(void *cls, const char *uri, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg)
Dispatch URIs to the appropriate GNUnet helper process.
Definition gnunet-qr.c:156
static char * run_zbar(void)
Run the zbar QR code parser.
Definition gnunet-qr.c:306
static struct GNUNET_ChildWaitHandle * waitchildproc
Child process handle for waiting.
Definition gnunet-qr.c:74
static const zbar_symbol_t * get_symbol(zbar_processor_t *proc)
Obtain a QR code symbol from proc.
Definition gnunet-qr.c:245
static char * device
Video device to capture from.
Definition gnunet-qr.c:50
static char * subsystem
Set to subsystem that we're going to get stats for (or NULL for all).
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_string(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, char **value)
Get a configuration value that should be a string.
#define GNUNET_GETOPT_OPTION_END
Marker for the end of the list of options.
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_verbose(unsigned int *level)
Define the '-V' verbosity option.
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_string(char shortName, const char *name, const char *argumentHelp, const char *description, char **str)
Allow user to specify a string.
#define GNUNET_log(kind,...)
void GNUNET_wait_child_cancel(struct GNUNET_ChildWaitHandle *cwh)
Stop waiting on this child.
struct GNUNET_ChildWaitHandle * GNUNET_wait_child(struct GNUNET_Process *proc, GNUNET_ChildCompletedCallback cb, void *cb_cls)
Starts the handling of the child processes.
GNUNET_GenericReturnValue
Named constants for return values.
@ GNUNET_OK
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
@ GNUNET_ERROR_TYPE_ERROR
int int GNUNET_asprintf(char **buf, const char *format,...) __attribute__((format(printf
Like asprintf, just portable.
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
#define GNUNET_strndup(a, length)
Wrapper around GNUNET_xstrndup_.
#define GNUNET_new_array(n, type)
Allocate a size n array with structs or unions of the given type.
#define GNUNET_free(ptr)
Wrapper around free.
const struct GNUNET_OS_ProjectData * GNUNET_OS_project_data_gnunet(void)
Return default project data used by 'libgnunetutil' for GNUnet.
enum GNUNET_GenericReturnValue GNUNET_process_run_command(struct GNUNET_Process *p, const char *command)
Set the command and start a process.
Definition os_process.c:921
void GNUNET_process_destroy(struct GNUNET_Process *proc)
Cleans up process structure contents (OS-dependent) and deallocates it.
Definition os_process.c:363
GNUNET_OS_ProcessStatusType
Process status types.
enum GNUNET_GenericReturnValue GNUNET_process_kill(struct GNUNET_Process *proc, int sig)
Sends a signal to the process.
Definition os_process.c:307
struct GNUNET_Process * GNUNET_process_create(enum GNUNET_OS_InheritStdioFlags std_inheritance)
Create a process handle.
Definition os_process.c:462
@ GNUNET_OS_INHERIT_STD_ALL
Use this option to have all of the standard streams (stdin, stdout and stderror) be inherited.
enum GNUNET_GenericReturnValue GNUNET_PROGRAM_run(const struct GNUNET_OS_ProjectData *pd, int argc, char *const *argv, const char *binaryName, const char *binaryHelp, const struct GNUNET_GETOPT_CommandLineOption *options, GNUNET_PROGRAM_Main task, void *task_cls)
Run a standard GNUnet command startup sequence (initialize loggers and configuration,...
Definition program.c:407
void GNUNET_SCHEDULER_shutdown(void)
Request the shutdown of a scheduler.
Definition scheduler.c:572
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_shutdown(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run on shutdown, that is when a CTRL-C signal is received,...
Definition scheduler.c:1345
#define _(String)
GNU gettext support macro.
Definition platform.h:179
Struct which defines a Child Wait handle.
struct GNUNET_Process * proc
Child process which is managed.
Definition of a command line option.