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