Application Skeleton is an example of creating an application for Asterisk.
#include <math.h>
static char *app = "SkelGuessNumber";
enum option_flags {
OPTION_CHEAT = (1 << 0),
OPTION_NUMGAMES = (1 << 1),
};
enum option_args {
OPTION_ARG_NUMGAMES,
OPTION_ARG_ARRAY_SIZE,
};
});
);
};
};
);
};
uint32_t total_games;
};
#define LEVEL_BUCKETS 1
};
.name = "globals",
.category = "general",
};
.name = "sounds",
.category = "sounds",
};
static const char *level_categories[] = {
"general",
"sounds",
NULL,
};
.name = "level",
.category = (const char *)level_categories,
};
.types =
ACO_TYPES(&global_option, &sound_option, &level_option),
};
.files = ACO_FILES(&app_skel_conf),
);
static void skel_global_config_destructor(void *obj)
{
}
static void skel_game_destructor(void *obj)
{
}
static void skel_state_destructor(void *obj)
{
return;
}
{
return NULL;
}
return game;
}
static void skel_level_destructor(void *obj)
{
ao2_cleanup(level->
state);
}
static int skel_level_hash(const void *obj, const int flags)
{
}
static int skel_level_cmp(void *obj, void *arg, int flags)
{
const char *match = (flags &
OBJ_KEY) ? arg : two->
name;
}
{
if (!strcasecmp(var->
name,
"cheat")) {
} else {
return -1;
}
return 0;
}
static void play_files_helper(
struct ast_channel *chan,
const char *prompts)
{
}
}
static int app_exec(
struct ast_channel *chan,
const char *data)
{
int win = 0;
uint32_t guesses;
char *parse, *opts[OPTION_ARG_ARRAY_SIZE];
);
if (!cfg) {
ast_log(LOG_ERROR, "Couldn't access configuratino data!\n");
return -1;
}
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "%s requires an argument (level[,options])\n", app);
return -1;
}
if (args.argc == 2) {
}
if (ast_strlen_zero(args.level)) {
ast_log(LOG_ERROR, "%s requires a level argument\n", app);
return -1;
}
if (!(level = ao2_find(cfg->levels, args.level,
OBJ_KEY))) {
ast_log(LOG_ERROR, "Unknown level: %s\n", args.level);
return -1;
}
if (!(game = skel_game_alloc(level))) {
return -1;
}
if (!ast_test_flag(&flags, OPTION_NUMGAMES) ||
ast_strlen_zero(opts[OPTION_ARG_NUMGAMES]) ||
ast_parse_arg(opts[OPTION_ARG_NUMGAMES], PARSE_UINT32, &game->
total_games)) {
game->total_games = cfg->global->num_games;
}
game->
cheat = ast_test_flag(&flags, OPTION_CHEAT) || cfg->global->cheat;
uint32_t num = ast_random() % level->
max_num;
ast_debug(1,
"They should totally should guess %u\n", num);
play_files_helper(chan, cfg->global->prompt);
for (guesses = 0; guesses < level->
max_guesses; guesses++) {
size_t buflen = log10(level->
max_num) + 1;
char buf[buflen];
int guess;
buf[buflen] = '\0';
if (guesses < level->max_guesses - 1) {
play_files_helper(chan, cfg->global->wrong);
}
continue;
}
if (guess == num && !game->
cheat) {
win = 1;
play_files_helper(chan, cfg->global->right);
guesses++;
break;
} else if (guess < num) {
play_files_helper(chan, cfg->global->low);
} else {
play_files_helper(chan, cfg->global->high);
}
if (guesses < level->max_guesses - 1) {
play_files_helper(chan, cfg->global->wrong);
}
}
if (win) {
} else {
play_files_helper(chan, cfg->global->lose);
}
ao2_unlock(level->
state);
}
return 0;
}
static struct skel_level *skel_state_alloc(
const char *name)
{
if (!(level = ao2_alloc(sizeof(*level), skel_state_destructor))) {
return NULL;
}
return level;
}
{
return ao2_find(tmp_container, category,
OBJ_KEY);
}
{
if (!cfg || !cfg->levels || !(level = ao2_find(cfg->levels, category,
OBJ_KEY))) {
return skel_state_alloc(category);
}
}
{
if (!(level = ao2_alloc(sizeof(*level), skel_level_destructor))) {
return NULL;
}
return NULL;
}
return NULL;
}
return level;
}
static void skel_config_destructor(void *obj)
{
ao2_cleanup(cfg->
global);
ao2_cleanup(cfg->
levels);
}
{
if (!(cfg = ao2_alloc(sizeof(*cfg), skel_config_destructor))) {
return NULL;
}
if (!(cfg->global = ao2_alloc(sizeof(*cfg->global), skel_global_config_destructor))) {
goto error;
}
goto error;
}
skel_level_hash, NULL, skel_level_cmp);
if (!cfg->levels) {
goto error;
}
return cfg;
error:
return NULL;
}
{
switch(cmd) {
case CLI_INIT:
"Usage: skel show config\n"
" List app_skel global config\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
return NULL;
}
ast_cli(a->
fd,
"games per call: %u\n", cfg->global->
num_games);
ast_cli(a->fd, "\n");
ast_cli(a->fd, "Sounds\n");
ast_cli(a->fd,
" prompt: %s\n", cfg->global->
prompt);
ast_cli(a->fd,
" wrong guess: %s\n", cfg->global->
wrong);
ast_cli(a->fd,
" right guess: %s\n", cfg->global->
right);
return CLI_SUCCESS;
}
{
switch(cmd) {
case CLI_INIT:
"Usage: skel show games\n"
" List app_skel active games\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
#define SKEL_FORMAT "%-15.15s %-15.15s %-15.15s\n"
#define SKEL_FORMAT1 "%-15.15s %-15u %-15u\n"
ast_cli(a->fd, SKEL_FORMAT, "Level", "Total Games", "Games Left");
while ((game = ao2_iterator_next(&iter))) {
}
#undef SKEL_FORMAT
#undef SKEL_FORMAT1
return CLI_SUCCESS;
}
{
switch(cmd) {
case CLI_INIT:
"Usage: skel show levels\n"
" List the app_skel levels\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
return NULL;
}
#define SKEL_FORMAT "%-15.15s %-11.11s %-12.12s %-8.8s %-8.8s %-12.12s\n"
#define SKEL_FORMAT1 "%-15.15s %-11u %-12u %-8u %-8u %-8f\n"
ast_cli(a->fd, SKEL_FORMAT, "Name", "Max number", "Max Guesses", "Wins", "Losses", "Avg Guesses");
while ((level = ao2_iterator_next(&iter))) {
}
#undef SKEL_FORMAT
#undef SKEL_FORMAT1
return CLI_SUCCESS;
}
AST_CLI_DEFINE(handle_skel_show_config, "Show app_skel global config options"),
AST_CLI_DEFINE(handle_skel_show_levels, "Show app_skel levels"),
AST_CLI_DEFINE(handle_skel_show_games, "Show app_skel active games"),
};
static int reload_module(void)
{
}
return 0;
}
static int unload_module(void)
{
ao2_cleanup(games);
}
{
goto error;
}
if (!games) {
goto error;
}
goto error;
}
goto error;
}
error:
ao2_cleanup(games);
}
AST_MODULE_INFO(
ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT,
"Skeleton (sample) Application",
.support_level = AST_MODULE_SUPPORT_CORE,
.unload = unload_module,
.reload = reload_module,
);