1 /*
2   libspeechd.c - Shared library for easy acces to Speech Dispatcher functions
3  *
4  * Copyright (C) 2001, 2002, 2003, 2006, 2007, 2008 Brailcom, o.p.s.
5  *
6  * This is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation; either version 2.1, or (at your option)
9  * any later version.
10  *
11  * This software is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
18  *
19  * $Id: libspeechd.c,v 1.37 2008-12-23 09:15:32 pdm Exp $
20  */
21 
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 
26 #include <sys/types.h>
27 #include <wchar.h>
28 #include <sys/socket.h>
29 #include <netinet/tcp.h>
30 #include <netinet/in.h>
31 #include <sys/un.h>
32 #include <arpa/inet.h>
33 #include <unistd.h>
34 
35 #include <stdio.h>
36 #include <string.h>
37 #include <stdlib.h>
38 #include <stdarg.h>
39 #include <string.h>
40 #include <ctype.h>
41 #include <glib.h>
42 #include <errno.h>
43 #include <assert.h>
44 #include <netdb.h>
45 
46 /*
47  * This is needed because speechd_types.h is in a different location in
48  * the source tree's include directory than it will be when it is
49  * installed on the user's system.
50  */
51 #include <speechd_types.h>
52 #include <speechd_defines.h>
53 #include "libspeechd.h"
54 
55 /* Comment/uncomment to switch debugging on/off */
56 // #define LIBSPEECHD_DEBUG 1
57 
58 /* Unless there is an fatal error, it doesn't print anything */
59 #define SPD_FATAL(msg) { printf("Fatal error (libspeechd) [%s:%d]:"msg, __FILE__, __LINE__); fflush(stdout); exit(EXIT_FAILURE); }
60 
61 /* --------------  Private functions headers ------------------------*/
62 
63 #ifdef LIBSPEECHD_DEBUG
64 static FILE *spd_debug = NULL;
65 #endif
66 
67 static int spd_set_priority(SPDConnection * connection, SPDPriority priority);
68 static char *escape_dot(const char *text);
69 static int isanum(char *str);
70 static char *get_reply(SPDConnection * connection);
71 static int get_err_code(char *reply);
72 static char *get_param_str(char *reply, int num, int *err);
73 static int get_param_int(char *reply, int num, int *err);
74 static int ret_ok(char *reply);
75 static void SPD_DBG(char *format, ...);
76 static void *spd_events_handler(void *);
77 
78 const int range_low = -100;
79 const int range_high = 100;
80 
81 pthread_mutex_t spd_logging_mutex;
82 
83 struct SPDConnection_threaddata {
84 	pthread_t events_thread;
85 	pthread_cond_t cond_reply_ready;
86 	pthread_mutex_t mutex_reply_ready;
87 	pthread_cond_t cond_reply_ack;
88 	pthread_mutex_t mutex_reply_ack;
89 };
90 
91 /*
92  * Added by Willie Walker - strndup and getline were GNU libc extensions
93  * that were adopted in the POSIX.1-2008 standard, but are not yet found
94  * on all systems.
95  */
96 #ifndef HAVE_STRNDUP
strndup(const char * s,size_t n)97 char *strndup(const char *s, size_t n)
98 {
99 	size_t nAvail;
100 	char *p;
101 
102 	if (!s)
103 		return 0;
104 
105 	if (strlen(s) > n)
106 		nAvail = n + 1;
107 	else
108 		nAvail = strlen(s) + 1;
109 	p = malloc(nAvail);
110 	memcpy(p, s, nAvail);
111 	p[nAvail - 1] = '\0';
112 
113 	return p;
114 }
115 #endif /* HAVE_STRNDUP */
116 
117 #ifndef HAVE_GETLINE
118 #define BUFFER_LEN 256
getline(char ** lineptr,size_t * n,FILE * f)119 ssize_t getline(char **lineptr, size_t * n, FILE * f)
120 {
121 	int ch;
122 	size_t m = 0;
123 	ssize_t buf_len = 0;
124 	char *buf = NULL;
125 	char *p = NULL;
126 
127 	if (errno != 0) {
128 		SPD_DBG("getline: errno came in as %d!!!\n", errno);
129 		errno = 0;
130 	}
131 	while ((ch = getc(f)) != EOF) {
132 		if (errno != 0)
133 			return -1;
134 		if (m++ >= buf_len) {
135 			buf_len += BUFFER_LEN;
136 			buf = (char *)realloc(buf, buf_len + 1);
137 			if (buf == NULL) {
138 				SPD_DBG("buf==NULL");
139 				return -1;
140 			}
141 			p = buf + buf_len - BUFFER_LEN;
142 		}
143 		*p = ch;
144 		p++;
145 		if (ch == '\n')
146 			break;
147 	}
148 	if (m == 0) {
149 		SPD_DBG("getline: m=%d!", m);
150 		return -1;
151 	} else {
152 		*p = '\0';
153 		*lineptr = buf;
154 		*n = m;
155 		return m;
156 	}
157 }
158 #endif /* HAVE_GETLINE */
159 
160 /* --------------------- Public functions ------------------------- */
161 
162 #define SPD_REPLY_BUF_SIZE 65536
163 
164 /* Determine address for the unix socket */
_get_default_unix_socket_name(void)165 static char *_get_default_unix_socket_name(void)
166 {
167 	GString *socket_filename;
168 	char *h;
169 	const char *rundir = g_get_user_runtime_dir();
170 	socket_filename = g_string_new("");
171 	g_string_printf(socket_filename, "%s/speech-dispatcher/speechd.sock",
172 			rundir);
173 	// Do not return glib string, but glibc string...
174 	h = strdup(socket_filename->str);
175 	g_string_free(socket_filename, 1);
176 	return h;
177 }
178 
SPDConnectionAddress__free(SPDConnectionAddress * address)179 void SPDConnectionAddress__free(SPDConnectionAddress * address)
180 {
181 	if (!address)
182 		return;
183 	free(address->unix_socket_name);
184 	free(address->inet_socket_host);
185 	free(address->dbus_bus);
186 	free(address);
187 }
188 
spd_get_default_address(char ** error)189 SPDConnectionAddress *spd_get_default_address(char **error)
190 {
191 	const gchar *env_address = g_getenv("SPEECHD_ADDRESS");
192 	gchar **pa;		/* parsed address */
193 	SPDConnectionAddress *address = malloc(sizeof(SPDConnectionAddress));
194 	address->unix_socket_name = NULL;
195 	address->inet_socket_host = NULL;
196 	address->dbus_bus = NULL;
197 
198 	if (env_address == NULL) {	// Default method = unix sockets
199 		address->method = SPD_METHOD_UNIX_SOCKET;
200 		address->unix_socket_name = _get_default_unix_socket_name();
201 	} else {
202 		pa = g_strsplit(env_address, ":", 0);
203 		assert(pa);
204 		if (!g_strcmp0(pa[0], "unix_socket") || pa[0] == NULL) {	// Unix sockets
205 			address->method = SPD_METHOD_UNIX_SOCKET;
206 			if (pa[1] == NULL) {
207 				address->unix_socket_name =
208 				    _get_default_unix_socket_name();
209 			} else {
210 				address->unix_socket_name = strdup(pa[1]);
211 			}
212 		} else if (!g_strcmp0(pa[0], "inet_socket")) {	// Inet sockets
213 			address->method = SPD_METHOD_INET_SOCKET;
214 			if (pa[1] == NULL) {
215 				address->inet_socket_host = strdup("127.0.0.1");
216 				address->inet_socket_port = 6560;
217 			} else {
218 				address->inet_socket_host = strdup(pa[1]);
219 				if (pa[2] == NULL) {
220 					address->inet_socket_port =
221 					    SPEECHD_DEFAULT_PORT;
222 				} else {
223 					address->inet_socket_port = atoi(pa[2]);
224 				}
225 			}
226 		} else {	// Unknown or unsupported method requested
227 			*error =
228 			    strdup
229 			    ("Unknown or unsupported communication method");
230 			SPDConnectionAddress__free(address);
231 			address = NULL;
232 		}
233 		g_strfreev(pa);
234 	}
235 	return address;
236 }
237 
_init_debug(void)238 static void _init_debug(void)
239 {
240 #ifdef LIBSPEECHD_DEBUG
241 	if (!spd_debug) {
242 		spd_debug = fopen("/tmp/libspeechd.log", "w");
243 		if (spd_debug == NULL)
244 			SPD_FATAL("COULDN'T ACCES FILE INTENDED FOR DEBUG");
245 
246 		if (pthread_mutex_init(&spd_logging_mutex, NULL)) {
247 			fprintf(stderr, "Mutex initialization failed");
248 			fflush(stderr);
249 			exit(1);
250 		}
251 		SPD_DBG("Debugging started");
252 	}
253 #endif /* LIBSPEECHD_DEBUG */
254 }
255 
256 /* Opens a new Speech Dispatcher connection.
257  * Returns socket file descriptor of the created connection
258  * or -1 if no connection was opened. */
259 
spd_open(const char * client_name,const char * connection_name,const char * user_name,SPDConnectionMode mode)260 SPDConnection *spd_open(const char *client_name, const char *connection_name,
261 			const char *user_name, SPDConnectionMode mode)
262 {
263 	char *error;
264 	int autospawn = 1;
265 	SPDConnection *conn;
266 	conn = spd_open2(client_name, connection_name, user_name,
267 			 mode, NULL, autospawn, &error);
268 	if (!conn) {
269 		_init_debug();
270 		assert(error);
271 		SPD_DBG("Could not connect to Speech Dispatcher: %s", error);
272 		free(error);
273 	}
274 	return conn;
275 }
276 
277 #define MAX_IP_SIZE 16+1
278 /* TODO: This only works in IPV4 */
resolve_host(char * host_name_or_ip,int * is_localhost,gchar ** error)279 static char *resolve_host(char *host_name_or_ip, int *is_localhost,
280 			  gchar ** error)
281 {
282 	struct addrinfo *addr_result;
283 	int err;
284 	char *resolve_buffer = malloc(MAX_IP_SIZE * sizeof(char));
285 	const char *resolved_ip = NULL;
286 	char *ip;
287 	*error = NULL;
288 	struct sockaddr_in *addr_in;
289 
290 	if (resolve_buffer == NULL) {
291 		*error = g_strdup("Failed to allocate memory.");
292 		return NULL;
293 	}
294 
295 	err = getaddrinfo(host_name_or_ip, 0, NULL, &addr_result);
296 	if (err) {
297 		*error =
298 		    g_strdup_printf("Can't resolve address %d due to error %s:",
299 				    err, gai_strerror(err));
300 		free(resolve_buffer);
301 		return NULL;
302 	}
303 	/* Take the first address returned as we are only interested in host ip */
304 	addr_in = (struct sockaddr_in *)addr_result->ai_addr;
305 	resolved_ip =
306 	    inet_ntop(AF_INET, &(addr_in->sin_addr.s_addr), resolve_buffer,
307 		      MAX_IP_SIZE);
308 	if (resolved_ip == NULL) {
309 		*error =
310 		    g_strdup_printf
311 		    ("Could not convert address, due to the following error: %s",
312 		     strerror(errno));
313 		freeaddrinfo(addr_result);
314 		free(resolve_buffer);
315 		return NULL;
316 	}
317 
318 	if (!strncmp(resolved_ip, "127.", 4)) {
319 		*is_localhost = 1;
320 		/* In case of local addresses, use 127.0.0.1 which is guaranteed
321 		   to be local and the server listens on it */
322 		free(resolve_buffer);
323 		ip = strdup("127.0.0.1");
324 	} else {
325 		*is_localhost = 0;
326 		ip = resolve_buffer;
327 	}
328 	freeaddrinfo(addr_result);
329 	return ip;
330 }
331 
332 static int
spawn_server(SPDConnectionAddress * address,int is_localhost,gchar ** spawn_error)333 spawn_server(SPDConnectionAddress * address, int is_localhost,
334 	     gchar ** spawn_error)
335 {
336 	gchar *speechd_cmd[16];
337 	gchar *stderr_output;
338 	gboolean spawn_ok;
339 	GError *gerror = NULL;
340 	int exit_status;
341 	int i;
342 
343 	if ((address->method == SPD_METHOD_INET_SOCKET) && (!is_localhost)) {
344 		*spawn_error =
345 		    g_strdup
346 		    ("Spawn failed, the given network address doesn't seem to be on localhost");
347 		return 1;
348 	}
349 
350 	speechd_cmd[0] = g_strdup(SPD_SPAWN_CMD);
351 	speechd_cmd[1] = g_strdup("--spawn");
352 	speechd_cmd[2] = g_strdup("--communication-method");
353 	if (address->method == SPD_METHOD_INET_SOCKET) {
354 		speechd_cmd[3] = g_strdup("inet_socket");
355 		speechd_cmd[4] = g_strdup("--port");
356 		speechd_cmd[5] =
357 		    g_strdup_printf("%d", address->inet_socket_port);
358 		speechd_cmd[6] = NULL;
359 	} else if (address->method == SPD_METHOD_UNIX_SOCKET) {
360 		speechd_cmd[3] = g_strdup("unix_socket");
361 		speechd_cmd[4] = g_strdup("--socket-path");
362 		speechd_cmd[5] =
363 		    g_strdup_printf("%s", address->unix_socket_name);
364 		speechd_cmd[6] = NULL;
365 	} else
366 		assert(0);
367 
368 	spawn_ok =
369 	    g_spawn_sync(NULL, (gchar **) speechd_cmd, NULL,
370 			 G_SPAWN_SEARCH_PATH | G_SPAWN_STDOUT_TO_DEV_NULL, NULL,
371 			 NULL, NULL, &stderr_output, &exit_status, &gerror);
372 	for (i = 0; speechd_cmd[i] != NULL; i++)
373 		g_free(speechd_cmd[i]);
374 	if (!spawn_ok) {
375 		*spawn_error =
376 		    g_strdup_printf("Autospawn failed. Spawn error %d: %s",
377 				    gerror->code, gerror->message);
378 		return 1;
379 	} else {
380 		if (exit_status) {
381 			*spawn_error =
382 			    g_strdup_printf
383 			    ("Autospawn failed. Speech Dispatcher refused to start with error code, "
384 			     "stating this as a reason: %s", stderr_output);
385 			return 1;
386 		} else {
387 			*spawn_error = NULL;
388 			return 0;
389 		}
390 	}
391 	assert(0);
392 }
393 
spd_open2(const char * client_name,const char * connection_name,const char * user_name,SPDConnectionMode mode,SPDConnectionAddress * address,int autospawn,char ** error_result)394 SPDConnection *spd_open2(const char *client_name, const char *connection_name,
395 			 const char *user_name, SPDConnectionMode mode,
396 			 SPDConnectionAddress * address, int autospawn,
397 			 char **error_result)
398 {
399 	SPDConnection *connection = NULL;
400 	SPDConnectionAddress *defaultAddress = NULL;
401 	char *set_client_name = NULL;
402 	char *conn_name = NULL;
403 	char *usr_name = NULL;
404 	int ret;
405 	int tcp_no_delay = 1;
406 
407 	/* Autospawn related */
408 	int spawn_err;
409 	gchar *spawn_report;
410 	char *host_ip;
411 	int is_localhost = 1;
412 
413 	struct sockaddr_in address_inet;
414 	struct sockaddr_un address_unix;
415 	struct sockaddr *sock_address;
416 	size_t sock_address_len;
417 
418 	_init_debug();
419 
420 	if (client_name == NULL) {
421 		*error_result = strdup("ERROR: Client name not specified");
422 		SPD_DBG(*error_result);
423 		return NULL;
424 	}
425 
426 	if (user_name == NULL) {
427 		usr_name = strdup((char *)g_get_user_name());
428 	} else
429 		usr_name = strdup(user_name);
430 
431 	if (connection_name == NULL)
432 		conn_name = strdup("main");
433 	else
434 		conn_name = strdup(connection_name);
435 
436 	if (address == NULL) {
437 		char *err = NULL;
438 		defaultAddress = spd_get_default_address(&err);
439 		address = defaultAddress;
440 		if (!address) {
441 			assert(err);
442 			*error_result = err;
443 			SPD_DBG(*error_result);
444 			goto out;
445 		}
446 	}
447 
448 	/* Connect to server using the selected method */
449 	connection = malloc(sizeof(SPDConnection));
450 	if (address->method == SPD_METHOD_INET_SOCKET) {
451 		gchar *resolve_error;
452 		host_ip =
453 		    resolve_host(address->inet_socket_host, &is_localhost,
454 				 &resolve_error);
455 		if (host_ip == NULL) {
456 			*error_result = strdup(resolve_error);
457 			g_free(resolve_error);
458 			free(connection);
459 			connection = NULL;
460 			goto out;
461 		}
462 		address_inet.sin_addr.s_addr = inet_addr(host_ip);
463 		free(host_ip);
464 		address_inet.sin_port = htons(address->inet_socket_port);
465 		address_inet.sin_family = AF_INET;
466 		connection->socket = socket(AF_INET, SOCK_STREAM, 0);
467 		sock_address = (struct sockaddr *)&address_inet;
468 		sock_address_len = sizeof(address_inet);
469 	} else if (address->method == SPD_METHOD_UNIX_SOCKET) {
470 		/* Create the unix socket */
471 		address_unix.sun_family = AF_UNIX;
472 		strncpy(address_unix.sun_path, address->unix_socket_name,
473 			sizeof(address_unix.sun_path));
474 		address_unix.sun_path[sizeof(address_unix.sun_path) - 1] = '\0';
475 		connection->socket = socket(AF_UNIX, SOCK_STREAM, 0);
476 		sock_address = (struct sockaddr *)&address_unix;
477 		sock_address_len = SUN_LEN(&address_unix);
478 	} else
479 		SPD_FATAL("Unsupported connection method for spd_open2()");
480 
481 	if (connection->socket < 0) {
482 		free(connection);
483 		connection = NULL;
484 		goto out;
485 	}
486 	ret = connect(connection->socket, sock_address, sock_address_len);
487 	if (ret == -1) {
488 		/* Suppose server might not be running, try to autospawn (autostart) it */
489 		if (autospawn) {
490 			spawn_err =
491 			    spawn_server(address, is_localhost, &spawn_report);
492 			if (!spawn_err)
493 				spawn_report =
494 				    g_strdup("Server successfully autospawned");
495 			ret =
496 			    connect(connection->socket, sock_address,
497 				    sock_address_len);
498 		} else {
499 			spawn_report = g_strdup("Autospawn disabled");
500 		}
501 		if (ret == -1) {
502 			if (address->method == SPD_METHOD_INET_SOCKET)
503 				*error_result =
504 				    g_strdup_printf
505 				    ("Error: Can't connect to %s on port %d using inet sockets: %s. "
506 				     "Autospawn: %s", address->inet_socket_host,
507 				     address->inet_socket_port, strerror(errno),
508 				     spawn_report);
509 			else if (address->method == SPD_METHOD_UNIX_SOCKET)
510 				*error_result =
511 				    g_strdup_printf
512 				    ("Error: Can't connect to unix socket %s: %s. Autospawn: %s",
513 				     address->unix_socket_name, strerror(errno),
514 				     spawn_report);
515 			else
516 				assert(0);
517 			SPD_DBG(*error_result);
518 			close(connection->socket);
519 			free(connection);
520 			connection = NULL;
521 			goto out;
522 		}
523 		g_free(spawn_report);
524 	}
525 
526 	if (address->method == SPD_METHOD_INET_SOCKET)
527 		setsockopt(connection->socket, IPPROTO_TCP, TCP_NODELAY,
528 			   &tcp_no_delay, sizeof(int));
529 
530 	connection->callback_begin = NULL;
531 	connection->callback_end = NULL;
532 	connection->callback_im = NULL;
533 	connection->callback_pause = NULL;
534 	connection->callback_resume = NULL;
535 	connection->callback_cancel = NULL;
536 
537 	connection->mode = mode;
538 
539 	/* Create a stream from the socket */
540 	connection->stream = fdopen(connection->socket, "r");
541 	if (!connection->stream)
542 		SPD_FATAL("Can't create a stream for socket, fdopen() failed.");
543 	/* Switch to line buffering mode */
544 	ret = setvbuf(connection->stream, NULL, _IONBF, SPD_REPLY_BUF_SIZE);
545 	if (ret)
546 		SPD_FATAL("Can't set buffering, setvbuf failed.");
547 
548 	pthread_mutex_init(&connection->ssip_mutex, NULL);
549 
550 	if (mode == SPD_MODE_THREADED) {
551 		SPD_DBG
552 		    ("Initializing threads, condition variables and mutexes...");
553 		connection->td = malloc(sizeof(*connection->td));
554 		pthread_cond_init(&connection->td->cond_reply_ready, NULL);
555 		pthread_mutex_init(&connection->td->mutex_reply_ready, NULL);
556 		pthread_cond_init(&connection->td->cond_reply_ack, NULL);
557 		pthread_mutex_init(&connection->td->mutex_reply_ack, NULL);
558 		ret =
559 		    pthread_create(&connection->td->events_thread, NULL,
560 				   spd_events_handler, connection);
561 		if (ret != 0) {
562 			*error_result = strdup("Thread initialization failed");
563 			SPD_DBG(*error_result);
564 			fclose(connection->stream);
565 			close(connection->socket);
566 			free(connection);
567 			connection = NULL;
568 			goto out;
569 		}
570 	}
571 
572 	/* By now, the connection is created and operational */
573 	set_client_name =
574 	    g_strdup_printf("SET SELF CLIENT_NAME \"%s:%s:%s\"", usr_name,
575 			    client_name, conn_name);
576 	ret = spd_execute_command_wo_mutex(connection, set_client_name);
577 
578 out:
579 	free(usr_name);
580 	free(conn_name);
581 	free(set_client_name);
582 	SPDConnectionAddress__free(defaultAddress);
583 	return connection;
584 }
585 
586 #define RET(r) \
587 	{ \
588 		pthread_mutex_unlock(&connection->ssip_mutex); \
589 		return r; \
590 	}
591 
592 /* Get the client id of the connection */
spd_get_client_id(SPDConnection * connection)593 int spd_get_client_id(SPDConnection * connection)
594 {
595 	int ret;
596 	int err;
597 	char *reply = NULL;
598 	spd_execute_command_with_reply(connection, "HISTORY GET CLIENT_ID", &reply);
599 	ret = get_param_int(reply, 1, &err);
600 	free(reply);
601 	return ret;
602 }
603 
604 /* Close a Speech Dispatcher connection */
spd_close(SPDConnection * connection)605 void spd_close(SPDConnection * connection)
606 {
607 
608 	pthread_mutex_lock(&connection->ssip_mutex);
609 
610 	if (connection->mode == SPD_MODE_THREADED) {
611 		pthread_cancel(connection->td->events_thread);
612 		pthread_mutex_destroy(&connection->td->mutex_reply_ready);
613 		pthread_mutex_destroy(&connection->td->mutex_reply_ack);
614 		pthread_cond_destroy(&connection->td->cond_reply_ready);
615 		pthread_cond_destroy(&connection->td->cond_reply_ack);
616 		pthread_join(connection->td->events_thread, NULL);
617 		connection->mode = SPD_MODE_SINGLE;
618 		free(connection->td);
619 	}
620 
621 	/* close the socket */
622 	close(connection->socket);
623 
624 	pthread_mutex_unlock(&connection->ssip_mutex);
625 
626 	pthread_mutex_destroy(&connection->ssip_mutex);
627 	free(connection);
628 }
629 
630 /* Helper functions for spd_say. */
631 static inline int
spd_say_prepare(SPDConnection * connection,SPDPriority priority,const char * text,char ** escaped_text)632 spd_say_prepare(SPDConnection * connection, SPDPriority priority,
633 		const char *text, char **escaped_text)
634 {
635 	int ret = 0;
636 
637 	SPD_DBG("Text to say is: %s", text);
638 
639 	/* Insure that there is no escape sequence in the text */
640 	*escaped_text = escape_dot(text);
641 	/* Caller is now responsible for escaped_text. */
642 	if (*escaped_text == NULL) {	/* Out of memory. */
643 		SPD_DBG("spd_say could not allocate memory.");
644 		ret = -1;
645 	} else {
646 		/* Set priority */
647 		SPD_DBG("Setting priority");
648 		ret = spd_set_priority(connection, priority);
649 		if (!ret) {
650 			/* Start the data flow */
651 			SPD_DBG("Sending SPEAK");
652 			ret = spd_execute_command_wo_mutex(connection, "speak");
653 			if (ret) {
654 				SPD_DBG("Error: Can't start data flow!");
655 			}
656 		}
657 	}
658 
659 	return ret;
660 }
661 
spd_say_sending(SPDConnection * connection,const char * text)662 static inline int spd_say_sending(SPDConnection * connection, const char *text)
663 {
664 	int msg_id = -1;
665 	int err = 0;
666 	char *reply = NULL;
667 	char *pret = NULL;
668 
669 	/* Send data */
670 	SPD_DBG("Sending data");
671 	pret = spd_send_data_wo_mutex(connection, text, SPD_NO_REPLY);
672 	if (pret == NULL) {
673 		SPD_DBG("Can't send data wo mutex");
674 	} else {
675 		/* Terminate data flow */
676 		SPD_DBG("Terminating data flow");
677 		err =
678 		    spd_execute_command_with_reply(connection, "\r\n.", &reply);
679 		if (err) {
680 			SPD_DBG("Can't terminate data flow");
681 		} else {
682 			msg_id = get_param_int(reply, 1, &err);
683 			if (err < 0) {
684 				SPD_DBG
685 				    ("Can't determine SSIP message unique ID parameter.");
686 				msg_id = -1;
687 			}
688 		}
689 	}
690 
691 	free(reply);
692 	free(pret);
693 	return msg_id;
694 }
695 
696 /* Say TEXT with priority PRIORITY.
697  * Returns msg_uid on success, -1 otherwise. */
spd_say(SPDConnection * connection,SPDPriority priority,const char * text)698 int spd_say(SPDConnection * connection, SPDPriority priority, const char *text)
699 {
700 	char *escaped_text = NULL;
701 	int msg_id = -1;
702 	int prepare_failed = 0;
703 
704 	if (text != NULL) {
705 		pthread_mutex_lock(&connection->ssip_mutex);
706 
707 		prepare_failed =
708 		    spd_say_prepare(connection, priority, text, &escaped_text);
709 		if (!prepare_failed)
710 			msg_id = spd_say_sending(connection, escaped_text);
711 
712 		free(escaped_text);
713 		pthread_mutex_unlock(&connection->ssip_mutex);
714 	} else {
715 		SPD_DBG("spd_say called with a NULL argument for <text>");
716 	}
717 
718 	SPD_DBG("Returning from spd_say");
719 	return msg_id;
720 }
721 
722 /* The same as spd_say, accepts also formated strings */
723 int
spd_sayf(SPDConnection * connection,SPDPriority priority,const char * format,...)724 spd_sayf(SPDConnection * connection, SPDPriority priority, const char *format,
725 	 ...)
726 {
727 	static int ret;
728 	va_list args;
729 	char *buf;
730 
731 	if (format == NULL)
732 		return -1;
733 
734 	/* Print the text to buffer */
735 	va_start(args, format);
736 	buf = g_strdup_vprintf(format, args);
737 	va_end(args);
738 
739 	/* Send the buffer to Speech Dispatcher */
740 	ret = spd_say(connection, priority, buf);
741 	free(buf);
742 
743 	return ret;
744 }
745 
spd_stop(SPDConnection * connection)746 int spd_stop(SPDConnection * connection)
747 {
748 	return spd_execute_command(connection, "STOP SELF");
749 }
750 
spd_stop_all(SPDConnection * connection)751 int spd_stop_all(SPDConnection * connection)
752 {
753 	return spd_execute_command(connection, "STOP ALL");
754 }
755 
spd_stop_uid(SPDConnection * connection,int target_uid)756 int spd_stop_uid(SPDConnection * connection, int target_uid)
757 {
758 	static char command[16];
759 
760 	sprintf(command, "STOP %d", target_uid);
761 	return spd_execute_command(connection, command);
762 }
763 
spd_cancel(SPDConnection * connection)764 int spd_cancel(SPDConnection * connection)
765 {
766 	return spd_execute_command(connection, "CANCEL SELF");
767 }
768 
spd_cancel_all(SPDConnection * connection)769 int spd_cancel_all(SPDConnection * connection)
770 {
771 	return spd_execute_command(connection, "CANCEL ALL");
772 }
773 
spd_cancel_uid(SPDConnection * connection,int target_uid)774 int spd_cancel_uid(SPDConnection * connection, int target_uid)
775 {
776 	static char command[16];
777 
778 	sprintf(command, "CANCEL %d", target_uid);
779 	return spd_execute_command(connection, command);
780 }
781 
spd_pause(SPDConnection * connection)782 int spd_pause(SPDConnection * connection)
783 {
784 	return spd_execute_command(connection, "PAUSE SELF");
785 }
786 
spd_pause_all(SPDConnection * connection)787 int spd_pause_all(SPDConnection * connection)
788 {
789 	return spd_execute_command(connection, "PAUSE ALL");
790 }
791 
spd_pause_uid(SPDConnection * connection,int target_uid)792 int spd_pause_uid(SPDConnection * connection, int target_uid)
793 {
794 	char command[16];
795 
796 	sprintf(command, "PAUSE %d", target_uid);
797 	return spd_execute_command(connection, command);
798 }
799 
spd_resume(SPDConnection * connection)800 int spd_resume(SPDConnection * connection)
801 {
802 	return spd_execute_command(connection, "RESUME SELF");
803 }
804 
spd_resume_all(SPDConnection * connection)805 int spd_resume_all(SPDConnection * connection)
806 {
807 	return spd_execute_command(connection, "RESUME ALL");
808 }
809 
spd_resume_uid(SPDConnection * connection,int target_uid)810 int spd_resume_uid(SPDConnection * connection, int target_uid)
811 {
812 	static char command[16];
813 
814 	sprintf(command, "RESUME %d", target_uid);
815 	return spd_execute_command(connection, command);
816 }
817 
818 int
spd_key(SPDConnection * connection,SPDPriority priority,const char * key_name)819 spd_key(SPDConnection * connection, SPDPriority priority, const char *key_name)
820 {
821 	char *command_key;
822 	int ret;
823 
824 	if (key_name == NULL)
825 		return -1;
826 
827 	pthread_mutex_lock(&connection->ssip_mutex);
828 
829 	ret = spd_set_priority(connection, priority);
830 	if (ret)
831 		RET(-1);
832 
833 	command_key = g_strdup_printf("KEY %s", key_name);
834 	ret = spd_execute_command_wo_mutex(connection, command_key);
835 	free(command_key);
836 	if (ret)
837 		RET(-1);
838 
839 	pthread_mutex_unlock(&connection->ssip_mutex);
840 
841 	return 0;
842 }
843 
844 int
spd_char(SPDConnection * connection,SPDPriority priority,const char * character)845 spd_char(SPDConnection * connection, SPDPriority priority,
846 	 const char *character)
847 {
848 	static char command[16];
849 	int ret;
850 
851 	if (character == NULL)
852 		return -1;
853 	if (strlen(character) > 6)
854 		return -1;
855 
856 	pthread_mutex_lock(&connection->ssip_mutex);
857 
858 	ret = spd_set_priority(connection, priority);
859 	if (ret)
860 		RET(-1);
861 
862 	sprintf(command, "CHAR %s", character);
863 	ret = spd_execute_command_wo_mutex(connection, command);
864 	if (ret)
865 		RET(-1);
866 
867 	pthread_mutex_unlock(&connection->ssip_mutex);
868 
869 	return 0;
870 }
871 
872 int
spd_wchar(SPDConnection * connection,SPDPriority priority,wchar_t wcharacter)873 spd_wchar(SPDConnection * connection, SPDPriority priority, wchar_t wcharacter)
874 {
875 	static char command[16];
876 	char character[8];
877 	int ret;
878 
879 	pthread_mutex_lock(&connection->ssip_mutex);
880 
881 	ret = wcrtomb(character, wcharacter, NULL);
882 	if (ret <= 0)
883 		RET(-1);
884 
885 	ret = spd_set_priority(connection, priority);
886 	if (ret)
887 		RET(-1);
888 
889 	assert(character != NULL);
890 	sprintf(command, "CHAR %s", character);
891 	ret = spd_execute_command_wo_mutex(connection, command);
892 	if (ret)
893 		RET(-1);
894 
895 	pthread_mutex_unlock(&connection->ssip_mutex);
896 
897 	return 0;
898 }
899 
900 int
spd_sound_icon(SPDConnection * connection,SPDPriority priority,const char * icon_name)901 spd_sound_icon(SPDConnection * connection, SPDPriority priority,
902 	       const char *icon_name)
903 {
904 	char *command;
905 	int ret;
906 
907 	if (icon_name == NULL)
908 		return -1;
909 
910 	pthread_mutex_lock(&connection->ssip_mutex);
911 
912 	ret = spd_set_priority(connection, priority);
913 	if (ret)
914 		RET(-1);
915 
916 	command = g_strdup_printf("SOUND_ICON %s", icon_name);
917 	ret = spd_execute_command_wo_mutex(connection, command);
918 	free(command);
919 	if (ret)
920 		RET(-1);
921 
922 	pthread_mutex_unlock(&connection->ssip_mutex);
923 
924 	return 0;
925 }
926 
927 // Set functions for Punctuation
spd_w_set_punctuation(SPDConnection * connection,SPDPunctuation type,const char * who)928 int spd_w_set_punctuation(SPDConnection * connection, SPDPunctuation type,
929 			  const char *who)
930 {
931 	char command[32];
932 	int ret;
933 
934 	if (type == SPD_PUNCT_ALL)
935 		sprintf(command, "SET %s PUNCTUATION all", who);
936 	if (type == SPD_PUNCT_NONE)
937 		sprintf(command, "SET %s PUNCTUATION none", who);
938 	if (type == SPD_PUNCT_SOME)
939 		sprintf(command, "SET %s PUNCTUATION some", who);
940 	if (type == SPD_PUNCT_MOST)
941 		sprintf(command, "SET %s PUNCTUATION most", who);
942 
943 	ret = spd_execute_command(connection, command);
944 
945 	return ret;
946 }
947 
spd_set_punctuation(SPDConnection * connection,SPDPunctuation type)948 int spd_set_punctuation(SPDConnection * connection, SPDPunctuation type)
949 {
950 	return spd_w_set_punctuation(connection, type, SPD_SELF);
951 }
952 
spd_set_punctuation_all(SPDConnection * connection,SPDPunctuation type)953 int spd_set_punctuation_all(SPDConnection * connection, SPDPunctuation type)
954 {
955 	return spd_w_set_punctuation(connection, type, SPD_ALLCLIENTS);
956 }
957 
spd_set_punctuation_uid(SPDConnection * connection,SPDPunctuation type,unsigned int uid)958 int spd_set_punctuation_uid(SPDConnection * connection, SPDPunctuation type,
959 			    unsigned int uid)
960 {
961 	char who[8];
962 	sprintf(who, "%d", uid);
963 	return spd_w_set_punctuation(connection, type, who);
964 }
965 
966 // Set functions for Capital Letters
spd_w_set_capital_letters(SPDConnection * connection,SPDCapitalLetters type,const char * who)967 int spd_w_set_capital_letters(SPDConnection * connection,
968 			      SPDCapitalLetters type, const char *who)
969 {
970 	char command[64];
971 	int ret;
972 
973 	if (type == SPD_CAP_NONE)
974 		sprintf(command, "SET %s CAP_LET_RECOGN none", who);
975 	if (type == SPD_CAP_SPELL)
976 		sprintf(command, "SET %s CAP_LET_RECOGN spell", who);
977 	if (type == SPD_CAP_ICON)
978 		sprintf(command, "SET %s CAP_LET_RECOGN icon", who);
979 
980 	ret = spd_execute_command(connection, command);
981 
982 	return ret;
983 }
984 
spd_set_capital_letters(SPDConnection * connection,SPDCapitalLetters type)985 int spd_set_capital_letters(SPDConnection * connection, SPDCapitalLetters type)
986 {
987 	return spd_w_set_capital_letters(connection, type, SPD_SELF);
988 }
989 
spd_set_capital_letters_all(SPDConnection * connection,SPDCapitalLetters type)990 int spd_set_capital_letters_all(SPDConnection * connection,
991 				SPDCapitalLetters type)
992 {
993 	return spd_w_set_capital_letters(connection, type, SPD_ALLCLIENTS);
994 }
995 
spd_set_capital_letters_uid(SPDConnection * connection,SPDCapitalLetters type,unsigned int uid)996 int spd_set_capital_letters_uid(SPDConnection * connection,
997 				SPDCapitalLetters type, unsigned int uid)
998 {
999 	char who[8];
1000 	sprintf(who, "%d", uid);
1001 	return spd_w_set_capital_letters(connection, type, who);
1002 }
1003 
1004 // Set functions for Spelling
spd_w_set_spelling(SPDConnection * connection,SPDSpelling type,const char * who)1005 int spd_w_set_spelling(SPDConnection * connection, SPDSpelling type,
1006 		       const char *who)
1007 {
1008 	char command[32];
1009 	int ret;
1010 
1011 	if (type == SPD_SPELL_ON)
1012 		sprintf(command, "SET %s SPELLING on", who);
1013 	if (type == SPD_SPELL_OFF)
1014 		sprintf(command, "SET %s SPELLING off", who);
1015 
1016 	ret = spd_execute_command(connection, command);
1017 
1018 	return ret;
1019 }
1020 
spd_set_spelling(SPDConnection * connection,SPDSpelling type)1021 int spd_set_spelling(SPDConnection * connection, SPDSpelling type)
1022 {
1023 	return spd_w_set_spelling(connection, type, SPD_SELF);
1024 }
1025 
spd_set_spelling_all(SPDConnection * connection,SPDSpelling type)1026 int spd_set_spelling_all(SPDConnection * connection, SPDSpelling type)
1027 {
1028 	return spd_w_set_spelling(connection, type, SPD_ALLCLIENTS);
1029 }
1030 
spd_set_spelling_uid(SPDConnection * connection,SPDSpelling type,unsigned int uid)1031 int spd_set_spelling_uid(SPDConnection * connection, SPDSpelling type,
1032 			 unsigned int uid)
1033 {
1034 	char who[8];
1035 	sprintf(who, "%d", uid);
1036 	return spd_w_set_spelling(connection, type, who);
1037 }
1038 
spd_set_data_mode(SPDConnection * connection,SPDDataMode mode)1039 int spd_set_data_mode(SPDConnection * connection, SPDDataMode mode)
1040 {
1041 	char command[32];
1042 	int ret;
1043 
1044 	if (mode == SPD_DATA_TEXT)
1045 		sprintf(command, "SET SELF SSML_MODE off");
1046 	if (mode == SPD_DATA_SSML)
1047 		sprintf(command, "SET SELF SSML_MODE on");
1048 
1049 	ret = spd_execute_command(connection, command);
1050 
1051 	return ret;
1052 }
1053 
1054 // Set functions for Voice type
spd_w_set_voice_type(SPDConnection * connection,SPDVoiceType type,const char * who)1055 int spd_w_set_voice_type(SPDConnection * connection, SPDVoiceType type,
1056 			 const char *who)
1057 {
1058 	static char command[64];
1059 
1060 	switch (type) {
1061 	case SPD_MALE1:
1062 		sprintf(command, "SET %s VOICE_TYPE MALE1", who);
1063 		break;
1064 	case SPD_MALE2:
1065 		sprintf(command, "SET %s VOICE_TYPE MALE2", who);
1066 		break;
1067 	case SPD_MALE3:
1068 		sprintf(command, "SET %s VOICE_TYPE MALE3", who);
1069 		break;
1070 	case SPD_FEMALE1:
1071 		sprintf(command, "SET %s VOICE_TYPE FEMALE1", who);
1072 		break;
1073 	case SPD_FEMALE2:
1074 		sprintf(command, "SET %s VOICE_TYPE FEMALE2", who);
1075 		break;
1076 	case SPD_FEMALE3:
1077 		sprintf(command, "SET %s VOICE_TYPE FEMALE3", who);
1078 		break;
1079 	case SPD_CHILD_MALE:
1080 		sprintf(command, "SET %s VOICE_TYPE CHILD_MALE", who);
1081 		break;
1082 	case SPD_CHILD_FEMALE:
1083 		sprintf(command, "SET %s VOICE_TYPE CHILD_FEMALE", who);
1084 		break;
1085 	default:
1086 		return -1;
1087 	}
1088 
1089 	return spd_execute_command(connection, command);
1090 }
1091 
spd_set_voice_type(SPDConnection * connection,SPDVoiceType type)1092 int spd_set_voice_type(SPDConnection * connection, SPDVoiceType type)
1093 {
1094 	return spd_w_set_voice_type(connection, type, SPD_SELF);
1095 }
1096 
spd_set_voice_type_all(SPDConnection * connection,SPDVoiceType type)1097 int spd_set_voice_type_all(SPDConnection * connection, SPDVoiceType type)
1098 {
1099 	return spd_w_set_voice_type(connection, type, SPD_ALLCLIENTS);
1100 }
1101 
spd_set_voice_type_uid(SPDConnection * connection,SPDVoiceType type,unsigned int uid)1102 int spd_set_voice_type_uid(SPDConnection * connection, SPDVoiceType type,
1103 			   unsigned int uid)
1104 {
1105 	char who[8];
1106 	sprintf(who, "%d", uid);
1107 	return spd_w_set_voice_type(connection, type, who);
1108 }
1109 
1110 // Set function for Voice type
spd_get_voice_type(SPDConnection * connection)1111 SPDVoiceType spd_get_voice_type(SPDConnection * connection)
1112 {
1113 	char *command;
1114 	SPDVoiceType ret;
1115 	int err;
1116 	char *reply = NULL;
1117 	command = g_strdup_printf("GET voice_type");
1118 	spd_execute_command_with_reply(connection, command, &reply);
1119 	free(command);
1120 	ret = get_param_int(reply, 1, &err);
1121 	free(reply);
1122 	return ret;
1123 }
1124 
spd_w_set_command_int(SPDConnection * connection,const char * ssip_name,signed int val,const char * who)1125 static int spd_w_set_command_int(SPDConnection * connection,
1126 				 const char *ssip_name, signed int val,
1127 				 const char *who)
1128 {
1129 	static char command[64];
1130 	// NOTE: if any new int ssip_name are added that don't use -100 - 100 as their
1131 	// range, these values will need to become parameters (or the new ssip_name)
1132 	// methods will need to call a different helper method.
1133 	if (val < range_low || val > range_high)
1134 		return -1;
1135 	sprintf(command, "SET %s %s %d", who, ssip_name, val);
1136 	return spd_execute_command(connection, command);
1137 }
1138 
spd_get_command_int(SPDConnection * connection,const char * ssip_name)1139 static int spd_get_command_int(SPDConnection * connection,
1140 			       const char *ssip_name)
1141 {
1142 	char *command;
1143 	int ret = 0;
1144 	int err;
1145 	char *reply = NULL;
1146 	command = g_strdup_printf("GET %s", ssip_name);
1147 	spd_execute_command_with_reply(connection, command, &reply);
1148 	free(command);
1149 	ret = get_param_int(reply, 1, &err);
1150 	free(reply);
1151 	return ret;
1152 }
1153 
spd_w_set_command_str(SPDConnection * connection,const char * ssip_name,const char * str,const char * who)1154 static int spd_w_set_command_str(SPDConnection * connection,
1155 				 const char *ssip_name, const char *str,
1156 				 const char *who)
1157 {
1158 	char *command;
1159 	int ret;
1160 	if (str == NULL)
1161 		return -1;
1162 	command = g_strdup_printf("SET %s %s %s", who, ssip_name, str);
1163 	ret = spd_execute_command(connection, command);
1164 	free(command);
1165 	return ret;
1166 }
1167 
spd_get_command_str(SPDConnection * connection,const char * ssip_name)1168 static char *spd_get_command_str(SPDConnection * connection,
1169 				 const char *ssip_name)
1170 {
1171 	char *command;
1172 	char *ret = NULL;
1173 	int err;
1174 	char *reply = NULL;
1175 	command = g_strdup_printf("GET %s", ssip_name);
1176 	spd_execute_command_with_reply(connection, command, &reply);
1177 	free(command);
1178 	ret = get_param_str(reply, 1, &err);
1179 	free(reply);
1180 	return ret;
1181 }
1182 
1183 // Set functions for rate
spd_set_voice_rate(SPDConnection * connection,signed int rate)1184 int spd_set_voice_rate(SPDConnection * connection, signed int rate)
1185 {
1186 	return spd_w_set_command_int(connection, SPD_RATE, rate, SPD_SELF);
1187 }
1188 
spd_set_voice_rate_all(SPDConnection * connection,signed int rate)1189 int spd_set_voice_rate_all(SPDConnection * connection, signed int rate)
1190 {
1191 	return spd_w_set_command_int(connection, SPD_RATE, rate,
1192 				     SPD_ALLCLIENTS);
1193 }
1194 
spd_set_voice_rate_uid(SPDConnection * connection,signed int rate,unsigned int uid)1195 int spd_set_voice_rate_uid(SPDConnection * connection, signed int rate,
1196 			   unsigned int uid)
1197 {
1198 	char who[8];
1199 	sprintf(who, "%d", uid);
1200 	return spd_w_set_command_int(connection, SPD_RATE, rate, who);
1201 }
1202 
1203 // Get function for rate
spd_get_voice_rate(SPDConnection * connection)1204 int spd_get_voice_rate(SPDConnection * connection)
1205 {
1206 	return spd_get_command_int(connection, SPD_RATE);
1207 }
1208 
1209 // Set functions for pitch
spd_set_voice_pitch(SPDConnection * connection,signed int pitch)1210 int spd_set_voice_pitch(SPDConnection * connection, signed int pitch)
1211 {
1212 	return spd_w_set_command_int(connection, SPD_PITCH, pitch, SPD_SELF);
1213 }
1214 
spd_set_voice_pitch_all(SPDConnection * connection,signed int pitch)1215 int spd_set_voice_pitch_all(SPDConnection * connection, signed int pitch)
1216 {
1217 	return spd_w_set_command_int(connection, SPD_PITCH, pitch,
1218 				     SPD_ALLCLIENTS);
1219 }
1220 
spd_set_voice_pitch_uid(SPDConnection * connection,signed int pitch,unsigned int uid)1221 int spd_set_voice_pitch_uid(SPDConnection * connection, signed int pitch,
1222 			    unsigned int uid)
1223 {
1224 	char who[8];
1225 	sprintf(who, "%d", uid);
1226 	return spd_w_set_command_int(connection, SPD_PITCH, pitch, who);
1227 }
1228 
1229 // Get function for pitch
spd_get_voice_pitch(SPDConnection * connection)1230 int spd_get_voice_pitch(SPDConnection * connection)
1231 {
1232 	return spd_get_command_int(connection, SPD_PITCH);
1233 }
1234 
1235 // Set functions for pitch_range
spd_set_voice_pitch_range(SPDConnection * connection,signed int pitch_range)1236 int spd_set_voice_pitch_range(SPDConnection * connection,
1237 			      signed int pitch_range)
1238 {
1239 	return spd_w_set_command_int(connection, SPD_PITCH_RANGE, pitch_range,
1240 				     SPD_SELF);
1241 }
1242 
spd_set_voice_pitch_range_all(SPDConnection * connection,signed int pitch_range)1243 int spd_set_voice_pitch_range_all(SPDConnection * connection,
1244 				  signed int pitch_range)
1245 {
1246 	return spd_w_set_command_int(connection, SPD_PITCH, pitch_range,
1247 				     SPD_ALLCLIENTS);
1248 }
1249 
spd_set_voice_pitch_range_uid(SPDConnection * connection,signed int pitch_range,unsigned int uid)1250 int spd_set_voice_pitch_range_uid(SPDConnection * connection,
1251 				  signed int pitch_range, unsigned int uid)
1252 {
1253 	char who[8];
1254 	sprintf(who, "%d", uid);
1255 	return spd_w_set_command_int(connection, SPD_PITCH, pitch_range, who);
1256 }
1257 
1258 // Set functions for volume
spd_set_volume(SPDConnection * connection,signed int volume)1259 int spd_set_volume(SPDConnection * connection, signed int volume)
1260 {
1261 	return spd_w_set_command_int(connection, SPD_VOLUME, volume, SPD_SELF);
1262 }
1263 
spd_set_volume_all(SPDConnection * connection,signed int volume)1264 int spd_set_volume_all(SPDConnection * connection, signed int volume)
1265 {
1266 	return spd_w_set_command_int(connection, SPD_VOLUME, volume,
1267 				     SPD_ALLCLIENTS);
1268 }
1269 
spd_set_volume_uid(SPDConnection * connection,signed int volume,unsigned int uid)1270 int spd_set_volume_uid(SPDConnection * connection, signed int volume,
1271 		       unsigned int uid)
1272 {
1273 	char who[8];
1274 	sprintf(who, "%d", uid);
1275 	return spd_w_set_command_int(connection, SPD_VOLUME, volume, who);
1276 }
1277 
1278 // Get function for volume
spd_get_volume(SPDConnection * connection)1279 int spd_get_volume(SPDConnection * connection)
1280 {
1281 	return spd_get_command_int(connection, SPD_VOLUME);
1282 }
1283 
1284 // Set functions for language
spd_set_language(SPDConnection * connection,const char * language)1285 int spd_set_language(SPDConnection * connection, const char *language)
1286 {
1287 	return spd_w_set_command_str(connection, SPD_LANGUAGE, language,
1288 				     SPD_SELF);
1289 }
1290 
spd_set_language_all(SPDConnection * connection,const char * language)1291 int spd_set_language_all(SPDConnection * connection, const char *language)
1292 {
1293 	return spd_w_set_command_str(connection, SPD_LANGUAGE, language,
1294 				     SPD_ALLCLIENTS);
1295 }
1296 
spd_set_language_uid(SPDConnection * connection,const char * language,unsigned int uid)1297 int spd_set_language_uid(SPDConnection * connection, const char *language,
1298 			 unsigned int uid)
1299 {
1300 	char who[8];
1301 	sprintf(who, "%d", uid);
1302 	return spd_w_set_command_str(connection, SPD_LANGUAGE, language, who);
1303 }
1304 
1305 // Get function for language
spd_get_language(SPDConnection * connection)1306 char *spd_get_language(SPDConnection * connection)
1307 {
1308 	return spd_get_command_str(connection, SPD_LANGUAGE);
1309 }
1310 
1311 // Set functions for output_module
spd_set_output_module(SPDConnection * connection,const char * output_module)1312 int spd_set_output_module(SPDConnection * connection, const char *output_module)
1313 {
1314 	return spd_w_set_command_str(connection, SPD_OUTPUT_MODULE,
1315 				     output_module, SPD_SELF);
1316 }
1317 
spd_set_output_module_all(SPDConnection * connection,const char * output_module)1318 int spd_set_output_module_all(SPDConnection * connection,
1319 			      const char *output_module)
1320 {
1321 	return spd_w_set_command_str(connection, SPD_OUTPUT_MODULE,
1322 				     output_module, SPD_ALLCLIENTS);
1323 }
1324 
spd_set_output_module_uid(SPDConnection * connection,const char * output_module,unsigned int uid)1325 int spd_set_output_module_uid(SPDConnection * connection,
1326 			      const char *output_module, unsigned int uid)
1327 {
1328 	char who[8];
1329 	sprintf(who, "%d", uid);
1330 	return spd_w_set_command_str(connection, SPD_OUTPUT_MODULE,
1331 				     output_module, who);
1332 }
1333 
1334 // Get function for output_module
spd_get_output_module(SPDConnection * connection)1335 char *spd_get_output_module(SPDConnection * connection)
1336 {
1337 	return spd_get_command_str(connection, SPD_OUTPUT_MODULE);
1338 }
1339 
1340 // Set functions for synthesis_voice
spd_set_synthesis_voice(SPDConnection * connection,const char * voice_name)1341 int spd_set_synthesis_voice(SPDConnection * connection, const char *voice_name)
1342 {
1343 	return spd_w_set_command_str(connection, SPD_SYNTHESIS_VOICE,
1344 				     voice_name, SPD_SELF);
1345 }
1346 
spd_set_synthesis_voice_all(SPDConnection * connection,const char * voice_name)1347 int spd_set_synthesis_voice_all(SPDConnection * connection,
1348 				const char *voice_name)
1349 {
1350 	return spd_w_set_command_str(connection, SPD_SYNTHESIS_VOICE,
1351 				     voice_name, SPD_ALLCLIENTS);
1352 }
1353 
spd_set_synthesis_voice_uid(SPDConnection * connection,const char * voice_name,unsigned int uid)1354 int spd_set_synthesis_voice_uid(SPDConnection * connection,
1355 				const char *voice_name, unsigned int uid)
1356 {
1357 	char who[8];
1358 	sprintf(who, "%d", uid);
1359 	return spd_w_set_command_str(connection, SPD_SYNTHESIS_VOICE,
1360 				     voice_name, who);
1361 }
1362 
1363 int
spd_set_notification_on(SPDConnection * connection,SPDNotification notification)1364 spd_set_notification_on(SPDConnection * connection,
1365 			SPDNotification notification)
1366 {
1367 	if (connection->mode == SPD_MODE_THREADED)
1368 		return spd_set_notification(connection, notification, "on");
1369 	else
1370 		return -1;
1371 }
1372 
1373 int
spd_set_notification_off(SPDConnection * connection,SPDNotification notification)1374 spd_set_notification_off(SPDConnection * connection,
1375 			 SPDNotification notification)
1376 {
1377 	if (connection->mode == SPD_MODE_THREADED)
1378 		return spd_set_notification(connection, notification, "off");
1379 	else
1380 		return -1;
1381 }
1382 
1383 #define NOTIFICATION_SET(val, ssip_val) \
1384 	if (notification & val){ \
1385 		sprintf(command, "SET SELF NOTIFICATION "ssip_val" %s", state);\
1386 		ret = spd_execute_command_wo_mutex(connection, command);\
1387 		if (ret < 0) RET(-1);\
1388 	}
1389 
1390 int
spd_set_notification(SPDConnection * connection,SPDNotification notification,const char * state)1391 spd_set_notification(SPDConnection * connection, SPDNotification notification,
1392 		     const char *state)
1393 {
1394 	static char command[64];
1395 	int ret;
1396 
1397 	if (connection->mode != SPD_MODE_THREADED)
1398 		return -1;
1399 
1400 	if (state == NULL) {
1401 		SPD_DBG("Requested state is NULL");
1402 		return -1;
1403 	}
1404 	if (strcmp(state, "on") && strcmp(state, "off")) {
1405 		SPD_DBG("Invalid argument for spd_set_notification: %s", state);
1406 		return -1;
1407 	}
1408 
1409 	pthread_mutex_lock(&connection->ssip_mutex);
1410 
1411 	NOTIFICATION_SET(SPD_INDEX_MARKS, "index_marks");
1412 	NOTIFICATION_SET(SPD_BEGIN, "begin");
1413 	NOTIFICATION_SET(SPD_END, "end");
1414 	NOTIFICATION_SET(SPD_CANCEL, "cancel");
1415 	NOTIFICATION_SET(SPD_PAUSE, "pause");
1416 	NOTIFICATION_SET(SPD_RESUME, "resume");
1417 	NOTIFICATION_SET(SPD_ALL, "all");
1418 
1419 	pthread_mutex_unlock(&connection->ssip_mutex);
1420 
1421 	return 0;
1422 }
1423 
1424 #undef NOTIFICATION_SET
1425 
1426 /* spd_list_modules retrieves information about the available output modules.
1427    The return value is a null-terminated array of strings containing output module
1428    names.
1429 */
1430 
spd_list_modules(SPDConnection * connection)1431 char **spd_list_modules(SPDConnection * connection)
1432 {
1433 	char **available_modules;
1434 	available_modules =
1435 	    spd_execute_command_with_list_reply(connection,
1436 						"LIST OUTPUT_MODULES");
1437 	return available_modules;
1438 }
1439 
free_spd_modules(char ** modules)1440 void free_spd_modules(char **modules)
1441 {
1442 	int i = 0;
1443 	while (modules != NULL && modules[i] != NULL) {
1444 		free(modules[i]);
1445 		++i;
1446 	}
1447 	free(modules);
1448 }
1449 
spd_list_voices(SPDConnection * connection)1450 char **spd_list_voices(SPDConnection * connection)
1451 {
1452 	char **voices;
1453 	voices = spd_execute_command_with_list_reply(connection, "LIST VOICES");
1454 	return voices;
1455 }
1456 
spd_list_synthesis_voices(SPDConnection * connection)1457 SPDVoice **spd_list_synthesis_voices(SPDConnection * connection)
1458 {
1459 	char **svoices_str;
1460 	SPDVoice **svoices;
1461 	int i, num_items;
1462 	svoices_str =
1463 	    spd_execute_command_with_list_reply(connection,
1464 						"LIST SYNTHESIS_VOICES");
1465 
1466 	if (svoices_str == NULL)
1467 		return NULL;
1468 
1469 	for (i = 0;; i++)
1470 		if (svoices_str[i] == NULL)
1471 			break;
1472 	num_items = i;
1473 	svoices = (SPDVoice **) malloc((num_items + 1) * sizeof(SPDVoice *));
1474 
1475 	for (i = 0; i <= num_items; i++) {
1476 		const char delimiters[] = "\t";
1477 		char *running;
1478 
1479 		if (svoices_str[i] == NULL)
1480 			break;
1481 		running = svoices_str[i];
1482 
1483 		svoices[i] = (SPDVoice *) malloc(sizeof(SPDVoice));
1484 		svoices[i]->name = strsep(&running, delimiters);
1485 		svoices[i]->language = strsep(&running, delimiters);
1486 		svoices[i]->variant = strsep(&running, delimiters);
1487 		assert(svoices[i]->name != NULL);
1488 	}
1489 	free(svoices_str);
1490 
1491 	svoices[num_items] = NULL;
1492 
1493 	return svoices;
1494 }
1495 
free_spd_voices(SPDVoice ** voices)1496 void free_spd_voices(SPDVoice ** voices)
1497 {
1498 	int i = 0;
1499 	while (voices != NULL && voices[i] != NULL) {
1500 		free(voices[i]->name);
1501 		free(voices[i]);
1502 		++i;
1503 	}
1504 	free(voices);
1505 }
1506 
spd_execute_command_with_list_reply(SPDConnection * connection,char * command)1507 char **spd_execute_command_with_list_reply(SPDConnection * connection,
1508 					   char *command)
1509 {
1510 	char *reply = NULL;
1511 	char *line;
1512 	int err;
1513 	int max_items = 50;
1514 	char **result;
1515 	int i;
1516 
1517 	spd_execute_command_with_reply(connection, command, &reply);
1518 	if (!ret_ok(reply)) {
1519 		if (reply != NULL)
1520 			free(reply);
1521 		return NULL;
1522 	}
1523 
1524 	result = malloc((max_items + 1) * sizeof(char *));
1525 
1526 	for (i = 0;; i++) {
1527 		line = get_param_str(reply, i + 1, &err);
1528 		if ((err) || (line == NULL))
1529 			break;
1530 		result[i] = line;
1531 		if (i >= max_items - 2) {
1532 			max_items *= 2;
1533 			result = realloc(result, max_items * sizeof(char *));
1534 		}
1535 	}
1536 
1537 	result[i] = NULL;
1538 
1539 	free(reply);
1540 	return result;
1541 }
1542 
1543 //int
1544 //spd_get_client_list(SPDConnection *connection, char **client_names, int *client_ids, int* active){
1545 //        SPD_DBG("spd_get_client_list: History is not yet implemented.");
1546 //        return -1;
1547 //
1548 //}
1549 
1550 int
spd_get_message_list_fd(SPDConnection * connection,int target,int * msg_ids,char ** client_names)1551 spd_get_message_list_fd(SPDConnection * connection, int target, int *msg_ids,
1552 			char **client_names)
1553 {
1554 	SPD_DBG("spd_get_client_list: History is not yet implemented.");
1555 	return -1;
1556 #if 0
1557 	sprintf(command, "HISTORY GET MESSAGE_LIST %d 0 20\r\n", target);
1558 	reply = spd_send_data(fd, command, 1);
1559 
1560 	/*      header_ok = parse_response_header(reply);
1561 	   if(header_ok != 1){
1562 	   free(reply);
1563 	   return -1;
1564 	   } */
1565 
1566 	for (count = 0;; count++) {
1567 		record = (char *)parse_response_data(reply, count + 1);
1568 		if (record == NULL)
1569 			break;
1570 		record_int = get_rec_int(record, 0);
1571 		msg_ids[count] = record_int;
1572 		record_str = (char *)get_rec_str(record, 1);
1573 		assert(record_str != NULL);
1574 		client_names[count] = record_str;
1575 	}
1576 	return count;
1577 #endif
1578 }
1579 
spd_execute_command(SPDConnection * connection,char * command)1580 int spd_execute_command(SPDConnection * connection, char *command)
1581 {
1582 	char *reply;
1583 	int ret;
1584 
1585 	pthread_mutex_lock(&connection->ssip_mutex);
1586 
1587 	ret = spd_execute_command_with_reply(connection, command, &reply);
1588 	if (ret) {
1589 		SPD_DBG("Can't execute command in spd_execute_command");
1590 	}
1591 	free(reply);
1592 
1593 	pthread_mutex_unlock(&connection->ssip_mutex);
1594 
1595 	return ret;
1596 }
1597 
spd_execute_command_wo_mutex(SPDConnection * connection,char * command)1598 int spd_execute_command_wo_mutex(SPDConnection * connection, char *command)
1599 {
1600 	char *reply;
1601 	int ret;
1602 
1603 	SPD_DBG("Executing command wo_mutex");
1604 	ret = spd_execute_command_with_reply(connection, command, &reply);
1605 	if (ret)
1606 		SPD_DBG
1607 		    ("Can't execute command in spd_execute_command_wo_mutex");
1608 
1609 	free(reply);
1610 
1611 	return ret;
1612 }
1613 
1614 int
spd_execute_command_with_reply(SPDConnection * connection,char * command,char ** reply)1615 spd_execute_command_with_reply(SPDConnection * connection, char *command,
1616 			       char **reply)
1617 {
1618 	char *buf;
1619 	int r;
1620 	SPD_DBG("Inside execute_command_with_reply");
1621 
1622 	buf = g_strdup_printf("%s\r\n", command);
1623 	*reply = spd_send_data_wo_mutex(connection, buf, SPD_WAIT_REPLY);
1624 	free(buf);
1625 	buf = NULL;
1626 	if (*reply == NULL) {
1627 		SPD_DBG
1628 		    ("Can't send data wo mutex in spd_execute_command_with_reply");
1629 		return -1;
1630 	}
1631 
1632 	r = ret_ok(*reply);
1633 
1634 	if (!r)
1635 		return -1;
1636 	else
1637 		return 0;
1638 }
1639 
spd_send_data(SPDConnection * connection,const char * message,int wfr)1640 char *spd_send_data(SPDConnection * connection, const char *message, int wfr)
1641 {
1642 	char *reply;
1643 	pthread_mutex_lock(&connection->ssip_mutex);
1644 
1645 	if (connection->stream == NULL)
1646 		RET(NULL);
1647 
1648 	reply = spd_send_data_wo_mutex(connection, message, wfr);
1649 	if (reply == NULL) {
1650 		SPD_DBG("Can't send data wo mutex in spd_send_data");
1651 		RET(NULL);
1652 	}
1653 
1654 	pthread_mutex_unlock(&connection->ssip_mutex);
1655 	return reply;
1656 }
1657 
spd_send_data_wo_mutex(SPDConnection * connection,const char * message,int wfr)1658 char *spd_send_data_wo_mutex(SPDConnection * connection, const char *message,
1659 			     int wfr)
1660 {
1661 
1662 	char *reply;
1663 	int bytes;
1664 
1665 	SPD_DBG("Inside spd_send_data_wo_mutex");
1666 
1667 	if (connection->stream == NULL)
1668 		return NULL;
1669 
1670 	if (connection->mode == SPD_MODE_THREADED) {
1671 		/* Make sure we don't get the cond_reply_ready signal before we are in
1672 		   cond_wait() */
1673 		pthread_mutex_lock(&connection->td->mutex_reply_ready);
1674 	}
1675 	/* write message to the socket */
1676 	SPD_DBG("Writing to socket");
1677 	if (!write(connection->socket, message, strlen(message))) {
1678 		SPD_DBG("Can't write to socket: %s", strerror(errno));
1679 		if (connection->mode == SPD_MODE_THREADED)
1680 			pthread_mutex_unlock(&connection->td->mutex_reply_ready);
1681 		return NULL;
1682 	}
1683 	SPD_DBG("Written to socket");
1684 	SPD_DBG(">> : |%s|", message);
1685 
1686 	/* read reply to the buffer */
1687 	if (wfr) {
1688 		if (connection->mode == SPD_MODE_THREADED) {
1689 			/* Wait until the reply is ready */
1690 			SPD_DBG
1691 			    ("Waiting for cond_reply_ready in spd_send_data_wo_mutex");
1692 			pthread_cond_wait(&connection->td->cond_reply_ready,
1693 					  &connection->td->mutex_reply_ready);
1694 			SPD_DBG("Condition for cond_reply_ready satisfied");
1695 			pthread_mutex_unlock(&connection->td->mutex_reply_ready);
1696 			SPD_DBG
1697 			    ("Reading the reply in spd_send_data_wo_mutex threaded mode");
1698 			/* Read the reply */
1699 			if (connection->reply != NULL) {
1700 				reply = connection->reply;
1701 				connection->reply = NULL;
1702 			} else {
1703 				SPD_DBG
1704 				    ("Error: Can't read reply, broken socket in spd_send_data.");
1705 				return NULL;
1706 			}
1707 			bytes = strlen(reply);
1708 			if (bytes == 0) {
1709 				free(reply);
1710 				SPD_DBG("Error: Empty reply, broken socket.");
1711 				return NULL;
1712 			}
1713 			/* Signal the reply has been read */
1714 			pthread_mutex_lock(&connection->td->mutex_reply_ack);
1715 			pthread_cond_signal(&connection->td->cond_reply_ack);
1716 			pthread_mutex_unlock(&connection->td->mutex_reply_ack);
1717 		} else {
1718 			reply = get_reply(connection);
1719 		}
1720 		if (reply != NULL)
1721 			SPD_DBG("<< : |%s|\n", reply);
1722 	} else {
1723 		if (connection->mode == SPD_MODE_THREADED)
1724 			pthread_mutex_unlock(&connection->td->mutex_reply_ready);
1725 		SPD_DBG("<< : no reply expected");
1726 		return strdup("NO REPLY");
1727 	}
1728 
1729 	if (reply == NULL)
1730 		SPD_DBG
1731 		    ("Reply from get_reply is NULL in spd_send_data_wo_mutex");
1732 
1733 	SPD_DBG("Returning from spd_send_data_wo_mutex");
1734 	return reply;
1735 }
1736 
1737 /* --------------------- Internal functions ------------------------- */
1738 
spd_set_priority(SPDConnection * connection,SPDPriority priority)1739 static int spd_set_priority(SPDConnection * connection, SPDPriority priority)
1740 {
1741 	static char p_name[16];
1742 	static char command[64];
1743 
1744 	switch (priority) {
1745 	case SPD_IMPORTANT:
1746 		strcpy(p_name, "IMPORTANT");
1747 		break;
1748 	case SPD_MESSAGE:
1749 		strcpy(p_name, "MESSAGE");
1750 		break;
1751 	case SPD_TEXT:
1752 		strcpy(p_name, "TEXT");
1753 		break;
1754 	case SPD_NOTIFICATION:
1755 		strcpy(p_name, "NOTIFICATION");
1756 		break;
1757 	case SPD_PROGRESS:
1758 		strcpy(p_name, "PROGRESS");
1759 		break;
1760 	default:
1761 		SPD_DBG("Error: Can't set priority! Incorrect value.");
1762 		return -1;
1763 	}
1764 
1765 	sprintf(command, "SET SELF PRIORITY %s", p_name);
1766 	return spd_execute_command_wo_mutex(connection, command);
1767 }
1768 
get_reply(SPDConnection * connection)1769 static char *get_reply(SPDConnection * connection)
1770 {
1771 	GString *str;
1772 	char *line = NULL;
1773 	size_t N = 0;
1774 	int bytes;
1775 	char *reply;
1776 	gboolean errors = FALSE;
1777 
1778 	str = g_string_new("");
1779 
1780 	/* Wait for activity on the socket, when there is some,
1781 	   read all the message line by line */
1782 	do {
1783 		bytes = getline(&line, &N, connection->stream);
1784 		if (bytes == -1) {
1785 			SPD_DBG
1786 			    ("Error: Can't read reply, broken socket in get_reply!");
1787 			if (connection->stream != NULL)
1788 				fclose(connection->stream);
1789 			connection->stream = NULL;
1790 			errors = TRUE;
1791 		} else {
1792 			g_string_append(str, line);
1793 		}
1794 		/* terminate if we reached the last line (without '-' after numcode) */
1795 	} while (!errors && !((strlen(line) < 4) || (line[3] == ' ')));
1796 
1797 	free(line);		/* getline allocates with malloc. */
1798 
1799 	if (errors) {
1800 		/* Free the GString and its character data, and return NULL. */
1801 		g_string_free(str, TRUE);
1802 		reply = NULL;
1803 	} else {
1804 		/* The resulting message received from the socket is stored in reply */
1805 		reply = str->str;
1806 		/* Free the GString, but not its character data. */
1807 		g_string_free(str, FALSE);
1808 	}
1809 
1810 	return reply;
1811 }
1812 
spd_events_handler(void * conn)1813 static void *spd_events_handler(void *conn)
1814 {
1815 	char *reply;
1816 	int reply_code;
1817 	SPDConnection *connection = conn;
1818 
1819 	while (1) {
1820 
1821 		/* Read the reply/event (block if none is available) */
1822 		SPD_DBG("Getting reply in spd_events_handler");
1823 		reply = get_reply(connection);
1824 		if (reply == NULL) {
1825 			SPD_DBG("ERROR: BROKEN SOCKET");
1826 			reply_code = -1;
1827 		} else {
1828 			SPD_DBG("<< : |%s|\n", reply);
1829 			reply_code = get_err_code(reply);
1830 		}
1831 
1832 		if ((reply_code >= 700) && (reply_code < 800)) {
1833 			int msg_id;
1834 			int client_id;
1835 			int err;
1836 
1837 			SPD_DBG("Callback detected: %s", reply);
1838 
1839 			/* This is an index mark */
1840 			/* Extract message id */
1841 			msg_id = get_param_int(reply, 1, &err);
1842 			if (err < 0) {
1843 				SPD_DBG
1844 				    ("Bad reply from Speech Dispatcher: %s (code %d)",
1845 				     reply, err);
1846 				free(reply);
1847 				break;
1848 			}
1849 			client_id = get_param_int(reply, 2, &err);
1850 			if (err < 0) {
1851 				SPD_DBG
1852 				    ("Bad reply from Speech Dispatcher: %s (code %d)",
1853 				     reply, err);
1854 				free(reply);
1855 				break;
1856 			}
1857 			/*  Decide if we want to call a callback */
1858 			if ((reply_code == 701) && (connection->callback_begin))
1859 				connection->callback_begin(msg_id, client_id,
1860 							   SPD_EVENT_BEGIN);
1861 			if ((reply_code == 702) && (connection->callback_end))
1862 				connection->callback_end(msg_id, client_id,
1863 							 SPD_EVENT_END);
1864 			if ((reply_code == 703)
1865 			    && (connection->callback_cancel))
1866 				connection->callback_cancel(msg_id, client_id,
1867 							    SPD_EVENT_CANCEL);
1868 			if ((reply_code == 704) && (connection->callback_pause))
1869 				connection->callback_pause(msg_id, client_id,
1870 							   SPD_EVENT_PAUSE);
1871 			if ((reply_code == 705)
1872 			    && (connection->callback_resume))
1873 				connection->callback_resume(msg_id, client_id,
1874 							    SPD_EVENT_RESUME);
1875 			if ((reply_code == 700) && (connection->callback_im)) {
1876 				char *im;
1877 				int err;
1878 				im = get_param_str(reply, 3, &err);
1879 				if ((err < 0) || (im == NULL)) {
1880 					SPD_DBG
1881 					    ("Broken reply from Speech Dispatcher: %s",
1882 					     reply);
1883 					free(reply);
1884 					break;
1885 				}
1886 				/* Call the callback */
1887 				connection->callback_im(msg_id, client_id,
1888 							SPD_EVENT_INDEX_MARK,
1889 							im);
1890 				free(im);
1891 			}
1892 			free(reply);
1893 
1894 		} else {
1895 			/* This is a protocol reply */
1896 			pthread_mutex_lock(&connection->td->mutex_reply_ready);
1897 			/* Prepare the reply to the reply buffer in connection */
1898 			if (reply != NULL) {
1899 				connection->reply = reply;
1900 			} else {
1901 				SPD_DBG("Connection reply is NULL");
1902 				connection->reply = NULL;
1903 				pthread_mutex_unlock(&connection->td->mutex_reply_ready);
1904 				break;
1905 			}
1906 			/* Signal the reply is available on the condition variable */
1907 			/* this order is correct and necessary */
1908 			pthread_cond_signal(&connection->td->cond_reply_ready);
1909 			pthread_mutex_lock(&connection->td->mutex_reply_ack);
1910 			pthread_mutex_unlock(&connection->td->mutex_reply_ready);
1911 			/* Wait until it has bean read */
1912 			pthread_cond_wait(&connection->td->cond_reply_ack,
1913 					  &connection->td->mutex_reply_ack);
1914 			pthread_mutex_unlock(&connection->td->mutex_reply_ack);
1915 			/* Continue */
1916 		}
1917 	}
1918 	/* In case of broken socket, we must still signal reply ready */
1919 	if (connection->reply == NULL) {
1920 		SPD_DBG("Signalling reply ready after communication failure");
1921 		if (connection->stream != NULL)
1922 			fclose(connection->stream);
1923 		connection->stream = NULL;
1924 		pthread_cond_signal(&connection->td->cond_reply_ready);
1925 		pthread_exit(0);
1926 	}
1927 	return 0;		/* to please gcc */
1928 }
1929 
ret_ok(char * reply)1930 static int ret_ok(char *reply)
1931 {
1932 	int err;
1933 
1934 	if (reply == NULL)
1935 		return -1;
1936 
1937 	err = get_err_code(reply);
1938 
1939 	if ((err >= 100) && (err < 300))
1940 		return 1;
1941 	if (err >= 300)
1942 		return 0;
1943 
1944 	SPD_FATAL("Internal error during communication.");
1945 }
1946 
get_param_str(char * reply,int num,int * err)1947 static char *get_param_str(char *reply, int num, int *err)
1948 {
1949 	int i;
1950 	char *tptr;
1951 	char *pos;
1952 	char *pos_begin;
1953 	char *pos_end;
1954 	char *rep;
1955 
1956 	assert(err != NULL);
1957 
1958 	if (num < 1) {
1959 		*err = -1;
1960 		return NULL;
1961 	}
1962 
1963 	pos = reply;
1964 	for (i = 0; i <= num - 2; i++) {
1965 		pos = strstr(pos, "\r\n");
1966 		if (pos == NULL) {
1967 			*err = -2;
1968 			return NULL;
1969 		}
1970 		pos += 2;
1971 	}
1972 
1973 	if (strlen(pos) < 4)
1974 		return NULL;
1975 
1976 	*err = strtol(pos, &tptr, 10);
1977 	if (*err >= 300 && *err <= 399)
1978 		return NULL;
1979 
1980 	if ((*tptr != '-') || (tptr != pos + 3)) {
1981 		*err = -3;
1982 		return NULL;
1983 	}
1984 
1985 	pos_begin = pos + 4;
1986 	pos_end = strstr(pos_begin, "\r\n");
1987 	if (pos_end == NULL) {
1988 		*err = -4;
1989 		return NULL;
1990 	}
1991 
1992 	rep = (char *)strndup(pos_begin, pos_end - pos_begin);
1993 	*err = 0;
1994 
1995 	return rep;
1996 }
1997 
get_param_int(char * reply,int num,int * err)1998 static int get_param_int(char *reply, int num, int *err)
1999 {
2000 	char *rep_str;
2001 	char *tptr;
2002 	int ret;
2003 
2004 	rep_str = get_param_str(reply, num, err);
2005 	if (rep_str == NULL) {
2006 		/* err is already set to the error return code, just return */
2007 		return 0;
2008 	}
2009 
2010 	ret = strtol(rep_str, &tptr, 10);
2011 	if (*tptr != '\0') {
2012 		/* this is not a number */
2013 		*err = -3;
2014 		free(rep_str);
2015 		return 0;
2016 	}
2017 	free(rep_str);
2018 
2019 	return ret;
2020 }
2021 
get_err_code(char * reply)2022 static int get_err_code(char *reply)
2023 {
2024 	char err_code[4];
2025 	int err;
2026 
2027 	if (reply == NULL)
2028 		return -1;
2029 	SPD_DBG("spd_send_data:	reply: %s\n", reply);
2030 
2031 	err_code[0] = reply[0];
2032 	err_code[1] = reply[1];
2033 	err_code[2] = reply[2];
2034 	err_code[3] = '\0';
2035 
2036 	SPD_DBG("ret_ok: err_code:	|%s|\n", err_code);
2037 
2038 	if (isanum(err_code)) {
2039 		err = atoi(err_code);
2040 	} else {
2041 		SPD_DBG("ret_ok: not a number\n");
2042 		return -1;
2043 	}
2044 
2045 	return err;
2046 }
2047 
2048 /* isanum() tests if the given string is a number,
2049  *  returns 1 if yes, 0 otherwise. */
isanum(char * str)2050 static int isanum(char *str)
2051 {
2052 	int i;
2053 	if (str == NULL)
2054 		return 0;
2055 	for (i = 0; i <= strlen(str) - 1; i++) {
2056 		if (!isdigit(str[i]))
2057 			return 0;
2058 	}
2059 	return 1;
2060 }
2061 
2062 /*
2063  * escape_dot: Replace . with .. at the start of lines.
2064  * @text: text to escape
2065  * @Returns: An allocated string, containing the escaped text.
2066  */
escape_dot(const char * text)2067 static char *escape_dot(const char *text)
2068 {
2069 	size_t orig_len = 0;
2070 	const char *orig_end;
2071 	char *result = NULL;
2072 	char *result_ptr;
2073 	static const char *ESCAPED_DOTLINE = "\r\n..";
2074 	static const size_t ESCAPED_DOTLINELEN = 4;
2075 	static const size_t DOTLINELEN = 3;
2076 
2077 	if (text == NULL)
2078 		return NULL;
2079 
2080 	orig_len = strlen(text);
2081 	orig_end = text + orig_len;
2082 	result = malloc((orig_len * 2 + 1) * sizeof(char));
2083 
2084 	if (result == NULL)
2085 		return NULL;
2086 
2087 	result_ptr = result;
2088 
2089 	/* We're over-allocating.  Even if we replaced every character
2090 	 * in text with "..", the length of the escaped string can be no more
2091 	 * than orig_len * 2.  We could tighten that upper bound with
2092 	 * a little more work.
2093 	 */
2094 
2095 	if ((orig_len >= 1) && (text[0] == '.')) {
2096 		*(result_ptr++) = '.';
2097 		*(result_ptr++) = '.';
2098 		text += 1;
2099 	}
2100 
2101 	while (text < orig_end) {
2102 		if ((text[0] == '\r') && (text[1] == '\n') && (text[2] == '.')) {
2103 			memcpy(result_ptr, ESCAPED_DOTLINE, ESCAPED_DOTLINELEN);
2104 			result_ptr += ESCAPED_DOTLINELEN;
2105 			text += DOTLINELEN;
2106 		} else {
2107 			*(result_ptr++) = *(text++);
2108 		}
2109 	}
2110 
2111 	*result_ptr = '\0';
2112 	return result;
2113 }
2114 
2115 #ifdef LIBSPEECHD_DEBUG
SPD_DBG(char * format,...)2116 static void SPD_DBG(char *format, ...)
2117 {
2118 	va_list args;
2119 
2120 	pthread_mutex_lock(&spd_logging_mutex);
2121 	va_start(args, format);
2122 	vfprintf(spd_debug, format, args);
2123 	va_end(args);
2124 	fprintf(spd_debug, "\n");
2125 	fflush(spd_debug);
2126 	pthread_mutex_unlock(&spd_logging_mutex);
2127 }
2128 #else /* LIBSPEECHD_DEBUG */
SPD_DBG(char * format,...)2129 static void SPD_DBG(char *format, ...)
2130 {
2131 }
2132 #endif /* LIBSPEECHD_DEBUG */
2133