00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "asterisk.h"
00028
00029 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 168565 $")
00030
00031 #include <ctype.h>
00032 #include <sys/stat.h>
00033
00034 #include "asterisk/lock.h"
00035 #include "asterisk/file.h"
00036 #include "asterisk/cli.h"
00037 #include "asterisk/config.h"
00038 #include "asterisk/channel.h"
00039 #include "asterisk/pbx.h"
00040 #include "asterisk/module.h"
00041 #include "asterisk/translate.h"
00042 #include "asterisk/indications.h"
00043 #include "asterisk/utils.h"
00044
00045
00046 static const char config[] = "indications.conf";
00047
00048 char *playtones_desc=
00049 " PlayTones(arg): Plays a tone list. Execution will continue with the next step immediately,\n"
00050 "while the tones continue to play.\n"
00051 "Arg is either the tone name defined in the indications.conf configuration file, or a directly\n"
00052 "specified list of frequencies and durations.\n"
00053 "See the sample indications.conf for a description of the specification of a tonelist.\n\n"
00054 "Use the StopPlayTones application to stop the tones playing. \n";
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066 static char *handle_cli_indication_add(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00067 {
00068 struct tone_zone *tz;
00069 int created_country = 0;
00070
00071 switch (cmd) {
00072 case CLI_INIT:
00073 e->command = "indication add";
00074 e->usage =
00075 "Usage: indication add <country> <indication> \"<tonelist>\"\n"
00076 " Add the given indication to the country.\n";
00077 return NULL;
00078 case CLI_GENERATE:
00079 return NULL;
00080 }
00081
00082 if (a->argc != 5)
00083 return CLI_SHOWUSAGE;
00084
00085 tz = ast_get_indication_zone(a->argv[2]);
00086 if (!tz) {
00087
00088 ast_log(LOG_NOTICE, "Country '%s' does not exist, creating it.\n", a->argv[2]);
00089
00090 if (!(tz = ast_calloc(1, sizeof(*tz)))) {
00091 return CLI_FAILURE;
00092 }
00093 ast_copy_string(tz->country, a->argv[2], sizeof(tz->country));
00094 if (ast_register_indication_country(tz)) {
00095 ast_log(LOG_WARNING, "Unable to register new country\n");
00096 ast_free(tz);
00097 return CLI_FAILURE;
00098 }
00099 created_country = 1;
00100 }
00101 if (ast_register_indication(tz, a->argv[3], a->argv[4])) {
00102 ast_log(LOG_WARNING, "Unable to register indication %s/%s\n", a->argv[2], a->argv[3]);
00103 if (created_country)
00104 ast_unregister_indication_country(a->argv[2]);
00105 return CLI_FAILURE;
00106 }
00107 return CLI_SUCCESS;
00108 }
00109
00110
00111
00112
00113
00114
00115
00116 static char *handle_cli_indication_remove(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00117 {
00118 struct tone_zone *tz;
00119
00120 switch (cmd) {
00121 case CLI_INIT:
00122 e->command = "indication remove";
00123 e->usage =
00124 "Usage: indication remove <country> <indication>\n"
00125 " Remove the given indication from the country.\n";
00126 return NULL;
00127 case CLI_GENERATE:
00128 return NULL;
00129 }
00130
00131 if (a->argc != 3 && a->argc != 4)
00132 return CLI_SHOWUSAGE;
00133
00134 if (a->argc == 3) {
00135
00136 if (ast_unregister_indication_country(a->argv[2])) {
00137 ast_log(LOG_WARNING, "Unable to unregister indication country %s\n", a->argv[2]);
00138 return CLI_FAILURE;
00139 }
00140 return CLI_SUCCESS;
00141 }
00142
00143 tz = ast_get_indication_zone(a->argv[2]);
00144 if (!tz) {
00145 ast_log(LOG_WARNING, "Unable to unregister indication %s/%s, country does not exists\n", a->argv[2], a->argv[3]);
00146 return CLI_FAILURE;
00147 }
00148 if (ast_unregister_indication(tz, a->argv[3])) {
00149 ast_log(LOG_WARNING, "Unable to unregister indication %s/%s\n", a->argv[2], a->argv[3]);
00150 return CLI_FAILURE;
00151 }
00152 return CLI_SUCCESS;
00153 }
00154
00155
00156
00157
00158
00159
00160
00161 static char *handle_cli_indication_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00162 {
00163 struct tone_zone *tz = NULL;
00164 char buf[256];
00165 int found_country = 0;
00166
00167 switch (cmd) {
00168 case CLI_INIT:
00169 e->command = "indication show";
00170 e->usage =
00171 "Usage: indication show [<country> ...]\n"
00172 " Display either a condensed for of all country/indications, or the\n"
00173 " indications for the specified countries.\n";
00174 return NULL;
00175 case CLI_GENERATE:
00176 return NULL;
00177 }
00178
00179 if (a->argc == 2) {
00180
00181 ast_cli(a->fd, "Country Alias Description\n");
00182 ast_cli(a->fd, "===========================\n");
00183 while ((tz = ast_walk_indications(tz)))
00184 ast_cli(a->fd, "%-7.7s %-7.7s %s\n", tz->country, tz->alias, tz->description);
00185 return CLI_SUCCESS;
00186 }
00187
00188 while ((tz = ast_walk_indications(tz))) {
00189 int i, j;
00190 for (i = 2; i < a->argc; i++) {
00191 if (strcasecmp(tz->country, a->argv[i]) == 0 && !tz->alias[0]) {
00192 struct tone_zone_sound* ts;
00193 if (!found_country) {
00194 found_country = 1;
00195 ast_cli(a->fd, "Country Indication PlayList\n");
00196 ast_cli(a->fd, "=====================================\n");
00197 }
00198 j = snprintf(buf, sizeof(buf), "%-7.7s %-15.15s ", tz->country, "<ringcadence>");
00199 for (i = 0; i < tz->nrringcadence; i++) {
00200 j += snprintf(buf + j, sizeof(buf) - j, "%d,", tz->ringcadence[i]);
00201 }
00202 if (tz->nrringcadence)
00203 j--;
00204 ast_copy_string(buf + j, "\n", sizeof(buf) - j);
00205 ast_cli(a->fd, "%s", buf);
00206 for (ts = tz->tones; ts; ts = ts->next)
00207 ast_cli(a->fd, "%-7.7s %-15.15s %s\n", tz->country, ts->name, ts->data);
00208 break;
00209 }
00210 }
00211 }
00212 if (!found_country)
00213 ast_cli(a->fd, "No countries matched your criteria.\n");
00214 return CLI_SUCCESS;
00215 }
00216
00217
00218
00219
00220
00221
00222 static int handle_playtones(struct ast_channel *chan, void *data)
00223 {
00224 struct tone_zone_sound *ts;
00225 int res;
00226
00227 if (!data || !((char*)data)[0]) {
00228 ast_log(LOG_NOTICE,"Nothing to play\n");
00229 return -1;
00230 }
00231 ts = ast_get_indication_tone(chan->zone, (const char*)data);
00232 if (ts && ts->data[0])
00233 res = ast_playtones_start(chan, 0, ts->data, 0);
00234 else
00235 res = ast_playtones_start(chan, 0, (const char*)data, 0);
00236 if (res)
00237 ast_log(LOG_NOTICE,"Unable to start playtones\n");
00238 return res;
00239 }
00240
00241
00242
00243
00244
00245
00246 static int handle_stopplaytones(struct ast_channel *chan, void *data)
00247 {
00248 ast_playtones_stop(chan);
00249 return 0;
00250 }
00251
00252
00253 static inline void free_zone(struct tone_zone* zone)
00254 {
00255 while (zone->tones) {
00256 struct tone_zone_sound *tmp = zone->tones->next;
00257 ast_free((void *)zone->tones->name);
00258 ast_free((void *)zone->tones->data);
00259 ast_free(zone->tones);
00260 zone->tones = tmp;
00261 }
00262
00263 if (zone->ringcadence)
00264 ast_free(zone->ringcadence);
00265
00266 ast_free(zone);
00267 }
00268
00269
00270 static int ind_load_module(int reload)
00271 {
00272 struct ast_config *cfg;
00273 struct ast_variable *v;
00274 char *cxt;
00275 char *c;
00276 struct tone_zone *tones;
00277 const char *country = NULL;
00278 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
00279
00280
00281
00282 cfg = ast_config_load((char *)config, config_flags);
00283 if (!cfg)
00284 return -1;
00285 else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
00286 return 0;
00287
00288 if (reload)
00289 ast_unregister_indication_country(NULL);
00290
00291
00292 cxt = ast_category_browse(cfg, NULL);
00293 while(cxt) {
00294
00295 if (!strcasecmp(cxt, "general")) {
00296 cxt = ast_category_browse(cfg, cxt);
00297 continue;
00298 }
00299 if (!(tones = ast_calloc(1, sizeof(*tones)))) {
00300 ast_config_destroy(cfg);
00301 return -1;
00302 }
00303 ast_copy_string(tones->country,cxt,sizeof(tones->country));
00304
00305 v = ast_variable_browse(cfg, cxt);
00306 while(v) {
00307 if (!strcasecmp(v->name, "description")) {
00308 ast_copy_string(tones->description, v->value, sizeof(tones->description));
00309 } else if ((!strcasecmp(v->name,"ringcadence"))||(!strcasecmp(v->name,"ringcadance"))) {
00310 char *ring,*rings = ast_strdupa(v->value);
00311 c = rings;
00312 ring = strsep(&c,",");
00313 while (ring) {
00314 int *tmp, val;
00315 if (!isdigit(ring[0]) || (val=atoi(ring))==-1) {
00316 ast_log(LOG_WARNING,"Invalid ringcadence given '%s' at line %d.\n",ring,v->lineno);
00317 ring = strsep(&c,",");
00318 continue;
00319 }
00320 if (!(tmp = ast_realloc(tones->ringcadence, (tones->nrringcadence + 1) * sizeof(int)))) {
00321 ast_config_destroy(cfg);
00322 free_zone(tones);
00323 return -1;
00324 }
00325 tones->ringcadence = tmp;
00326 tmp[tones->nrringcadence] = val;
00327 tones->nrringcadence++;
00328
00329 ring = strsep(&c,",");
00330 }
00331 } else if (!strcasecmp(v->name,"alias")) {
00332 char *countries = ast_strdupa(v->value);
00333 c = countries;
00334 country = strsep(&c,",");
00335 while (country) {
00336 struct tone_zone* azone;
00337 if (!(azone = ast_calloc(1, sizeof(*azone)))) {
00338 ast_config_destroy(cfg);
00339 free_zone(tones);
00340 return -1;
00341 }
00342 ast_copy_string(azone->country, country, sizeof(azone->country));
00343 ast_copy_string(azone->alias, cxt, sizeof(azone->alias));
00344 if (ast_register_indication_country(azone)) {
00345 ast_log(LOG_WARNING, "Unable to register indication alias at line %d.\n",v->lineno);
00346 free_zone(tones);
00347 }
00348
00349 country = strsep(&c,",");
00350 }
00351 } else {
00352
00353 struct tone_zone_sound *ps,*ts;
00354 for (ps=NULL,ts=tones->tones; ts; ps=ts, ts=ts->next) {
00355 if (strcasecmp(v->name,ts->name)==0) {
00356
00357 ast_log(LOG_NOTICE,"Duplicate entry '%s', skipped.\n",v->name);
00358 goto out;
00359 }
00360 }
00361
00362 if (!(ts = ast_malloc(sizeof(*ts)))) {
00363 ast_config_destroy(cfg);
00364 return -1;
00365 }
00366 ts->next = NULL;
00367 ts->name = ast_strdup(v->name);
00368 ts->data = ast_strdup(v->value);
00369 if (ps)
00370 ps->next = ts;
00371 else
00372 tones->tones = ts;
00373 }
00374 out: v = v->next;
00375 }
00376 if (tones->description[0] || tones->alias[0] || tones->tones) {
00377 if (ast_register_indication_country(tones)) {
00378 ast_log(LOG_WARNING, "Unable to register indication at line %d.\n",v->lineno);
00379 free_zone(tones);
00380 }
00381 } else {
00382 free_zone(tones);
00383 }
00384
00385 cxt = ast_category_browse(cfg, cxt);
00386 }
00387
00388
00389 country = ast_variable_retrieve(cfg,"general","country");
00390 if (ast_strlen_zero(country) || ast_set_indication_country(country)) {
00391 ast_log(LOG_WARNING,"Unable to set the default country (for indication tones)\n");
00392 }
00393
00394 ast_config_destroy(cfg);
00395 return 0;
00396 }
00397
00398
00399 static struct ast_cli_entry cli_indications[] = {
00400 AST_CLI_DEFINE(handle_cli_indication_add, "Add the given indication to the country"),
00401 AST_CLI_DEFINE(handle_cli_indication_remove, "Remove the given indication from the country"),
00402 AST_CLI_DEFINE(handle_cli_indication_show, "Display a list of all countries/indications")
00403 };
00404
00405
00406 static int unload_module(void)
00407 {
00408
00409 ast_unregister_indication_country(NULL);
00410
00411
00412 ast_cli_unregister_multiple(cli_indications, sizeof(cli_indications) / sizeof(struct ast_cli_entry));
00413 ast_unregister_application("PlayTones");
00414 ast_unregister_application("StopPlayTones");
00415 return 0;
00416 }
00417
00418
00419
00420 static int load_module(void)
00421 {
00422 if (ind_load_module(0))
00423 return AST_MODULE_LOAD_DECLINE;
00424 ast_cli_register_multiple(cli_indications, sizeof(cli_indications) / sizeof(struct ast_cli_entry));
00425 ast_register_application("PlayTones", handle_playtones, "Play a tone list", playtones_desc);
00426 ast_register_application("StopPlayTones", handle_stopplaytones, "Stop playing a tone list"," StopPlayTones(): Stop playing a tone list");
00427
00428 return AST_MODULE_LOAD_SUCCESS;
00429 }
00430
00431
00432 static int reload(void)
00433 {
00434 return ind_load_module(1);
00435 }
00436
00437 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Region-specific tones",
00438 .load = load_module,
00439 .unload = unload_module,
00440 .reload = reload,
00441 );