Fri Jul 24 00:41:02 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: 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 /* 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 /* helper function to delete a tone_zone in its entirety */
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 /*! \brief load indications module */
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    /* that the following cast is needed, is yuk! */
00281    /* yup, checked it out. It is NOT written to. */
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    /* Use existing config to populate the Indication table */
00292    cxt = ast_category_browse(cfg, NULL);
00293    while(cxt) {
00294       /* All categories but "general" are considered countries */
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                /* next item */
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                /* next item */
00349                country = strsep(&c,",");
00350             }
00351          } else {
00352             /* add tone to country */
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                   /* already there */
00357                   ast_log(LOG_NOTICE,"Duplicate entry '%s', skipped.\n",v->name);
00358                   goto out;
00359                }
00360             }
00361             /* not there, add it to the back */          
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    /* determine which country is the default */
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 /*! \brief CLI entries for commands provided by this module */
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 /*! \brief Unload indicators module */
00406 static int unload_module(void)
00407 {
00408    /* remove the registed indications... */
00409    ast_unregister_indication_country(NULL);
00410 
00411    /* and the functions */
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 /*! \brief Load indications module */
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 /*! \brief Reload indications module */
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           );

Generated on Fri Jul 24 00:41:02 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7