1 /*------------------------------------------------------------------------
2 * Copyright 2019 (c) Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
3 *
4 * This file is part of the ZBar Bar Code Reader.
5 *
6 * The ZBar Bar Code Reader is free software; you can redistribute it
7 * and/or modify it under the terms of the GNU Lesser Public License as
8 * published by the Free Software Foundation; either version 2.1 of
9 * the License, or (at your option) any later version.
10 *
11 * The ZBar Bar Code Reader is distributed in the hope that it will be
12 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser Public License for more details.
15 *------------------------------------------------------------------------*/
16
17 #include <argp.h>
18 #include <stdarg.h>
19 #include <stdbool.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <unistd.h>
23 #include <dbus/dbus.h>
24
25 #define ZBAR_INTERFACE "org.linuxtv.Zbar1.Code"
26 #define ZBAR_SIGNAL_CODE "Code"
27 #define ZBAR_SIGNAL_TYPE "Type"
28 #define ZBAR_SIGNAL_DATA "Data"
29 #define ZBAR_SIGNAL_BINARY_DATA "BinaryData"
30
31 #define PROGRAM_NAME "test_dbus"
32
33 static const char doc[] = "\nTest if ZBar is sending codes via D-Bus\n";
34
35 static const struct argp_option options[] = {
36 {"count", 'c', "#codes", 0, "Stop after received #codes", 0},
37 {"time", 't', "#seconds", 0, "Stop after #seconds", 0},
38 {"log", 'l', "#file", 0, "Write log to #file", 0},
39 {"bin-log", 'b', "#file", 0, "Write binary log to #file", 0},
40 {"help", '?', 0, 0, "Give this help list", -1},
41 {"usage", -3, 0, 0, "Give a short usage message", 0},
42 { 0 }
43 };
44
45 static int max_msg = 0;
46 static int timeout = 0;
47 static FILE *log = NULL;
48 static FILE *bin_log = NULL;
49
parse_opt(int k,char * optarg,struct argp_state * state)50 static error_t parse_opt(int k, char *optarg, struct argp_state *state)
51 {
52 switch (k) {
53 case 'c':
54 max_msg = strtoul(optarg, NULL, 0);
55 break;
56 case 't':
57 timeout = strtoul(optarg, NULL, 0);
58 break;
59 case 'l':
60 log = fopen(optarg, "wb");
61 break;
62 case 'b':
63 bin_log = fopen(optarg, "wb");
64 break;
65 case '?':
66 argp_state_help(state, state->out_stream,
67 ARGP_HELP_SHORT_USAGE | ARGP_HELP_LONG |
68 ARGP_HELP_DOC);
69 exit(0);
70 case -3:
71 argp_state_help(state, state->out_stream, ARGP_HELP_USAGE);
72 exit(0);
73 default:
74 return ARGP_ERR_UNKNOWN;
75 };
76 return 0;
77 }
78
79 static const struct argp argp = {
80 .options = options,
81 .parser = parse_opt,
82 .doc = doc,
83 };
84
main(int argc,char * argv[])85 int main(int argc, char *argv[])
86 {
87 DBusMessage* msg;
88 DBusMessageIter args, entry, dict, val;
89 DBusConnection* conn;
90 DBusError err;
91 char *str, *property;
92 int count = 0, length = 0;
93
94 if (argp_parse(&argp, argc, argv, ARGP_NO_HELP | ARGP_NO_EXIT, 0, 0)) {
95 argp_help(&argp, stderr, ARGP_HELP_SHORT_USAGE, PROGRAM_NAME);
96 return -1;
97 }
98
99 if (!log)
100 log = fdopen(dup(fileno(stderr)), "w+");
101
102 if (!bin_log)
103 bin_log = fdopen(dup(fileno(stderr)), "w+");
104
105 // initialise the error value
106 dbus_error_init(&err);
107
108 // connect to the DBUS system bus, and check for errors
109 conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
110 if (dbus_error_is_set(&err)) {
111 fprintf(stderr, "Connection Error (%s)\n", err.message);
112 dbus_error_free(&err);
113 }
114 if (!conn) {
115 fprintf(stderr, "Connection Null\n");
116 return -1;
117 }
118
119 dbus_bus_add_match(conn,
120 "type='signal',interface='" ZBAR_INTERFACE "'",
121 &err);
122 dbus_connection_flush(conn);
123 if (dbus_error_is_set(&err)) {
124 fprintf(stderr, "Match Error (%s)\n", err.message);
125 exit(1);
126 }
127
128 if (timeout)
129 alarm(timeout);
130
131 /* loop listening for signals being emitted */
132 fprintf(stderr, "Waiting for Zbar events\n");
133 while (true) {
134 // non blocking read of the next available message
135 dbus_connection_read_write(conn, 0);
136 msg = dbus_connection_pop_message(conn);
137
138 // loop again if we haven't read a message
139 if (NULL == msg) {
140 sleep(1);
141 continue;
142 }
143
144 // check if the message is a signal from the correct interface and with the correct name
145 if (dbus_message_is_signal(msg, ZBAR_INTERFACE, ZBAR_SIGNAL_CODE)) {
146 // read the parameters
147 if (!dbus_message_iter_init(msg, &args))
148 fprintf(stderr, "Message has no arguments!\n");
149 else if (DBUS_TYPE_ARRAY != dbus_message_iter_get_arg_type(&args))
150 fprintf(stderr, "Argument is not array!\n");
151 else {
152 while (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_INVALID) {
153 dbus_message_iter_recurse(&args, &entry);
154 if (DBUS_TYPE_DICT_ENTRY != dbus_message_iter_get_arg_type(&entry)) {
155 fprintf(stderr, "Element is not dict entry!\n");
156 } else {
157 while (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_INVALID) {
158 dbus_message_iter_recurse(&entry, &dict);
159 if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&dict)) {
160 fprintf(stderr, "Dict Entry key is not string!\n");
161 } else {
162 dbus_message_iter_get_basic(&dict, &property);
163 dbus_message_iter_next(&dict);
164 if (DBUS_TYPE_VARIANT != dbus_message_iter_get_arg_type(&dict)) {
165 fprintf(stderr, "Dict Entry value is not variant!\n");
166 } else {
167 dbus_message_iter_recurse(&dict, &val);
168 if (strcmp(property, ZBAR_SIGNAL_TYPE) == 0) {
169 if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&val)) {
170 fprintf(stderr, "Dict Entry value for barcode type is not string!\n");
171 } else {
172 dbus_message_iter_get_basic(&val, &str);
173 fprintf(stderr, "Type = %s\n", str);
174 }
175 } else if (strcmp(property, ZBAR_SIGNAL_DATA) == 0) {
176 if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&val)) {
177 fprintf(stderr, "Dict Entry value for barcode text data is not string!\n");
178 } else {
179 dbus_message_iter_get_basic(&val, &str);
180 fprintf(stderr, "Value = %s\n", str);
181 fprintf(log, "%s\n", str);
182 }
183 } else if (strcmp(property, ZBAR_SIGNAL_BINARY_DATA) == 0) {
184 if (DBUS_TYPE_ARRAY != dbus_message_iter_get_arg_type(&val)) {
185 fprintf(stderr, "Dict Entry value for barcode binary data is not array!\n");
186 } else {
187 dbus_message_iter_recurse(&val, &val);
188 if (DBUS_TYPE_BYTE != dbus_message_iter_get_arg_type(&val)) {
189 fprintf(stderr, "Dict Entry value for barcode binary data is not array of bytes!\n");
190 } else {
191 dbus_message_iter_get_fixed_array(&val, &str, &length);
192 fprintf(stderr, "BinaryData[%d]\n", length);
193 fwrite(str, sizeof(*str), length, bin_log);
194 }
195 }
196 }
197 }
198 }
199 dbus_message_iter_next(&entry);
200 }
201 /* If max_msg > 0, stops after receiving 'count' messages */
202 if (++count == max_msg) {
203 dbus_message_unref(msg);
204 return 0;
205 }
206 }
207 dbus_message_iter_next(&args);
208 }
209 }
210 }
211 // free the message
212 dbus_message_unref(msg);
213 }
214
215 fclose(log);
216 fclose(bin_log);
217
218 return 0;
219 }
220