/*
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
*/
/**
* @file util/gnunet-qr.c
* @author Hartmut Goebel (original implementation)
* @author Martin Schanzenbach (integrate gnunet-uri)
* @author Christian Grothoff (error handling)
*/
#include
#include
#include
#include
#include "platform.h"
#include "gnunet_util_lib.h"
#if HAVE_PNG
#include
#endif
/**
* Global exit code.
* Set to non-zero if an error occurs after the scheduler has started.
*/
static int exit_code = 0;
/**
* Video device to capture from.
* Used by default if PNG support is disabled or no PNG file is specified.
* Defaults to /dev/video0.
*/
static char *device = NULL;
#if HAVE_PNG
/**
* Name of the file to read from.
* If the file is not a PNG-encoded image of a QR code, an error will be
* thrown.
*/
static char *pngfilename = NULL;
#endif
/**
* Requested verbosity.
*/
static unsigned int verbosity = 0;
/**
* Child process handle.
*/
struct GNUNET_OS_Process *childproc = NULL;
/**
* Child process handle for waiting.
*/
static struct GNUNET_ChildWaitHandle *waitchildproc = NULL;
/**
* Macro to handle verbosity when printing messages.
*/
#define LOG(fmt, ...) \
do \
{ \
if (0 < verbosity) \
{ \
GNUNET_log (GNUNET_ERROR_TYPE_INFO, fmt, ##__VA_ARGS__); \
if (verbosity > 1) \
{ \
fprintf (stdout, fmt, ##__VA_ARGS__); \
} \
} \
} \
while (0)
/**
* Executed when program is terminating.
*/
static void
shutdown_program (void *cls)
{
if (NULL != waitchildproc)
{
GNUNET_wait_child_cancel (waitchildproc);
}
if (NULL != childproc)
{
/* A bit brutal, but this process is terminating so we're out of time */
GNUNET_OS_process_kill (childproc, SIGKILL);
}
}
/**
* Callback executed when the child process terminates.
*
* @param cls closure
* @param type status of the child process
* @param code the exit code of the child process
*/
static void
wait_child (void *cls,
enum GNUNET_OS_ProcessStatusType type,
long unsigned int code)
{
GNUNET_OS_process_destroy (childproc);
childproc = NULL;
waitchildproc = NULL;
char *uri = cls;
if (0 != exit_code)
{
fprintf (stdout, _("Failed to add URI %s\n"), uri);
}
else
{
fprintf (stdout, _("Added URI %s\n"), uri);
}
GNUNET_free (uri);
GNUNET_SCHEDULER_shutdown ();
}
/**
* Dispatch URIs to the appropriate GNUnet helper process.
*
* @param cls closure
* @param uri URI to dispatch
* @param cfgfile name of the configuration file in use
* @param cfg the configuration in use
*/
static void
handle_uri (void *cls,
const char *uri,
const char *cfgfile,
const struct GNUNET_CONFIGURATION_Handle *cfg)
{
const char *cursor = uri;
if (0 != strncasecmp ("gnunet://", uri, strlen ("gnunet://")))
{
fprintf (stderr,
_("Invalid URI: does not start with `gnunet://'\n"));
exit_code = 1;
return;
}
cursor += strlen ("gnunet://");
const char *slash = strchr (cursor, '/');
if (NULL == slash)
{
fprintf (stderr, _("Invalid URI: fails to specify a subsystem\n"));
exit_code = 1;
return;
}
char *subsystem = GNUNET_strndup (cursor, slash - cursor);
char *program = NULL;
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_string (cfg, "uri", subsystem, &program))
{
fprintf (stderr, _("No known handler for subsystem `%s'\n"), subsystem);
GNUNET_free (subsystem);
exit_code = 1;
return;
}
GNUNET_free (subsystem);
char **childargv = NULL;
unsigned int childargc = 0;
for (const char *token=strtok (program, " ");
NULL!=token;
token=strtok(NULL, " "))
{
GNUNET_array_append (childargv, childargc, GNUNET_strdup (token));
}
GNUNET_array_append (childargv, childargc, GNUNET_strdup (uri));
GNUNET_array_append (childargv, childargc, NULL);
childproc = GNUNET_OS_start_process_vap (GNUNET_OS_INHERIT_STD_ALL,
NULL,
NULL,
NULL,
childargv[0],
childargv);
for (size_t i=0; i