remove extraneous svn:executable properties
[asterisk/asterisk.git] / res / res_indications.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2002, Pauline Middelink
5  *
6  *
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.
12  *
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.
16  */
17
18 /*! \file res_indications.c 
19  *
20  * \brief Load the indications
21  * 
22  * \author Pauline Middelink <middelink@polyware.nl>
23  *
24  * Load the country specific dialtones into the asterisk PBX.
25  */
26  
27 #include <unistd.h>
28 #include <string.h>
29 #include <ctype.h>
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <errno.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35
36 #include "asterisk.h"
37
38 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
39
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
51
52 /* Globals */
53 static const char dtext[] = "Indications Configuration";
54 static const char config[] = "indications.conf";
55
56 /*
57  * Help for commands provided by this module ...
58  */
59 static char help_add_indication[] =
60 "Usage: indication add <country> <indication> \"<tonelist>\"\n"
61 "       Add the given indication to the country.\n";
62
63 static char help_remove_indication[] =
64 "Usage: indication remove <country> <indication>\n"
65 "       Remove the given indication from the country.\n";
66
67 static char help_show_indications[] =
68 "Usage: show indications [<country> ...]\n"
69 "       Show either a condensed for of all country/indications, or the\n"
70 "       indications for the specified countries.\n";
71
72 char *playtones_desc=
73 "PlayTones(arg): Plays a tone list. Execution will continue with the next step immediately,\n"
74 "while the tones continue to play.\n"
75 "Arg is either the tone name defined in the indications.conf configuration file, or a directly\n"
76 "specified list of frequencies and durations.\n"
77 "See the sample indications.conf for a description of the specification of a tonelist.\n\n"
78 "Use the StopPlayTones application to stop the tones playing. \n";
79
80 /*
81  * Implementation of functions provided by this module
82  */
83
84 /*
85  * ADD INDICATION command stuff
86  */
87 static int handle_add_indication(int fd, int argc, char *argv[])
88 {
89         struct tone_zone *tz;
90         int created_country = 0;
91         if (argc != 5) return RESULT_SHOWUSAGE;
92
93         tz = ast_get_indication_zone(argv[2]);
94         if (!tz) {
95                 /* country does not exist, create it */
96                 ast_log(LOG_NOTICE, "Country '%s' does not exist, creating it.\n",argv[2]);
97
98                 tz = malloc(sizeof(struct tone_zone));
99                 if (!tz) {
100                         ast_log(LOG_WARNING, "Out of memory\n");
101                         return -1;
102                 }
103                 memset(tz,0,sizeof(struct tone_zone));
104                 ast_copy_string(tz->country,argv[2],sizeof(tz->country));
105                 if (ast_register_indication_country(tz)) {
106                         ast_log(LOG_WARNING, "Unable to register new country\n");
107                         free(tz);
108                         return -1;
109                 }
110                 created_country = 1;
111         }
112         if (ast_register_indication(tz,argv[3],argv[4])) {
113                 ast_log(LOG_WARNING, "Unable to register indication %s/%s\n",argv[2],argv[3]);
114                 if (created_country)
115                         ast_unregister_indication_country(argv[2]);
116                 return -1;
117         }
118         return 0;
119 }
120
121 /*
122  * REMOVE INDICATION command stuff
123  */
124 static int handle_remove_indication(int fd, int argc, char *argv[])
125 {
126         struct tone_zone *tz;
127         if (argc != 3 && argc != 4) return RESULT_SHOWUSAGE;
128
129         if (argc == 3) {
130                 /* remove entiry country */
131                 if (ast_unregister_indication_country(argv[2])) {
132                         ast_log(LOG_WARNING, "Unable to unregister indication country %s\n",argv[2]);
133                         return -1;
134                 }
135                 return 0;
136         }
137
138         tz = ast_get_indication_zone(argv[2]);
139         if (!tz) {
140                 ast_log(LOG_WARNING, "Unable to unregister indication %s/%s, country does not exists\n",argv[2],argv[3]);
141                 return -1;
142         }
143         if (ast_unregister_indication(tz,argv[3])) {
144                 ast_log(LOG_WARNING, "Unable to unregister indication %s/%s\n",argv[2],argv[3]);
145                 return -1;
146         }
147         return 0;
148 }
149
150 /*
151  * SHOW INDICATIONS command stuff
152  */
153 static int handle_show_indications(int fd, int argc, char *argv[])
154 {
155         struct tone_zone *tz;
156         char buf[256];
157         int found_country = 0;
158
159         if (ast_mutex_lock(&tzlock)) {
160                 ast_log(LOG_WARNING, "Unable to lock tone_zones list\n");
161                 return 0;
162         }
163         if (argc == 2) {
164                 /* no arguments, show a list of countries */
165                 ast_cli(fd,"Country Alias   Description\n"
166                            "===========================\n");
167                 for (tz=tone_zones; tz; tz=tz->next) {
168                         ast_cli(fd,"%-7.7s %-7.7s %s\n", tz->country, tz->alias, tz->description);
169                 }
170                 ast_mutex_unlock(&tzlock);
171                 return 0;
172         }
173         /* there was a request for specific country(ies), lets humor them */
174         for (tz=tone_zones; tz; tz=tz->next) {
175                 int i,j;
176                 for (i=2; i<argc; i++) {
177                         if (strcasecmp(tz->country,argv[i])==0 &&
178                             !tz->alias[0]) {
179                                 struct tone_zone_sound* ts;
180                                 if (!found_country) {
181                                         found_country = 1;
182                                         ast_cli(fd,"Country Indication      PlayList\n"
183                                                    "=====================================\n");
184                                 }
185                                 j = snprintf(buf,sizeof(buf),"%-7.7s %-15.15s ",tz->country,"<ringcadence>");
186                                 for (i=0; i<tz->nrringcadence; i++) {
187                                         j += snprintf(buf+j,sizeof(buf)-j,"%d,",tz->ringcadence[i]);
188                                 }
189                                 if (tz->nrringcadence) j--;
190                                 ast_copy_string(buf+j,"\n",sizeof(buf)-j);
191                                 ast_cli(fd,buf);
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);
194                                 break;
195                         }
196                 }
197         }
198         if (!found_country)
199                 ast_cli(fd,"No countries matched your criteria.\n");
200         ast_mutex_unlock(&tzlock);
201         return -1;
202 }
203
204 /*
205  * Playtones command stuff
206  */
207 static int handle_playtones(struct ast_channel *chan, void *data)
208 {
209         struct tone_zone_sound *ts;
210         int res;
211
212         if (!data || !((char*)data)[0]) {
213                 ast_log(LOG_NOTICE,"Nothing to play\n");
214                 return -1;
215         }
216         ts = ast_get_indication_tone(chan->zone, (const char*)data);
217         if (ts && ts->data[0])
218                 res = ast_playtones_start(chan, 0, ts->data, 0);
219         else
220                 res = ast_playtones_start(chan, 0, (const char*)data, 0);
221         if (res)
222                 ast_log(LOG_NOTICE,"Unable to start playtones\n");
223         return res;
224 }
225
226 /*
227  * StopPlaylist command stuff
228  */
229 static int handle_stopplaytones(struct ast_channel *chan, void *data)
230 {
231         ast_playtones_stop(chan);
232         return 0;
233 }
234
235 /*
236  * Load module stuff
237  */
238 static int ind_load_module(void)
239 {
240         struct ast_config *cfg;
241         struct ast_variable *v;
242         char *cxt;
243         char *c;
244         struct tone_zone *tones;
245         const char *country = NULL;
246
247         /* that the following cast is needed, is yuk! */
248         /* yup, checked it out. It is NOT written to. */
249         cfg = ast_config_load((char *)config);
250         if (!cfg)
251                 return 0;
252
253         /* Use existing config to populate the Indication table */
254         cxt = ast_category_browse(cfg, NULL);
255         while(cxt) {
256                 /* All categories but "general" are considered countries */
257                 if (!strcasecmp(cxt, "general")) {
258                         cxt = ast_category_browse(cfg, cxt);
259                         continue;
260                 }
261                 tones = malloc(sizeof(struct tone_zone));
262                 if (!tones) {
263                         ast_log(LOG_WARNING,"Out of memory\n");
264                         ast_config_destroy(cfg);
265                         return -1;
266                 }
267                 memset(tones,0,sizeof(struct tone_zone));
268                 ast_copy_string(tones->country,cxt,sizeof(tones->country));
269
270                 v = ast_variable_browse(cfg, cxt);
271                 while(v) {
272                         if (!strcasecmp(v->name, "description")) {
273                                 ast_copy_string(tones->description, v->value, sizeof(tones->description));
274                         } else if ((!strcasecmp(v->name,"ringcadence"))||(!strcasecmp(v->name,"ringcadance"))) {
275                                 char *ring,*rings = ast_strdupa(v->value);
276                                 c = rings;
277                                 ring = strsep(&c,",");
278                                 while (ring) {
279                                         int *tmp, val;
280                                         if (!isdigit(ring[0]) || (val=atoi(ring))==-1) {
281                                                 ast_log(LOG_WARNING,"Invalid ringcadence given '%s' at line %d.\n",ring,v->lineno);
282                                                 ring = strsep(&c,",");
283                                                 continue;
284                                         }
285                                         tmp = realloc(tones->ringcadence,(tones->nrringcadence+1)*sizeof(int));
286                                         if (!tmp) {
287                                                 ast_log(LOG_WARNING, "Out of memory\n");
288                                                 ast_config_destroy(cfg);
289                                                 return -1;
290                                         }
291                                         tones->ringcadence = tmp;
292                                         tmp[tones->nrringcadence] = val;
293                                         tones->nrringcadence++;
294                                         /* next item */
295                                         ring = strsep(&c,",");
296                                 }
297                         } else if (!strcasecmp(v->name,"alias")) {
298                                 char *countries = ast_strdupa(v->value);
299                                 c = countries;
300                                 country = strsep(&c,",");
301                                 while (country) {
302                                         struct tone_zone* azone = malloc(sizeof(struct tone_zone));
303                                         if (!azone) {
304                                                 ast_log(LOG_WARNING,"Out of memory\n");
305                                                 ast_config_destroy(cfg);
306                                                 return -1;
307                                         }
308                                         memset(azone,0,sizeof(struct tone_zone));
309                                         ast_copy_string(azone->country, country, sizeof(azone->country));
310                                         ast_copy_string(azone->alias, cxt, sizeof(azone->alias));
311                                         if (ast_register_indication_country(azone)) {
312                                                 ast_log(LOG_WARNING, "Unable to register indication alias at line %d.\n",v->lineno);
313                                                 free(tones);
314                                         }
315                                         /* next item */
316                                         country = strsep(&c,",");
317                                 }
318                         } else {
319                                 /* add tone to country */
320                                 struct tone_zone_sound *ps,*ts;
321                                 for (ps=NULL,ts=tones->tones; ts; ps=ts, ts=ts->next) {
322                                         if (strcasecmp(v->name,ts->name)==0) {
323                                                 /* already there */
324                                                 ast_log(LOG_NOTICE,"Duplicate entry '%s', skipped.\n",v->name);
325                                                 goto out;
326                                         }
327                                 }
328                                 /* not there, add it to the back */
329                                 ts = malloc(sizeof(struct tone_zone_sound));
330                                 if (!ts) {
331                                         ast_log(LOG_WARNING, "Out of memory\n");
332                                         ast_config_destroy(cfg);
333                                         return -1;
334                                 }
335                                 ts->next = NULL;
336                                 ts->name = strdup(v->name);
337                                 ts->data = strdup(v->value);
338                                 if (ps)
339                                         ps->next = ts;
340                                 else
341                                         tones->tones = ts;
342                         }
343 out:                    v = v->next;
344                 }
345                 if (tones->description[0] || tones->alias[0] || tones->tones) {
346                         if (ast_register_indication_country(tones)) {
347                                 ast_log(LOG_WARNING, "Unable to register indication at line %d.\n",v->lineno);
348                                 free(tones);
349                         }
350                 } else free(tones);
351
352                 cxt = ast_category_browse(cfg, cxt);
353         }
354
355         /* determine which country is the default */
356         country = ast_variable_retrieve(cfg,"general","country");
357         if (!country || !*country || ast_set_indication_country(country))
358                 ast_log(LOG_WARNING,"Unable to set the default country (for indication tones)\n");
359
360         ast_config_destroy(cfg);
361         return 0;
362 }
363
364 /*
365  * CLI entries for commands provided by this module
366  */
367 static struct ast_cli_entry add_indication_cli =
368         { { "indication", "add", NULL }, handle_add_indication,
369                 "Add the given indication to the country", help_add_indication,
370                 NULL };
371
372 static struct ast_cli_entry remove_indication_cli =
373         { { "indication", "remove", NULL }, handle_remove_indication,
374                 "Remove the given indication from the country", help_remove_indication,
375                 NULL };
376
377 static struct ast_cli_entry show_indications_cli =
378         { { "show", "indications", NULL }, handle_show_indications,
379                 "Show a list of all country/indications", help_show_indications,
380                 NULL };
381
382 /*
383  * Standard module functions ...
384  */
385 int unload_module(void)
386 {
387         /* remove the registed indications... */
388         ast_unregister_indication_country(NULL);
389
390         /* and the functions */
391         ast_cli_unregister(&add_indication_cli);
392         ast_cli_unregister(&remove_indication_cli);
393         ast_cli_unregister(&show_indications_cli);
394         ast_unregister_application("PlayTones");
395         ast_unregister_application("StopPlayTones");
396         return 0;
397 }
398
399
400 int load_module(void)
401 {
402         if (ind_load_module()) return -1;
403  
404         ast_cli_register(&add_indication_cli);
405         ast_cli_register(&remove_indication_cli);
406         ast_cli_register(&show_indications_cli);
407         ast_register_application("PlayTones", handle_playtones, "Play a tone list", playtones_desc);
408         ast_register_application("StopPlayTones", handle_stopplaytones, "Stop playing a tone list","Stop playing a tone list");
409
410         return 0;
411 }
412
413 int reload(void)
414 {
415         /* remove the registed indications... */
416         ast_unregister_indication_country(NULL);
417
418         return ind_load_module();
419 }
420
421 char *description(void)
422 {
423         /* that the following cast is needed, is yuk! */
424         return (char*)dtext;
425 }
426
427 int usecount(void)
428 {
429         return 0;
430 }
431
432 char *key()
433 {
434         return ASTERISK_GPL_KEY;
435 }