GNUnet 0.26.2-32-gd298f7855
 
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);
218 childproc,
221 if ( (GNUNET_OK !=
223 fullcmd)) ||
224 (GNUNET_OK !=
226 {
228 _ ("Unable to start child process `%s'\n"),
229 program);
230 }
231 GNUNET_free (fullcmd);
232 }
233 GNUNET_free (program);
234 if (NULL == childproc)
235 {
236 exit_code = 1;
237 return;
238 }
240 &wait_child,
241 (void *) uri);
242}
243
244
251static const zbar_symbol_t *
252get_symbol (zbar_processor_t *proc)
253{
254 const zbar_symbol_set_t *symbols;
255 int r, n;
256
257 if (0 != zbar_processor_parse_config (proc, "enable"))
258 {
259 GNUNET_break (0);
260 return NULL;
261 }
262
263 r = zbar_processor_init (proc, device, 1);
264 if (0 != r)
265 {
267 _ ("Failed to open device: `%s': %d\n"),
268 device,
269 r);
270 return NULL;
271 }
272
273 r = zbar_processor_set_visible (proc, 1);
274 r += zbar_processor_set_active (proc, 1);
275 if (0 != r)
276 {
277 GNUNET_break (0);
278 return NULL;
279 }
280
281 LOG (_ ("Capturing...\n"));
282
283 n = zbar_process_one (proc, -1);
284
285 zbar_processor_set_active (proc, 0);
286 zbar_processor_set_visible (proc, 0);
287
288 if (-1 == n)
289 {
290 LOG (_ ("No captured images\n"));
291 return NULL;
292 }
293
294 LOG (_ ("Got %d images\n"), n);
295
296 symbols = zbar_processor_get_results (proc);
297 if (NULL == symbols)
298 {
299 GNUNET_break (0);
300 return NULL;
301 }
302
303 return zbar_symbol_set_first_symbol (symbols);
304}
305
306
312static char *
314{
315 zbar_processor_t *proc = zbar_processor_create (1);
316 const zbar_symbol_t *symbol;
317 const char *data;
318 char *copy;
319
320 if (NULL == proc)
321 {
322 GNUNET_break (0);
323 return NULL;
324 }
325
326 if (NULL == device)
327 {
328 device = GNUNET_strdup ("/dev/video0");
329 }
330
331 symbol = get_symbol (proc);
332 if (NULL == symbol)
333 {
334 zbar_processor_destroy (proc);
335 return NULL;
336 }
337
338 data = zbar_symbol_get_data (symbol);
339 if (NULL == data)
340 {
341 GNUNET_break (0);
342 zbar_processor_destroy (proc);
343 return NULL;
344 }
345
346 LOG (_ ("Found %s: \"%s\"\n"),
347 zbar_get_symbol_name (zbar_symbol_get_type (symbol)),
348 data);
349
350 copy = GNUNET_strdup (data);
351
352 zbar_processor_destroy (proc);
354
355 return copy;
356}
357
358
359#if HAVE_PNG
366static char *
367png_parse (uint32_t *width, uint32_t *height)
368{
369 if (NULL == width || NULL == height)
370 {
371 return NULL;
372 }
373
374 FILE *pngfile = fopen (pngfilename, "rb");
375 if (NULL == pngfile)
376 {
377 return NULL;
378 }
379
380 unsigned char header[8];
381 if (8 != fread (header, 1, 8, pngfile))
382 {
383 fclose (pngfile);
384 return NULL;
385 }
386
387 if (png_sig_cmp (header, 0, 8))
388 {
389 fclose (pngfile);
391 _ ("%s is not a PNG file\n"),
392 pngfilename);
393 fprintf (stderr, _ ("%s is not a PNG file\n"), pngfilename);
394 return NULL;
395 }
396
397 /* libpng's default error handling might or might not conflict with GNUnet's
398 scheduler and event loop. Beware of strange interactions. */
399 png_structp png = png_create_read_struct (PNG_LIBPNG_VER_STRING,
400 NULL,
401 NULL,
402 NULL);
403 if (NULL == png)
404 {
405 GNUNET_break (0);
406 fclose (pngfile);
407 return NULL;
408 }
409
410 png_infop pnginfo = png_create_info_struct (png);
411 if (NULL == pnginfo)
412 {
413 GNUNET_break (0);
414 png_destroy_read_struct (&png, NULL, NULL);
415 fclose (pngfile);
416 return NULL;
417 }
418
419 if (setjmp (png_jmpbuf (png)))
420 {
421 GNUNET_break (0);
422 png_destroy_read_struct (&png, &pnginfo, NULL);
423 fclose (pngfile);
424 return NULL;
425 }
426
427 png_init_io (png, pngfile);
428 png_set_sig_bytes (png, 8);
429
430 png_read_info (png, pnginfo);
431
432 png_byte pngcolor = png_get_color_type (png, pnginfo);
433 png_byte pngdepth = png_get_bit_depth (png, pnginfo);
434
435 /* Normalize picture --- based on a zbar example */
436 if (0 != (pngcolor & PNG_COLOR_TYPE_PALETTE))
437 {
438 png_set_palette_to_rgb (png);
439 }
440
441 if (pngcolor == PNG_COLOR_TYPE_GRAY && pngdepth < 8)
442 {
443 png_set_expand_gray_1_2_4_to_8 (png);
444 }
445
446 if (16 == pngdepth)
447 {
448 png_set_strip_16 (png);
449 }
450
451 if (0 != (pngcolor & PNG_COLOR_MASK_ALPHA))
452 {
453 png_set_strip_alpha (png);
454 }
455
456 if (0 != (pngcolor & PNG_COLOR_MASK_COLOR))
457 {
458 png_set_rgb_to_gray_fixed (png, 1, -1, -1);
459 }
460
461 png_uint_32 pngwidth = png_get_image_width (png, pnginfo);
462 png_uint_32 pngheight = png_get_image_height (png, pnginfo);
463
464 char *buffer = GNUNET_new_array (pngwidth * pngheight, char);
465 png_bytepp rows = GNUNET_new_array (pngheight, png_bytep);
466
467 for (png_uint_32 i = 0; i<pngheight; ++i)
468 {
469 rows[i] = (unsigned char *) buffer + (pngwidth * i);
470 }
471
472 png_read_image (png, rows);
473
474 GNUNET_free (rows);
475 fclose (pngfile);
476
477 *width = pngwidth;
478 *height = pngheight;
479
480 return buffer;
481}
482
483
489static char *
490run_png_reader (void)
491{
492 uint32_t width = 0;
493 uint32_t height = 0;
494 char *buffer = png_parse (&width, &height);
495 if (NULL == buffer)
496 {
497 return NULL;
498 }
499
500 zbar_image_scanner_t *scanner = zbar_image_scanner_create ();
501 zbar_image_scanner_set_config (scanner,0, ZBAR_CFG_ENABLE, 1);
502
503 zbar_image_t *zimage = zbar_image_create ();
504 zbar_image_set_format (zimage, zbar_fourcc ('Y', '8', '0', '0'));
505 zbar_image_set_size (zimage, width, height);
506 zbar_image_set_data (zimage, buffer, width * height, &zbar_image_free_data);
507
508 int n = zbar_scan_image (scanner, zimage);
509
510 if (-1 == n)
511 {
512 LOG (_ ("No captured images\n"));
513 return NULL;
514 }
515
516 LOG (_ ("Got %d images\n"), n);
517
518 const zbar_symbol_t *symbol = zbar_image_first_symbol (zimage);
519
520 const char *data = zbar_symbol_get_data (symbol);
521 if (NULL == data)
522 {
523 GNUNET_break (0);
524 zbar_image_destroy (zimage);
525 zbar_image_scanner_destroy (scanner);
526 return NULL;
527 }
528
529 LOG (_ ("Found %s: \"%s\"\n"),
530 zbar_get_symbol_name (zbar_symbol_get_type (symbol)),
531 data);
532
533 char *copy = GNUNET_strdup (data);
534
535 zbar_image_destroy (zimage);
536 zbar_image_scanner_destroy (scanner);
537
538 return copy;
539}
540
541
542#endif
543
552static void
553run (void *cls,
554 char *const *args,
555 const char *cfgfile,
556 const struct GNUNET_CONFIGURATION_Handle *cfg)
557{
558 char *data = NULL;
559
561
562#if HAVE_PNG
563 if (NULL != pngfilename)
564 {
565 data = run_png_reader ();
566 }
567 else
568#endif
569 {
570 data = run_zbar ();
571 }
572
573 if (NULL == data)
574 {
575 LOG (_ ("No data found\n"));
576 exit_code = 1;
578 return;
579 }
580
581 handle_uri (cls, data, cfgfile, cfg);
582
583 if (0 != exit_code)
584 {
585 fprintf (stdout, _ ("Failed to add URI %s\n"), data);
588 return;
589 }
590
591 LOG (_ ("Dispatching the URI\n"));
592}
593
594
595int
596main (int argc, char *const *argv)
597{
600 'd',
601 "device",
602 "DEVICE",
603 gettext_noop ("use the video device DEVICE (defaults to /dev/video0)"),
604 &device),
605#if HAVE_PNG
607 'f',
608 "file",
609 "FILE",
610 gettext_noop ("read from the PNG-encoded file FILE"),
611 &pngfilename),
612#endif
615 };
616
619 argc,
620 argv,
621 "gnunet-qr",
622 gettext_noop ("Scan a QR code and import the URI read"),
623 options,
624 &run,
625 NULL);
626
627 return ((GNUNET_OK == ret) && (0 == exit_code)) ? 0 : 1;
628}
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:553
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:313
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:252
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_assert(cond)
Use this for fatal errors that cannot be handled.
#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.
struct GNUNET_Process * GNUNET_process_create(void)
Create a process handle.
Definition os_process.c:446
enum GNUNET_GenericReturnValue GNUNET_process_set_command(struct GNUNET_Process *p, const char *command)
Set the command to start a process.
Definition os_process.c:925
void GNUNET_process_destroy(struct GNUNET_Process *proc)
Cleans up process structure contents (OS-dependent) and deallocates it.
Definition os_process.c:350
#define GNUNET_process_option_std_inheritance(flags)
Set flags about standard inheritance options.
enum GNUNET_GenericReturnValue GNUNET_process_start(struct GNUNET_Process *proc)
Start a process.
Definition os_process.c:563
#define GNUNET_process_set_options(proc,...)
Set the requested options for the process.
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:302
@ 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.