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$")
37 #include <sys/types.h>
40 #include "asterisk/lock.h"
41 #include "asterisk/file.h"
42 #include "asterisk/cli.h"
43 #include "asterisk/logger.h"
44 #include "asterisk/config.h"
45 #include "asterisk/channel.h"
46 #include "asterisk/pbx.h"
47 #include "asterisk/module.h"
48 #include "asterisk/translate.h"
49 #include "asterisk/indications.h"
50 #include "asterisk/utils.h"
53 static const char config[] = "indications.conf";
56 * Help for commands provided by this module ...
58 static char help_add_indication[] =
59 "Usage: indication add <country> <indication> \"<tonelist>\"\n"
60 " Add the given indication to the country.\n";
62 static char help_remove_indication[] =
63 "Usage: indication remove <country> <indication>\n"
64 " Remove the given indication from the country.\n";
66 static char help_show_indications[] =
67 "Usage: indication show [<country> ...]\n"
68 " Display either a condensed for of all country/indications, or the\n"
69 " indications for the specified countries.\n";
72 "PlayTones(arg): Plays a tone list. Execution will continue with the next step immediately,\n"
73 "while the tones continue to play.\n"
74 "Arg is either the tone name defined in the indications.conf configuration file, or a directly\n"
75 "specified list of frequencies and durations.\n"
76 "See the sample indications.conf for a description of the specification of a tonelist.\n\n"
77 "Use the StopPlayTones application to stop the tones playing. \n";
80 * Implementation of functions provided by this module
84 * \brief Add a country to indication
85 * \param fd file descriptor of CLI
86 * \param argc no of args
87 * \param argv arguements
89 static int handle_add_indication(int fd, int argc, char *argv[])
91 struct ind_tone_zone *tz;
92 int created_country = 0;
93 if (argc != 5) return RESULT_SHOWUSAGE;
95 tz = ast_get_indication_zone(argv[2]);
97 /* country does not exist, create it */
98 ast_log(LOG_NOTICE, "Country '%s' does not exist, creating it.\n",argv[2]);
100 if (!(tz = ast_calloc(1, sizeof(*tz)))) {
103 ast_copy_string(tz->country,argv[2],sizeof(tz->country));
104 if (ast_register_indication_country(tz)) {
105 ast_log(LOG_WARNING, "Unable to register new country\n");
111 if (ast_register_indication(tz,argv[3],argv[4])) {
112 ast_log(LOG_WARNING, "Unable to register indication %s/%s\n",argv[2],argv[3]);
114 ast_unregister_indication_country(argv[2]);
121 * \brief Remove a country from indication
122 * \param fd file descriptor of CLI
123 * \param argc no of args
124 * \param argv arguements
126 static int handle_remove_indication(int fd, int argc, char *argv[])
128 struct ind_tone_zone *tz;
129 if (argc != 3 && argc != 4) return RESULT_SHOWUSAGE;
132 /* remove entiry country */
133 if (ast_unregister_indication_country(argv[2])) {
134 ast_log(LOG_WARNING, "Unable to unregister indication country %s\n",argv[2]);
140 tz = ast_get_indication_zone(argv[2]);
142 ast_log(LOG_WARNING, "Unable to unregister indication %s/%s, country does not exists\n",argv[2],argv[3]);
145 if (ast_unregister_indication(tz,argv[3])) {
146 ast_log(LOG_WARNING, "Unable to unregister indication %s/%s\n",argv[2],argv[3]);
153 * \brief Show the current indications
154 * \param fd file descriptor of CLI
155 * \param argc no of args
156 * \param argv arguements
158 static int handle_show_indications(int fd, int argc, char *argv[])
160 struct ind_tone_zone *tz = NULL;
162 int found_country = 0;
165 /* no arguments, show a list of countries */
166 ast_cli(fd,"Country Alias Description\n"
167 "===========================\n");
168 while ( (tz = ast_walk_indications(tz) ) )
169 ast_cli(fd,"%-7.7s %-7.7s %s\n", tz->country, tz->alias, tz->description);
172 /* there was a request for specific country(ies), lets humor them */
173 while ( (tz = ast_walk_indications(tz) ) ) {
175 for (i=2; i<argc; i++) {
176 if (strcasecmp(tz->country,argv[i])==0 &&
178 struct ind_tone_zone_sound* ts;
179 if (!found_country) {
181 ast_cli(fd,"Country Indication PlayList\n"
182 "=====================================\n");
184 j = snprintf(buf,sizeof(buf),"%-7.7s %-15.15s ",tz->country,"<ringcadence>");
185 for (i=0; i<tz->nrringcadence; i++) {
186 j += snprintf(buf+j,sizeof(buf)-j,"%d,",tz->ringcadence[i]);
188 if (tz->nrringcadence)
190 ast_copy_string(buf+j,"\n",sizeof(buf)-j);
192 for (ts=tz->tones; ts; ts=ts->next)
193 ast_cli(fd,"%-7.7s %-15.15s %s\n",tz->country,ts->name,ts->data);
199 ast_cli(fd,"No countries matched your criteria.\n");
204 * \brief play tone for indication country
205 * \param chan ast_channel to play the sounds back to
206 * \param data contains tone to play
208 static int handle_playtones(struct ast_channel *chan, void *data)
210 struct ind_tone_zone_sound *ts;
213 if (!data || !((char*)data)[0]) {
214 ast_log(LOG_NOTICE,"Nothing to play\n");
217 ts = ast_get_indication_tone(chan->zone, (const char*)data);
218 if (ts && ts->data[0])
219 res = ast_playtones_start(chan, 0, ts->data, 0);
221 res = ast_playtones_start(chan, 0, (const char*)data, 0);
223 ast_log(LOG_NOTICE,"Unable to start playtones\n");
228 * \brief Stop tones playing
232 static int handle_stopplaytones(struct ast_channel *chan, void *data)
234 ast_playtones_stop(chan);
238 /*! \brief load indications module */
239 static int ind_load_module(void)
241 struct ast_config *cfg;
242 struct ast_variable *v;
245 struct ind_tone_zone *tones;
246 const char *country = NULL;
248 /* that the following cast is needed, is yuk! */
249 /* yup, checked it out. It is NOT written to. */
250 cfg = ast_config_load((char *)config);
254 /* Use existing config to populate the Indication table */
255 cxt = ast_category_browse(cfg, NULL);
257 /* All categories but "general" are considered countries */
258 if (!strcasecmp(cxt, "general")) {
259 cxt = ast_category_browse(cfg, cxt);
262 if (!(tones = ast_calloc(1, sizeof(*tones)))) {
263 ast_config_destroy(cfg);
266 ast_copy_string(tones->country,cxt,sizeof(tones->country));
268 v = ast_variable_browse(cfg, cxt);
270 if (!strcasecmp(v->name, "description")) {
271 ast_copy_string(tones->description, v->value, sizeof(tones->description));
272 } else if ((!strcasecmp(v->name,"ringcadence"))||(!strcasecmp(v->name,"ringcadance"))) {
273 char *ring,*rings = ast_strdupa(v->value);
275 ring = strsep(&c,",");
278 if (!isdigit(ring[0]) || (val=atoi(ring))==-1) {
279 ast_log(LOG_WARNING,"Invalid ringcadence given '%s' at line %d.\n",ring,v->lineno);
280 ring = strsep(&c,",");
283 if (!(tmp = ast_realloc(tones->ringcadence, (tones->nrringcadence + 1) * sizeof(int)))) {
284 ast_config_destroy(cfg);
287 tones->ringcadence = tmp;
288 tmp[tones->nrringcadence] = val;
289 tones->nrringcadence++;
291 ring = strsep(&c,",");
293 } else if (!strcasecmp(v->name,"alias")) {
294 char *countries = ast_strdupa(v->value);
296 country = strsep(&c,",");
298 struct ind_tone_zone* azone;
299 if (!(azone = ast_calloc(1, sizeof(*azone)))) {
300 ast_config_destroy(cfg);
303 ast_copy_string(azone->country, country, sizeof(azone->country));
304 ast_copy_string(azone->alias, cxt, sizeof(azone->alias));
305 if (ast_register_indication_country(azone)) {
306 ast_log(LOG_WARNING, "Unable to register indication alias at line %d.\n",v->lineno);
310 country = strsep(&c,",");
313 /* add tone to country */
314 struct ind_tone_zone_sound *ps,*ts;
315 for (ps=NULL,ts=tones->tones; ts; ps=ts, ts=ts->next) {
316 if (strcasecmp(v->name,ts->name)==0) {
318 ast_log(LOG_NOTICE,"Duplicate entry '%s', skipped.\n",v->name);
322 /* not there, add it to the back */
323 if (!(ts = ast_malloc(sizeof(*ts)))) {
324 ast_config_destroy(cfg);
328 ts->name = ast_strdup(v->name);
329 ts->data = ast_strdup(v->value);
337 if (tones->description[0] || tones->alias[0] || tones->tones) {
338 if (ast_register_indication_country(tones)) {
339 ast_log(LOG_WARNING, "Unable to register indication at line %d.\n",v->lineno);
342 } else ast_free(tones);
344 cxt = ast_category_browse(cfg, cxt);
347 /* determine which country is the default */
348 country = ast_variable_retrieve(cfg,"general","country");
349 if (!country || !*country || ast_set_indication_country(country))
350 ast_log(LOG_WARNING,"Unable to set the default country (for indication tones)\n");
352 ast_config_destroy(cfg);
356 /*! \brief CLI entries for commands provided by this module */
357 static struct ast_cli_entry cli_indications[] = {
358 { { "indication", "add", NULL },
359 handle_add_indication, "Add the given indication to the country",
360 help_add_indication, NULL },
362 { { "indication", "remove", NULL },
363 handle_remove_indication, "Remove the given indication from the country",
364 help_remove_indication, NULL },
366 { { "indication", "show", NULL },
367 handle_show_indications, "Display a list of all countries/indications",
368 help_show_indications },
371 /*! \brief Unload indicators module */
372 static int unload_module(void)
374 /* remove the registed indications... */
375 ast_unregister_indication_country(NULL);
377 /* and the functions */
378 ast_cli_unregister_multiple(cli_indications, sizeof(cli_indications) / sizeof(struct ast_cli_entry));
379 ast_unregister_application("PlayTones");
380 ast_unregister_application("StopPlayTones");
385 /*! \brief Load indications module */
386 static int load_module(void)
388 if (ind_load_module())
389 return AST_MODULE_LOAD_DECLINE;
390 ast_cli_register_multiple(cli_indications, sizeof(cli_indications) / sizeof(struct ast_cli_entry));
391 ast_register_application("PlayTones", handle_playtones, "Play a tone list", playtones_desc);
392 ast_register_application("StopPlayTones", handle_stopplaytones, "Stop playing a tone list","Stop playing a tone list");
397 /*! \brief Reload indications module */
398 static int reload(void)
400 /* remove the registed indications... */
401 ast_unregister_indication_country(NULL);
403 return ind_load_module();
406 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Region-specific tones",
408 .unload = unload_module,