Asterisk.org: Developer Documentation (28 Oct 2009)

Wed Oct 28 15:47:55 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 <unistd.h>
    00028 #include <string.h>
    00029 #include <ctype.h>
    00030 #include <stdlib.h>
    00031 #include <stdio.h>
    00032 #include <errno.h>
    00033 #include <sys/types.h>
    00034 #include <sys/stat.h>
    00035
    00036 #include "asterisk.h"
    00037
    00038 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 7221 $")
    00039
    00040 #include "asterisk/lock.h"
    00041 #include "asterisk/file.h"
    00042 #include "asterisk/cli.h"
    00043 #include "asterisk/logger.h"
    00044 #include "asterisk/config.h"
    00045 #include "asterisk/channel.h"
    00046 #include "asterisk/pbx.h"
    00047 #include "asterisk/module.h"
    00048 #include "asterisk/translate.h"
    00049 #include "asterisk/indications.h"
    00050
    00051
    00052 /* Globals */
    00053 static const char dtext[] = "Indications Configuration";
    00054 static const char config[] = "indications.conf";
    00055
    00056 /*
    00057  * Help for commands provided by this module ...
    00058  */
    00059 static char help_add_indication[] =
    00060 "Usage: indication add <country> <indication> \"<tonelist>\"\n"
    00061 "       Add the given indication to the country.\n";
    00062
    00063 static char help_remove_indication[] =
    00064 "Usage: indication remove <country> <indication>\n"
    00065 "       Remove the given indication from the country.\n";
    00066
    00067 static char help_show_indications[] =
    00068 "Usage: show indications [<country> ...]\n"
    00069 "       Show either a condensed for of all country/indications, or the\n"
    00070 "       indications for the specified countries.\n";
    00071
    00072 char *playtones_desc=
    00073 "PlayTones(arg): Plays a tone list. Execution will continue with the next step immediately,\n"
    00074 "while the tones continue to play.\n"
    00075 "Arg is either the tone name defined in the indications.conf configuration file, or a directly\n"
    00076 "specified list of frequencies and durations.\n"
    00077 "See the sample indications.conf for a description of the specification of a tonelist.\n\n"
    00078 "Use the StopPlayTones application to stop the tones playing. \n";
    00079
    00080 /*
    00081  * Implementation of functions provided by this module
    00082  */
    00083
    00084 /*
    00085  * ADD INDICATION command stuff
    00086  */
    00087 static int handle_add_indication(int fd, int argc, char *argv[])
    00088 {
    00089    struct tone_zone *tz;
    00090    int created_country = 0;
    00091    if (argc != 5) return RESULT_SHOWUSAGE;
    00092
    00093    tz = ast_get_indication_zone(argv[2]);
    00094    if (!tz) {
    00095       /* country does not exist, create it */
    00096       ast_log(LOG_NOTICE, "Country '%s' does not exist, creating it.\n",argv[2]);
    00097
    00098       tz = malloc(sizeof(struct tone_zone));
    00099       if (!tz) {
    00100          ast_log(LOG_WARNING, "Out of memory\n");
    00101          return -1;
    00102       }
    00103       memset(tz,0,sizeof(struct tone_zone));
    00104       ast_copy_string(tz->country,argv[2],sizeof(tz->country));
    00105       if (ast_register_indication_country(tz)) {
    00106          ast_log(LOG_WARNING, "Unable to register new country\n");
    00107          free(tz);
    00108          return -1;
    00109       }
    00110       created_country = 1;
    00111    }
    00112    if (ast_register_indication(tz,argv[3],argv[4])) {
    00113       ast_log(LOG_WARNING, "Unable to register indication %s/%s\n",argv[2],argv[3]);
    00114       if (created_country)
    00115          ast_unregister_indication_country(argv[2]);
    00116       return -1;
    00117    }
    00118    return 0;
    00119 }
    00120
    00121 /*
    00122  * REMOVE INDICATION command stuff
    00123  */
    00124 static int handle_remove_indication(int fd, int argc, char *argv[])
    00125 {
    00126    struct tone_zone *tz;
    00127    if (argc != 3 && argc != 4) return RESULT_SHOWUSAGE;
    00128
    00129    if (argc == 3) {
    00130       /* remove entiry country */
    00131       if (ast_unregister_indication_country(argv[2])) {
    00132          ast_log(LOG_WARNING, "Unable to unregister indication country %s\n",argv[2]);
    00133          return -1;
    00134       }
    00135       return 0;
    00136    }
    00137
    00138    tz = ast_get_indication_zone(argv[2]);
    00139    if (!tz) {
    00140       ast_log(LOG_WARNING, "Unable to unregister indication %s/%s, country does not exists\n",argv[2],argv[3]);
    00141       return -1;
    00142    }
    00143    if (ast_unregister_indication(tz,argv[3])) {
    00144       ast_log(LOG_WARNING, "Unable to unregister indication %s/%s\n",argv[2],argv[3]);
    00145       return -1;
    00146    }
    00147    return 0;
    00148 }
    00149
    00150 /*
    00151  * SHOW INDICATIONS command stuff
    00152  */
    00153 static int handle_show_indications(int fd, int argc, char *argv[])
    00154 {
    00155    struct tone_zone *tz;
    00156    char buf[256];
    00157    int found_country = 0;
    00158
    00159    if (ast_mutex_lock(&tzlock)) {
    00160       ast_log(LOG_WARNING, "Unable to lock tone_zones list\n");
    00161       return 0;
    00162    }
    00163    if (argc == 2) {
    00164       /* no arguments, show a list of countries */
    00165       ast_cli(fd,"Country Alias   Description\n"
    00166             "===========================\n");
    00167       for (tz=tone_zones; tz; tz=tz->next) {
    00168          ast_cli(fd,"%-7.7s %-7.7s %s\n", tz->country, tz->alias, tz->description);
    00169       }
    00170       ast_mutex_unlock(&tzlock);
    00171       return 0;
    00172    }
    00173    /* there was a request for specific country(ies), lets humor them */
    00174    for (tz=tone_zones; tz; tz=tz->next) {
    00175       int i,j;
    00176       for (i=2; i<argc; i++) {
    00177          if (strcasecmp(tz->country,argv[i])==0 &&
    00178              !tz->alias[0]) {
    00179             struct tone_zone_sound* ts;
    00180             if (!found_country) {
    00181                found_country = 1;
    00182                ast_cli(fd,"Country Indication      PlayList\n"
    00183                      "=====================================\n");
    00184             }
    00185             j = snprintf(buf,sizeof(buf),"%-7.7s %-15.15s ",tz->country,"<ringcadence>");
    00186             for (i=0; i<tz->nrringcadence; i++) {
    00187                j += snprintf(buf+j,sizeof(buf)-j,"%d,",tz->ringcadence[i]);
    00188             }
    00189             if (tz->nrringcadence) j--;
    00190             ast_copy_string(buf+j,"\n",sizeof(buf)-j);
    00191             ast_cli(fd,buf);
    00192             for (ts=tz->tones; ts; ts=ts->next)
    00193                ast_cli(fd,"%-7.7s %-15.15s %s\n",tz->country,ts->name,ts->data);
    00194             break;
    00195          }
    00196       }
    00197    }
    00198    if (!found_country)
    00199       ast_cli(fd,"No countries matched your criteria.\n");
    00200    ast_mutex_unlock(&tzlock);
    00201    return -1;
    00202 }
    00203
    00204 /*
    00205  * Playtones command stuff
    00206  */
    00207 static int handle_playtones(struct ast_channel *chan, void *data)
    00208 {
    00209    struct tone_zone_sound *ts;
    00210    int res;
    00211
    00212    if (!data || !((char*)data)[0]) {
    00213       ast_log(LOG_NOTICE,"Nothing to play\n");
    00214       return -1;
    00215    }
    00216    ts = ast_get_indication_tone(chan->zone, (const char*)data);
    00217    if (ts && ts->data[0])
    00218       res = ast_playtones_start(chan, 0, ts->data, 0);
    00219    else
    00220       res = ast_playtones_start(chan, 0, (const char*)data, 0);
    00221    if (res)
    00222       ast_log(LOG_NOTICE,"Unable to start playtones\n");
    00223    return res;
    00224 }
    00225
    00226 /*
    00227  * StopPlaylist command stuff
    00228  */
    00229 static int handle_stopplaytones(struct ast_channel *chan, void *data)
    00230 {
    00231    ast_playtones_stop(chan);
    00232    return 0;
    00233 }
    00234
    00235 /*
    00236  * Load module stuff
    00237  */
    00238 static int ind_load_module(void)
    00239 {
    00240    struct ast_config *cfg;
    00241    struct ast_variable *v;
    00242    char *cxt;
    00243    char *c;
    00244    struct tone_zone *tones;
    00245    const char *country = NULL;
    00246
    00247    /* that the following cast is needed, is yuk! */
    00248    /* yup, checked it out. It is NOT written to. */
    00249    cfg = ast_config_load((char *)config);
    00250    if (!cfg)
    00251       return 0;
    00252
    00253    /* Use existing config to populate the Indication table */
    00254    cxt = ast_category_browse(cfg, NULL);
    00255    while(cxt) {
    00256       /* All categories but "general" are considered countries */
    00257       if (!strcasecmp(cxt, "general")) {
    00258          cxt = ast_category_browse(cfg, cxt);
    00259          continue;
    00260       }
    00261       tones = malloc(sizeof(struct tone_zone));
    00262       if (!tones) {
    00263          ast_log(LOG_WARNING,"Out of memory\n");
    00264          ast_config_destroy(cfg);
    00265          return -1;
    00266       }
    00267       memset(tones,0,sizeof(struct tone_zone));
    00268       ast_copy_string(tones->country,cxt,sizeof(tones->country));
    00269
    00270       v = ast_variable_browse(cfg, cxt);
    00271       while(v) {
    00272          if (!strcasecmp(v->name, "description")) {
    00273             ast_copy_string(tones->description, v->value, sizeof(tones->description));
    00274          } else if ((!strcasecmp(v->name,"ringcadence"))||(!strcasecmp(v->name,"ringcadance"))) {
    00275             char *ring,*rings = ast_strdupa(v->value);
    00276             c = rings;
    00277             ring = strsep(&c,",");
    00278             while (ring) {
    00279                int *tmp, val;
    00280                if (!isdigit(ring[0]) || (val=atoi(ring))==-1) {
    00281                   ast_log(LOG_WARNING,"Invalid ringcadence given '%s' at line %d.\n",ring,v->lineno);
    00282                   ring = strsep(&c,",");
    00283                   continue;
    00284                }
    00285                tmp = realloc(tones->ringcadence,(tones->nrringcadence+1)*sizeof(int));
    00286                if (!tmp) {
    00287                   ast_log(LOG_WARNING, "Out of memory\n");
    00288                   ast_config_destroy(cfg);
    00289                   return -1;
    00290                }
    00291                tones->ringcadence = tmp;
    00292                tmp[tones->nrringcadence] = val;
    00293                tones->nrringcadence++;
    00294                /* next item */
    00295                ring = strsep(&c,",");
    00296             }
    00297          } else if (!strcasecmp(v->name,"alias")) {
    00298             char *countries = ast_strdupa(v->value);
    00299             c = countries;
    00300             country = strsep(&c,",");
    00301             while (country) {
    00302                struct tone_zone* azone = malloc(sizeof(struct tone_zone));
    00303                if (!azone) {
    00304                   ast_log(LOG_WARNING,"Out of memory\n");
    00305                   ast_config_destroy(cfg);
    00306                   return -1;
    00307                }
    00308                memset(azone,0,sizeof(struct tone_zone));
    00309                ast_copy_string(azone->country, country, sizeof(azone->country));
    00310                ast_copy_string(azone->alias, cxt, sizeof(azone->alias));
    00311                if (ast_register_indication_country(azone)) {
    00312                   ast_log(LOG_WARNING, "Unable to register indication alias at line %d.\n",v->lineno);
    00313                   free(tones);
    00314                }
    00315                /* next item */
    00316                country = strsep(&c,",");
    00317             }
    00318          } else {
    00319             /* add tone to country */
    00320             struct tone_zone_sound *ps,*ts;
    00321             for (ps=NULL,ts=tones->tones; ts; ps=ts, ts=ts->next) {
    00322                if (strcasecmp(v->name,ts->name)==0) {
    00323                   /* already there */
    00324                   ast_log(LOG_NOTICE,"Duplicate entry '%s', skipped.\n",v->name);
    00325                   goto out;
    00326                }
    00327             }
    00328             /* not there, add it to the back */
    00329             ts = malloc(sizeof(struct tone_zone_sound));
    00330             if (!ts) {
    00331                ast_log(LOG_WARNING, "Out of memory\n");
    00332                ast_config_destroy(cfg);
    00333                return -1;
    00334             }
    00335             ts->next = NULL;
    00336             ts->name = strdup(v->name);
    00337             ts->data = strdup(v->value);
    00338             if (ps)
    00339                ps->next = ts;
    00340             else
    00341                tones->tones = ts;
    00342          }
    00343 out:        v = v->next;
    00344       }
    00345       if (tones->description[0] || tones->alias[0] || tones->tones) {
    00346          if (ast_register_indication_country(tones)) {
    00347             ast_log(LOG_WARNING, "Unable to register indication at line %d.\n",v->lineno);
    00348             free(tones);
    00349          }
    00350       } else free(tones);
    00351
    00352       cxt = ast_category_browse(cfg, cxt);
    00353    }
    00354
    00355    /* determine which country is the default */
    00356    country = ast_variable_retrieve(cfg,"general","country");
    00357    if (!country || !*country || ast_set_indication_country(country))
    00358       ast_log(LOG_WARNING,"Unable to set the default country (for indication tones)\n");
    00359
    00360    ast_config_destroy(cfg);
    00361    return 0;
    00362 }
    00363
    00364 /*
    00365  * CLI entries for commands provided by this module
    00366  */
    00367 static struct ast_cli_entry add_indication_cli =
    00368    { { "indication", "add", NULL }, handle_add_indication,
    00369       "Add the given indication to the country", help_add_indication,
    00370       NULL };
    00371
    00372 static struct ast_cli_entry remove_indication_cli =
    00373    { { "indication", "remove", NULL }, handle_remove_indication,
    00374       "Remove the given indication from the country", help_remove_indication,
    00375       NULL };
    00376
    00377 static struct ast_cli_entry show_indications_cli =
    00378    { { "show", "indications", NULL }, handle_show_indications,
    00379       "Show a list of all country/indications", help_show_indications,
    00380       NULL };
    00381
    00382 /*
    00383  * Standard module functions ...
    00384  */
    00385 int unload_module(void)
    00386 {
    00387    /* remove the registed indications... */
    00388    ast_unregister_indication_country(NULL);
    00389
    00390    /* and the functions */
    00391    ast_cli_unregister(&add_indication_cli);
    00392    ast_cli_unregister(&remove_indication_cli);
    00393    ast_cli_unregister(&show_indications_cli);
    00394    ast_unregister_application("PlayTones");
    00395    ast_unregister_application("StopPlayTones");
    00396    return 0;
    00397 }
    00398
    00399
    00400 int load_module(void)
    00401 {
    00402    if (ind_load_module()) return -1;
    00403
    00404    ast_cli_register(&add_indication_cli);
    00405    ast_cli_register(&remove_indication_cli);
    00406    ast_cli_register(&show_indications_cli);
    00407    ast_register_application("PlayTones", handle_playtones, "Play a tone list", playtones_desc);
    00408    ast_register_application("StopPlayTones", handle_stopplaytones, "Stop playing a tone list","Stop playing a tone list");
    00409
    00410    return 0;
    00411 }
    00412
    00413 int reload(void)
    00414 {
    00415    /* remove the registed indications... */
    00416    ast_unregister_indication_country(NULL);
    00417
    00418    return ind_load_module();
    00419 }
    00420
    00421 char *description(void)
    00422 {
    00423    /* that the following cast is needed, is yuk! */
    00424    return (char*)dtext;
    00425 }
    00426
    00427 int usecount(void)
    00428 {
    00429    return 0;
    00430 }
    00431
    00432 char *key()
    00433 {
    00434    return ASTERISK_GPL_KEY;
    00435 }