1 /*
2  * output.c - Output layer for Speech Dispatcher
3  *
4  * Copyright (C) 2001, 2002, 2003, 2007 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 General Public License as published by
8  * the Free Software Foundation; either version 2, 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  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
18  *
19  * $Id: output.c,v 1.38 2008-06-27 12:28:48 hanke Exp $
20  */
21 
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 
26 #include <fdsetconv.h>
27 #include <safe_io.h>
28 #include <spd_utils.h>
29 #include "output.h"
30 #include "parse.h"
31 
32 #ifndef HAVE_STRNDUP
33 /*
34  * Added by Willie Walker - strndup was a GNU libc extension, later adopted
35  * in the POSIX.1-2008 standard, but not yet found on all systems.
36  */
strndup(const char * s,size_t n)37 char *strndup(const char *s, size_t n)
38 {
39 	size_t nAvail;
40 	char *p;
41 
42 	if (!s)
43 		return 0;
44 
45 	if (strlen(s) > n)
46 		nAvail = n + 1;
47 	else
48 		nAvail = strlen(s) + 1;
49 	p = g_malloc(nAvail);
50 	memcpy(p, s, nAvail);
51 	p[nAvail - 1] = '\0';
52 
53 	return p;
54 }
55 #endif /* HAVE_STRNDUP */
56 
output_set_speaking_monitor(TSpeechDMessage * msg,OutputModule * output)57 void output_set_speaking_monitor(TSpeechDMessage * msg, OutputModule * output)
58 {
59 	/* Set the speaking-monitor so that we know who is speaking */
60 	speaking_module = output;
61 	speaking_uid = msg->settings.uid;
62 	speaking_gid = msg->settings.reparted;
63 }
64 
get_output_module_by_name(char * name)65 OutputModule *get_output_module_by_name(char *name)
66 {
67 	OutputModule *output;
68 	int i;
69 
70 	for (i = 0; i < g_list_length(output_modules); i++) {
71 		output = g_list_nth_data(output_modules, i);
72 		if (!strcmp(output->name, name)) {
73 			if (output->working)
74 				return output;
75 			else
76 				return NULL;
77 		}
78 	}
79 
80 	return NULL;
81 }
82 
83 /* get_output_module tries to return a pointer to the
84    appropriate output module according to message context.
85    If it is not possible to find the required module,
86    it will subsequently try to get the default module,
87    any of the other remaining modules except dummy and
88    at last, the dummy output module.
89 
90    Only if not even dummy output module is working
91    (serious issues), it will log an error message and return
92    a NULL pointer.
93 
94 */
95 
get_output_module(const TSpeechDMessage * message)96 OutputModule *get_output_module(const TSpeechDMessage * message)
97 {
98 	OutputModule *output = NULL;
99 	int i, len;
100 
101 	if (message->settings.output_module != NULL) {
102 		MSG(5, "Desired output module is %s",
103 		    message->settings.output_module);
104 		output =
105 		    get_output_module_by_name(message->settings.output_module);
106 		if ((output != NULL) && output->working)
107 			return output;
108 	}
109 
110 	MSG(3, "Warning: Didn't find preferred output module, using default");
111 	// If the requested module was not found or is not working,
112 	// first try to use the default output module
113 	if (GlobalFDSet.output_module != NULL)
114 		output = get_output_module_by_name(GlobalFDSet.output_module);
115 
116 	if (output != NULL && output->working)
117 		return output;
118 
119 	MSG(3, "Couldn't load default output module, trying other modules");
120 
121 	/* Try all other output modules other than dummy */
122 	len = g_list_length(output_modules);
123 	for (i = 0; i < len; i++) {
124 		output = g_list_nth_data(output_modules, i);
125 		if (0 == strcmp(output->name, "dummy"))
126 			continue;
127 
128 		if (output->working) {
129 			MSG(3, "Output module %s seems to be working, using it",
130 			    output->name);
131 			return output;
132 		}
133 	}
134 
135 	// if we get here there are no good modules use the dummy
136 	// a pre-synthesized error message with some hints over and over).
137 	if (output == NULL || !output->working)
138 		output = get_output_module_by_name("dummy");
139 
140 	// Give up....
141 	if (output == NULL)
142 		MSG(1,
143 		    "Error: No output module working, not even dummy, no sound produced!\n");
144 
145 	return output;
146 }
147 
148 void
output_lock(void)149 static output_lock(void)
150 {
151 	pthread_mutex_lock(&output_layer_mutex);
152 }
153 
154 void
output_unlock(void)155 static output_unlock(void)
156 {
157 	pthread_mutex_unlock(&output_layer_mutex);
158 }
159 
160 #define OL_RET(value) \
161 	{  output_unlock(); \
162 		return (value); }
163 
output_read_reply(OutputModule * output)164 GString *output_read_reply(OutputModule * output)
165 {
166 	GString *rstr;
167 	int bytes;
168 	char *line = NULL;
169 	size_t N = 0;
170 	gboolean errors = FALSE;
171 
172 	rstr = g_string_new("");
173 
174 	/* Wait for activity on the socket, when there is some,
175 	   read all the message line by line */
176 	do {
177 		bytes = spd_getline(&line, &N, output->stream_out);
178 		if (bytes == -1) {
179 			MSG(2, "Error: Broken pipe to module.");
180 			output->working = 0;
181 			speaking_module = NULL;
182 			output_check_module(output);
183 			errors = TRUE;	/* Broken pipe */
184 		} else {
185 			MSG(5, "Got %d bytes from output module over socket",
186 			    bytes);
187 			g_string_append(rstr, line);
188 		}
189 		/* terminate if we reached the last line (without '-' after numcode) */
190 	} while (!errors && !((strlen(line) < 4) || (line[3] == ' ')));
191 
192 	if (line != NULL)
193 		g_free(line);
194 
195 	if (errors) {
196 		g_string_free(rstr, TRUE);
197 		rstr = NULL;
198 	}
199 
200 	return rstr;
201 }
202 
output_send_data(char * cmd,OutputModule * output,int wfr)203 int output_send_data(char *cmd, OutputModule * output, int wfr)
204 {
205 	int ret;
206 	GString *response;
207 
208 	if (output == NULL)
209 		return -1;
210 	if (cmd == NULL)
211 		return -1;
212 
213 	ret = safe_write(output->pipe_in[1], cmd, strlen(cmd));
214 	fflush(NULL);
215 	if (ret == -1) {
216 		MSG(2, "Error: Broken pipe to module.");
217 		output->working = 0;
218 		speaking_module = NULL;
219 		output_check_module(output);
220 		return -1;	/* Broken pipe */
221 	}
222 	MSG2(5, "output_module", "Command sent to output module: |%s| (%d)",
223 	     cmd, wfr);
224 
225 	if (wfr) {		/* wait for reply? */
226 		int ret = 0;
227 		response = output_read_reply(output);
228 		if (response == NULL)
229 			return -1;
230 
231 		MSG2(5, "output_module", "Reply from output module: |%s|",
232 		     response->str);
233 
234 		switch (response->str[0]) {
235 		case '3':
236 			MSG(2,
237 			    "Error: Module reported error in request from speechd (code 3xx): %s.",
238 			    response->str);
239 			ret = -2;	/* User (speechd) side error */
240 			break;
241 
242 		case '4':
243 			MSG(2,
244 			    "Error: Module reported error in itself (code 4xx): %s",
245 			    response->str);
246 			ret = -3;	/* Module side error */
247 			break;
248 
249 		case '2':
250 			ret = 0;
251 			break;
252 		default:	/* unknown response */
253 			MSG(3, "Unknown response from output module!");
254 			ret = -3;
255 			break;
256 		}
257 		g_string_free(response, TRUE);
258 		return ret;
259 	}
260 
261 	return 0;
262 }
263 
free_voice(gpointer data)264 static void free_voice(gpointer data)
265 {
266 	SPDVoice *voice = (SPDVoice *)data;
267 
268 	if (voice != NULL) {
269 		if (voice->name != NULL)
270 			g_free(voice->name);
271 		if (voice->language != NULL)
272 			g_free(voice->language);
273 		if (voice->variant != NULL)
274 			g_free(voice->variant);
275 
276 		g_free(voice);
277 	}
278 }
279 
output_get_voices(OutputModule * module)280 static SPDVoice **output_get_voices(OutputModule * module)
281 {
282 	SPDVoice **voice_dscr;
283 	SPDVoice *voice;
284 	GString *reply;
285 	gchar **lines;
286 	gchar **atoms;
287 	GQueue *voices;
288 	int i;
289 	int numvoices = 0;
290 	gboolean errors = FALSE;
291 
292 	output_lock();
293 
294 	if (module == NULL) {
295 		MSG(1, "ERROR: Can't list voices for broken output module");
296 		OL_RET(NULL);
297 	}
298 	output_send_data("LIST VOICES\n", module, 0);
299 	reply = output_read_reply(module);
300 
301 	if (reply == NULL) {
302 		output_unlock();
303 		return NULL;
304 	}
305 
306 	lines = g_strsplit(reply->str, "\n", -1);
307 	g_string_free(reply, TRUE);
308 	voices = g_queue_new();
309 	for (i = 0; !errors && (lines[i] != NULL); i++) {
310 		MSG(1, "LINE here:|%s|", lines[i]);
311 		if (strlen(lines[i]) <= 4) {
312 			MSG(1,
313 			    "ERROR: Bad communication from driver in synth_voices");
314 			errors = TRUE;
315 		} else if (lines[i][3] == ' ')
316 			break;
317 		else if (lines[i][3] == '-') {
318 			atoms = g_strsplit(&lines[i][4], "\t", 0);
319 			// Name, language, variant
320 			if ((atoms[0] == NULL) || (atoms[1] == NULL)
321 			    || (atoms[2] == NULL)) {
322 				errors = TRUE;
323 			} else {
324 				//Fill in VoiceDescription
325 				voice = g_malloc(sizeof(SPDVoice));
326 				voice->name = g_strdup(atoms[0]);
327 				voice->language = g_strdup(atoms[1]);
328 				voice->variant = g_strdup(atoms[2]);
329 				g_queue_push_tail(voices, voice);
330 			}
331 			g_strfreev(atoms);
332 		}
333 		/* Should we do something in a final "else" branch? */
334 
335 	}
336 
337 	numvoices = g_queue_get_length(voices);
338 
339 	if (errors == TRUE) {
340 		g_queue_free_full(voices, (GDestroyNotify)free_voice);
341 		g_strfreev(lines);
342 		output_unlock();
343 		return NULL;
344 	}
345 
346 	voice_dscr = g_malloc((numvoices + 1) * sizeof(SPDVoice *));
347 
348 	for (i = 0; i < numvoices; i++) {
349 		voice_dscr[i] = g_queue_pop_head(voices);
350 	}
351 
352 	voice_dscr[i] = NULL;
353 	g_queue_free(voices);
354 	g_strfreev(lines);
355 
356 	output_unlock();
357 	return voice_dscr;
358 }
359 
output_list_voices(char * module_name)360 SPDVoice **output_list_voices(char *module_name)
361 {
362 	OutputModule *module;
363 	if (module_name == NULL)
364 		return NULL;
365 	module = get_output_module_by_name(module_name);
366 	if (module == NULL) {
367 		MSG(1, "ERROR: Can't list voices for module %s", module_name);
368 		return NULL;
369 	}
370 	return output_get_voices(module);
371 }
372 
373 #define SEND_CMD_N(cmd) \
374 	{  err = output_send_data(cmd"\n", output, 1); \
375 		if (err < 0) return (err); }
376 
377 #define SEND_CMD(cmd) \
378 	{  err = output_send_data(cmd"\n", output, 1); \
379 		if (err < 0) OL_RET(err)}
380 
381 #define SEND_DATA_N(data) \
382 	{  err = output_send_data(data, output, 0); \
383 		if (err < 0) return (err); }
384 
385 #define SEND_DATA(data) \
386 	{  err = output_send_data(data, output, 0); \
387 		if (err < 0) OL_RET(err); }
388 
389 #define SEND_CMD_GET_VALUE(data) \
390 	{  err = output_send_data(data"\n", output, 1); \
391 		OL_RET(err); }
392 
393 #define ADD_SET_INT(name) \
394 	g_string_append_printf(set_str, #name"=%d\n", msg->settings.name);
395 #define ADD_SET_STR(name) \
396 	if (msg->settings.name != NULL){ \
397 		g_string_append_printf(set_str, #name"=%s\n", msg->settings.name); \
398 	}else{ \
399 		g_string_append_printf(set_str, #name"=NULL\n"); \
400 	}
401 #define ADD_SET_STR_C(name, fconv) \
402 	val = fconv(msg->settings.msg_settings.name); \
403 	if (val != NULL){ \
404 		g_string_append_printf(set_str, #name"=%s\n", val); \
405 	} \
406 	g_free(val);
407 
output_send_settings(TSpeechDMessage * msg,OutputModule * output)408 int output_send_settings(TSpeechDMessage * msg, OutputModule * output)
409 {
410 	GString *set_str;
411 	char *val;
412 	int err;
413 
414 	MSG(4, "Module set parameters.");
415 	set_str = g_string_new("");
416 	g_string_append_printf(set_str, "pitch=%d\n",
417 			       msg->settings.msg_settings.pitch);
418 	g_string_append_printf(set_str, "pitch_range=%d\n",
419 			       msg->settings.msg_settings.pitch_range);
420 	g_string_append_printf(set_str, "rate=%d\n",
421 			       msg->settings.msg_settings.rate);
422 	g_string_append_printf(set_str, "volume=%d\n",
423 			       msg->settings.msg_settings.volume);
424 	ADD_SET_STR_C(punctuation_mode, EPunctMode2str);
425 	ADD_SET_STR_C(spelling_mode, ESpellMode2str);
426 	ADD_SET_STR_C(cap_let_recogn, ECapLetRecogn2str);
427 	val = EVoice2str(msg->settings.msg_settings.voice_type);
428 	if (val != NULL) {
429 		g_string_append_printf(set_str, "voice=%s\n", val);
430 	}
431 	g_free(val);
432 	if (msg->settings.msg_settings.voice.language != NULL) {
433 		g_string_append_printf(set_str, "language=%s\n",
434 				       msg->settings.msg_settings.voice.
435 				       language);
436 	} else {
437 		g_string_append_printf(set_str, "language=NULL\n");
438 	}
439 	if (msg->settings.msg_settings.voice.name != NULL) {
440 		g_string_append_printf(set_str, "synthesis_voice=%s\n",
441 				       msg->settings.msg_settings.voice.name);
442 	} else {
443 		g_string_append_printf(set_str, "synthesis_voice=NULL\n");
444 	}
445 
446 	SEND_CMD_N("SET");
447 	SEND_DATA_N(set_str->str);
448 	SEND_CMD_N(".");
449 
450 	g_string_free(set_str, 1);
451 
452 	return 0;
453 }
454 
455 #undef ADD_SET_INT
456 #undef ADD_SET_STR
457 
458 #define ADD_SET_INT(name) \
459 	g_string_append_printf(set_str, #name"=%d\n", GlobalFDSet.name);
460 #define ADD_SET_STR(name) \
461 	if (GlobalFDSet.name != NULL){ \
462 		g_string_append_printf(set_str, #name"=%s\n", GlobalFDSet.name); \
463 	}else{ \
464 		g_string_append_printf(set_str, #name"=NULL\n"); \
465 	}
466 
output_send_audio_settings(OutputModule * output)467 int output_send_audio_settings(OutputModule * output)
468 {
469 	GString *set_str;
470 	int err;
471 
472 	MSG(4, "Module set parameters.");
473 	set_str = g_string_new("");
474 	ADD_SET_STR(audio_output_method);
475 	ADD_SET_STR(audio_oss_device);
476 	ADD_SET_STR(audio_alsa_device);
477 	ADD_SET_STR(audio_nas_server);
478 	// TODO: restore AudioPulseServer option
479 	//ADD_SET_STR(audio_pulse_server);
480 	ADD_SET_STR(audio_pulse_device);
481 	ADD_SET_INT(audio_pulse_min_length);
482 
483 	SEND_CMD_N("AUDIO");
484 	SEND_DATA_N(set_str->str);
485 	SEND_CMD_N(".");
486 
487 	g_string_free(set_str, 1);
488 
489 	return 0;
490 }
491 
output_send_loglevel_setting(OutputModule * output)492 int output_send_loglevel_setting(OutputModule * output)
493 {
494 	GString *set_str;
495 	int err;
496 
497 	MSG(4, "Module set parameters.");
498 	set_str = g_string_new("");
499 	ADD_SET_INT(log_level);
500 
501 	SEND_CMD_N("LOGLEVEL");
502 	SEND_DATA_N(set_str->str);
503 	SEND_CMD_N(".");
504 
505 	g_string_free(set_str, 1);
506 
507 	return 0;
508 }
509 
510 #undef ADD_SET_INT
511 #undef ADD_SET_STR
512 
output_send_debug(OutputModule * output,int flag,char * log_path)513 int output_send_debug(OutputModule * output, int flag, char *log_path)
514 {
515 	char *cmd_str;
516 	int err;
517 
518 	MSG(4, "Module sending debug flag %d with file %s", flag, log_path);
519 
520 	output_lock();
521 	if (flag) {
522 		cmd_str = g_strdup_printf("DEBUG ON %s \n", log_path);
523 		err = output_send_data(cmd_str, output, 1);
524 		g_free(cmd_str);
525 		if (err) {
526 			MSG(3,
527 			    "ERROR: Can't set debugging on for output module %s",
528 			    output->name);
529 			OL_RET(-1);
530 		}
531 	} else {
532 		err = output_send_data("DEBUG OFF \n", output, 1);
533 		if (err) {
534 			MSG(3,
535 			    "ERROR: Can't switch debugging off for output module %s",
536 			    output->name);
537 			OL_RET(-1);
538 		}
539 
540 	}
541 
542 	OL_RET(0);
543 }
544 
output_speak(TSpeechDMessage * msg,OutputModule * output)545 int output_speak(TSpeechDMessage * msg, OutputModule *output)
546 {
547 	int err;
548 	int ret;
549 
550 	if (msg == NULL)
551 		return -1;
552 
553 	output_lock();
554 
555 	msg->buf = escape_dot(msg->buf);
556 	msg->bytes = -1;
557 
558 	output_set_speaking_monitor(msg, output);
559 
560 	ret = output_send_settings(msg, output);
561 	if (ret != 0)
562 		OL_RET(ret);
563 
564 	MSG(4, "Module speak!");
565 
566 	switch (msg->settings.type) {
567 	case SPD_MSGTYPE_TEXT:
568 		SEND_CMD("SPEAK") break;
569 	case SPD_MSGTYPE_SOUND_ICON:
570 		SEND_CMD("SOUND_ICON");
571 		break;
572 	case SPD_MSGTYPE_CHAR:
573 		SEND_CMD("CHAR");
574 		break;
575 	case SPD_MSGTYPE_KEY:
576 		SEND_CMD("KEY");
577 		break;
578 	default:
579 		MSG(2, "Invalid message type in output_speak()!");
580 	}
581 
582 	SEND_DATA(msg->buf)
583 	    SEND_CMD("\n.")
584 
585 	    OL_RET(0)
586 }
587 
output_stop()588 int output_stop()
589 {
590 	int err;
591 	OutputModule *output;
592 
593 	output_lock();
594 
595 	if (speaking_module == NULL)
596 		OL_RET(0)
597 		    else
598 		output = speaking_module;
599 
600 	MSG(4, "Module stop!");
601 	SEND_DATA("STOP\n");
602 
603 	OL_RET(0)
604 }
605 
output_pause()606 size_t output_pause()
607 {
608 	static int err;
609 	static OutputModule *output;
610 
611 	output_lock();
612 
613 	if (speaking_module == NULL)
614 		OL_RET(0)
615 		    else
616 		output = speaking_module;
617 
618 	MSG(4, "Module pause!");
619 	SEND_DATA("PAUSE\n");
620 
621 	OL_RET(0)
622 }
623 
output_module_is_speaking(OutputModule * output,char ** index_mark)624 int output_module_is_speaking(OutputModule * output, char **index_mark)
625 {
626 	GString *response;
627 	int retcode = -1;
628 
629 	output_lock();
630 
631 	MSG(5, "output_module_is_speaking()");
632 
633 	if (output == NULL) {
634 		MSG(5, "output==NULL in output_module_is_speaking()");
635 		OL_RET(-1);
636 	}
637 
638 	response = output_read_reply(output);
639 	if (response == NULL) {
640 		*index_mark = NULL;
641 		OL_RET(-1);
642 	}
643 
644 	MSG2(5, "output_module", "Reply from output module: |%s|",
645 	     response->str);
646 
647 	if (response->len < 4) {
648 		MSG2(2, "output_module",
649 		     "Error: Wrong communication from output module! Reply less than four bytes.");
650 		g_string_free(response, TRUE);
651 		OL_RET(-1);
652 	}
653 
654 	switch (response->str[0]) {
655 	case '3':
656 		MSG(2,
657 		    "Error: Module reported error in request from speechd (code 3xx).");
658 		retcode = -2;	/* User (speechd) side error */
659 		break;
660 
661 	case '4':
662 		MSG(2, "Error: Module reported error in itself (code 4xx).");
663 		retcode = -3;	/* Module side error */
664 		break;
665 
666 	case '2':
667 		retcode = 0;
668 		if (response->len > 4) {
669 			if (response->str[3] == '-') {
670 				char *p;
671 				p = strchr(response->str, '\n');
672 				*index_mark =
673 				    (char *)strndup(response->str + 4,
674 						    p - response->str - 4);
675 				MSG2(5, "output_module",
676 				     "Detected INDEX MARK: %s", *index_mark);
677 			} else {
678 				MSG2(2, "output_module",
679 				     "Error: Wrong communication from output module!"
680 				     "Reply on SPEAKING not multi-line.");
681 				retcode = -1;
682 			}
683 		}
684 		break;
685 
686 	case '7':
687 		retcode = 0;
688 		MSG2(5, "output_module", "Received event:\n %s", response->str);
689 		if (!strncmp(response->str, "701", 3))
690 			*index_mark = (char *)g_strdup("__spd_begin");
691 		else if (!strncmp(response->str, "702", 3))
692 			*index_mark = (char *)g_strdup("__spd_end");
693 		else if (!strncmp(response->str, "703", 3))
694 			*index_mark = (char *)g_strdup("__spd_stopped");
695 		else if (!strncmp(response->str, "704", 3))
696 			*index_mark = (char *)g_strdup("__spd_paused");
697 		else if (!strncmp(response->str, "700", 3)) {
698 			char *p;
699 			p = strchr(response->str, '\n');
700 			MSG2(5, "output_module", "response:|%s|\n p:|%s|",
701 			     response->str, p);
702 			*index_mark =
703 			    (char *)strndup(response->str + 4,
704 					    p - response->str - 4);
705 			MSG2(5, "output_module", "Detected INDEX MARK: %s",
706 			     *index_mark);
707 		} else {
708 			MSG2(2, "output_module",
709 			     "ERROR: Unknown event received from output module");
710 			retcode = -5;
711 		}
712 		break;
713 
714 	default:		/* unknown response */
715 		MSG(3, "Unknown response from output module!");
716 		retcode = -3;
717 		break;
718 
719 	}
720 
721 	g_string_free(response, TRUE);
722 	OL_RET(retcode)
723 }
724 
output_is_speaking(char ** index_mark)725 int output_is_speaking(char **index_mark)
726 {
727 	int err;
728 	OutputModule *output;
729 
730 	output = speaking_module;
731 
732 	err = output_module_is_speaking(output, index_mark);
733 	if (err < 0) {
734 		*index_mark = NULL;
735 	}
736 
737 	return err;
738 }
739 
740 /* Wait until the child _pid_ returns with timeout. Calls waitpid() each 100ms
741  until timeout is exceeded. This is not exact and you should not rely on the
742  exact time waited. */
743 int
waitpid_with_timeout(pid_t pid,int * status_ptr,int options,size_t timeout)744 waitpid_with_timeout(pid_t pid, int *status_ptr, int options, size_t timeout)
745 {
746 	size_t i;
747 	int ret;
748 	for (i = 0; i <= timeout; i += 100) {
749 		ret = waitpid(pid, status_ptr, options | WNOHANG);
750 		if (ret > 0)
751 			return ret;
752 		if (ret < 0)
753 			return ret;
754 		usleep(100 * 1000);	/* Sleep 100 ms */
755 	}
756 	return 0;
757 }
758 
output_close(OutputModule * module)759 int output_close(OutputModule * module)
760 {
761 	int err;
762 	int ret;
763 	OutputModule *output;
764 	output = module;
765 
766 	if (output == NULL)
767 		return -1;
768 
769 	output_lock();
770 
771 	assert(output->name != NULL);
772 	MSG(3, "Closing module \"%s\"...", output->name);
773 	if (output->working) {
774 		SEND_DATA("STOP\n");
775 		SEND_CMD("QUIT");
776 		usleep(100);
777 		/* So that the module has some time to exit() correctly */
778 	}
779 
780 	MSG(4, "Waiting for module pid %d", module->pid);
781 	ret = waitpid_with_timeout(module->pid, NULL, 0, 1000);
782 	if (ret > 0) {
783 		MSG(4, "Ok, module closed successfully.");
784 	} else if (ret == 0) {
785 		int ret2;
786 		MSG(1, "ERROR: Timed out when waiting for child cancellation");
787 		MSG(3, "Killing the module");
788 		kill(module->pid, SIGKILL);
789 		MSG(4, "Waiting until the child terminates.");
790 		ret2 = waitpid_with_timeout(module->pid, NULL, 0, 1000);
791 		if (ret2 > 0) {
792 			MSG(3, "Module terminated");
793 		} else {
794 			MSG(1,
795 			    "ERROR: Module is not able to terminate, giving up.");
796 		}
797 	} else {
798 		MSG(1,
799 		    "ERROR: waitpid() failed when waiting for child (module).");
800 	}
801 
802 	OL_RET(0)
803 }
804 
805 #undef SEND_CMD
806 #undef SEND_DATA
807 
output_check_module(OutputModule * output)808 int output_check_module(OutputModule * output)
809 {
810 	int ret;
811 	int err;
812 	int status;
813 
814 	if (output == NULL)
815 		return -1;
816 
817 	MSG(4, "Output module working status: %d (pid:%d)", output->working,
818 	    output->pid);
819 
820 	if (output->working == 0) {
821 		/* Investigate on why it crashed */
822 		ret = waitpid(output->pid, &status, WNOHANG);
823 		if (ret == 0) {
824 			MSG(2, "Output module not running.");
825 			return 0;
826 		}
827 		ret = WIFEXITED(status);
828 
829 		/* TODO: Linux kernel implementation of threads is not very good :(  */
830 		//        if (ret == 0){
831 		if (1) {
832 			/* Module terminated abnormally */
833 			MSG(2,
834 			    "Output module terminated abnormally, probably crashed.");
835 		} else {
836 			/* Module terminated normally, check status */
837 			err = WEXITSTATUS(status);
838 			if (err == 0)
839 				MSG(2, "Module exited normally");
840 			if (err == 1)
841 				MSG(2, "Internal error in output module!");
842 			if (err == 2) {
843 				MSG(2,
844 				    "Output device not working. For software devices, this can mean"
845 				    "that they are not running or they are not accessible due to wrong"
846 				    "acces permissions.");
847 			}
848 			if (err > 2)
849 				MSG(2,
850 				    "Unknown error happened in output module, exit status: %d !",
851 				    err);
852 		}
853 	}
854 	return 0;
855 }
856 
escape_dot(char * otext)857 char *escape_dot(char *otext)
858 {
859 	char *seq;
860 	GString *ntext;
861 	char *ootext;
862 	char *ret = NULL;
863 	int len;
864 
865 	if (otext == NULL)
866 		return NULL;
867 
868 	MSG2(5, "escaping", "Incoming text: |%s|", otext);
869 
870 	ootext = otext;
871 
872 	ntext = g_string_new("");
873 
874 	if (strlen(otext) == 1) {
875 		if (!strcmp(otext, ".")) {
876 			g_string_append(ntext, "..");
877 			otext += 1;
878 		}
879 	}
880 
881 	if (strlen(otext) >= 2) {
882 		if ((otext[0] == '.') && (otext[1] == '\n')) {
883 			g_string_append(ntext, "..\n");
884 			otext = otext + 2;
885 		}
886 	}
887 
888 	MSG2(6, "escaping", "Altering text (I): |%s|", ntext->str);
889 
890 	while ((seq = strstr(otext, "\n.\n"))) {
891 		*seq = 0;
892 		g_string_append(ntext, otext);
893 		g_string_append(ntext, "\n..\n");
894 		otext = seq + 3;
895 	}
896 
897 	MSG2(6, "escaping", "Altering text (II): |%s|", ntext->str);
898 
899 	len = strlen(otext);
900 	if (len >= 2) {
901 		if ((otext[len - 2] == '\n') && (otext[len - 1] == '.')) {
902 			g_string_append(ntext, otext);
903 			g_string_append(ntext, ".");
904 			otext = otext + len;
905 			MSG2(6, "escaping", "Altering text (II-b): |%s|",
906 			     ntext->str);
907 		}
908 	}
909 
910 	if (otext == ootext) {
911 		g_string_free(ntext, 1);
912 		ret = otext;
913 	} else {
914 		g_string_append(ntext, otext);
915 		g_free(ootext);
916 		ret = ntext->str;
917 		g_string_free(ntext, 0);
918 	}
919 
920 	MSG2(6, "escaping", "Altered text: |%s|", ret);
921 
922 	return ret;
923 }
924