diff --git a/include/asterisk/indications.h b/include/asterisk/indications.h index 2841a9fdfc555aff71e98b3250bd91bee73dc4a4..be65b9ba9b8435da96b2c78c78359d44c2832ad0 100644 --- a/include/asterisk/indications.h +++ b/include/asterisk/indications.h @@ -40,9 +40,9 @@ first tone description not preceeded by !. Duration is specified in milliseconds */ struct ind_tone_zone_sound { - struct ind_tone_zone_sound *next; /*!< next element */ const char *name; /*!< Identifing name */ const char *data; /*!< Actual zone description */ + AST_LIST_ENTRY(ind_tone_zone_sound) list; }; struct ind_tone_zone { @@ -52,7 +52,7 @@ struct ind_tone_zone { char description[40]; /*!< Description */ int nrringcadence; /*!< # registered ringcadence elements */ int *ringcadence; /*!< Ring cadence */ - struct ind_tone_zone_sound *tones; /*!< The known tones for this zone */ + AST_LIST_HEAD_NOLOCK(, ind_tone_zone_sound) tones; /*!< The known tones for this zone */ }; /*! \brief set the default tone country */ @@ -62,6 +62,8 @@ int ast_set_indication_country(const char *country); struct ind_tone_zone *ast_get_indication_zone(const char *country); /*! \brief locate a tone_zone_sound, given the tone_zone. if tone_zone == NULL, use the default tone_zone */ struct ind_tone_zone_sound *ast_get_indication_tone(const struct ind_tone_zone *zone, const char *indication); +/*! \brief deallocate the passed tone zone */ +void ast_destroy_indication_zone(struct ind_tone_zone *zone); /*! \brief add a new country, if country exists, it will be replaced. */ int ast_register_indication_country(struct ind_tone_zone *country); diff --git a/main/indications.c b/main/indications.c index edde12a90c54a79de1ebc0abfb76dec3bc9fca51..e1ec4e2935e593f7e6aa10c7e7948bd5a0205d45 100644 --- a/main/indications.c +++ b/main/indications.c @@ -432,7 +432,7 @@ struct ind_tone_zone_sound *ast_get_indication_tone(const struct ind_tone_zone * } /* Look through list of tones in the zone searching for the right one */ - for (ts = zone->tones; ts; ts = ts->next) { + AST_LIST_TRAVERSE(&zone->tones, ts, list) { if (!strcasecmp(ts->name, indication)) break; } @@ -442,15 +442,21 @@ struct ind_tone_zone_sound *ast_get_indication_tone(const struct ind_tone_zone * return ts; } -/* helper function to delete a tone_zone in its entirety */ -static inline void free_zone(struct ind_tone_zone* zone) +static inline void clear_zone_sound(struct ind_tone_zone_sound *ts) { - while (zone->tones) { - struct ind_tone_zone_sound *tmp = zone->tones->next; - ast_free((void *)zone->tones->name); - ast_free((void *)zone->tones->data); - ast_free(zone->tones); - zone->tones = tmp; + /* Deconstify the 'const char *'s so the compiler doesn't complain. (but it's safe) */ + ast_free((char *) ts->name); + ast_free((char *) ts->data); +} + +/*! \brief deallocate the passed tone zone */ +void ast_destroy_indication_zone(struct ind_tone_zone *zone) +{ + struct ind_tone_zone_sound *current; + + while ((current = AST_LIST_REMOVE_HEAD(&zone->tones, list))) { + clear_zone_sound(current); + ast_free(current); } if (zone->ringcadence) @@ -477,7 +483,7 @@ int ast_register_indication_country(struct ind_tone_zone *zone) /* Remove from the linked list */ AST_RWLIST_REMOVE_CURRENT(list); /* Finally free the zone itself */ - free_zone(tz); + ast_destroy_indication_zone(tz); break; } AST_RWLIST_TRAVERSE_SAFE_END; @@ -512,7 +518,7 @@ int ast_unregister_indication_country(const char *country) /* Remove from the list */ AST_RWLIST_REMOVE_CURRENT(list); ast_verb(3, "Unregistered indication country '%s'\n", tz->country); - free_zone(tz); + ast_destroy_indication_zone(tz); res = 0; } AST_RWLIST_TRAVERSE_SAFE_END; @@ -525,37 +531,39 @@ int ast_unregister_indication_country(const char *country) * exists, it will be replaced. */ int ast_register_indication(struct ind_tone_zone *zone, const char *indication, const char *tonelist) { - struct ind_tone_zone_sound *ts, *ps; + struct ind_tone_zone_sound *ts; + int found = 0; /* is it an alias? stop */ if (zone->alias[0]) return -1; AST_RWLIST_WRLOCK(&tone_zones); - for (ps=NULL,ts=zone->tones; ts; ps=ts,ts=ts->next) { - if (!strcasecmp(indication,ts->name)) { - /* indication already there, replace */ - ast_free((void*)ts->name); - ast_free((void*)ts->data); + + AST_LIST_TRAVERSE(&zone->tones, ts, list) { + if (!strcasecmp(indication, ts->name)) { + clear_zone_sound(ts); + found = 1; break; } } if (!ts) { /* not there, we have to add */ - if (!(ts = ast_malloc(sizeof(*ts)))) { + if (!(ts = ast_calloc(1, sizeof(*ts)))) { AST_RWLIST_UNLOCK(&tone_zones); return -2; } - ts->next = NULL; } if (!(ts->name = ast_strdup(indication)) || !(ts->data = ast_strdup(tonelist))) { + ast_free(ts); AST_RWLIST_UNLOCK(&tone_zones); return -2; } - if (ps) - ps->next = ts; - else - zone->tones = ts; + + if (!found) { + AST_LIST_INSERT_TAIL(&zone->tones, ts, list); + } + AST_RWLIST_UNLOCK(&tone_zones); return 0; } @@ -563,7 +571,7 @@ int ast_register_indication(struct ind_tone_zone *zone, const char *indication, /* remove an existing country's indication. Both country and indication must exist */ int ast_unregister_indication(struct ind_tone_zone *zone, const char *indication) { - struct ind_tone_zone_sound *ts,*ps = NULL, *tmp; + struct ind_tone_zone_sound *ts; int res = -1; /* is it an alias? stop */ @@ -571,27 +579,18 @@ int ast_unregister_indication(struct ind_tone_zone *zone, const char *indication return -1; AST_RWLIST_WRLOCK(&tone_zones); - ts = zone->tones; - while (ts) { - if (!strcasecmp(indication,ts->name)) { - /* indication found */ - tmp = ts->next; - if (ps) - ps->next = tmp; - else - zone->tones = tmp; - ast_free((void*)ts->name); - ast_free((void*)ts->data); + + AST_LIST_TRAVERSE_SAFE_BEGIN(&zone->tones, ts, list) { + if (!strcasecmp(indication, ts->name)) { + AST_LIST_REMOVE_CURRENT(list); + clear_zone_sound(ts); ast_free(ts); - ts = tmp; res = 0; - } - else { - /* next zone please */ - ps = ts; - ts = ts->next; + break; } } + AST_LIST_TRAVERSE_SAFE_END; + /* indication not found, goodbye */ AST_RWLIST_UNLOCK(&tone_zones); return res; diff --git a/res/res_indications.c b/res/res_indications.c index 836abffc3efa521d34c4c6284b8b1168b9230ef6..34193412dc2069338380fdc53031bdce69b3f2e2 100644 --- a/res/res_indications.c +++ b/res/res_indications.c @@ -216,7 +216,7 @@ static char *handle_cli_indication_show(struct ast_cli_entry *e, int cmd, struct int i, j; for (i = 2; i < a->argc; i++) { if (strcasecmp(tz->country, a->argv[i]) == 0 && !tz->alias[0]) { - struct ind_tone_zone_sound* ts; + struct ind_tone_zone_sound *ts; if (!found_country) { found_country = 1; ast_cli(a->fd, "Country Indication PlayList\n"); @@ -230,8 +230,9 @@ static char *handle_cli_indication_show(struct ast_cli_entry *e, int cmd, struct j--; ast_copy_string(buf + j, "\n", sizeof(buf) - j); ast_cli(a->fd, "%s", buf); - for (ts = tz->tones; ts; ts = ts->next) + AST_LIST_TRAVERSE(&tz->tones, ts, list) { ast_cli(a->fd, "%-7.7s %-15.15s %s\n", tz->country, ts->name, ts->data); + } break; } } @@ -276,23 +277,6 @@ static int handle_stopplaytones(struct ast_channel *chan, void *data) return 0; } -/* helper function to delete a tone_zone in its entirety */ -static inline void free_zone(struct ind_tone_zone* zone) -{ - while (zone->tones) { - struct ind_tone_zone_sound *tmp = zone->tones->next; - ast_free((void *)zone->tones->name); - ast_free((void *)zone->tones->data); - ast_free(zone->tones); - zone->tones = tmp; - } - - if (zone->ringcadence) - ast_free(zone->ringcadence); - - ast_free(zone); -} - /*! \brief load indications module */ static int ind_load_module(int reload) { @@ -347,7 +331,7 @@ static int ind_load_module(int reload) } if (!(tmp = ast_realloc(tones->ringcadence, (tones->nrringcadence + 1) * sizeof(int)))) { ast_config_destroy(cfg); - free_zone(tones); + ast_destroy_indication_zone(tones); return -1; } tones->ringcadence = tmp; @@ -364,50 +348,49 @@ static int ind_load_module(int reload) struct ind_tone_zone* azone; if (!(azone = ast_calloc(1, sizeof(*azone)))) { ast_config_destroy(cfg); - free_zone(tones); + ast_destroy_indication_zone(tones); return -1; } ast_copy_string(azone->country, country, sizeof(azone->country)); ast_copy_string(azone->alias, cxt, sizeof(azone->alias)); if (ast_register_indication_country(azone)) { ast_log(LOG_WARNING, "Unable to register indication alias at line %d.\n",v->lineno); - free_zone(tones); + ast_destroy_indication_zone(tones); } /* next item */ country = strsep(&c,","); } } else { + struct ind_tone_zone_sound *ts; + /* add tone to country */ - struct ind_tone_zone_sound *ps,*ts; - for (ps=NULL,ts=tones->tones; ts; ps=ts, ts=ts->next) { - if (strcasecmp(v->name,ts->name)==0) { + AST_LIST_TRAVERSE(&tones->tones, ts, list) { + if (!strcasecmp(v->name, ts->name)) { /* already there */ - ast_log(LOG_NOTICE,"Duplicate entry '%s', skipped.\n",v->name); + ast_log(LOG_NOTICE, "Duplicate entry '%s' skipped.\n", v->name); goto out; } } - /* not there, add it to the back */ - if (!(ts = ast_malloc(sizeof(*ts)))) { + + /* not there, add it to the back */ + if (!(ts = ast_calloc(1, sizeof(*ts)))) { ast_config_destroy(cfg); return -1; } - ts->next = NULL; ts->name = ast_strdup(v->name); ts->data = ast_strdup(v->value); - if (ps) - ps->next = ts; - else - tones->tones = ts; + + AST_LIST_INSERT_TAIL(&tones->tones, ts, list); } out: v = v->next; } - if (tones->description[0] || tones->alias[0] || tones->tones) { + if (tones->description[0] || tones->alias[0] || !AST_LIST_EMPTY(&tones->tones)) { if (ast_register_indication_country(tones)) { ast_log(LOG_WARNING, "Unable to register indication at line %d.\n",v->lineno); - free_zone(tones); + ast_destroy_indication_zone(tones); } } else { - free_zone(tones); + ast_destroy_indication_zone(tones); } cxt = ast_category_browse(cfg, cxt);