Correction to commmit 120863, make sure proper destructor function is called as well...
[asterisk-bristuff.git] / res / res_indications.c
blobed8a24b334ed510f76d799e38dbbb6d24983ed21
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 <unistd.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <errno.h>
37 #include <sys/types.h>
38 #include <sys/stat.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"
52 /* Globals */
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";
71 char *playtones_desc=
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 * ADD INDICATION command stuff
86 static int handle_add_indication(int fd, int argc, char *argv[])
88 struct tone_zone *tz;
89 int created_country = 0;
90 if (argc != 5) return RESULT_SHOWUSAGE;
92 tz = ast_get_indication_zone(argv[2]);
93 if (!tz) {
94 /* country does not exist, create it */
95 ast_log(LOG_NOTICE, "Country '%s' does not exist, creating it.\n",argv[2]);
97 if (!(tz = ast_calloc(1, sizeof(*tz)))) {
98 return -1;
100 ast_copy_string(tz->country,argv[2],sizeof(tz->country));
101 if (ast_register_indication_country(tz)) {
102 ast_log(LOG_WARNING, "Unable to register new country\n");
103 free(tz);
104 return -1;
106 created_country = 1;
108 if (ast_register_indication(tz,argv[3],argv[4])) {
109 ast_log(LOG_WARNING, "Unable to register indication %s/%s\n",argv[2],argv[3]);
110 if (created_country)
111 ast_unregister_indication_country(argv[2]);
112 return -1;
114 return 0;
118 * REMOVE INDICATION command stuff
120 static int handle_remove_indication(int fd, int argc, char *argv[])
122 struct tone_zone *tz;
123 if (argc != 3 && argc != 4) return RESULT_SHOWUSAGE;
125 if (argc == 3) {
126 /* remove entiry country */
127 if (ast_unregister_indication_country(argv[2])) {
128 ast_log(LOG_WARNING, "Unable to unregister indication country %s\n",argv[2]);
129 return -1;
131 return 0;
134 tz = ast_get_indication_zone(argv[2]);
135 if (!tz) {
136 ast_log(LOG_WARNING, "Unable to unregister indication %s/%s, country does not exists\n",argv[2],argv[3]);
137 return -1;
139 if (ast_unregister_indication(tz,argv[3])) {
140 ast_log(LOG_WARNING, "Unable to unregister indication %s/%s\n",argv[2],argv[3]);
141 return -1;
143 return 0;
147 * SHOW INDICATIONS command stuff
149 static int handle_show_indications(int fd, int argc, char *argv[])
151 struct tone_zone *tz = NULL;
152 char buf[256];
153 int found_country = 0;
155 if (argc == 2) {
156 /* no arguments, show a list of countries */
157 ast_cli(fd,"Country Alias Description\n"
158 "===========================\n");
159 while ( (tz = ast_walk_indications(tz) ) )
160 ast_cli(fd,"%-7.7s %-7.7s %s\n", tz->country, tz->alias, tz->description);
161 return 0;
163 /* there was a request for specific country(ies), lets humor them */
164 while ( (tz = ast_walk_indications(tz) ) ) {
165 int i,j;
166 for (i=2; i<argc; i++) {
167 if (strcasecmp(tz->country,argv[i])==0 &&
168 !tz->alias[0]) {
169 struct tone_zone_sound* ts;
170 if (!found_country) {
171 found_country = 1;
172 ast_cli(fd,"Country Indication PlayList\n"
173 "=====================================\n");
175 j = snprintf(buf,sizeof(buf),"%-7.7s %-15.15s ",tz->country,"<ringcadence>");
176 for (i=0; i<tz->nrringcadence; i++) {
177 j += snprintf(buf+j,sizeof(buf)-j,"%d,",tz->ringcadence[i]);
179 if (tz->nrringcadence)
180 j--;
181 ast_copy_string(buf+j,"\n",sizeof(buf)-j);
182 ast_cli(fd,buf);
183 for (ts=tz->tones; ts; ts=ts->next)
184 ast_cli(fd,"%-7.7s %-15.15s %s\n",tz->country,ts->name,ts->data);
185 break;
189 if (!found_country)
190 ast_cli(fd,"No countries matched your criteria.\n");
191 return -1;
195 * Playtones command stuff
197 static int handle_playtones(struct ast_channel *chan, void *data)
199 struct tone_zone_sound *ts;
200 int res;
202 if (!data || !((char*)data)[0]) {
203 ast_log(LOG_NOTICE,"Nothing to play\n");
204 return -1;
206 ts = ast_get_indication_tone(chan->zone, (const char*)data);
207 if (ts && ts->data[0])
208 res = ast_playtones_start(chan, 0, ts->data, 0);
209 else
210 res = ast_playtones_start(chan, 0, (const char*)data, 0);
211 if (res)
212 ast_log(LOG_NOTICE,"Unable to start playtones\n");
213 return res;
217 * StopPlaylist command stuff
219 static int handle_stopplaytones(struct ast_channel *chan, void *data)
221 ast_playtones_stop(chan);
222 return 0;
226 * Load module stuff
228 static int ind_load_module(void)
230 struct ast_config *cfg;
231 struct ast_variable *v;
232 char *cxt;
233 char *c;
234 struct tone_zone *tones;
235 const char *country = NULL;
237 /* that the following cast is needed, is yuk! */
238 /* yup, checked it out. It is NOT written to. */
239 cfg = ast_config_load((char *)config);
240 if (!cfg)
241 return -1;
243 /* Use existing config to populate the Indication table */
244 cxt = ast_category_browse(cfg, NULL);
245 while(cxt) {
246 /* All categories but "general" are considered countries */
247 if (!strcasecmp(cxt, "general")) {
248 cxt = ast_category_browse(cfg, cxt);
249 continue;
251 if (!(tones = ast_calloc(1, sizeof(*tones)))) {
252 ast_config_destroy(cfg);
253 return -1;
255 ast_copy_string(tones->country,cxt,sizeof(tones->country));
257 v = ast_variable_browse(cfg, cxt);
258 while(v) {
259 if (!strcasecmp(v->name, "description")) {
260 ast_copy_string(tones->description, v->value, sizeof(tones->description));
261 } else if ((!strcasecmp(v->name,"ringcadence"))||(!strcasecmp(v->name,"ringcadance"))) {
262 char *ring,*rings = ast_strdupa(v->value);
263 c = rings;
264 ring = strsep(&c,",");
265 while (ring) {
266 int *tmp, val;
267 if (!isdigit(ring[0]) || (val=atoi(ring))==-1) {
268 ast_log(LOG_WARNING,"Invalid ringcadence given '%s' at line %d.\n",ring,v->lineno);
269 ring = strsep(&c,",");
270 continue;
272 if (!(tmp = ast_realloc(tones->ringcadence, (tones->nrringcadence + 1) * sizeof(int)))) {
273 ast_config_destroy(cfg);
274 return -1;
276 tones->ringcadence = tmp;
277 tmp[tones->nrringcadence] = val;
278 tones->nrringcadence++;
279 /* next item */
280 ring = strsep(&c,",");
282 } else if (!strcasecmp(v->name,"alias")) {
283 char *countries = ast_strdupa(v->value);
284 c = countries;
285 country = strsep(&c,",");
286 while (country) {
287 struct tone_zone* azone;
288 if (!(azone = ast_calloc(1, sizeof(*azone)))) {
289 ast_config_destroy(cfg);
290 return -1;
292 ast_copy_string(azone->country, country, sizeof(azone->country));
293 ast_copy_string(azone->alias, cxt, sizeof(azone->alias));
294 if (ast_register_indication_country(azone)) {
295 ast_log(LOG_WARNING, "Unable to register indication alias at line %d.\n",v->lineno);
296 free(tones);
298 /* next item */
299 country = strsep(&c,",");
301 } else {
302 /* add tone to country */
303 struct tone_zone_sound *ps,*ts;
304 for (ps=NULL,ts=tones->tones; ts; ps=ts, ts=ts->next) {
305 if (strcasecmp(v->name,ts->name)==0) {
306 /* already there */
307 ast_log(LOG_NOTICE,"Duplicate entry '%s', skipped.\n",v->name);
308 goto out;
311 /* not there, add it to the back */
312 if (!(ts = ast_malloc(sizeof(*ts)))) {
313 ast_config_destroy(cfg);
314 return -1;
316 ts->next = NULL;
317 ts->name = strdup(v->name);
318 ts->data = strdup(v->value);
319 if (ps)
320 ps->next = ts;
321 else
322 tones->tones = ts;
324 out: v = v->next;
326 if (tones->description[0] || tones->alias[0] || tones->tones) {
327 if (ast_register_indication_country(tones)) {
328 ast_log(LOG_WARNING, "Unable to register indication at line %d.\n",v->lineno);
329 free(tones);
331 } else free(tones);
333 cxt = ast_category_browse(cfg, cxt);
336 /* determine which country is the default */
337 country = ast_variable_retrieve(cfg,"general","country");
338 if (!country || !*country || ast_set_indication_country(country))
339 ast_log(LOG_WARNING,"Unable to set the default country (for indication tones)\n");
341 ast_config_destroy(cfg);
342 return 0;
346 * CLI entries for commands provided by this module
348 static struct ast_cli_entry cli_show_indications_deprecated = {
349 { "show", "indications", NULL },
350 handle_show_indications, NULL,
351 NULL };
353 static struct ast_cli_entry cli_indications[] = {
354 { { "indication", "add", NULL },
355 handle_add_indication, "Add the given indication to the country",
356 help_add_indication, NULL },
358 { { "indication", "remove", NULL },
359 handle_remove_indication, "Remove the given indication from the country",
360 help_remove_indication, NULL },
362 { { "indication", "show", NULL },
363 handle_show_indications, "Display a list of all countries/indications",
364 help_show_indications, NULL, &cli_show_indications_deprecated },
368 * Standard module functions ...
370 static int unload_module(void)
372 /* remove the registed indications... */
373 ast_unregister_indication_country(NULL);
375 /* and the functions */
376 ast_cli_unregister_multiple(cli_indications, sizeof(cli_indications) / sizeof(struct ast_cli_entry));
377 ast_unregister_application("PlayTones");
378 ast_unregister_application("StopPlayTones");
379 return 0;
383 static int load_module(void)
385 if (ind_load_module())
386 return AST_MODULE_LOAD_DECLINE;
387 ast_cli_register_multiple(cli_indications, sizeof(cli_indications) / sizeof(struct ast_cli_entry));
388 ast_register_application("PlayTones", handle_playtones, "Play a tone list", playtones_desc);
389 ast_register_application("StopPlayTones", handle_stopplaytones, "Stop playing a tone list","Stop playing a tone list");
391 return 0;
394 static int reload(void)
396 /* remove the registed indications... */
397 ast_unregister_indication_country(NULL);
399 return ind_load_module();
402 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Indications Resource",
403 .load = load_module,
404 .unload = unload_module,
405 .reload = reload,