1 
2 /*
3  * set.c - Settings related functions for Speech Dispatcher
4  *
5  * Copyright (C) 2001, 2002, 2003 Brailcom, o.p.s.
6  *
7  * This is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2, or (at your option)
10  * any later version.
11  *
12  * This software is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19  *
20  * $Id: set.c,v 1.46 2008-07-01 09:00:32 hanke Exp $
21  */
22 
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 
27 #include <fnmatch.h>
28 
29 #include "set.h"
30 #include "alloc.h"
31 #include "msg.h"
32 
spd_str_compare(gconstpointer a,gconstpointer b)33 gint spd_str_compare(gconstpointer a, gconstpointer b)
34 {
35 	return strcmp((char *)a, (char *)b);
36 }
37 
set_priority_self(int fd,SPDPriority priority)38 int set_priority_self(int fd, SPDPriority priority)
39 {
40 	int uid;
41 	int ret;
42 
43 	uid = get_client_uid_by_fd(fd);
44 	if (uid == 0)
45 		return 1;
46 	ret = set_priority_uid(uid, priority);
47 
48 	return ret;
49 }
50 
set_priority_uid(int uid,SPDPriority priority)51 int set_priority_uid(int uid, SPDPriority priority)
52 {
53 	TFDSetElement *settings;
54 	if ((priority < SPD_IMPORTANT) || (priority > SPD_PROGRESS))
55 		return 1;
56 	settings = get_client_settings_by_uid(uid);
57 	if (settings == NULL)
58 		return 1;
59 
60 	settings->priority = priority;
61 	return 0;
62 }
63 
64 #define SET_SELF_ALL(type, param) \
65 	int \
66 	set_ ## param ## _self(int fd, type param) \
67 	{ \
68 		int uid; \
69 		uid = get_client_uid_by_fd(fd); \
70 		if (uid == 0) return 1; \
71 		return set_ ## param ## _uid(uid, param); \
72 	} \
73 	int \
74 	set_ ## param ## _all(type param) \
75 	{ \
76 		int i; \
77 		int uid; \
78 		int err = 0; \
79 		for(i=1;i<=SpeechdStatus.max_fd;i++){ \
80 			uid = get_client_uid_by_fd(i); \
81 			if (uid == 0) continue; \
82 			err += set_ ## param ## _uid(uid, param); \
83 		} \
84 		if (err > 0) return 1; \
85 		return 0; \
86 	}
87 
SET_SELF_ALL(int,rate)88 SET_SELF_ALL(int, rate)
89 
90 int set_rate_uid(int uid, int rate)
91 {
92 	TFDSetElement *settings;
93 
94 	if ((rate > 100) || (rate < -100))
95 		return 1;
96 
97 	settings = get_client_settings_by_uid(uid);
98 	if (settings == NULL)
99 		return 1;
100 
101 	settings->msg_settings.rate = rate;
102 	return 0;
103 }
104 
SET_SELF_ALL(int,pitch)105 SET_SELF_ALL(int, pitch)
106 
107 int set_pitch_uid(int uid, int pitch)
108 {
109 	TFDSetElement *settings;
110 
111 	if ((pitch > 100) || (pitch < -100))
112 		return 1;
113 
114 	settings = get_client_settings_by_uid(uid);
115 	if (settings == NULL)
116 		return 1;
117 
118 	settings->msg_settings.pitch = pitch;
119 	return 0;
120 }
121 
SET_SELF_ALL(int,pitch_range)122 SET_SELF_ALL(int, pitch_range)
123 
124 int set_pitch_range_uid(int uid, int pitch_range)
125 {
126 	TFDSetElement *settings;
127 
128 	if ((pitch_range > 100) || (pitch_range < -100))
129 		return 1;
130 
131 	settings = get_client_settings_by_uid(uid);
132 	if (settings == NULL)
133 		return 1;
134 
135 	settings->msg_settings.pitch_range = pitch_range;
136 	return 0;
137 }
138 
SET_SELF_ALL(int,volume)139 SET_SELF_ALL(int, volume)
140 
141 int set_volume_uid(int uid, int volume)
142 {
143 	TFDSetElement *settings;
144 
145 	if ((volume > 100) || (volume < -100))
146 		return 1;
147 
148 	settings = get_client_settings_by_uid(uid);
149 	if (settings == NULL)
150 		return 1;
151 
152 	settings->msg_settings.volume = volume;
153 	return 0;
154 }
155 
SET_SELF_ALL(char *,voice)156 SET_SELF_ALL(char *, voice)
157 
158 int set_voice_uid(int uid, char *voice)
159 {
160 	TFDSetElement *settings;
161 
162 	settings = get_client_settings_by_uid(uid);
163 	if (settings == NULL)
164 		return 1;
165 
166 	if (!strcmp(voice, "male1"))
167 		settings->msg_settings.voice_type = SPD_MALE1;
168 	else if (!strcmp(voice, "male2"))
169 		settings->msg_settings.voice_type = SPD_MALE2;
170 	else if (!strcmp(voice, "male3"))
171 		settings->msg_settings.voice_type = SPD_MALE3;
172 	else if (!strcmp(voice, "female1"))
173 		settings->msg_settings.voice_type = SPD_FEMALE1;
174 	else if (!strcmp(voice, "female2"))
175 		settings->msg_settings.voice_type = SPD_FEMALE2;
176 	else if (!strcmp(voice, "female3"))
177 		settings->msg_settings.voice_type = SPD_FEMALE3;
178 	else if (!strcmp(voice, "child_male"))
179 		settings->msg_settings.voice_type = SPD_CHILD_MALE;
180 	else if (!strcmp(voice, "child_female"))
181 		settings->msg_settings.voice_type = SPD_CHILD_FEMALE;
182 	else
183 		return 1;
184 
185 	if (settings->msg_settings.voice.name != NULL) {
186 		g_free(settings->msg_settings.voice.name);
187 		settings->msg_settings.voice.name = NULL;
188 	}
189 	return 0;
190 }
191 
SET_SELF_ALL(SPDPunctuation,punctuation_mode)192 SET_SELF_ALL(SPDPunctuation, punctuation_mode)
193 
194 int set_punctuation_mode_uid(int uid, SPDPunctuation punctuation)
195 {
196 	TFDSetElement *settings;
197 
198 	settings = get_client_settings_by_uid(uid);
199 	if (settings == NULL)
200 		return 1;
201 
202 	settings->msg_settings.punctuation_mode = punctuation;
203 	return 0;
204 }
205 
206 #define SET_PARAM_STR(name) \
207 	settings->name = set_param_str(settings->name, name);
208 
SET_SELF_ALL(SPDCapitalLetters,capital_letter_recognition)209 SET_SELF_ALL(SPDCapitalLetters, capital_letter_recognition)
210 
211 int set_capital_letter_recognition_uid(int uid, SPDCapitalLetters recogn)
212 {
213 	TFDSetElement *settings;
214 
215 	settings = get_client_settings_by_uid(uid);
216 	if (settings == NULL)
217 		return 1;
218 
219 	settings->msg_settings.cap_let_recogn = recogn;
220 	return 0;
221 }
222 
SET_SELF_ALL(SPDSpelling,spelling)223 SET_SELF_ALL(SPDSpelling, spelling)
224 
225 int set_spelling_uid(int uid, SPDSpelling spelling)
226 {
227 	TFDSetElement *settings;
228 
229 	assert((spelling == 0) || (spelling == 1));
230 
231 	settings = get_client_settings_by_uid(uid);
232 	if (settings == NULL)
233 		return 1;
234 
235 	settings->msg_settings.spelling_mode = spelling;
236 	return 0;
237 }
238 
SET_SELF_ALL(char *,language)239 SET_SELF_ALL(char *, language)
240 
241 int set_language_uid(int uid, char *language)
242 {
243 	TFDSetElement *settings;
244 	char *output_module;
245 
246 	settings = get_client_settings_by_uid(uid);
247 	if (settings == NULL)
248 		return 1;
249 
250 	settings->msg_settings.voice.language =
251 	    set_param_str(settings->msg_settings.voice.language, language);
252 
253 	/* Check if it is not desired to change output module */
254 	output_module = g_hash_table_lookup(language_default_modules, language);
255 	if (output_module != NULL) {
256 		set_output_module_uid(uid, output_module);
257 	} else {
258 		char *dash = strchr(language, '-');
259 
260 		if (dash) {
261 			*dash = 0;
262 
263 			output_module = g_hash_table_lookup(language_default_modules, language);
264 			if (output_module != NULL) {
265 				set_output_module_uid(uid, output_module);
266 			}
267 		}
268 	}
269 
270 	return 0;
271 }
272 
SET_SELF_ALL(char *,synthesis_voice)273 SET_SELF_ALL(char *, synthesis_voice)
274 
275 int set_synthesis_voice_uid(int uid, char *synthesis_voice)
276 {
277 	TFDSetElement *settings;
278 
279 	settings = get_client_settings_by_uid(uid);
280 	if (settings == NULL)
281 		return 1;
282 
283 	settings->msg_settings.voice.name =
284 	    set_param_str(settings->msg_settings.voice.name, synthesis_voice);
285 
286 	/* Delete ordinary voice settings so that we don't mix */
287 	settings->msg_settings.voice_type = -1;
288 
289 	return 0;
290 }
291 
292 #define CHECK_SET_PAR(name, ival) \
293 	if (cl_set->val.name != ival){ set->name = cl_set->val.name; \
294 		MSG(4,"parameter " #name " set to %d", cl_set->val.name); }
295 #define CHECK_SET_PAR_STR(name) \
296 	if (cl_set->val.name != NULL){ \
297 		g_free(set->name); \
298 		set->name = g_strdup(cl_set->val.name); \
299 		MSG(4,"parameter " #name " set to %s", cl_set->val.name); \
300 	}
301 
update_cl_settings(gpointer data,gpointer user_data)302 void update_cl_settings(gpointer data, gpointer user_data)
303 {
304 	TFDSetClientSpecific *cl_set = data;
305 	TFDSetElement *set = user_data;
306 
307 	MSG(4, "Updating client specific settings %s against %s",
308 	    set->client_name, cl_set->pattern);
309 
310 	if (fnmatch(cl_set->pattern, set->client_name, 0))
311 		return;
312 
313 	/*  Warning: If you modify this, you must also modify cb_BeginClient in config.c ! */
314 	CHECK_SET_PAR(msg_settings.rate, -101)
315 	    CHECK_SET_PAR(msg_settings.pitch, -101)
316 	    CHECK_SET_PAR(msg_settings.pitch_range, -101)
317 	    CHECK_SET_PAR(msg_settings.volume, -101)
318 	    CHECK_SET_PAR(msg_settings.punctuation_mode, -1)
319 	    CHECK_SET_PAR(msg_settings.spelling_mode, -1)
320 	    CHECK_SET_PAR(msg_settings.voice_type, -1)
321 	    CHECK_SET_PAR(msg_settings.cap_let_recogn, -1)
322 	    CHECK_SET_PAR(pause_context, -1)
323 	    CHECK_SET_PAR(ssml_mode, -1)
324 	    CHECK_SET_PAR(symbols_preprocessing, -1)
325 	    CHECK_SET_PAR_STR(msg_settings.voice.language)
326 	    CHECK_SET_PAR_STR(output_module)
327 
328 	    return;
329 }
330 
331 #undef CHECK_SET_PAR
332 #undef CHECK_SET_PAR_STR
333 
set_client_name_self(int fd,char * client_name)334 int set_client_name_self(int fd, char *client_name)
335 {
336 	TFDSetElement *settings;
337 	int dividers = 0;
338 	int i;
339 
340 	assert(client_name != NULL);
341 
342 	settings = get_client_settings_by_fd(fd);
343 	if (settings == NULL)
344 		return 1;
345 
346 	/* Is the parameter a valid client name? */
347 	for (i = 0; i <= strlen(client_name) - 1; i++)
348 		if (client_name[i] == ':')
349 			dividers++;
350 	if (dividers != 2)
351 		return 1;
352 
353 	SET_PARAM_STR(client_name);
354 
355 	/* Update fd_set for this cilent with client-specific options */
356 	g_list_foreach(client_specific_settings, update_cl_settings, settings);
357 
358 	return 0;
359 }
360 
SET_SELF_ALL(char *,output_module)361 SET_SELF_ALL(char *, output_module)
362 
363 int set_output_module_uid(int uid, char *output_module)
364 {
365 	TFDSetElement *settings;
366 
367 	settings = get_client_settings_by_uid(uid);
368 	if (settings == NULL)
369 		return 1;
370 	if (output_module == NULL)
371 		return 1;
372 
373 	MSG(5, "Setting output module to %s", output_module);
374 
375 	MSG(5, "In set_output_module the desired output module is x%s",
376 	    output_module);
377 
378 	SET_PARAM_STR(output_module);
379 
380 	/* Delete synth_voice since it is module specific */
381 	if (settings->msg_settings.voice.name != NULL) {
382 		g_free(settings->msg_settings.voice.name);
383 		settings->msg_settings.voice.name = NULL;
384 	}
385 
386 	return 0;
387 }
388 
SET_SELF_ALL(int,pause_context)389 SET_SELF_ALL(int, pause_context)
390 
391 int set_pause_context_uid(int uid, int pause_context)
392 {
393 	TFDSetElement *settings;
394 
395 	settings = get_client_settings_by_uid(uid);
396 	if (settings == NULL)
397 		return 1;
398 
399 	settings->pause_context = pause_context;
400 	return 0;
401 }
402 
SET_SELF_ALL(SPDDataMode,ssml_mode)403 SET_SELF_ALL(SPDDataMode, ssml_mode)
404 
405 int set_ssml_mode_uid(int uid, SPDDataMode ssml_mode)
406 {
407 	TFDSetElement *settings;
408 
409 	settings = get_client_settings_by_uid(uid);
410 	if (settings == NULL)
411 		return 1;
412 
413 	settings->ssml_mode = ssml_mode;
414 	return 0;
415 }
416 
SET_SELF_ALL(gboolean,symbols_preprocessing)417 SET_SELF_ALL(gboolean, symbols_preprocessing)
418 
419 int set_symbols_preprocessing_uid(int uid, gboolean symbols_preprocessing)
420 {
421 	TFDSetElement *settings;
422 
423 	settings = get_client_settings_by_uid(uid);
424 	if (settings == NULL)
425 		return 1;
426 
427 	settings->symbols_preprocessing = symbols_preprocessing;
428 	return 0;
429 }
430 
SET_SELF_ALL(int,debug)431 SET_SELF_ALL(int, debug)
432 
433 int set_debug_uid(int uid, int debug)
434 {
435 	char *debug_logfile_path;
436 
437 	/* Do not switch debugging on when already on
438 	   and vice-versa */
439 	if (SpeechdOptions.debug && debug)
440 		return 1;
441 	if (!SpeechdOptions.debug && !debug)
442 		return 1;
443 
444 	if (debug) {
445 		debug_logfile_path =
446 		    g_strdup_printf("%s/speech-dispatcher.log",
447 				    SpeechdOptions.debug_destination);
448 
449 		debug_logfile = fopen(debug_logfile_path, "w");
450 		if (debug_logfile == NULL) {
451 			MSG(3,
452 			    "Error: can't open additional debug logging file %s!\n",
453 			    debug_logfile_path);
454 			return 1;
455 		}
456 		SpeechdOptions.debug = debug;
457 
458 		g_free(debug_logfile_path);
459 
460 		/* Redirecting debugging for all output modules */
461 		speechd_modules_debug();
462 	} else {
463 		SpeechdOptions.debug = 0;
464 		speechd_modules_nodebug();
465 		fclose(debug_logfile);
466 	}
467 	return 0;
468 }
469 
470 #define SET_NOTIFICATION_STATE(state) \
471 	if (val) \
472 		settings->notification = settings->notification | SPD_ ## state; \
473 	else \
474 		settings->notification = settings->notification & (~ SPD_ ## state);
475 
set_notification_self(int fd,char * type,int val)476 int set_notification_self(int fd, char *type, int val)
477 {
478 	TFDSetElement *settings;
479 	int uid;
480 
481 	uid = get_client_uid_by_fd(fd);
482 	if (uid == 0)
483 		return 1;
484 
485 	settings = get_client_settings_by_uid(uid);
486 	if (settings == NULL)
487 		return 1;
488 
489 	if (!strcmp(type, "begin")) {
490 		SET_NOTIFICATION_STATE(BEGIN);
491 	} else if (!strcmp(type, "end")) {
492 		SET_NOTIFICATION_STATE(END);
493 	} else if (!strcmp(type, "index_marks")) {
494 		SET_NOTIFICATION_STATE(INDEX_MARKS);
495 	} else if (!strcmp(type, "pause")) {
496 		SET_NOTIFICATION_STATE(PAUSE);
497 	} else if (!strcmp(type, "resume")) {
498 		SET_NOTIFICATION_STATE(RESUME);
499 	} else if (!strcmp(type, "cancel")) {
500 		SET_NOTIFICATION_STATE(CANCEL);
501 	} else if (!strcmp(type, "all")) {
502 		SET_NOTIFICATION_STATE(END);
503 		SET_NOTIFICATION_STATE(BEGIN);
504 		SET_NOTIFICATION_STATE(INDEX_MARKS);
505 		SET_NOTIFICATION_STATE(CANCEL);
506 		SET_NOTIFICATION_STATE(PAUSE);
507 		SET_NOTIFICATION_STATE(RESUME);
508 	} else
509 		return 1;
510 
511 	return 0;
512 
513 }
514 
default_fd_set(void)515 TFDSetElement *default_fd_set(void)
516 {
517 	TFDSetElement *new;
518 
519 	new = (TFDSetElement *) g_malloc(sizeof(TFDSetElement));
520 
521 	new->paused = 0;
522 
523 	/* Fill with the global settings values */
524 	/* We can't use global_fdset copy as this
525 	   returns static structure and we need dynamic */
526 	new->priority = GlobalFDSet.priority;
527 	new->msg_settings.punctuation_mode =
528 	    GlobalFDSet.msg_settings.punctuation_mode;
529 	new->msg_settings.rate = GlobalFDSet.msg_settings.rate;
530 	new->msg_settings.pitch = GlobalFDSet.msg_settings.pitch;
531 	new->msg_settings.pitch_range = GlobalFDSet.msg_settings.pitch_range;
532 	new->msg_settings.volume = GlobalFDSet.msg_settings.volume;
533 	new->msg_settings.voice.language =
534 	    g_strdup(GlobalFDSet.msg_settings.voice.language);
535 	new->output_module = g_strdup(GlobalFDSet.output_module);
536 	new->client_name = g_strdup(GlobalFDSet.client_name);
537 	new->index_mark = g_strdup(GlobalFDSet.index_mark);
538 	new->audio_output_method = g_strdup(GlobalFDSet.audio_output_method);
539 	new->audio_oss_device = g_strdup(GlobalFDSet.audio_oss_device);
540 	new->audio_alsa_device = g_strdup(GlobalFDSet.audio_alsa_device);
541 	new->audio_nas_server = g_strdup(GlobalFDSet.audio_nas_server);
542 	new->audio_pulse_server = g_strdup(GlobalFDSet.audio_pulse_server);
543 	new->audio_pulse_device = g_strdup(GlobalFDSet.audio_pulse_device);
544 
545 	new->msg_settings.voice_type = GlobalFDSet.msg_settings.voice_type;
546 	new->msg_settings.voice.name = NULL;
547 	new->msg_settings.spelling_mode =
548 	    GlobalFDSet.msg_settings.spelling_mode;
549 	new->msg_settings.cap_let_recogn =
550 	    GlobalFDSet.msg_settings.cap_let_recogn;
551 
552 	new->pause_context = GlobalFDSet.pause_context;
553 	new->ssml_mode = GlobalFDSet.ssml_mode;
554 	new->symbols_preprocessing = GlobalFDSet.symbols_preprocessing;
555 	new->notification = GlobalFDSet.notification;
556 
557 	new->active = 1;
558 	new->hist_cur_uid = -1;
559 	new->hist_cur_pos = -1;
560 	new->hist_sorted = 0;
561 	new->index_mark = NULL;
562 	new->paused_while_speaking = 0;
563 
564 	return (new);
565 }
566 
get_client_uid_by_fd(int fd)567 int get_client_uid_by_fd(int fd)
568 {
569 	int *uid;
570 	if (fd <= 0)
571 		return 0;
572 	uid = g_hash_table_lookup(fd_uid, &fd);
573 	if (uid == NULL)
574 		return 0;
575 	return *uid;
576 }
577 
get_client_settings_by_fd(int fd)578 TFDSetElement *get_client_settings_by_fd(int fd)
579 {
580 	TFDSetElement *settings;
581 	int uid;
582 
583 	uid = get_client_uid_by_fd(fd);
584 	if (uid == 0)
585 		return NULL;
586 
587 	settings = g_hash_table_lookup(fd_settings, &uid);
588 	return settings;
589 }
590 
get_client_settings_by_uid(int uid)591 TFDSetElement *get_client_settings_by_uid(int uid)
592 {
593 	TFDSetElement *element;
594 
595 	if (uid < 0)
596 		return NULL;
597 
598 	element = g_hash_table_lookup(fd_settings, &uid);
599 	return element;
600 }
601 
remove_client_settings_by_uid(int uid)602 void remove_client_settings_by_uid(int uid)
603 {
604 	TFDSetElement *element;
605 	assert(uid > 0);
606 	element = (TFDSetElement *) g_hash_table_lookup(fd_settings, &uid);
607 	if (element) {
608 		mem_free_fdset(element);
609 		g_hash_table_remove(fd_settings, &uid);
610 		g_free(element);
611 	} else {
612 		MSG(5, "Warning: FDSet element to be removed not found");
613 	}
614 }
615 
set_param_str(char * parameter,char * value)616 char *set_param_str(char *parameter, char *value)
617 {
618 	char *new;
619 
620 	if (value == NULL) {
621 		new = NULL;
622 		return new;
623 	}
624 
625 	new = g_realloc(parameter, (strlen(value) + 1) * sizeof(char));
626 	strcpy(new, value);
627 
628 	return new;
629 }
630