2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2002, Pauline Middelink
7 * See http://www.asterisk.org for more information about
8 * the Asterisk project. Please do not directly contact
9 * any of the maintainers of this project for assistance;
10 * the project provides a web site, mailing lists and IRC
11 * channels for your use.
13 * This program is free software, distributed under the terms of
14 * the GNU General Public License Version 2. See the LICENSE file
15 * at the top of the source tree.
18 /*! \file res_indications.c
20 * \brief Load the indications
22 * \author Pauline Middelink <middelink@polyware.nl>
24 * Load the country specific dialtones into the asterisk PBX.
29 ASTERISK_FILE_VERSION(__FILE__
, "$Revision$")
34 #include "asterisk/lock.h"
35 #include "asterisk/file.h"
36 #include "asterisk/cli.h"
37 #include "asterisk/config.h"
38 #include "asterisk/channel.h"
39 #include "asterisk/pbx.h"
40 #include "asterisk/module.h"
41 #include "asterisk/translate.h"
42 #include "asterisk/indications.h"
43 #include "asterisk/utils.h"
46 static const char config
[] = "indications.conf";
49 " PlayTones(arg): Plays a tone list. Execution will continue with the next step immediately,\n"
50 "while the tones continue to play.\n"
51 "Arg is either the tone name defined in the indications.conf configuration file, or a directly\n"
52 "specified list of frequencies and durations.\n"
53 "See the sample indications.conf for a description of the specification of a tonelist.\n\n"
54 "Use the StopPlayTones application to stop the tones playing. \n";
57 * Implementation of functions provided by this module
61 * \brief Add a country to indication
62 * \param e the ast_cli_entry for this CLI command
63 * \param cmd the reason we are being called
64 * \param a the arguments being passed to us
66 static char *handle_cli_indication_add(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
68 struct ind_tone_zone
*tz
;
69 int created_country
= 0;
73 e
->command
= "indication add";
75 "Usage: indication add <country> <indication> \"<tonelist>\"\n"
76 " Add the given indication to the country.\n";
85 tz
= ast_get_indication_zone(a
->argv
[2]);
87 /* country does not exist, create it */
88 ast_log(LOG_NOTICE
, "Country '%s' does not exist, creating it.\n", a
->argv
[2]);
90 if (!(tz
= ast_calloc(1, sizeof(*tz
)))) {
93 ast_copy_string(tz
->country
, a
->argv
[2], sizeof(tz
->country
));
94 if (ast_register_indication_country(tz
)) {
95 ast_log(LOG_WARNING
, "Unable to register new country\n");
101 if (ast_register_indication(tz
, a
->argv
[3], a
->argv
[4])) {
102 ast_log(LOG_WARNING
, "Unable to register indication %s/%s\n", a
->argv
[2], a
->argv
[3]);
104 ast_unregister_indication_country(a
->argv
[2]);
111 * \brief Remove a country from indication
112 * \param e the ast_cli_entry for this CLI command
113 * \param cmd the reason we are being called
114 * \param a the arguments being passed to us
116 static char *handle_cli_indication_remove(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
118 struct ind_tone_zone
*tz
;
122 e
->command
= "indication remove";
124 "Usage: indication remove <country> <indication>\n"
125 " Remove the given indication from the country.\n";
131 if (a
->argc
!= 3 && a
->argc
!= 4)
132 return CLI_SHOWUSAGE
;
135 /* remove entiry country */
136 if (ast_unregister_indication_country(a
->argv
[2])) {
137 ast_log(LOG_WARNING
, "Unable to unregister indication country %s\n", a
->argv
[2]);
143 tz
= ast_get_indication_zone(a
->argv
[2]);
145 ast_log(LOG_WARNING
, "Unable to unregister indication %s/%s, country does not exists\n", a
->argv
[2], a
->argv
[3]);
148 if (ast_unregister_indication(tz
, a
->argv
[3])) {
149 ast_log(LOG_WARNING
, "Unable to unregister indication %s/%s\n", a
->argv
[2], a
->argv
[3]);
156 * \brief Show the current indications
157 * \param e the ast_cli_entry for this CLI command
158 * \param cmd the reason we are being called
159 * \param a the arguments being passed to us
161 static char *handle_cli_indication_show(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
163 struct ind_tone_zone
*tz
= NULL
;
165 int found_country
= 0;
169 e
->command
= "indication show";
171 "Usage: indication show [<country> ...]\n"
172 " Display either a condensed for of all country/indications, or the\n"
173 " indications for the specified countries.\n";
180 /* no arguments, show a list of countries */
181 ast_cli(a
->fd
, "Country Alias Description\n");
182 ast_cli(a
->fd
, "===========================\n");
183 while ((tz
= ast_walk_indications(tz
)))
184 ast_cli(a
->fd
, "%-7.7s %-7.7s %s\n", tz
->country
, tz
->alias
, tz
->description
);
187 /* there was a request for specific country(ies), lets humor them */
188 while ((tz
= ast_walk_indications(tz
))) {
190 for (i
= 2; i
< a
->argc
; i
++) {
191 if (strcasecmp(tz
->country
, a
->argv
[i
]) == 0 && !tz
->alias
[0]) {
192 struct ind_tone_zone_sound
* ts
;
193 if (!found_country
) {
195 ast_cli(a
->fd
, "Country Indication PlayList\n");
196 ast_cli(a
->fd
, "=====================================\n");
198 j
= snprintf(buf
, sizeof(buf
), "%-7.7s %-15.15s ", tz
->country
, "<ringcadence>");
199 for (i
= 0; i
< tz
->nrringcadence
; i
++) {
200 j
+= snprintf(buf
+ j
, sizeof(buf
) - j
, "%d,", tz
->ringcadence
[i
]);
202 if (tz
->nrringcadence
)
204 ast_copy_string(buf
+ j
, "\n", sizeof(buf
) - j
);
205 ast_cli(a
->fd
, "%s", buf
);
206 for (ts
= tz
->tones
; ts
; ts
= ts
->next
)
207 ast_cli(a
->fd
, "%-7.7s %-15.15s %s\n", tz
->country
, ts
->name
, ts
->data
);
213 ast_cli(a
->fd
, "No countries matched your criteria.\n");
218 * \brief play tone for indication country
219 * \param chan ast_channel to play the sounds back to
220 * \param data contains tone to play
222 static int handle_playtones(struct ast_channel
*chan
, void *data
)
224 struct ind_tone_zone_sound
*ts
;
227 if (!data
|| !((char*)data
)[0]) {
228 ast_log(LOG_NOTICE
,"Nothing to play\n");
231 ts
= ast_get_indication_tone(chan
->zone
, (const char*)data
);
232 if (ts
&& ts
->data
[0])
233 res
= ast_playtones_start(chan
, 0, ts
->data
, 0);
235 res
= ast_playtones_start(chan
, 0, (const char*)data
, 0);
237 ast_log(LOG_NOTICE
,"Unable to start playtones\n");
242 * \brief Stop tones playing
246 static int handle_stopplaytones(struct ast_channel
*chan
, void *data
)
248 ast_playtones_stop(chan
);
252 /*! \brief load indications module */
253 static int ind_load_module(int reload
)
255 struct ast_config
*cfg
;
256 struct ast_variable
*v
;
259 struct ind_tone_zone
*tones
;
260 const char *country
= NULL
;
261 struct ast_flags config_flags
= { reload
? CONFIG_FLAG_FILEUNCHANGED
: 0 };
263 /* that the following cast is needed, is yuk! */
264 /* yup, checked it out. It is NOT written to. */
265 cfg
= ast_config_load((char *)config
, config_flags
);
268 else if (cfg
== CONFIG_STATUS_FILEUNCHANGED
)
272 ast_unregister_indication_country(NULL
);
274 /* Use existing config to populate the Indication table */
275 cxt
= ast_category_browse(cfg
, NULL
);
277 /* All categories but "general" are considered countries */
278 if (!strcasecmp(cxt
, "general")) {
279 cxt
= ast_category_browse(cfg
, cxt
);
282 if (!(tones
= ast_calloc(1, sizeof(*tones
)))) {
283 ast_config_destroy(cfg
);
286 ast_copy_string(tones
->country
,cxt
,sizeof(tones
->country
));
288 v
= ast_variable_browse(cfg
, cxt
);
290 if (!strcasecmp(v
->name
, "description")) {
291 ast_copy_string(tones
->description
, v
->value
, sizeof(tones
->description
));
292 } else if ((!strcasecmp(v
->name
,"ringcadence"))||(!strcasecmp(v
->name
,"ringcadance"))) {
293 char *ring
,*rings
= ast_strdupa(v
->value
);
295 ring
= strsep(&c
,",");
298 if (!isdigit(ring
[0]) || (val
=atoi(ring
))==-1) {
299 ast_log(LOG_WARNING
,"Invalid ringcadence given '%s' at line %d.\n",ring
,v
->lineno
);
300 ring
= strsep(&c
,",");
303 if (!(tmp
= ast_realloc(tones
->ringcadence
, (tones
->nrringcadence
+ 1) * sizeof(int)))) {
304 ast_config_destroy(cfg
);
307 tones
->ringcadence
= tmp
;
308 tmp
[tones
->nrringcadence
] = val
;
309 tones
->nrringcadence
++;
311 ring
= strsep(&c
,",");
313 } else if (!strcasecmp(v
->name
,"alias")) {
314 char *countries
= ast_strdupa(v
->value
);
316 country
= strsep(&c
,",");
318 struct ind_tone_zone
* azone
;
319 if (!(azone
= ast_calloc(1, sizeof(*azone
)))) {
320 ast_config_destroy(cfg
);
323 ast_copy_string(azone
->country
, country
, sizeof(azone
->country
));
324 ast_copy_string(azone
->alias
, cxt
, sizeof(azone
->alias
));
325 if (ast_register_indication_country(azone
)) {
326 ast_log(LOG_WARNING
, "Unable to register indication alias at line %d.\n",v
->lineno
);
330 country
= strsep(&c
,",");
333 /* add tone to country */
334 struct ind_tone_zone_sound
*ps
,*ts
;
335 for (ps
=NULL
,ts
=tones
->tones
; ts
; ps
=ts
, ts
=ts
->next
) {
336 if (strcasecmp(v
->name
,ts
->name
)==0) {
338 ast_log(LOG_NOTICE
,"Duplicate entry '%s', skipped.\n",v
->name
);
342 /* not there, add it to the back */
343 if (!(ts
= ast_malloc(sizeof(*ts
)))) {
344 ast_config_destroy(cfg
);
348 ts
->name
= ast_strdup(v
->name
);
349 ts
->data
= ast_strdup(v
->value
);
357 if (tones
->description
[0] || tones
->alias
[0] || tones
->tones
) {
358 if (ast_register_indication_country(tones
)) {
359 ast_log(LOG_WARNING
, "Unable to register indication at line %d.\n",v
->lineno
);
362 } else ast_free(tones
);
364 cxt
= ast_category_browse(cfg
, cxt
);
367 /* determine which country is the default */
368 country
= ast_variable_retrieve(cfg
,"general","country");
369 if (!country
|| !*country
|| ast_set_indication_country(country
))
370 ast_log(LOG_WARNING
,"Unable to set the default country (for indication tones)\n");
372 ast_config_destroy(cfg
);
376 /*! \brief CLI entries for commands provided by this module */
377 static struct ast_cli_entry cli_indications
[] = {
378 AST_CLI_DEFINE(handle_cli_indication_add
, "Add the given indication to the country"),
379 AST_CLI_DEFINE(handle_cli_indication_remove
, "Remove the given indication from the country"),
380 AST_CLI_DEFINE(handle_cli_indication_show
, "Display a list of all countries/indications")
383 /*! \brief Unload indicators module */
384 static int unload_module(void)
386 /* remove the registed indications... */
387 ast_unregister_indication_country(NULL
);
389 /* and the functions */
390 ast_cli_unregister_multiple(cli_indications
, sizeof(cli_indications
) / sizeof(struct ast_cli_entry
));
391 ast_unregister_application("PlayTones");
392 ast_unregister_application("StopPlayTones");
397 /*! \brief Load indications module */
398 static int load_module(void)
400 if (ind_load_module(0))
401 return AST_MODULE_LOAD_DECLINE
;
402 ast_cli_register_multiple(cli_indications
, sizeof(cli_indications
) / sizeof(struct ast_cli_entry
));
403 ast_register_application("PlayTones", handle_playtones
, "Play a tone list", playtones_desc
);
404 ast_register_application("StopPlayTones", handle_stopplaytones
, "Stop playing a tone list"," StopPlayTones(): Stop playing a tone list");
406 return AST_MODULE_LOAD_SUCCESS
;
409 /*! \brief Reload indications module */
410 static int reload(void)
412 return ind_load_module(1);
415 AST_MODULE_INFO(ASTERISK_GPL_KEY
, AST_MODFLAG_GLOBAL_SYMBOLS
, "Region-specific tones",
417 .unload
= unload_module
,