From d5cfe4c295d7136a4c82fea0ccd927f2a9a900d3 Mon Sep 17 00:00:00 2001 From: Hartmut Goebel Date: Sat, 2 Mar 2019 11:00:53 +0100 Subject: gnunet-qr: Reimplement in C - yet only a proof of concept. Still to-do: * running gnunet-uri * Proper error handling * integration into build system (automake) Reimplementing in C was chosen since - official zbar python-bindings support python 2 only, - none of the other bindings available at PyPI supports the high-level "processor" interface which gnunet-qr uses - implementing bindings for zbar using ctypes required addin a lot of low-level error handling code, thus implementing in C seamed to be easier, - the programm is short, thus re-implementing is not such complicated, and - this allows to reduce the number of dependencies (here: another Python version), which should ease porting to other plattforms (zbar is a dependency anyway). --- src/util/gnunet-qr.c | 160 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/util/gnunet-qr.in | 46 --------------- src/util/gnunet-qr.py | 110 ---------------------------------- 3 files changed, 160 insertions(+), 156 deletions(-) create mode 100644 src/util/gnunet-qr.c delete mode 100755 src/util/gnunet-qr.in delete mode 100644 src/util/gnunet-qr.py (limited to 'src') diff --git a/src/util/gnunet-qr.c b/src/util/gnunet-qr.c new file mode 100644 index 000000000..c02212a51 --- /dev/null +++ b/src/util/gnunet-qr.c @@ -0,0 +1,160 @@ +/* + This file is part of GNUnet. + Copyright (C) 2013-2019 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + SPDX-License-Identifier: AGPL3.0-or-later +*/ + +#include +#include +#include +#include + +static const char *usage_note = + "gnunet-qr\n" + "Scan a QR code using a video device and import\n" + "\n" + "Arguments mandatory for long options are also mandatory for short options.\n" + " -c, --config FILENAME use configuration file FILENAME\n" + " -d, --device DEVICE use device DEVICE\n" + " -s, --silent do not show preview windows\n" + " -h, --help print this help\n" + " -v, --verbose be verbose\n" + "Report bugs to gnunet-developers@gnu.org.\n" + "\n" + "GNUnet home page: https://gnunet.org/\n" + "General help using GNU software: https://www.gnu.org/gethelp/\n"; + +int main (int argc, char **argv) +{ + const char* configuration = NULL; + const char* device = "/dev/video0"; + static bool verbose = false; + static bool silent = false; + + static struct option long_options[] = { + {"verbose", no_argument, 0, 'v'}, + {"silent", no_argument, 0, 's'}, + {"help", no_argument, 0, 'h'}, + {"config", required_argument, 0, 'c'}, + {"device", required_argument, 0, 'd'}, + {0, 0, 0, 0} + }; + while (1) { + int opt; + opt = getopt_long (argc, argv, "c:hd:sv", + long_options, NULL); + if (opt == -1) + break; + + switch (opt) { + case 'h': + printf(usage_note); + return 0; + case 'c': + configuration = optarg; + break; + case 'd': + device = optarg; + break; + case 's': + silent = true; + break; + case 'v': + verbose = true; + break; + default: + printf(usage_note); + return 1; + } + } + + /* create a Processor */ + if (verbose == true) { + printf("Initializing\n"); + }; + zbar_processor_t *proc = zbar_processor_create(1); + + // FIXME: Wrap all this into a function which returns an error on + // failure. And here ensure the processor is destroyed at the end. + + /* configure the Processor */ + zbar_processor_parse_config(proc, "enable"); + + /* initialize the Processor */ + if (verbose == true) { + printf("Opening video device %s\n", device); + }; + // FIXME: error handling + zbar_processor_init(proc, device, 1); + + /* enable the preview window */ + zbar_processor_set_visible(proc, 1); + zbar_processor_set_active(proc, 1); + + /* keep scanning until user provides key/mouse input */ + //zbar_processor_user_wait(proc, -1); + + // read at least one barcode (or until window closed) + if (verbose == true) { + printf("Capturing\n"); + } + int n; + n = zbar_process_one(proc, -1); + if (verbose == true) { + printf("Got %i images\n", n); + }; + // FIXME: Error handling (n = -1) + + // hide the preview window + zbar_processor_set_active(proc, 0); + zbar_processor_set_visible(proc, 0); + + // extract results + int rc = 1; + + const zbar_symbol_set_t* symbols = zbar_processor_get_results(proc); + const zbar_symbol_t* symbol = zbar_symbol_set_first_symbol(symbols); + + if (symbol != NULL) { + const char* data = zbar_symbol_get_data(symbol); + if (verbose = true) { + zbar_symbol_type_t type = + printf("Found %s \"%s\"\n", + zbar_get_symbol_name(zbar_symbol_get_type(symbol)), data); + } + /* TODO + args = ["gnunet-uri", + // FIXME: "-c", configuration, + data]; + if (verbose = true) { + // TODO: print arguments: + printf("Running `%s %s %s %s`", *args, "", ""); // FIXME variable num args + }; + rc = popen("gnunet-uri", *args); + */ + if (rc != 0) { + printf("Failed to add URI %s\n", data); + } else { + printf("Added URI %s\n", data); + } + } + + /* clean up */ + zbar_processor_destroy(proc); + + return(rc); +} diff --git a/src/util/gnunet-qr.in b/src/util/gnunet-qr.in deleted file mode 100755 index ce7a19b69..000000000 --- a/src/util/gnunet-qr.in +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/sh -# -# From curl's buildconf, making this script subject to the -# curl license: https://curl.haxx.se/docs/copyright.html -# Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. -# Copyright (C) 2019 GNUnet e.V. - -# findtool works like which without relying on which (which is a problem -# for some limited shells. -findtool(){ - file="$1" - - if { echo "$file" | grep "/" >/dev/null 2>&1; } then - # when file is given with a path check it first - if test -f "$file"; then - echo "$file" - return - fi - fi - - old_IFS=$IFS; IFS=':' - for path in $PATH - do - IFS=$old_IFS - # echo "checks for $file in $path" >&2 - if test "$path" -a "$path" != '.' -a -f "$path/$file"; then - echo "$path/$file" - return - fi - done - IFS=$old_IFS -} - -# end curl licensed code -pythonize=`findtool python2.7 2>/dev/null` -if test ! -x "$pythonize"; then - pythonize=`findtool ${PYTHON2:-python2.7}` -fi - -if test -z "$pythonize"; then - echo "ERROR: python2.7 not found." - echo " You need python2.7 installed." - exit 1 -fi - -${pythonize} @PREFIX@/share/gnunet/gnunet-qr.py $@ diff --git a/src/util/gnunet-qr.py b/src/util/gnunet-qr.py deleted file mode 100644 index 0ee0b9507..000000000 --- a/src/util/gnunet-qr.py +++ /dev/null @@ -1,110 +0,0 @@ -import sys -import getopt -import subprocess -from sys import argv -try: - import zbar -except ImportError as e: - print('Cannot run gnunet-qr, please install the zbar module.') - print('For Debian, you can obtain it as "python-zbar".') - print('Upstream: http://zbar.sourceforge.net/') - sys.exit(1) - - -def help(): - print('gnunet-qr\n\ -Scan a QR code using a video device and import\n\ -Arguments mandatory for long options are also mandatory for short options.\n\ - -c, --config FILENAME use configuration file FILENAME\n\ - -d, --device DEVICE use device DEVICE\n\ - -s, --silent do not show preview windows\n\ - -h, --help print this help\n\ - -v, --verbose be verbose\n\ -Report bugs to gnunet-developers@gnu.org.\n\ -GNUnet home page: https://gnunet.org/\n\ -General help using GNU software: https://www.gnu.org/gethelp/') - - -if __name__ == '__main__': - configuration = '' - device = '/dev/video0' - url = '' - verbose = False - silent = False - # Parse arguments - try: - opts, args = getopt.gnu_getopt(sys.argv[1:], "c:hd:sv", ["config", "help", "device", "silent", "verbose"]) - except getopt.GetoptError as e: - help() - print(str(e)) - exit(1) - for o, a in opts: - if o in ("-h", "--help"): - help() - sys.exit(0) - elif o in ("-c", "--config"): - configuration = a - elif o in ("-d", "--device"): - device = a - elif o in ("-s", "--silent"): - silent = True - elif o in ("-v", "--verbose"): - verbose = True - if (True == verbose): - print('Initializing') - # create a Processor - proc = zbar.Processor() - - # configure the Processor - proc.parse_config('enable') - - # initialize the Processor - try: - if (True == verbose): - print('Opening video device ' + device) - proc.init(device) - except Exception as e: - print('Failed to open device ' + device) - exit(1) - - # enable the preview window - # if (True == silent): - # proc.visible = True - # else: - # proc.visible = False - - proc.visible = True - # read at least one barcode (or until window closed) - try: - if (True == verbose): - print('Capturing') - proc.process_one() - except Exception as e: - # Window was closed without finding code - exit(1) - - # hide the preview window - proc.visible = False - - # extract results - for symbol in proc.results: - # do something useful with results - if (True == verbose): - print('Found ', symbol.type, ' symbol ', '"%s"' % symbol.data) - args = list() - args.append("gnunet-uri") - if (configuration != ''): - args.append(str("-c " + str(configuration))) - args.append(str(symbol.data)) - cmd = '' - for a in args: - cmd += " " + str(a) - if (verbose): - print('Running `' + cmd +'`') - res = subprocess.call(args) - if (0 != res): - print('Failed to add URI ' + str(symbol.data)) - else: - print('Added URI ' + str(symbol.data)) - exit(res) - exit(1) -- cgit v1.2.3 From eaf7440ec8e19df09b0ae632c4b200a0511069aa Mon Sep 17 00:00:00 2001 From: Hartmut Goebel Date: Sat, 2 Mar 2019 12:37:46 +0100 Subject: gnunet-qr: Simplify verbose messaging. --- src/util/gnunet-qr.c | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/util/gnunet-qr.c b/src/util/gnunet-qr.c index c02212a51..b375d20a7 100644 --- a/src/util/gnunet-qr.c +++ b/src/util/gnunet-qr.c @@ -38,6 +38,8 @@ static const char *usage_note = "GNUnet home page: https://gnunet.org/\n" "General help using GNU software: https://www.gnu.org/gethelp/\n"; +#define LOG(fmt, ...) if (verbose == true) printf(fmt, ## __VA_ARGS__) + int main (int argc, char **argv) { const char* configuration = NULL; @@ -83,9 +85,7 @@ int main (int argc, char **argv) } /* create a Processor */ - if (verbose == true) { - printf("Initializing\n"); - }; + LOG("Initializing\n"); zbar_processor_t *proc = zbar_processor_create(1); // FIXME: Wrap all this into a function which returns an error on @@ -95,9 +95,7 @@ int main (int argc, char **argv) zbar_processor_parse_config(proc, "enable"); /* initialize the Processor */ - if (verbose == true) { - printf("Opening video device %s\n", device); - }; + LOG("Opening video device %s\n", device); // FIXME: error handling zbar_processor_init(proc, device, 1); @@ -109,14 +107,10 @@ int main (int argc, char **argv) //zbar_processor_user_wait(proc, -1); // read at least one barcode (or until window closed) - if (verbose == true) { - printf("Capturing\n"); - } + LOG("Capturing\n"); int n; n = zbar_process_one(proc, -1); - if (verbose == true) { - printf("Got %i images\n", n); - }; + LOG("Got %i images\n", n); // FIXME: Error handling (n = -1) // hide the preview window @@ -131,11 +125,9 @@ int main (int argc, char **argv) if (symbol != NULL) { const char* data = zbar_symbol_get_data(symbol); - if (verbose = true) { - zbar_symbol_type_t type = - printf("Found %s \"%s\"\n", - zbar_get_symbol_name(zbar_symbol_get_type(symbol)), data); - } + LOG("Found %s \"%s\"\n", + zbar_get_symbol_name(zbar_symbol_get_type(symbol)), data); + /* TODO args = ["gnunet-uri", // FIXME: "-c", configuration, -- cgit v1.2.3 From a5de52ae3c590a829055d9233c4feb2813a5fbe9 Mon Sep 17 00:00:00 2001 From: Hartmut Goebel Date: Sat, 2 Mar 2019 17:26:35 +0100 Subject: Add helper lib "gnunet-qr-utils.h". These functions are copied from dns/gnunet-helper-dns.c, move them into a common library. Or think about implementing a even more elaborate version. --- src/util/gnunet-qr-utils.h | 111 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 src/util/gnunet-qr-utils.h (limited to 'src') diff --git a/src/util/gnunet-qr-utils.h b/src/util/gnunet-qr-utils.h new file mode 100644 index 000000000..6d821633c --- /dev/null +++ b/src/util/gnunet-qr-utils.h @@ -0,0 +1,111 @@ +/* + This file is part of GNUnet. + Copyright (C) 2010, 2011, 2012 Christian Grothoff + Copyright (C) 2019 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + SPDX-License-Identifier: AGPL3.0-or-later +*/ + +#include "platform.h" + +// +// FIXME: These functions are copied from dns/gnunet-helper-dns.c, +// move them into a common library. Or think about implementing a even +// more elaborate version. +// + +/** + * Open '/dev/null' and make the result the given + * file descriptor. + * + * @param target_fd desired FD to point to /dev/null + * @param flags open flags (O_RDONLY, O_WRONLY) + */ +static void +open_dev_null (int target_fd, + int flags) +{ + int fd; + + fd = open ("/dev/null", flags); + if (-1 == fd) + abort (); + if (fd == target_fd) + return; + if (-1 == dup2 (fd, target_fd)) + { + (void) close (fd); + abort (); + } + (void) close (fd); +} + +/** + * Run the given command and wait for it to complete. + * + * @param file name of the binary to run + * @param cmd command line arguments (as given to 'execv') + * @return 0 on success, 1 on any error + */ +static int +fork_and_exec (const char *file, + char *const cmd[]) +{ + int status; + pid_t pid; + pid_t ret; + + pid = fork (); + if (-1 == pid) + { + fprintf (stderr, + "fork failed: %s\n", + strerror (errno)); + return 1; + } + if (0 == pid) + { + /* we are the child process */ + /* close stdin/stdout to not cause interference + with the helper's main protocol! */ + (void) close (0); + open_dev_null (0, O_RDONLY); + (void) close (1); + open_dev_null (1, O_WRONLY); + (void) execv (file, cmd); + /* can only get here on error */ + fprintf (stderr, + "exec `%s' failed: %s\n", + file, + strerror (errno)); + _exit (1); + } + /* keep running waitpid as long as the only error we get is 'EINTR' */ + while ( (-1 == (ret = waitpid (pid, &status, 0))) && + (errno == EINTR) ); + if (-1 == ret) + { + fprintf (stderr, + "waitpid failed: %s\n", + strerror (errno)); + return 1; + } + if (! (WIFEXITED (status) && (0 == WEXITSTATUS (status)))) + return 1; + /* child process completed and returned success, we're happy */ + return 0; +} + -- cgit v1.2.3 From e8e2d599bca5e88fa210c61676d8370fc112c66a Mon Sep 17 00:00:00 2001 From: Hartmut Goebel Date: Sat, 2 Mar 2019 17:27:36 +0100 Subject: gnunet-qr: Actually run gnunet-uri. --- src/util/gnunet-qr.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/util/gnunet-qr.c b/src/util/gnunet-qr.c index b375d20a7..c8919dae4 100644 --- a/src/util/gnunet-qr.c +++ b/src/util/gnunet-qr.c @@ -22,6 +22,7 @@ #include #include #include +#include "gnunet-qr-utils.h" static const char *usage_note = "gnunet-qr\n" @@ -128,16 +129,16 @@ int main (int argc, char **argv) LOG("Found %s \"%s\"\n", zbar_get_symbol_name(zbar_symbol_get_type(symbol)), data); - /* TODO - args = ["gnunet-uri", - // FIXME: "-c", configuration, - data]; - if (verbose = true) { - // TODO: print arguments: - printf("Running `%s %s %s %s`", *args, "", ""); // FIXME variable num args + if (configuration == NULL) { + char* command_args[] = {"gnunet-uri", data, NULL }; + LOG("Running `gnunet-uri %s`\n", data); + rc = fork_and_exec("gnunet-uri", command_args); + } else { + char* command_args[] = {"gnunet-uri", "-c", configuration, data, NULL }; + LOG("Running `gnunet-uri -c '%s' %s`\n", configuration, data); + rc = fork_and_exec("gnunet-uri", command_args); }; - rc = popen("gnunet-uri", *args); - */ + if (rc != 0) { printf("Failed to add URI %s\n", data); } else { -- cgit v1.2.3 From d60866a5dfb1a3529d40ee4c445b891c68a362c8 Mon Sep 17 00:00:00 2001 From: Hartmut Goebel Date: Sun, 3 Mar 2019 02:06:31 +0100 Subject: gnunet-qr: Add into Makefile.am and pofiles, --- po/POTFILES.in | 1 + src/util/Makefile.am | 26 +++++++++++--------------- 2 files changed, 12 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/po/POTFILES.in b/po/POTFILES.in index 09e4c533d..deeffe180 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -480,6 +480,7 @@ src/util/gnunet-config-diff.c src/util/gnunet-config.c src/util/gnunet-ecc.c src/util/gnunet-helper-w32-console.c +src/util/gnunet-qr.c src/util/gnunet-resolver.c src/util/gnunet-scrypt.c src/util/gnunet-service-resolver.c diff --git a/src/util/Makefile.am b/src/util/Makefile.am index 645289f59..ba3c98ad1 100644 --- a/src/util/Makefile.am +++ b/src/util/Makefile.am @@ -204,24 +204,15 @@ libexec_PROGRAMS = \ gnunet-timeout \ $(W32CONSOLEHELPER) -do_subst = $(SED) -e 's,[@]PREFIX[@],$(prefix),g' - -gnunet-qr: gnunet-qr.in Makefile - $(do_subst) < $(srcdir)/gnunet-qr.in > gnunet-qr - chmod +x gnunet-qr - -CLEANFILES = gnunet-qr - -bin_SCRIPTS =\ - gnunet-qr \ - gnunet-qr.py - bin_PROGRAMS = \ gnunet-resolver \ gnunet-config \ $(GNUNET_ECC) \ $(GNUNET_SCRYPT) \ gnunet-uri +if HAVE_ZBAR +bin_PROGRAMS += gnunet-qr +endif noinst_PROGRAMS = \ gnunet-config-diff \ @@ -281,13 +272,19 @@ gnunet_config_LDADD = \ libgnunetutil.la \ $(GN_LIBINTL) - gnunet_uri_SOURCES = \ gnunet-uri.c gnunet_uri_LDADD = \ libgnunetutil.la \ $(GN_LIBINTL) + +gnunet_qr_SOURCES = \ + gnunet-qr.c \ + gnunet-qr-utils.h +gnunet_qr_LDFLAGS= $(libzbar_LIBS) +gnunet_qr_CFLAGS = $(libzbar_CFLAGS) + plugin_LTLIBRARIES = \ libgnunet_plugin_test.la @@ -668,5 +665,4 @@ EXTRA_DIST = \ test_program_data.conf \ test_resolver_api_data.conf \ test_service_data.conf \ - test_speedup_data.conf \ - gnunet-qr.in + test_speedup_data.conf -- cgit v1.2.3 From 70a749982e4ed34468d11affebe03a718facf3f4 Mon Sep 17 00:00:00 2001 From: Hartmut Goebel Date: Sun, 3 Mar 2019 02:10:13 +0100 Subject: gnunet-qr: Use the `gnunet-uri` binary installed into PREFIX. This helps keeping environments concise and functional package managers like guix this will ensure `gnunet-uri` from the same environment is used. --- src/util/Makefile.am | 2 +- src/util/gnunet-qr.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/util/Makefile.am b/src/util/Makefile.am index ba3c98ad1..98997efbd 100644 --- a/src/util/Makefile.am +++ b/src/util/Makefile.am @@ -283,7 +283,7 @@ gnunet_qr_SOURCES = \ gnunet-qr.c \ gnunet-qr-utils.h gnunet_qr_LDFLAGS= $(libzbar_LIBS) -gnunet_qr_CFLAGS = $(libzbar_CFLAGS) +gnunet_qr_CFLAGS = $(libzbar_CFLAGS) -DBINDIR=\"@bindir@/\" plugin_LTLIBRARIES = \ libgnunet_plugin_test.la diff --git a/src/util/gnunet-qr.c b/src/util/gnunet-qr.c index c8919dae4..ea0e0fea2 100644 --- a/src/util/gnunet-qr.c +++ b/src/util/gnunet-qr.c @@ -132,11 +132,11 @@ int main (int argc, char **argv) if (configuration == NULL) { char* command_args[] = {"gnunet-uri", data, NULL }; LOG("Running `gnunet-uri %s`\n", data); - rc = fork_and_exec("gnunet-uri", command_args); + rc = fork_and_exec(BINDIR "gnunet-uri", command_args); } else { char* command_args[] = {"gnunet-uri", "-c", configuration, data, NULL }; LOG("Running `gnunet-uri -c '%s' %s`\n", configuration, data); - rc = fork_and_exec("gnunet-uri", command_args); + rc = fork_and_exec(BINDIR "gnunet-uri", command_args); }; if (rc != 0) { -- cgit v1.2.3 From e14a51a2bb759429cb624cf4eba59454b6af24e7 Mon Sep 17 00:00:00 2001 From: Hartmut Goebel Date: Sun, 3 Mar 2019 22:08:53 +0100 Subject: gnunet-qr: Use GNUNET_PROGRAM_run to simplify the code. --- src/util/Makefile.am | 3 ++ src/util/gnunet-qr.c | 115 ++++++++++++++++++++++----------------------------- 2 files changed, 53 insertions(+), 65 deletions(-) (limited to 'src') diff --git a/src/util/Makefile.am b/src/util/Makefile.am index 98997efbd..89d0462c5 100644 --- a/src/util/Makefile.am +++ b/src/util/Makefile.am @@ -282,6 +282,9 @@ gnunet_uri_LDADD = \ gnunet_qr_SOURCES = \ gnunet-qr.c \ gnunet-qr-utils.h +gnunet_qr_LDADD = \ + libgnunetutil.la \ + $(GN_LIBINTL) gnunet_qr_LDFLAGS= $(libzbar_LIBS) gnunet_qr_CFLAGS = $(libzbar_CFLAGS) -DBINDIR=\"@bindir@/\" diff --git a/src/util/gnunet-qr.c b/src/util/gnunet-qr.c index ea0e0fea2..b54f352d5 100644 --- a/src/util/gnunet-qr.c +++ b/src/util/gnunet-qr.c @@ -21,70 +21,34 @@ #include #include #include -#include +#include "platform.h" +#include "gnunet_util_lib.h" #include "gnunet-qr-utils.h" -static const char *usage_note = - "gnunet-qr\n" - "Scan a QR code using a video device and import\n" - "\n" - "Arguments mandatory for long options are also mandatory for short options.\n" - " -c, --config FILENAME use configuration file FILENAME\n" - " -d, --device DEVICE use device DEVICE\n" - " -s, --silent do not show preview windows\n" - " -h, --help print this help\n" - " -v, --verbose be verbose\n" - "Report bugs to gnunet-developers@gnu.org.\n" - "\n" - "GNUnet home page: https://gnunet.org/\n" - "General help using GNU software: https://www.gnu.org/gethelp/\n"; - #define LOG(fmt, ...) if (verbose == true) printf(fmt, ## __VA_ARGS__) -int main (int argc, char **argv) +// Command line options +// program exit code +static long unsigned int exit_code = 1; + +static char* device = "/dev/video0"; +static int verbose = false; +static int silent = false; + +/** + * Main function that will be run by the scheduler. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param cfg configuration + */ +static void +run (void *cls, + char *const *args, + const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) { - const char* configuration = NULL; - const char* device = "/dev/video0"; - static bool verbose = false; - static bool silent = false; - - static struct option long_options[] = { - {"verbose", no_argument, 0, 'v'}, - {"silent", no_argument, 0, 's'}, - {"help", no_argument, 0, 'h'}, - {"config", required_argument, 0, 'c'}, - {"device", required_argument, 0, 'd'}, - {0, 0, 0, 0} - }; - while (1) { - int opt; - opt = getopt_long (argc, argv, "c:hd:sv", - long_options, NULL); - if (opt == -1) - break; - - switch (opt) { - case 'h': - printf(usage_note); - return 0; - case 'c': - configuration = optarg; - break; - case 'd': - device = optarg; - break; - case 's': - silent = true; - break; - case 'v': - verbose = true; - break; - default: - printf(usage_note); - return 1; - } - } - /* create a Processor */ LOG("Initializing\n"); zbar_processor_t *proc = zbar_processor_create(1); @@ -119,8 +83,6 @@ int main (int argc, char **argv) zbar_processor_set_visible(proc, 0); // extract results - int rc = 1; - const zbar_symbol_set_t* symbols = zbar_processor_get_results(proc); const zbar_symbol_t* symbol = zbar_symbol_set_first_symbol(symbols); @@ -132,14 +94,14 @@ int main (int argc, char **argv) if (configuration == NULL) { char* command_args[] = {"gnunet-uri", data, NULL }; LOG("Running `gnunet-uri %s`\n", data); - rc = fork_and_exec(BINDIR "gnunet-uri", command_args); + exit_code = fork_and_exec(BINDIR "gnunet-uri", command_args); } else { char* command_args[] = {"gnunet-uri", "-c", configuration, data, NULL }; LOG("Running `gnunet-uri -c '%s' %s`\n", configuration, data); - rc = fork_and_exec(BINDIR "gnunet-uri", command_args); + exit_code = fork_and_exec(BINDIR "gnunet-uri", command_args); }; - if (rc != 0) { + if (exit_code != 0) { printf("Failed to add URI %s\n", data); } else { printf("Added URI %s\n", data); @@ -148,6 +110,29 @@ int main (int argc, char **argv) /* clean up */ zbar_processor_destroy(proc); +}; - return(rc); + +int +main (int argc, char *const *argv) +{ + static int ret; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_option_string ('d', "device", "DEVICE", + gettext_noop ("use video-device DEVICE (default: /dev/video0"), + &device), + GNUNET_GETOPT_option_flag ('\0', "verbose", + gettext_noop ("be verbose"), + &verbose), + GNUNET_GETOPT_option_flag ('s', "silent", + gettext_noop ("do not show preview windows"), + &silent), + GNUNET_GETOPT_OPTION_END + }; + ret = GNUNET_PROGRAM_run (argc, + argv, + "gnunet-qr", + gettext_noop ("Scan a QR code using a video device and import the uri read"), + options, &run, NULL); + return ((GNUNET_OK == ret) && (0 == exit_code)) ? 0 : 1; } -- cgit v1.2.3 From 9f8374622c5b258cabb51b115a839d6cb2faeed6 Mon Sep 17 00:00:00 2001 From: Hartmut Goebel Date: Tue, 5 Mar 2019 23:43:25 +0100 Subject: gnunet-qr: Implement functionality of gnunet-uri, don't spawn. This copies the central part of gnunet-uri. Should better be in some shared code. Also eliminate helper lib "gnunet-qr-utils.h", which is no longer used. --- src/util/gnunet-qr-utils.h | 111 --------------------------------------------- src/util/gnunet-qr.c | 103 +++++++++++++++++++++++++++++++++++------ 2 files changed, 89 insertions(+), 125 deletions(-) delete mode 100644 src/util/gnunet-qr-utils.h (limited to 'src') diff --git a/src/util/gnunet-qr-utils.h b/src/util/gnunet-qr-utils.h deleted file mode 100644 index 6d821633c..000000000 --- a/src/util/gnunet-qr-utils.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2010, 2011, 2012 Christian Grothoff - Copyright (C) 2019 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - or (at your option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later -*/ - -#include "platform.h" - -// -// FIXME: These functions are copied from dns/gnunet-helper-dns.c, -// move them into a common library. Or think about implementing a even -// more elaborate version. -// - -/** - * Open '/dev/null' and make the result the given - * file descriptor. - * - * @param target_fd desired FD to point to /dev/null - * @param flags open flags (O_RDONLY, O_WRONLY) - */ -static void -open_dev_null (int target_fd, - int flags) -{ - int fd; - - fd = open ("/dev/null", flags); - if (-1 == fd) - abort (); - if (fd == target_fd) - return; - if (-1 == dup2 (fd, target_fd)) - { - (void) close (fd); - abort (); - } - (void) close (fd); -} - -/** - * Run the given command and wait for it to complete. - * - * @param file name of the binary to run - * @param cmd command line arguments (as given to 'execv') - * @return 0 on success, 1 on any error - */ -static int -fork_and_exec (const char *file, - char *const cmd[]) -{ - int status; - pid_t pid; - pid_t ret; - - pid = fork (); - if (-1 == pid) - { - fprintf (stderr, - "fork failed: %s\n", - strerror (errno)); - return 1; - } - if (0 == pid) - { - /* we are the child process */ - /* close stdin/stdout to not cause interference - with the helper's main protocol! */ - (void) close (0); - open_dev_null (0, O_RDONLY); - (void) close (1); - open_dev_null (1, O_WRONLY); - (void) execv (file, cmd); - /* can only get here on error */ - fprintf (stderr, - "exec `%s' failed: %s\n", - file, - strerror (errno)); - _exit (1); - } - /* keep running waitpid as long as the only error we get is 'EINTR' */ - while ( (-1 == (ret = waitpid (pid, &status, 0))) && - (errno == EINTR) ); - if (-1 == ret) - { - fprintf (stderr, - "waitpid failed: %s\n", - strerror (errno)); - return 1; - } - if (! (WIFEXITED (status) && (0 == WEXITSTATUS (status)))) - return 1; - /* child process completed and returned success, we're happy */ - return 0; -} - diff --git a/src/util/gnunet-qr.c b/src/util/gnunet-qr.c index b54f352d5..1106d5cb2 100644 --- a/src/util/gnunet-qr.c +++ b/src/util/gnunet-qr.c @@ -23,18 +23,102 @@ #include #include "platform.h" #include "gnunet_util_lib.h" -#include "gnunet-qr-utils.h" #define LOG(fmt, ...) if (verbose == true) printf(fmt, ## __VA_ARGS__) // Command line options -// program exit code -static long unsigned int exit_code = 1; - static char* device = "/dev/video0"; static int verbose = false; static int silent = false; +// Handler exit code +static long unsigned int exit_code = 1; + +// Helper process we started. +static struct GNUNET_OS_Process *p; + +// Pipe used to communicate shutdown via signal. +static struct GNUNET_DISK_PipeHandle *sigpipe; + + +/** + * Task triggered whenever we receive a SIGCHLD (child + * process died) or when user presses CTRL-C. + * + * @param cls closure, NULL + */ +static void +maint_child_death (void *cls) +{ + enum GNUNET_OS_ProcessStatusType type; + + if ( (GNUNET_OK != + GNUNET_OS_process_status (p, &type, &exit_code)) || + (type != GNUNET_OS_PROCESS_EXITED) ) + GNUNET_break (0 == GNUNET_OS_process_kill (p, GNUNET_TERM_SIG)); + GNUNET_OS_process_destroy (p); +} + + +/** + * Dispatch URIs to the appropriate GNUnet helper process + * + * @param cls closure + * @param uri uri to dispatch + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param cfg configuration + */ +static void +gnunet_uri (void *cls, const char *uri, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + const char *orig_uri; + const char *slash; + char *subsystem; + char *program; + struct GNUNET_SCHEDULER_Task * rt; + + orig_uri = uri; + if (0 != strncasecmp ("gnunet://", uri, strlen ("gnunet://"))) { + fprintf (stderr, + _("Invalid URI: does not start with `%s'\n"), + "gnunet://"); + return; + } + uri += strlen ("gnunet://"); + if (NULL == (slash = strchr (uri, '/'))) + { + fprintf (stderr, _("Invalid URI: fails to specify subsystem\n")); + return; + } + subsystem = GNUNET_strndup (uri, slash - uri); + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + "uri", + subsystem, + &program)) + { + fprintf (stderr, _("No handler known for subsystem `%s'\n"), subsystem); + GNUNET_free (subsystem); + return; + } + GNUNET_free (subsystem); + rt = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, + GNUNET_DISK_pipe_handle (sigpipe, + GNUNET_DISK_PIPE_END_READ), + &maint_child_death, NULL); + p = GNUNET_OS_start_process (GNUNET_NO, 0, + NULL, NULL, NULL, + program, + program, + orig_uri, + NULL); + GNUNET_free (program); + if (NULL == p) + GNUNET_SCHEDULER_cancel (rt); +} + + /** * Main function that will be run by the scheduler. * @@ -91,16 +175,7 @@ run (void *cls, LOG("Found %s \"%s\"\n", zbar_get_symbol_name(zbar_symbol_get_type(symbol)), data); - if (configuration == NULL) { - char* command_args[] = {"gnunet-uri", data, NULL }; - LOG("Running `gnunet-uri %s`\n", data); - exit_code = fork_and_exec(BINDIR "gnunet-uri", command_args); - } else { - char* command_args[] = {"gnunet-uri", "-c", configuration, data, NULL }; - LOG("Running `gnunet-uri -c '%s' %s`\n", configuration, data); - exit_code = fork_and_exec(BINDIR "gnunet-uri", command_args); - }; - + gnunet_uri(cls, data, cfgfile, cfg); if (exit_code != 0) { printf("Failed to add URI %s\n", data); } else { -- cgit v1.2.3 From c7ec9cc03a383a33315c9cc126ebbf73135a17cc Mon Sep 17 00:00:00 2001 From: Hartmut Goebel Date: Sat, 2 Mar 2019 11:00:53 +0100 Subject: gnunet-qr: Reimplement in C - yet only a proof of concept. Still to-do: * running gnunet-uri * Proper error handling * integration into build system (automake) Reimplementing in C was chosen since - official zbar python-bindings support python 2 only, - none of the other bindings available at PyPI supports the high-level "processor" interface which gnunet-qr uses - implementing bindings for zbar using ctypes required addin a lot of low-level error handling code, thus implementing in C seamed to be easier, - the programm is short, thus re-implementing is not such complicated, and - this allows to reduce the number of dependencies (here: another Python version), which should ease porting to other plattforms (zbar is a dependency anyway). --- src/util/gnunet-qr.c | 160 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/util/gnunet-qr.in | 46 --------------- src/util/gnunet-qr.py | 110 ---------------------------------- 3 files changed, 160 insertions(+), 156 deletions(-) create mode 100644 src/util/gnunet-qr.c delete mode 100755 src/util/gnunet-qr.in delete mode 100644 src/util/gnunet-qr.py (limited to 'src') diff --git a/src/util/gnunet-qr.c b/src/util/gnunet-qr.c new file mode 100644 index 000000000..c02212a51 --- /dev/null +++ b/src/util/gnunet-qr.c @@ -0,0 +1,160 @@ +/* + This file is part of GNUnet. + Copyright (C) 2013-2019 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + SPDX-License-Identifier: AGPL3.0-or-later +*/ + +#include +#include +#include +#include + +static const char *usage_note = + "gnunet-qr\n" + "Scan a QR code using a video device and import\n" + "\n" + "Arguments mandatory for long options are also mandatory for short options.\n" + " -c, --config FILENAME use configuration file FILENAME\n" + " -d, --device DEVICE use device DEVICE\n" + " -s, --silent do not show preview windows\n" + " -h, --help print this help\n" + " -v, --verbose be verbose\n" + "Report bugs to gnunet-developers@gnu.org.\n" + "\n" + "GNUnet home page: https://gnunet.org/\n" + "General help using GNU software: https://www.gnu.org/gethelp/\n"; + +int main (int argc, char **argv) +{ + const char* configuration = NULL; + const char* device = "/dev/video0"; + static bool verbose = false; + static bool silent = false; + + static struct option long_options[] = { + {"verbose", no_argument, 0, 'v'}, + {"silent", no_argument, 0, 's'}, + {"help", no_argument, 0, 'h'}, + {"config", required_argument, 0, 'c'}, + {"device", required_argument, 0, 'd'}, + {0, 0, 0, 0} + }; + while (1) { + int opt; + opt = getopt_long (argc, argv, "c:hd:sv", + long_options, NULL); + if (opt == -1) + break; + + switch (opt) { + case 'h': + printf(usage_note); + return 0; + case 'c': + configuration = optarg; + break; + case 'd': + device = optarg; + break; + case 's': + silent = true; + break; + case 'v': + verbose = true; + break; + default: + printf(usage_note); + return 1; + } + } + + /* create a Processor */ + if (verbose == true) { + printf("Initializing\n"); + }; + zbar_processor_t *proc = zbar_processor_create(1); + + // FIXME: Wrap all this into a function which returns an error on + // failure. And here ensure the processor is destroyed at the end. + + /* configure the Processor */ + zbar_processor_parse_config(proc, "enable"); + + /* initialize the Processor */ + if (verbose == true) { + printf("Opening video device %s\n", device); + }; + // FIXME: error handling + zbar_processor_init(proc, device, 1); + + /* enable the preview window */ + zbar_processor_set_visible(proc, 1); + zbar_processor_set_active(proc, 1); + + /* keep scanning until user provides key/mouse input */ + //zbar_processor_user_wait(proc, -1); + + // read at least one barcode (or until window closed) + if (verbose == true) { + printf("Capturing\n"); + } + int n; + n = zbar_process_one(proc, -1); + if (verbose == true) { + printf("Got %i images\n", n); + }; + // FIXME: Error handling (n = -1) + + // hide the preview window + zbar_processor_set_active(proc, 0); + zbar_processor_set_visible(proc, 0); + + // extract results + int rc = 1; + + const zbar_symbol_set_t* symbols = zbar_processor_get_results(proc); + const zbar_symbol_t* symbol = zbar_symbol_set_first_symbol(symbols); + + if (symbol != NULL) { + const char* data = zbar_symbol_get_data(symbol); + if (verbose = true) { + zbar_symbol_type_t type = + printf("Found %s \"%s\"\n", + zbar_get_symbol_name(zbar_symbol_get_type(symbol)), data); + } + /* TODO + args = ["gnunet-uri", + // FIXME: "-c", configuration, + data]; + if (verbose = true) { + // TODO: print arguments: + printf("Running `%s %s %s %s`", *args, "", ""); // FIXME variable num args + }; + rc = popen("gnunet-uri", *args); + */ + if (rc != 0) { + printf("Failed to add URI %s\n", data); + } else { + printf("Added URI %s\n", data); + } + } + + /* clean up */ + zbar_processor_destroy(proc); + + return(rc); +} diff --git a/src/util/gnunet-qr.in b/src/util/gnunet-qr.in deleted file mode 100755 index ce7a19b69..000000000 --- a/src/util/gnunet-qr.in +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/sh -# -# From curl's buildconf, making this script subject to the -# curl license: https://curl.haxx.se/docs/copyright.html -# Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. -# Copyright (C) 2019 GNUnet e.V. - -# findtool works like which without relying on which (which is a problem -# for some limited shells. -findtool(){ - file="$1" - - if { echo "$file" | grep "/" >/dev/null 2>&1; } then - # when file is given with a path check it first - if test -f "$file"; then - echo "$file" - return - fi - fi - - old_IFS=$IFS; IFS=':' - for path in $PATH - do - IFS=$old_IFS - # echo "checks for $file in $path" >&2 - if test "$path" -a "$path" != '.' -a -f "$path/$file"; then - echo "$path/$file" - return - fi - done - IFS=$old_IFS -} - -# end curl licensed code -pythonize=`findtool python2.7 2>/dev/null` -if test ! -x "$pythonize"; then - pythonize=`findtool ${PYTHON2:-python2.7}` -fi - -if test -z "$pythonize"; then - echo "ERROR: python2.7 not found." - echo " You need python2.7 installed." - exit 1 -fi - -${pythonize} @PREFIX@/share/gnunet/gnunet-qr.py $@ diff --git a/src/util/gnunet-qr.py b/src/util/gnunet-qr.py deleted file mode 100644 index 0ee0b9507..000000000 --- a/src/util/gnunet-qr.py +++ /dev/null @@ -1,110 +0,0 @@ -import sys -import getopt -import subprocess -from sys import argv -try: - import zbar -except ImportError as e: - print('Cannot run gnunet-qr, please install the zbar module.') - print('For Debian, you can obtain it as "python-zbar".') - print('Upstream: http://zbar.sourceforge.net/') - sys.exit(1) - - -def help(): - print('gnunet-qr\n\ -Scan a QR code using a video device and import\n\ -Arguments mandatory for long options are also mandatory for short options.\n\ - -c, --config FILENAME use configuration file FILENAME\n\ - -d, --device DEVICE use device DEVICE\n\ - -s, --silent do not show preview windows\n\ - -h, --help print this help\n\ - -v, --verbose be verbose\n\ -Report bugs to gnunet-developers@gnu.org.\n\ -GNUnet home page: https://gnunet.org/\n\ -General help using GNU software: https://www.gnu.org/gethelp/') - - -if __name__ == '__main__': - configuration = '' - device = '/dev/video0' - url = '' - verbose = False - silent = False - # Parse arguments - try: - opts, args = getopt.gnu_getopt(sys.argv[1:], "c:hd:sv", ["config", "help", "device", "silent", "verbose"]) - except getopt.GetoptError as e: - help() - print(str(e)) - exit(1) - for o, a in opts: - if o in ("-h", "--help"): - help() - sys.exit(0) - elif o in ("-c", "--config"): - configuration = a - elif o in ("-d", "--device"): - device = a - elif o in ("-s", "--silent"): - silent = True - elif o in ("-v", "--verbose"): - verbose = True - if (True == verbose): - print('Initializing') - # create a Processor - proc = zbar.Processor() - - # configure the Processor - proc.parse_config('enable') - - # initialize the Processor - try: - if (True == verbose): - print('Opening video device ' + device) - proc.init(device) - except Exception as e: - print('Failed to open device ' + device) - exit(1) - - # enable the preview window - # if (True == silent): - # proc.visible = True - # else: - # proc.visible = False - - proc.visible = True - # read at least one barcode (or until window closed) - try: - if (True == verbose): - print('Capturing') - proc.process_one() - except Exception as e: - # Window was closed without finding code - exit(1) - - # hide the preview window - proc.visible = False - - # extract results - for symbol in proc.results: - # do something useful with results - if (True == verbose): - print('Found ', symbol.type, ' symbol ', '"%s"' % symbol.data) - args = list() - args.append("gnunet-uri") - if (configuration != ''): - args.append(str("-c " + str(configuration))) - args.append(str(symbol.data)) - cmd = '' - for a in args: - cmd += " " + str(a) - if (verbose): - print('Running `' + cmd +'`') - res = subprocess.call(args) - if (0 != res): - print('Failed to add URI ' + str(symbol.data)) - else: - print('Added URI ' + str(symbol.data)) - exit(res) - exit(1) -- cgit v1.2.3 From 2a302e5716711e4bae796ac3c272972859a3a122 Mon Sep 17 00:00:00 2001 From: Hartmut Goebel Date: Sat, 2 Mar 2019 12:37:46 +0100 Subject: gnunet-qr: Simplify verbose messaging. --- src/util/gnunet-qr.c | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/util/gnunet-qr.c b/src/util/gnunet-qr.c index c02212a51..b375d20a7 100644 --- a/src/util/gnunet-qr.c +++ b/src/util/gnunet-qr.c @@ -38,6 +38,8 @@ static const char *usage_note = "GNUnet home page: https://gnunet.org/\n" "General help using GNU software: https://www.gnu.org/gethelp/\n"; +#define LOG(fmt, ...) if (verbose == true) printf(fmt, ## __VA_ARGS__) + int main (int argc, char **argv) { const char* configuration = NULL; @@ -83,9 +85,7 @@ int main (int argc, char **argv) } /* create a Processor */ - if (verbose == true) { - printf("Initializing\n"); - }; + LOG("Initializing\n"); zbar_processor_t *proc = zbar_processor_create(1); // FIXME: Wrap all this into a function which returns an error on @@ -95,9 +95,7 @@ int main (int argc, char **argv) zbar_processor_parse_config(proc, "enable"); /* initialize the Processor */ - if (verbose == true) { - printf("Opening video device %s\n", device); - }; + LOG("Opening video device %s\n", device); // FIXME: error handling zbar_processor_init(proc, device, 1); @@ -109,14 +107,10 @@ int main (int argc, char **argv) //zbar_processor_user_wait(proc, -1); // read at least one barcode (or until window closed) - if (verbose == true) { - printf("Capturing\n"); - } + LOG("Capturing\n"); int n; n = zbar_process_one(proc, -1); - if (verbose == true) { - printf("Got %i images\n", n); - }; + LOG("Got %i images\n", n); // FIXME: Error handling (n = -1) // hide the preview window @@ -131,11 +125,9 @@ int main (int argc, char **argv) if (symbol != NULL) { const char* data = zbar_symbol_get_data(symbol); - if (verbose = true) { - zbar_symbol_type_t type = - printf("Found %s \"%s\"\n", - zbar_get_symbol_name(zbar_symbol_get_type(symbol)), data); - } + LOG("Found %s \"%s\"\n", + zbar_get_symbol_name(zbar_symbol_get_type(symbol)), data); + /* TODO args = ["gnunet-uri", // FIXME: "-c", configuration, -- cgit v1.2.3 From 6f4f14aa56a879587ae731751d51ea062e3d0956 Mon Sep 17 00:00:00 2001 From: Hartmut Goebel Date: Sat, 2 Mar 2019 17:26:35 +0100 Subject: Add helper lib "gnunet-qr-utils.h". These functions are copied from dns/gnunet-helper-dns.c, move them into a common library. Or think about implementing a even more elaborate version. --- src/util/gnunet-qr-utils.h | 111 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 src/util/gnunet-qr-utils.h (limited to 'src') diff --git a/src/util/gnunet-qr-utils.h b/src/util/gnunet-qr-utils.h new file mode 100644 index 000000000..6d821633c --- /dev/null +++ b/src/util/gnunet-qr-utils.h @@ -0,0 +1,111 @@ +/* + This file is part of GNUnet. + Copyright (C) 2010, 2011, 2012 Christian Grothoff + Copyright (C) 2019 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + SPDX-License-Identifier: AGPL3.0-or-later +*/ + +#include "platform.h" + +// +// FIXME: These functions are copied from dns/gnunet-helper-dns.c, +// move them into a common library. Or think about implementing a even +// more elaborate version. +// + +/** + * Open '/dev/null' and make the result the given + * file descriptor. + * + * @param target_fd desired FD to point to /dev/null + * @param flags open flags (O_RDONLY, O_WRONLY) + */ +static void +open_dev_null (int target_fd, + int flags) +{ + int fd; + + fd = open ("/dev/null", flags); + if (-1 == fd) + abort (); + if (fd == target_fd) + return; + if (-1 == dup2 (fd, target_fd)) + { + (void) close (fd); + abort (); + } + (void) close (fd); +} + +/** + * Run the given command and wait for it to complete. + * + * @param file name of the binary to run + * @param cmd command line arguments (as given to 'execv') + * @return 0 on success, 1 on any error + */ +static int +fork_and_exec (const char *file, + char *const cmd[]) +{ + int status; + pid_t pid; + pid_t ret; + + pid = fork (); + if (-1 == pid) + { + fprintf (stderr, + "fork failed: %s\n", + strerror (errno)); + return 1; + } + if (0 == pid) + { + /* we are the child process */ + /* close stdin/stdout to not cause interference + with the helper's main protocol! */ + (void) close (0); + open_dev_null (0, O_RDONLY); + (void) close (1); + open_dev_null (1, O_WRONLY); + (void) execv (file, cmd); + /* can only get here on error */ + fprintf (stderr, + "exec `%s' failed: %s\n", + file, + strerror (errno)); + _exit (1); + } + /* keep running waitpid as long as the only error we get is 'EINTR' */ + while ( (-1 == (ret = waitpid (pid, &status, 0))) && + (errno == EINTR) ); + if (-1 == ret) + { + fprintf (stderr, + "waitpid failed: %s\n", + strerror (errno)); + return 1; + } + if (! (WIFEXITED (status) && (0 == WEXITSTATUS (status)))) + return 1; + /* child process completed and returned success, we're happy */ + return 0; +} + -- cgit v1.2.3 From e729040833049ada5bb642e1084b603ec428742d Mon Sep 17 00:00:00 2001 From: Hartmut Goebel Date: Sat, 2 Mar 2019 17:27:36 +0100 Subject: gnunet-qr: Actually run gnunet-uri. --- src/util/gnunet-qr.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/util/gnunet-qr.c b/src/util/gnunet-qr.c index b375d20a7..c8919dae4 100644 --- a/src/util/gnunet-qr.c +++ b/src/util/gnunet-qr.c @@ -22,6 +22,7 @@ #include #include #include +#include "gnunet-qr-utils.h" static const char *usage_note = "gnunet-qr\n" @@ -128,16 +129,16 @@ int main (int argc, char **argv) LOG("Found %s \"%s\"\n", zbar_get_symbol_name(zbar_symbol_get_type(symbol)), data); - /* TODO - args = ["gnunet-uri", - // FIXME: "-c", configuration, - data]; - if (verbose = true) { - // TODO: print arguments: - printf("Running `%s %s %s %s`", *args, "", ""); // FIXME variable num args + if (configuration == NULL) { + char* command_args[] = {"gnunet-uri", data, NULL }; + LOG("Running `gnunet-uri %s`\n", data); + rc = fork_and_exec("gnunet-uri", command_args); + } else { + char* command_args[] = {"gnunet-uri", "-c", configuration, data, NULL }; + LOG("Running `gnunet-uri -c '%s' %s`\n", configuration, data); + rc = fork_and_exec("gnunet-uri", command_args); }; - rc = popen("gnunet-uri", *args); - */ + if (rc != 0) { printf("Failed to add URI %s\n", data); } else { -- cgit v1.2.3 From 4cecaf9d96ef62430ad81fe5e7a24ca68cd27095 Mon Sep 17 00:00:00 2001 From: Hartmut Goebel Date: Sun, 3 Mar 2019 02:06:31 +0100 Subject: gnunet-qr: Add into Makefile.am and pofiles, --- po/POTFILES.in | 1 + src/util/Makefile.am | 29 ++++++++++++++--------------- 2 files changed, 15 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/po/POTFILES.in b/po/POTFILES.in index fe788fdae..67c22aaed 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -480,6 +480,7 @@ src/util/gnunet-config.c src/util/gnunet-config-diff.c src/util/gnunet-ecc.c src/util/gnunet-helper-w32-console.c +src/util/gnunet-qr.c src/util/gnunet-resolver.c src/util/gnunet-scrypt.c src/util/gnunet-service-resolver.c diff --git a/src/util/Makefile.am b/src/util/Makefile.am index cd14fb4ca..02dede372 100644 --- a/src/util/Makefile.am +++ b/src/util/Makefile.am @@ -204,26 +204,15 @@ libexec_PROGRAMS = \ gnunet-timeout \ $(W32CONSOLEHELPER) -do_subst = $(SED) -e 's,[@]PREFIX[@],$(prefix),g' - -gnunet-qr: gnunet-qr.in Makefile - $(do_subst) < $(srcdir)/gnunet-qr.in > gnunet-qr - chmod +x gnunet-qr - -CLEANFILES = gnunet-qr - -pkgdata_DATA = \ - gnunet-qr.py - -bin_SCRIPTS =\ - gnunet-qr - bin_PROGRAMS = \ gnunet-resolver \ gnunet-config \ $(GNUNET_ECC) \ $(GNUNET_SCRYPT) \ gnunet-uri +if HAVE_ZBAR +bin_PROGRAMS += gnunet-qr +endif noinst_PROGRAMS = \ gnunet-config-diff \ @@ -283,13 +272,19 @@ gnunet_config_LDADD = \ libgnunetutil.la \ $(GN_LIBINTL) - gnunet_uri_SOURCES = \ gnunet-uri.c gnunet_uri_LDADD = \ libgnunetutil.la \ $(GN_LIBINTL) + +gnunet_qr_SOURCES = \ + gnunet-qr.c \ + gnunet-qr-utils.h +gnunet_qr_LDFLAGS= $(libzbar_LIBS) +gnunet_qr_CFLAGS = $(libzbar_CFLAGS) + plugin_LTLIBRARIES = \ libgnunet_plugin_test.la @@ -670,6 +665,10 @@ EXTRA_DIST = \ test_program_data.conf \ test_resolver_api_data.conf \ test_service_data.conf \ +<<<<<<< HEAD test_speedup_data.conf \ gnunet-qr.in \ gnunet-qr.py +======= + test_speedup_data.conf +>>>>>>> gnunet-qr: Add into Makefile.am and pofiles, -- cgit v1.2.3 From 8f07aace2f2842b506350e608616c8055a2c71f9 Mon Sep 17 00:00:00 2001 From: Hartmut Goebel Date: Sun, 3 Mar 2019 02:10:13 +0100 Subject: gnunet-qr: Use the `gnunet-uri` binary installed into PREFIX. This helps keeping environments concise and functional package managers like guix this will ensure `gnunet-uri` from the same environment is used. --- src/util/Makefile.am | 2 +- src/util/gnunet-qr.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/util/Makefile.am b/src/util/Makefile.am index 02dede372..548af6305 100644 --- a/src/util/Makefile.am +++ b/src/util/Makefile.am @@ -283,7 +283,7 @@ gnunet_qr_SOURCES = \ gnunet-qr.c \ gnunet-qr-utils.h gnunet_qr_LDFLAGS= $(libzbar_LIBS) -gnunet_qr_CFLAGS = $(libzbar_CFLAGS) +gnunet_qr_CFLAGS = $(libzbar_CFLAGS) -DBINDIR=\"@bindir@/\" plugin_LTLIBRARIES = \ libgnunet_plugin_test.la diff --git a/src/util/gnunet-qr.c b/src/util/gnunet-qr.c index c8919dae4..ea0e0fea2 100644 --- a/src/util/gnunet-qr.c +++ b/src/util/gnunet-qr.c @@ -132,11 +132,11 @@ int main (int argc, char **argv) if (configuration == NULL) { char* command_args[] = {"gnunet-uri", data, NULL }; LOG("Running `gnunet-uri %s`\n", data); - rc = fork_and_exec("gnunet-uri", command_args); + rc = fork_and_exec(BINDIR "gnunet-uri", command_args); } else { char* command_args[] = {"gnunet-uri", "-c", configuration, data, NULL }; LOG("Running `gnunet-uri -c '%s' %s`\n", configuration, data); - rc = fork_and_exec("gnunet-uri", command_args); + rc = fork_and_exec(BINDIR "gnunet-uri", command_args); }; if (rc != 0) { -- cgit v1.2.3 From ac123283d47ff2418111cb194a7aa92e9dfa0cd0 Mon Sep 17 00:00:00 2001 From: Hartmut Goebel Date: Sun, 3 Mar 2019 22:08:53 +0100 Subject: gnunet-qr: Use GNUNET_PROGRAM_run to simplify the code. --- src/util/Makefile.am | 3 ++ src/util/gnunet-qr.c | 115 ++++++++++++++++++++++----------------------------- 2 files changed, 53 insertions(+), 65 deletions(-) (limited to 'src') diff --git a/src/util/Makefile.am b/src/util/Makefile.am index 548af6305..a5a7ff288 100644 --- a/src/util/Makefile.am +++ b/src/util/Makefile.am @@ -282,6 +282,9 @@ gnunet_uri_LDADD = \ gnunet_qr_SOURCES = \ gnunet-qr.c \ gnunet-qr-utils.h +gnunet_qr_LDADD = \ + libgnunetutil.la \ + $(GN_LIBINTL) gnunet_qr_LDFLAGS= $(libzbar_LIBS) gnunet_qr_CFLAGS = $(libzbar_CFLAGS) -DBINDIR=\"@bindir@/\" diff --git a/src/util/gnunet-qr.c b/src/util/gnunet-qr.c index ea0e0fea2..b54f352d5 100644 --- a/src/util/gnunet-qr.c +++ b/src/util/gnunet-qr.c @@ -21,70 +21,34 @@ #include #include #include -#include +#include "platform.h" +#include "gnunet_util_lib.h" #include "gnunet-qr-utils.h" -static const char *usage_note = - "gnunet-qr\n" - "Scan a QR code using a video device and import\n" - "\n" - "Arguments mandatory for long options are also mandatory for short options.\n" - " -c, --config FILENAME use configuration file FILENAME\n" - " -d, --device DEVICE use device DEVICE\n" - " -s, --silent do not show preview windows\n" - " -h, --help print this help\n" - " -v, --verbose be verbose\n" - "Report bugs to gnunet-developers@gnu.org.\n" - "\n" - "GNUnet home page: https://gnunet.org/\n" - "General help using GNU software: https://www.gnu.org/gethelp/\n"; - #define LOG(fmt, ...) if (verbose == true) printf(fmt, ## __VA_ARGS__) -int main (int argc, char **argv) +// Command line options +// program exit code +static long unsigned int exit_code = 1; + +static char* device = "/dev/video0"; +static int verbose = false; +static int silent = false; + +/** + * Main function that will be run by the scheduler. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param cfg configuration + */ +static void +run (void *cls, + char *const *args, + const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) { - const char* configuration = NULL; - const char* device = "/dev/video0"; - static bool verbose = false; - static bool silent = false; - - static struct option long_options[] = { - {"verbose", no_argument, 0, 'v'}, - {"silent", no_argument, 0, 's'}, - {"help", no_argument, 0, 'h'}, - {"config", required_argument, 0, 'c'}, - {"device", required_argument, 0, 'd'}, - {0, 0, 0, 0} - }; - while (1) { - int opt; - opt = getopt_long (argc, argv, "c:hd:sv", - long_options, NULL); - if (opt == -1) - break; - - switch (opt) { - case 'h': - printf(usage_note); - return 0; - case 'c': - configuration = optarg; - break; - case 'd': - device = optarg; - break; - case 's': - silent = true; - break; - case 'v': - verbose = true; - break; - default: - printf(usage_note); - return 1; - } - } - /* create a Processor */ LOG("Initializing\n"); zbar_processor_t *proc = zbar_processor_create(1); @@ -119,8 +83,6 @@ int main (int argc, char **argv) zbar_processor_set_visible(proc, 0); // extract results - int rc = 1; - const zbar_symbol_set_t* symbols = zbar_processor_get_results(proc); const zbar_symbol_t* symbol = zbar_symbol_set_first_symbol(symbols); @@ -132,14 +94,14 @@ int main (int argc, char **argv) if (configuration == NULL) { char* command_args[] = {"gnunet-uri", data, NULL }; LOG("Running `gnunet-uri %s`\n", data); - rc = fork_and_exec(BINDIR "gnunet-uri", command_args); + exit_code = fork_and_exec(BINDIR "gnunet-uri", command_args); } else { char* command_args[] = {"gnunet-uri", "-c", configuration, data, NULL }; LOG("Running `gnunet-uri -c '%s' %s`\n", configuration, data); - rc = fork_and_exec(BINDIR "gnunet-uri", command_args); + exit_code = fork_and_exec(BINDIR "gnunet-uri", command_args); }; - if (rc != 0) { + if (exit_code != 0) { printf("Failed to add URI %s\n", data); } else { printf("Added URI %s\n", data); @@ -148,6 +110,29 @@ int main (int argc, char **argv) /* clean up */ zbar_processor_destroy(proc); +}; - return(rc); + +int +main (int argc, char *const *argv) +{ + static int ret; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_option_string ('d', "device", "DEVICE", + gettext_noop ("use video-device DEVICE (default: /dev/video0"), + &device), + GNUNET_GETOPT_option_flag ('\0', "verbose", + gettext_noop ("be verbose"), + &verbose), + GNUNET_GETOPT_option_flag ('s', "silent", + gettext_noop ("do not show preview windows"), + &silent), + GNUNET_GETOPT_OPTION_END + }; + ret = GNUNET_PROGRAM_run (argc, + argv, + "gnunet-qr", + gettext_noop ("Scan a QR code using a video device and import the uri read"), + options, &run, NULL); + return ((GNUNET_OK == ret) && (0 == exit_code)) ? 0 : 1; } -- cgit v1.2.3 From 9915d8f8a7b67b6eff91a8afbcb99c3b33df95f5 Mon Sep 17 00:00:00 2001 From: Hartmut Goebel Date: Tue, 5 Mar 2019 23:43:25 +0100 Subject: gnunet-qr: Implement functionality of gnunet-uri, don't spawn. This copies the central part of gnunet-uri. Should better be in some shared code. Also eliminate helper lib "gnunet-qr-utils.h", which is no longer used. --- src/util/gnunet-qr-utils.h | 111 --------------------------------------------- src/util/gnunet-qr.c | 103 +++++++++++++++++++++++++++++++++++------ 2 files changed, 89 insertions(+), 125 deletions(-) delete mode 100644 src/util/gnunet-qr-utils.h (limited to 'src') diff --git a/src/util/gnunet-qr-utils.h b/src/util/gnunet-qr-utils.h deleted file mode 100644 index 6d821633c..000000000 --- a/src/util/gnunet-qr-utils.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2010, 2011, 2012 Christian Grothoff - Copyright (C) 2019 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - or (at your option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later -*/ - -#include "platform.h" - -// -// FIXME: These functions are copied from dns/gnunet-helper-dns.c, -// move them into a common library. Or think about implementing a even -// more elaborate version. -// - -/** - * Open '/dev/null' and make the result the given - * file descriptor. - * - * @param target_fd desired FD to point to /dev/null - * @param flags open flags (O_RDONLY, O_WRONLY) - */ -static void -open_dev_null (int target_fd, - int flags) -{ - int fd; - - fd = open ("/dev/null", flags); - if (-1 == fd) - abort (); - if (fd == target_fd) - return; - if (-1 == dup2 (fd, target_fd)) - { - (void) close (fd); - abort (); - } - (void) close (fd); -} - -/** - * Run the given command and wait for it to complete. - * - * @param file name of the binary to run - * @param cmd command line arguments (as given to 'execv') - * @return 0 on success, 1 on any error - */ -static int -fork_and_exec (const char *file, - char *const cmd[]) -{ - int status; - pid_t pid; - pid_t ret; - - pid = fork (); - if (-1 == pid) - { - fprintf (stderr, - "fork failed: %s\n", - strerror (errno)); - return 1; - } - if (0 == pid) - { - /* we are the child process */ - /* close stdin/stdout to not cause interference - with the helper's main protocol! */ - (void) close (0); - open_dev_null (0, O_RDONLY); - (void) close (1); - open_dev_null (1, O_WRONLY); - (void) execv (file, cmd); - /* can only get here on error */ - fprintf (stderr, - "exec `%s' failed: %s\n", - file, - strerror (errno)); - _exit (1); - } - /* keep running waitpid as long as the only error we get is 'EINTR' */ - while ( (-1 == (ret = waitpid (pid, &status, 0))) && - (errno == EINTR) ); - if (-1 == ret) - { - fprintf (stderr, - "waitpid failed: %s\n", - strerror (errno)); - return 1; - } - if (! (WIFEXITED (status) && (0 == WEXITSTATUS (status)))) - return 1; - /* child process completed and returned success, we're happy */ - return 0; -} - diff --git a/src/util/gnunet-qr.c b/src/util/gnunet-qr.c index b54f352d5..1106d5cb2 100644 --- a/src/util/gnunet-qr.c +++ b/src/util/gnunet-qr.c @@ -23,18 +23,102 @@ #include #include "platform.h" #include "gnunet_util_lib.h" -#include "gnunet-qr-utils.h" #define LOG(fmt, ...) if (verbose == true) printf(fmt, ## __VA_ARGS__) // Command line options -// program exit code -static long unsigned int exit_code = 1; - static char* device = "/dev/video0"; static int verbose = false; static int silent = false; +// Handler exit code +static long unsigned int exit_code = 1; + +// Helper process we started. +static struct GNUNET_OS_Process *p; + +// Pipe used to communicate shutdown via signal. +static struct GNUNET_DISK_PipeHandle *sigpipe; + + +/** + * Task triggered whenever we receive a SIGCHLD (child + * process died) or when user presses CTRL-C. + * + * @param cls closure, NULL + */ +static void +maint_child_death (void *cls) +{ + enum GNUNET_OS_ProcessStatusType type; + + if ( (GNUNET_OK != + GNUNET_OS_process_status (p, &type, &exit_code)) || + (type != GNUNET_OS_PROCESS_EXITED) ) + GNUNET_break (0 == GNUNET_OS_process_kill (p, GNUNET_TERM_SIG)); + GNUNET_OS_process_destroy (p); +} + + +/** + * Dispatch URIs to the appropriate GNUnet helper process + * + * @param cls closure + * @param uri uri to dispatch + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param cfg configuration + */ +static void +gnunet_uri (void *cls, const char *uri, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + const char *orig_uri; + const char *slash; + char *subsystem; + char *program; + struct GNUNET_SCHEDULER_Task * rt; + + orig_uri = uri; + if (0 != strncasecmp ("gnunet://", uri, strlen ("gnunet://"))) { + fprintf (stderr, + _("Invalid URI: does not start with `%s'\n"), + "gnunet://"); + return; + } + uri += strlen ("gnunet://"); + if (NULL == (slash = strchr (uri, '/'))) + { + fprintf (stderr, _("Invalid URI: fails to specify subsystem\n")); + return; + } + subsystem = GNUNET_strndup (uri, slash - uri); + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + "uri", + subsystem, + &program)) + { + fprintf (stderr, _("No handler known for subsystem `%s'\n"), subsystem); + GNUNET_free (subsystem); + return; + } + GNUNET_free (subsystem); + rt = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, + GNUNET_DISK_pipe_handle (sigpipe, + GNUNET_DISK_PIPE_END_READ), + &maint_child_death, NULL); + p = GNUNET_OS_start_process (GNUNET_NO, 0, + NULL, NULL, NULL, + program, + program, + orig_uri, + NULL); + GNUNET_free (program); + if (NULL == p) + GNUNET_SCHEDULER_cancel (rt); +} + + /** * Main function that will be run by the scheduler. * @@ -91,16 +175,7 @@ run (void *cls, LOG("Found %s \"%s\"\n", zbar_get_symbol_name(zbar_symbol_get_type(symbol)), data); - if (configuration == NULL) { - char* command_args[] = {"gnunet-uri", data, NULL }; - LOG("Running `gnunet-uri %s`\n", data); - exit_code = fork_and_exec(BINDIR "gnunet-uri", command_args); - } else { - char* command_args[] = {"gnunet-uri", "-c", configuration, data, NULL }; - LOG("Running `gnunet-uri -c '%s' %s`\n", configuration, data); - exit_code = fork_and_exec(BINDIR "gnunet-uri", command_args); - }; - + gnunet_uri(cls, data, cfgfile, cfg); if (exit_code != 0) { printf("Failed to add URI %s\n", data); } else { -- cgit v1.2.3 From 311795caa390858b627428629a6621def8949a7c Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Wed, 3 Apr 2019 13:42:07 +0200 Subject: add error handling for gnunet-qr --- src/util/gnunet-qr.c | 221 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 161 insertions(+), 60 deletions(-) (limited to 'src') diff --git a/src/util/gnunet-qr.c b/src/util/gnunet-qr.c index 1106d5cb2..fa95d6c05 100644 --- a/src/util/gnunet-qr.c +++ b/src/util/gnunet-qr.c @@ -17,7 +17,12 @@ SPDX-License-Identifier: AGPL3.0-or-later */ - +/** + * @file util/gnunet-qr.c + * @author Hartmut Goebel (original implementation) + * @author Martin Schanzenbach (integrate gnunet-uri) + * @author Christian Grothoff (error handling) + */ #include #include #include @@ -26,18 +31,35 @@ #define LOG(fmt, ...) if (verbose == true) printf(fmt, ## __VA_ARGS__) -// Command line options +/** + * Video device to capture from. Sane default for GNU/Linux systems. + */ static char* device = "/dev/video0"; + +/** + * --verbose option + */ static int verbose = false; + +/** + * --silent option + */ static int silent = false; -// Handler exit code +/** + * Handler exit code + */ static long unsigned int exit_code = 1; -// Helper process we started. +/** + * Helper process we started. + */ static struct GNUNET_OS_Process *p; -// Pipe used to communicate shutdown via signal. + +/** + * Pipe used to communicate child death via signal. + */ static struct GNUNET_DISK_PipeHandle *sigpipe; @@ -69,8 +91,10 @@ maint_child_death (void *cls) * @param cfg configuration */ static void -gnunet_uri (void *cls, const char *uri, const char *cfgfile, - const struct GNUNET_CONFIGURATION_Handle *cfg) +gnunet_uri (void *cls, + const char *uri, + const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) { const char *orig_uri; const char *slash; @@ -88,7 +112,8 @@ gnunet_uri (void *cls, const char *uri, const char *cfgfile, uri += strlen ("gnunet://"); if (NULL == (slash = strchr (uri, '/'))) { - fprintf (stderr, _("Invalid URI: fails to specify subsystem\n")); + fprintf (stderr, + _("Invalid URI: fails to specify subsystem\n")); return; } subsystem = GNUNET_strndup (uri, slash - uri); @@ -98,7 +123,9 @@ gnunet_uri (void *cls, const char *uri, const char *cfgfile, subsystem, &program)) { - fprintf (stderr, _("No handler known for subsystem `%s'\n"), subsystem); + fprintf (stderr, + _("No handler known for subsystem `%s'\n"), + subsystem); GNUNET_free (subsystem); return; } @@ -119,6 +146,111 @@ gnunet_uri (void *cls, const char *uri, const char *cfgfile, } +/** + * Obtain QR code 'symbol' from @a proc. + * + * @param proc zbar processor to use + * @return NULL on error + */ +static const zbar_symbol_t * +get_symbol (zbar_processor_t *proc) +{ + const zbar_symbol_set_t* symbols; + int rc; + int n; + + if (0 != + zbar_processor_parse_config (proc, "enable")) + { + GNUNET_break (0); + return NULL; + } + + /* initialize the Processor */ + if (0 != + (rc = zbar_processor_init(proc, device, 1))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to open device `%s': %d\n", + device, + rc); + return NULL; + } + + /* enable the preview window */ + if ( (0 != (rc = zbar_processor_set_visible (proc, 1))) || + (0 != (rc = zbar_processor_set_active(proc, 1))) ) + { + GNUNET_break (0); + return NULL; + } + + /* read at least one barcode (or until window closed) */ + LOG ("Capturing\n"); + n = zbar_process_one (proc, -1); + + /* hide the preview window */ + (void) zbar_processor_set_active (proc, 0); + (void) zbar_processor_set_visible (proc, 0); + if (-1 == n) + return NULL; /* likely user closed the window */ + LOG ("Got %i images\n", + n); + /* extract results */ + symbols = zbar_processor_get_results (proc); + if (NULL == symbols) + { + GNUNET_break (0); + return NULL; + } + return zbar_symbol_set_first_symbol (symbols); +} + + +/** + * Run zbar QR code parser. + * + * @return NULL on error, otherwise the URI that we found + */ +static char * +run_zbar () +{ + zbar_processor_t *proc; + const char *data; + char *ret; + const zbar_symbol_t* symbol; + + /* configure the Processor */ + proc = zbar_processor_create (1); + if (NULL == proc) + { + GNUNET_break (0); + return NULL; + } + + symbol = get_symbol (proc); + if (NULL == symbol) + { + zbar_processor_destroy (proc); + return NULL; + } + data = zbar_symbol_get_data (symbol); + if (NULL == data) + { + GNUNET_break (0); + zbar_processor_destroy (proc); + return NULL; + } + LOG ("Found %s \"%s\"\n", + zbar_get_symbol_name (zbar_symbol_get_type(symbol)), + data); + ret = GNUNET_strdup (data); + /* clean up */ + zbar_processor_destroy(proc); + return ret; +} + + /** * Main function that will be run by the scheduler. * @@ -133,65 +265,33 @@ run (void *cls, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { - /* create a Processor */ - LOG("Initializing\n"); - zbar_processor_t *proc = zbar_processor_create(1); - - // FIXME: Wrap all this into a function which returns an error on - // failure. And here ensure the processor is destroyed at the end. - - /* configure the Processor */ - zbar_processor_parse_config(proc, "enable"); - - /* initialize the Processor */ - LOG("Opening video device %s\n", device); - // FIXME: error handling - zbar_processor_init(proc, device, 1); - - /* enable the preview window */ - zbar_processor_set_visible(proc, 1); - zbar_processor_set_active(proc, 1); - - /* keep scanning until user provides key/mouse input */ - //zbar_processor_user_wait(proc, -1); + char *data; - // read at least one barcode (or until window closed) - LOG("Capturing\n"); - int n; - n = zbar_process_one(proc, -1); - LOG("Got %i images\n", n); - // FIXME: Error handling (n = -1) - - // hide the preview window - zbar_processor_set_active(proc, 0); - zbar_processor_set_visible(proc, 0); - - // extract results - const zbar_symbol_set_t* symbols = zbar_processor_get_results(proc); - const zbar_symbol_t* symbol = zbar_symbol_set_first_symbol(symbols); - - if (symbol != NULL) { - const char* data = zbar_symbol_get_data(symbol); - LOG("Found %s \"%s\"\n", - zbar_get_symbol_name(zbar_symbol_get_type(symbol)), data); - - gnunet_uri(cls, data, cfgfile, cfg); - if (exit_code != 0) { - printf("Failed to add URI %s\n", data); - } else { - printf("Added URI %s\n", data); - } + data = run_zbar (); + if (NULL == data) + return; + gnunet_uri (cls, + data, + cfgfile, + cfg); + if (exit_code != 0) + { + printf ("Failed to add URI %s\n", + data); } - - /* clean up */ - zbar_processor_destroy(proc); + else + { + printf ("Added URI %s\n", + data); + } + GNUNET_free (data); }; int main (int argc, char *const *argv) { - static int ret; + int ret; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_option_string ('d', "device", "DEVICE", gettext_noop ("use video-device DEVICE (default: /dev/video0"), @@ -204,6 +304,7 @@ main (int argc, char *const *argv) &silent), GNUNET_GETOPT_OPTION_END }; + ret = GNUNET_PROGRAM_run (argc, argv, "gnunet-qr", -- cgit v1.2.3