1 
2 /*
3  * run_test.c - Read a set of Speech Dispatcher commands and try them
4  *
5  * Copyright (C) 2001, 2002, 2003 Brailcom, o.p.s.
6  *
7  * This is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2, or (at your option)
10  * any later version.
11  *
12  * This software is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19  *
20  * $Id: run_test.c,v 1.14 2008-02-08 10:01:08 hanke Exp $
21  */
22 
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 
27 #include <stdio.h>
28 #include <string.h>
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <sys/un.h>
32 #include <unistd.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <assert.h>
36 #include <ctype.h>
37 #include <errno.h>
38 #include <glib.h>
39 
40 #define FATAL(msg) { printf(msg"\n"); exit(1); }
41 
42 int sockk;
43 
44 #ifndef HAVE_STRCASESTR
45 /* Added by Willie Walker - strcasestr is a common but non-standard extension
46  */
strcasestr(const char * a,const char * b)47 char *strcasestr(const char *a, const char *b)
48 {
49 	size_t l;
50 	char f[3];
51 
52 	snprintf(f, sizeof(f), "%c%c", tolower(*b), toupper(*b));
53 	for (l = strcspn(a, f); l != strlen(a); l += strcspn(a + l + 1, f) + 1)
54 		if (strncasecmp(a + l, b, strlen(b)) == 0)
55 			return (a + l);
56 	return NULL;
57 }
58 #endif /* HAVE_STRCASESTR */
59 
send_data(int fd,char * message,int wfr)60 char *send_data(int fd, char *message, int wfr)
61 {
62 	char *reply;
63 	int bytes;
64 
65 	/* TODO: 1000?! */
66 	reply = (char *)malloc(sizeof(char) * 1000);
67 
68 	/* write message to the socket */
69 	if (!write(fd, message, strlen(message))) {
70 		fprintf(stderr, "send_data filed: %s", strerror(errno));
71 	}
72 
73 	/* read reply to the buffer */
74 	if (wfr == 1) {
75 		bytes = read(fd, reply, 1000);
76 		/* print server reply to as a string */
77 		reply[bytes] = 0;
78 	} else {
79 		return "";
80 	}
81 
82 	return reply;
83 }
84 
wait_for(int fd,char * event)85 void wait_for(int fd, char *event)
86 {
87 	char *reply;
88 	int bytes;
89 
90 	printf("       Waiting for: |%s|\n", event);
91 	reply = (char *)malloc(sizeof(char) * 1000);
92 	reply[0] = 0;
93 	while (0 == strcasestr(reply, event)) {
94 		bytes = read(fd, reply, 1000);
95 		if (bytes > 0) {
96 			reply[bytes] = 0;
97 			printf("       < %s\n", reply);
98 			fflush(NULL);
99 		}
100 	}
101 	free(reply);
102 	printf("       Continuing.\n");
103 	fflush(NULL);
104 }
105 
106 /*
107  * set_socket_path: establish the pathname that our Unix socket should
108  * have.  If the SPEECHD_SOCKET environment variable is set, then that
109  * will be our pathname.  Otherwise, the pathname
110  * is $XDG_RUNTIME_DIR/speech-dispatcher/speechd.sock.
111  */
112 
set_socket_path(struct sockaddr_un * address)113 void set_socket_path(struct sockaddr_un *address)
114 {
115 	size_t path_max = sizeof(address->sun_path);
116 	const char *path;
117 	char *pathcopy = NULL;
118 
119 	path = g_getenv("SPEECHD_SOCKET");
120 	if (path == NULL || path[0] == '\0') {
121 		pathcopy = g_build_filename(g_get_user_runtime_dir(),
122 					    "speech-dispatcher",
123 					    "speechd.sock", NULL);
124 		path = pathcopy;
125 	}
126 
127 	strncpy(address->sun_path, path, path_max - 1);
128 	address->sun_path[path_max - 1] = '\0';
129 
130 	g_free(pathcopy);
131 }
132 
133 /*
134  * init: create and connect our Unix-domain socket.
135  * Returns the file descriptor of the socket on success, or -1 on
136  * failure.
137  */
138 
init(void)139 int init(void)
140 {
141 	int sockfd;
142 	int connect_success;
143 	struct sockaddr_un address;
144 
145 	set_socket_path(&address);
146 	address.sun_family = AF_UNIX;
147 	sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
148 	if (sockfd != -1) {
149 		connect_success =
150 		    connect(sockfd, (struct sockaddr *)&address,
151 			    SUN_LEN(&address));
152 		if (connect_success == -1) {
153 			close(sockfd);
154 			sockfd = -1;
155 		}
156 	}
157 
158 	return sockfd;
159 }
160 
main(int argc,char * argv[])161 int main(int argc, char *argv[])
162 {
163 	char *line;
164 	char *command;
165 	char *reply;
166 	int i;
167 	char *ret;
168 	FILE *test_file = NULL;
169 	int delays = 1;
170 	int indent = 0;
171 
172 	if (argc < 2) {
173 		printf("No test script specified!\n");
174 		exit(1);
175 	}
176 
177 	if (!strcmp(argv[1], "stdin")) {
178 		test_file = stdin;
179 	} else {
180 		test_file = fopen(argv[1], "r");
181 		if (test_file == NULL)
182 			FATAL("Test file doesn't exist");
183 	}
184 
185 	if (argc == 3) {
186 		if (!strcmp(argv[2], "fast"))
187 			delays = 0;
188 		else {
189 			printf("Unrecognized parameter\n");
190 			exit(1);
191 		}
192 	}
193 
194 	printf("Start of the test.\n");
195 	printf("==================\n\n");
196 
197 	line = malloc(1024 * sizeof(char));
198 	reply = malloc(4096 * sizeof(char));
199 
200 	sockk = init();
201 	if (sockk == -1)
202 		FATAL("Can't connect to Speech Dispatcher");
203 
204 	assert(line != 0);
205 
206 	while (1) {
207 		ret = fgets(line, 1024, test_file);
208 		if (ret == NULL)
209 			break;
210 		if (strlen(line) <= 1) {
211 			printf("\n");
212 			continue;
213 		}
214 
215 		if (line[0] == '@') {
216 			command = (char *)strtok(line, "@\r\n");
217 			if (command == NULL)
218 				printf("\n");
219 			else
220 				printf("  %s\n", command);
221 			continue;
222 		}
223 
224 		if (line[0] == '!') {
225 			command = (char *)strtok(line, "!\r\n");
226 			strcat(command, "\r\n");
227 			if (command == NULL)
228 				continue;
229 
230 			printf("     >> %s", command);
231 			fflush(NULL);
232 			reply = send_data(sockk, command, 1);
233 			printf("     < %s", reply);
234 			fflush(NULL);
235 			continue;
236 		}
237 
238 		if (line[0] == '.') {
239 			reply = send_data(sockk, "\r\n.\r\n", 1);
240 			printf("       < %s", reply);
241 			continue;
242 		}
243 
244 		if (line[0] == '+') {
245 			command = (char *)strtok(&(line[1]), "+\r\n");
246 			wait_for(sockk, command);
247 			continue;
248 		}
249 
250 		if (line[0] == '$') {
251 			if (delays) {
252 				command = (char *)strtok(&(line[1]), "$\r\n");
253 				sleep(atoi(command));
254 			}
255 			continue;
256 		}
257 
258 		if (line[0] == '^') {
259 			if (delays) {
260 				command = (char *)strtok(&(line[1]), "$\r\n");
261 				usleep(atol(command));
262 			}
263 			continue;
264 		}
265 
266 		if (line[0] == '~') {
267 			command = (char *)strtok(line, "~\r\n");
268 			indent = atoi(command);
269 			continue;
270 		}
271 
272 		if (line[0] == '?') {
273 			getc(stdin);
274 			continue;
275 		}
276 
277 		if (line[0] == '*') {
278 			int ret = system("clear");
279 			if (ret == -1)
280 				FATAL("Could not execute subprocess");
281 			for (i = 0; i <= indent - 1; i++) {
282 				printf("\n");
283 			}
284 			continue;
285 		}
286 
287 		if (line[0] == '#') {
288 			/* Comment */
289 			continue;
290 		}
291 
292 		send_data(sockk, line, 0);
293 		printf("     >> %s", line);
294 	}
295 
296 	close(sockk);
297 
298 	printf("\n==================\n");
299 	printf("End of the test.\n");
300 	exit(0);
301 }
302