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