Add a function, CHANNELS(), which retrieves a list of all active channels.
[asterisk-bristuff.git] / res / res_indications.c
blobaf56444cd115b1e7661ecdc11bd7f864ed008475
1 /*
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.
27 #include "asterisk.h"
29 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
31 #include <ctype.h>
32 #include <sys/stat.h>
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"
45 /* Globals */
46 static const char config[] = "indications.conf";
48 char *playtones_desc=
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
60 /*!
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;
71 switch (cmd) {
72 case CLI_INIT:
73 e->command = "indication add";
74 e->usage =
75 "Usage: indication add <country> <indication> \"<tonelist>\"\n"
76 " Add the given indication to the country.\n";
77 return NULL;
78 case CLI_GENERATE:
79 return NULL;
82 if (a->argc != 5)
83 return CLI_SHOWUSAGE;
85 tz = ast_get_indication_zone(a->argv[2]);
86 if (!tz) {
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)))) {
91 return CLI_FAILURE;
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");
96 ast_free(tz);
97 return CLI_FAILURE;
99 created_country = 1;
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]);
103 if (created_country)
104 ast_unregister_indication_country(a->argv[2]);
105 return CLI_FAILURE;
107 return CLI_SUCCESS;
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;
120 switch (cmd) {
121 case CLI_INIT:
122 e->command = "indication remove";
123 e->usage =
124 "Usage: indication remove <country> <indication>\n"
125 " Remove the given indication from the country.\n";
126 return NULL;
127 case CLI_GENERATE:
128 return NULL;
131 if (a->argc != 3 && a->argc != 4)
132 return CLI_SHOWUSAGE;
134 if (a->argc == 3) {
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]);
138 return CLI_FAILURE;
140 return CLI_SUCCESS;
143 tz = ast_get_indication_zone(a->argv[2]);
144 if (!tz) {
145 ast_log(LOG_WARNING, "Unable to unregister indication %s/%s, country does not exists\n", a->argv[2], a->argv[3]);
146 return CLI_FAILURE;
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]);
150 return CLI_FAILURE;
152 return CLI_SUCCESS;
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;
164 char buf[256];
165 int found_country = 0;
167 switch (cmd) {
168 case CLI_INIT:
169 e->command = "indication show";
170 e->usage =
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";
174 return NULL;
175 case CLI_GENERATE:
176 return NULL;
179 if (a->argc == 2) {
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);
185 return CLI_SUCCESS;
187 /* there was a request for specific country(ies), lets humor them */
188 while ((tz = ast_walk_indications(tz))) {
189 int i, j;
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) {
194 found_country = 1;
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)
203 j--;
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);
208 break;
212 if (!found_country)
213 ast_cli(a->fd, "No countries matched your criteria.\n");
214 return CLI_SUCCESS;
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;
225 int res;
227 if (!data || !((char*)data)[0]) {
228 ast_log(LOG_NOTICE,"Nothing to play\n");
229 return -1;
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);
234 else
235 res = ast_playtones_start(chan, 0, (const char*)data, 0);
236 if (res)
237 ast_log(LOG_NOTICE,"Unable to start playtones\n");
238 return res;
242 * \brief Stop tones playing
243 * \param chan
244 * \param data
246 static int handle_stopplaytones(struct ast_channel *chan, void *data)
248 ast_playtones_stop(chan);
249 return 0;
252 /*! \brief load indications module */
253 static int ind_load_module(int reload)
255 struct ast_config *cfg;
256 struct ast_variable *v;
257 char *cxt;
258 char *c;
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);
266 if (!cfg)
267 return -1;
268 else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
269 return 0;
271 if (reload)
272 ast_unregister_indication_country(NULL);
274 /* Use existing config to populate the Indication table */
275 cxt = ast_category_browse(cfg, NULL);
276 while(cxt) {
277 /* All categories but "general" are considered countries */
278 if (!strcasecmp(cxt, "general")) {
279 cxt = ast_category_browse(cfg, cxt);
280 continue;
282 if (!(tones = ast_calloc(1, sizeof(*tones)))) {
283 ast_config_destroy(cfg);
284 return -1;
286 ast_copy_string(tones->country,cxt,sizeof(tones->country));
288 v = ast_variable_browse(cfg, cxt);
289 while(v) {
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);
294 c = rings;
295 ring = strsep(&c,",");
296 while (ring) {
297 int *tmp, val;
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,",");
301 continue;
303 if (!(tmp = ast_realloc(tones->ringcadence, (tones->nrringcadence + 1) * sizeof(int)))) {
304 ast_config_destroy(cfg);
305 return -1;
307 tones->ringcadence = tmp;
308 tmp[tones->nrringcadence] = val;
309 tones->nrringcadence++;
310 /* next item */
311 ring = strsep(&c,",");
313 } else if (!strcasecmp(v->name,"alias")) {
314 char *countries = ast_strdupa(v->value);
315 c = countries;
316 country = strsep(&c,",");
317 while (country) {
318 struct ind_tone_zone* azone;
319 if (!(azone = ast_calloc(1, sizeof(*azone)))) {
320 ast_config_destroy(cfg);
321 return -1;
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);
327 ast_free(tones);
329 /* next item */
330 country = strsep(&c,",");
332 } else {
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) {
337 /* already there */
338 ast_log(LOG_NOTICE,"Duplicate entry '%s', skipped.\n",v->name);
339 goto out;
342 /* not there, add it to the back */
343 if (!(ts = ast_malloc(sizeof(*ts)))) {
344 ast_config_destroy(cfg);
345 return -1;
347 ts->next = NULL;
348 ts->name = ast_strdup(v->name);
349 ts->data = ast_strdup(v->value);
350 if (ps)
351 ps->next = ts;
352 else
353 tones->tones = ts;
355 out: v = v->next;
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);
360 ast_free(tones);
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);
373 return 0;
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");
393 return 0;
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",
416 .load = load_module,
417 .unload = unload_module,
418 .reload = reload,