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: 168564 $")
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 int ind_load_module(int reload)
00254 {
00255 struct ast_config *cfg;
00256 struct ast_variable *v;
00257 char *cxt;
00258 char *c;
00259 struct tone_zone *tones;
00260 const char *country = NULL;
00261 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
00262
00263
00264
00265 cfg = ast_config_load((char *)config, config_flags);
00266 if (!cfg)
00267 return -1;
00268 else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
00269 return 0;
00270
00271 if (reload)
00272 ast_unregister_indication_country(NULL);
00273
00274
00275 cxt = ast_category_browse(cfg, NULL);
00276 while(cxt) {
00277
00278 if (!strcasecmp(cxt, "general")) {
00279 cxt = ast_category_browse(cfg, cxt);
00280 continue;
00281 }
00282 if (!(tones = ast_calloc(1, sizeof(*tones)))) {
00283 ast_config_destroy(cfg);
00284 return -1;
00285 }
00286 ast_copy_string(tones->country,cxt,sizeof(tones->country));
00287
00288 v = ast_variable_browse(cfg, cxt);
00289 while(v) {
00290 if (!strcasecmp(v->name, "description")) {
00291 ast_copy_string(tones->description, v->value, sizeof(tones->description));
00292 } else if ((!strcasecmp(v->name,"ringcadence"))||(!strcasecmp(v->name,"ringcadance"))) {
00293 char *ring,*rings = ast_strdupa(v->value);
00294 c = rings;
00295 ring = strsep(&c,",");
00296 while (ring) {
00297 int *tmp, val;
00298 if (!isdigit(ring[0]) || (val=atoi(ring))==-1) {
00299 ast_log(LOG_WARNING,"Invalid ringcadence given '%s' at line %d.\n",ring,v->lineno);
00300 ring = strsep(&c,",");
00301 continue;
00302 }
00303 if (!(tmp = ast_realloc(tones->ringcadence, (tones->nrringcadence + 1) * sizeof(int)))) {
00304 ast_config_destroy(cfg);
00305 return -1;
00306 }
00307 tones->ringcadence = tmp;
00308 tmp[tones->nrringcadence] = val;
00309 tones->nrringcadence++;
00310
00311 ring = strsep(&c,",");
00312 }
00313 } else if (!strcasecmp(v->name,"alias")) {
00314 char *countries = ast_strdupa(v->value);
00315 c = countries;
00316 country = strsep(&c,",");
00317 while (country) {
00318 struct tone_zone* azone;
00319 if (!(azone = ast_calloc(1, sizeof(*azone)))) {
00320 ast_config_destroy(cfg);
00321 return -1;
00322 }
00323 ast_copy_string(azone->country, country, sizeof(azone->country));
00324 ast_copy_string(azone->alias, cxt, sizeof(azone->alias));
00325 if (ast_register_indication_country(azone)) {
00326 ast_log(LOG_WARNING, "Unable to register indication alias at line %d.\n",v->lineno);
00327 ast_free(tones);
00328 }
00329
00330 country = strsep(&c,",");
00331 }
00332 } else {
00333
00334 struct tone_zone_sound *ps,*ts;
00335 for (ps=NULL,ts=tones->tones; ts; ps=ts, ts=ts->next) {
00336 if (strcasecmp(v->name,ts->name)==0) {
00337
00338 ast_log(LOG_NOTICE,"Duplicate entry '%s', skipped.\n",v->name);
00339 goto out;
00340 }
00341 }
00342
00343 if (!(ts = ast_malloc(sizeof(*ts)))) {
00344 ast_config_destroy(cfg);
00345 return -1;
00346 }
00347 ts->next = NULL;
00348 ts->name = ast_strdup(v->name);
00349 ts->data = ast_strdup(v->value);
00350 if (ps)
00351 ps->next = ts;
00352 else
00353 tones->tones = ts;
00354 }
00355 out: v = v->next;
00356 }
00357 if (tones->description[0] || tones->alias[0] || tones->tones) {
00358 if (ast_register_indication_country(tones)) {
00359 ast_log(LOG_WARNING, "Unable to register indication at line %d.\n",v->lineno);
00360 ast_free(tones);
00361 }
00362 } else ast_free(tones);
00363
00364 cxt = ast_category_browse(cfg, cxt);
00365 }
00366
00367
00368 country = ast_variable_retrieve(cfg,"general","country");
00369 if (!country || !*country || ast_set_indication_country(country))
00370 ast_log(LOG_WARNING,"Unable to set the default country (for indication tones)\n");
00371
00372 ast_config_destroy(cfg);
00373 return 0;
00374 }
00375
00376
00377 static struct ast_cli_entry cli_indications[] = {
00378 AST_CLI_DEFINE(handle_cli_indication_add, "Add the given indication to the country"),
00379 AST_CLI_DEFINE(handle_cli_indication_remove, "Remove the given indication from the country"),
00380 AST_CLI_DEFINE(handle_cli_indication_show, "Display a list of all countries/indications")
00381 };
00382
00383
00384 static int unload_module(void)
00385 {
00386
00387 ast_unregister_indication_country(NULL);
00388
00389
00390 ast_cli_unregister_multiple(cli_indications, sizeof(cli_indications) / sizeof(struct ast_cli_entry));
00391 ast_unregister_application("PlayTones");
00392 ast_unregister_application("StopPlayTones");
00393 return 0;
00394 }
00395
00396
00397
00398 static int load_module(void)
00399 {
00400 if (ind_load_module(0))
00401 return AST_MODULE_LOAD_DECLINE;
00402 ast_cli_register_multiple(cli_indications, sizeof(cli_indications) / sizeof(struct ast_cli_entry));
00403 ast_register_application("PlayTones", handle_playtones, "Play a tone list", playtones_desc);
00404 ast_register_application("StopPlayTones", handle_stopplaytones, "Stop playing a tone list"," StopPlayTones(): Stop playing a tone list");
00405
00406 return AST_MODULE_LOAD_SUCCESS;
00407 }
00408
00409
00410 static int reload(void)
00411 {
00412 return ind_load_module(1);
00413 }
00414
00415 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Region-specific tones",
00416 .load = load_module,
00417 .unload = unload_module,
00418 .reload = reload,
00419 );