Skip to content
Snippets Groups Projects
indications.c 28.9 KiB
Newer Older
  • Learn to ignore specific revisions
  • Mark Spencer's avatar
    Mark Spencer committed
    	return 0;
    }
    
    
     * Mark the zone and its tones before parsing configuration.  We will use this
     * to know what to remove after configuration is parsed.
     */
    static int tone_zone_mark(void *obj, void *arg, int flags)
    {
    	struct ast_tone_zone *zone = obj;
    	struct ast_tone_zone_sound *s;
    
    	ast_tone_zone_lock(zone);
    
    	zone->killme = 1;
    
    	AST_LIST_TRAVERSE(&zone->tones, s, entry) {
    		s->killme = 1;
    	}
    
    	ast_tone_zone_unlock(zone);
    
    	return 0;
    }
    
    
     * Prune tones no longer in the configuration, and have the tone zone unlinked
     * if it is no longer in the configuration at all.
     */
    static int prune_tone_zone(void *obj, void *arg, int flags)
    {
    	struct ast_tone_zone *zone = obj;
    	struct ast_tone_zone_sound *s;
    
    	ast_tone_zone_lock(zone);
    
    	AST_LIST_TRAVERSE_SAFE_BEGIN(&zone->tones, s, entry) {
    		if (s->killme) {
    			AST_LIST_REMOVE_CURRENT(entry);
    			s = ast_tone_zone_sound_unref(s);
    		}
    	}
    	AST_LIST_TRAVERSE_SAFE_END;
    
    	ast_tone_zone_unlock(zone);
    
    	return zone->killme ? CMP_MATCH : 0;
    }
    
    /*! \brief load indications module */
    static int load_indications(int reload)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    	struct ast_config *cfg;
    	const char *cxt = NULL;
    	const char *country = NULL;
    	struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int res = -1;
    
    
    	cfg = ast_config_load2(config, "indications", config_flags);
    
    	if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
    
    		ast_log(LOG_WARNING, "Can't find indications config file %s.\n", config);
    
    	} else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
    		return 0;
    	}
    
    	/* Lock the container to prevent multiple simultaneous reloads */
    	ao2_lock(ast_tone_zones);
    
    	ao2_callback(ast_tone_zones, OBJ_NODATA, tone_zone_mark, NULL);
    
    	/* Use existing config to populate the Indication table */
    	while ((cxt = ast_category_browse(cfg, cxt))) {
    		/* All categories but "general" are considered countries */
    		if (!strcasecmp(cxt, "general")) {
    			continue;
    		}
    
    		if (parse_tone_zone(cfg, cxt)) {
    			goto return_cleanup;
    
    	ao2_callback(ast_tone_zones, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK,
    			prune_tone_zone, NULL);
    
    	/* determine which country is the default */
    	country = ast_variable_retrieve(cfg, "general", "country");
    	if (ast_strlen_zero(country) || ast_set_indication_country(country)) {
    		ast_log(LOG_WARNING, "Unable to set the default country (for indication tones)\n");
    	}
    
    	res = 0;
    
    return_cleanup:
    	ao2_unlock(ast_tone_zones);
    	ast_config_destroy(cfg);
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return res;
    }
    
    
    /*! \brief CLI entries for commands provided by this module */
    static struct ast_cli_entry cli_indications[] = {
    	AST_CLI_DEFINE(handle_cli_indication_add,    "Add the given indication to the country"),
    	AST_CLI_DEFINE(handle_cli_indication_remove, "Remove the given indication from the country"),
    	AST_CLI_DEFINE(handle_cli_indication_show,   "Display a list of all countries/indications")
    };
    
    static int ast_tone_zone_hash(const void *obj, const int flags)
    {
    	const struct ast_tone_zone *zone = obj;
    
    	return ast_str_case_hash(zone->country);
    }
    
    static int ast_tone_zone_cmp(void *obj, void *arg, int flags)
    {
    	struct ast_tone_zone *zone = obj;
    	struct ast_tone_zone *zone_arg = arg;
    
    	return (!strcasecmp(zone->country, zone_arg->country)) ?
    			CMP_MATCH | CMP_STOP : 0;
    }
    
    
    int ast_tone_zone_data_add_structure(struct ast_data *tree, struct ast_tone_zone *zone)
    {
    	struct ast_data *data_zone_sound;
    	struct ast_tone_zone_sound *s;
    
    	ast_data_add_structure(ast_tone_zone, tree, zone);
    
    	if (AST_LIST_EMPTY(&zone->tones)) {
    		return 0;
    	}
    
    	data_zone_sound = ast_data_add_node(tree, "tones");
    	if (!data_zone_sound) {
    		return -1;
    	}
    
    	ast_tone_zone_lock(zone);
    
    	AST_LIST_TRAVERSE(&zone->tones, s, entry) {
    		ast_data_add_structure(ast_tone_zone_sound, data_zone_sound, s);
    	}
    
    	ast_tone_zone_unlock(zone);
    
    	return 0;
    }
    
    
    Richard Mudgett's avatar
    Richard Mudgett committed
    /*!
     * \internal
     * \brief Clean up resources on Asterisk shutdown
     */
    
    static void indications_shutdown(void)
    {
    
    	ast_cli_unregister_multiple(cli_indications, ARRAY_LEN(cli_indications));
    	if (default_tone_zone) {
    		ast_tone_zone_unref(default_tone_zone);
    		default_tone_zone = NULL;
    	}
    
    	if (ast_tone_zones) {
    		ao2_ref(ast_tone_zones, -1);
    		ast_tone_zones = NULL;
    	}
    }
    
    
    /*! \brief Load indications module */
    int ast_indications_init(void)
    {
    	if (!(ast_tone_zones = ao2_container_alloc(NUM_TONE_ZONE_BUCKETS,
    			ast_tone_zone_hash, ast_tone_zone_cmp))) {
    		return -1;
    	}
    
    	if (load_indications(0)) {
    
    		indications_shutdown();
    
    		return -1;
    	}
    
    	ast_cli_register_multiple(cli_indications, ARRAY_LEN(cli_indications));
    
    
    	ast_register_cleanup(indications_shutdown);
    
    	return 0;
    }
    
    /*! \brief Reload indications module */
    int ast_indications_reload(void)
    {
    	return load_indications(1);
    }