Wed Oct 28 11:45:41 2009

Asterisk developer's documentation


res_indications.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2002, Pauline Middelink
00005  *
00006  *
00007  * See http://www.asterisk.org for more information about
00008  * the Asterisk project. Please do not directly contact
00009  * any of the maintainers of this project for assistance;
00010  * the project provides a web site, mailing lists and IRC
00011  * channels for your use.
00012  *
00013  * This program is free software, distributed under the terms of
00014  * the GNU General Public License Version 2. See the LICENSE file
00015  * at the top of the source tree.
00016  */
00017 
00018 /*! \file res_indications.c 
00019  *
00020  * \brief Load the indications
00021  * 
00022  * \author Pauline Middelink <middelink@polyware.nl>
00023  *
00024  * Load the country specific dialtones into the asterisk PBX.
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 /* Globals */
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  * Implementation of functions provided by this module
00058  */
00059 
00060 /*!
00061  * \brief Add a country to indication
00062  * \param e the ast_cli_entry for this CLI command
00063  * \param cmd the reason we are being called
00064  * \param a the arguments being passed to us
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       /* country does not exist, create it */
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  * \brief Remove a country from indication
00112  * \param e the ast_cli_entry for this CLI command
00113  * \param cmd the reason we are being called
00114  * \param a the arguments being passed to us
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       /* remove entiry country */
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  * \brief Show the current indications
00157  * \param e the ast_cli_entry for this CLI command
00158  * \param cmd the reason we are being called
00159  * \param a the arguments being passed to us
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       /* no arguments, show a list of countries */
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    /* there was a request for specific country(ies), lets humor them */
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  * \brief play tone for indication country
00219  * \param chan ast_channel to play the sounds back to
00220  * \param data contains tone to play
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  * \brief Stop tones playing
00243  * \param chan 
00244  * \param data 
00245  */
00246 static int handle_stopplaytones(struct ast_channel *chan, void *data)
00247 {
00248    ast_playtones_stop(chan);
00249    return 0;
00250 }
00251 
00252 /*! \brief load indications module */
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    /* that the following cast is needed, is yuk! */
00264    /* yup, checked it out. It is NOT written to. */
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    /* Use existing config to populate the Indication table */
00275    cxt = ast_category_browse(cfg, NULL);
00276    while(cxt) {
00277       /* All categories but "general" are considered countries */
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                /* next item */
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                /* next item */
00330                country = strsep(&c,",");
00331             }
00332          } else {
00333             /* add tone to country */
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                   /* already there */
00338                   ast_log(LOG_NOTICE,"Duplicate entry '%s', skipped.\n",v->name);
00339                   goto out;
00340                }
00341             }
00342             /* not there, add it to the back */          
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    /* determine which country is the default */
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 /*! \brief CLI entries for commands provided by this module */
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 /*! \brief Unload indicators module */
00384 static int unload_module(void)
00385 {
00386    /* remove the registed indications... */
00387    ast_unregister_indication_country(NULL);
00388 
00389    /* and the functions */
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 /*! \brief Load indications module */
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 /*! \brief Reload indications module */
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           );

Generated on Wed Oct 28 11:45:41 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6