Asterisk - The Open Source Telephony Project GIT-master-3dae2cf
app_skel.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) <Year>, <Your Name Here>
5 *
6 * <Your Name Here> <<Your Email Here>>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 *
18 * Please follow coding guidelines
19 * https://docs.asterisk.org/Development/Policies-and-Procedures/Coding-Guidelines/
20 */
21
22/*! \file
23 *
24 * \brief Skeleton application
25 *
26 * \author\verbatim <Your Name Here> <<Your Email Here>> \endverbatim
27 *
28 * This is a skeleton for development of an Asterisk application
29 * \ingroup applications
30 */
31
32/*! \li \ref app_skel.c uses configuration file \ref app_skel.conf
33 * \addtogroup configuration_file Configuration Files
34 */
35
36/*!
37 * \page app_skel.conf app_skel.conf
38 * \verbinclude app_skel.conf.sample
39 */
40
41/*** MODULEINFO
42 <defaultenabled>no</defaultenabled>
43 <support_level>core</support_level>
44 ***/
45
46#include "asterisk.h"
47
48#include <math.h> /* log10 */
49#include "asterisk/file.h"
50#include "asterisk/channel.h"
51#include "asterisk/pbx.h"
52#include "asterisk/module.h"
53#include "asterisk/lock.h"
54#include "asterisk/app.h"
55#include "asterisk/config.h"
57#include "asterisk/say.h"
58#include "asterisk/astobj2.h"
59#include "asterisk/acl.h"
60#include "asterisk/netsock2.h"
61#include "asterisk/strings.h"
62#include "asterisk/cli.h"
63
64/*** DOCUMENTATION
65 <application name="SkelGuessNumber" language="en_US">
66 <synopsis>
67 An example number guessing game
68 </synopsis>
69 <syntax>
70 <parameter name="level" required="true"/>
71 <parameter name="options">
72 <optionlist>
73 <option name="c">
74 <para>The computer should cheat</para>
75 </option>
76 <option name="n">
77 <para>How many games to play before hanging up</para>
78 </option>
79 </optionlist>
80 </parameter>
81 </syntax>
82 <description>
83 <para>This simple number guessing application is a template to build other applications
84 from. It shows you the basic structure to create your own Asterisk applications.</para>
85 </description>
86 </application>
87
88 <configInfo name="app_skel" language="en_US">
89 <configFile name="app_skel.conf">
90 <configObject name="globals">
91 <synopsis>Options that apply globally to app_skel</synopsis>
92 <configOption name="games">
93 <synopsis>The number of games a single execution of SkelGuessNumber will play</synopsis>
94 </configOption>
95 <configOption name="cheat">
96 <synopsis>Should the computer cheat?</synopsis>
97 <description><para>If enabled, the computer will ignore winning guesses.</para></description>
98 </configOption>
99 </configObject>
100 <configObject name="sounds">
101 <synopsis>Prompts for SkelGuessNumber to play</synopsis>
102 <configOption name="prompt" default="please-enter-your&amp;number&amp;queue-less-than">
103 <synopsis>A prompt directing the user to enter a number less than the max number</synopsis>
104 </configOption>
105 <configOption name="wrong_guess" default="vm-pls-try-again">
106 <synopsis>The sound file to play when a wrong guess is made</synopsis>
107 </configOption>
108 <configOption name="right_guess" default="auth-thankyou">
109 <synopsis>The sound file to play when a correct guess is made</synopsis>
110 </configOption>
111 <configOption name="too_low">
112 <synopsis>The sound file to play when a guess is too low</synopsis>
113 </configOption>
114 <configOption name="too_high">
115 <synopsis>The sound file to play when a guess is too high</synopsis>
116 </configOption>
117 <configOption name="lose" default="vm-goodbye">
118 <synopsis>The sound file to play when a player loses</synopsis>
119 </configOption>
120 </configObject>
121 <configObject name="level">
122 <synopsis>Defined levels for the SkelGuessNumber game</synopsis>
123 <configOption name="max_number">
124 <synopsis>The maximum in the range of numbers to guess (1 is the implied minimum)</synopsis>
125 </configOption>
126 <configOption name="max_guesses">
127 <synopsis>The maximum number of guesses before a game is considered lost</synopsis>
128 </configOption>
129 </configObject>
130 </configFile>
131 </configInfo>
132 ***/
133
134static char *app = "SkelGuessNumber";
135
137 OPTION_CHEAT = (1 << 0),
138 OPTION_NUMGAMES = (1 << 1),
139};
140
143 /* This *must* be the last value in this enum! */
145};
146
150});
151
152/*! \brief A structure to hold global configuration-related options */
155 AST_STRING_FIELD(prompt); /*!< The comma-separated list of sounds to prompt to enter a number */
156 AST_STRING_FIELD(wrong); /*!< The comma-separated list of sounds to indicate a wrong guess */
157 AST_STRING_FIELD(right); /*!< The comma-separated list of sounds to indicate a right guess */
158 AST_STRING_FIELD(high); /*!< The comma-separated list of sounds to indicate a high guess */
159 AST_STRING_FIELD(low); /*!< The comma-separated list of sounds to indicate a low guess */
160 AST_STRING_FIELD(lose); /*!< The comma-separated list of sounds to indicate a lost game */
161 );
162 uint32_t num_games; /*!< The number of games to play before hanging up */
163 unsigned char cheat:1; /*!< Whether the computer can cheat or not */
164};
165
166/*! \brief A structure to maintain level state across reloads */
168 uint32_t wins; /*!< How many wins for this level */
169 uint32_t losses; /*!< How many losses for this level */
170 double avg_guesses; /*!< The average number of guesses to win for this level */
171};
172
173/*! \brief Object to hold level config information.
174 * \note This object should hold a reference to an object that holds state across reloads.
175 * The other fields are just examples of the kind of data that might be stored in an level.
176 */
179 AST_STRING_FIELD(name); /*!< The name of the level */
180 );
181 uint32_t max_num; /*!< The upper value on th range of numbers to guess */
182 uint32_t max_guesses; /*!< The maximum number of guesses before losing */
183 struct skel_level_state *state; /*!< A pointer to level state that must exist across all reloads */
184};
185
186/*! \brief Information about a currently running set of games
187 * \note Because we want to be able to show true running information about the games
188 * regardless of whether or not a reload has modified what the level looks like, it
189 * is important to either copy the information we need from the level to the
190 * current_game struct, or as we do here, store a reference to the level as it is for
191 * the running game.
192 */
194 uint32_t total_games; /*! The total number of games for this call to the app */
195 uint32_t games_left; /*! How many games are left to play in this set */
196 uint32_t cheat; /*! Whether or not cheating was enabled for the game */
197 struct skel_level *level_info; /*! The level information for the running game */
198};
199
200/* Treat the levels as an array--there won't be many and this will maintain the order */
201#define LEVEL_BUCKETS 1
202
203/*! \brief A container that holds all config-related information
204 * \note This object should contain a pointer to structs for global data and containers for
205 * any levels that are configured. Objects of this type will be swapped out on reload. If an
206 * level needs to maintain state across reloads, it needs to allocate a refcounted object to
207 * hold that state and ensure that a reference is passed to that state when creating a new
208 * level for reload. */
212};
213
214/* Config Options API callbacks */
215
216/*! \brief Allocate a skel_config to hold a snapshot of the complete results of parsing a config
217 * \internal
218 * \returns A void pointer to a newly allocated skel_config
219 */
220static void *skel_config_alloc(void);
221
222/*! \brief Allocate a skel_level based on a category in a configuration file
223 * \param cat The category to base the level on
224 * \returns A void pointer to a newly allocated skel_level
225 */
226static void *skel_level_alloc(const char *cat);
227
228/*! \brief Find a skel level in the specified container
229 * \note This function *does not* look for a skel_level in the active container. It is used
230 * internally by the Config Options code to check if an level has already been added to the
231 * container that will be swapped for the live container on a successul reload.
232 *
233 * \param tmp_container A non-active container to search for a level
234 * \param category The category associated with the level to check for
235 * \retval non-NULL The level from the container
236 * \retval NULL The level does not exist in the container
237 */
238static void *skel_level_find(struct ao2_container *tmp_container, const char *category);
239
240/*! \brief An aco_type structure to link the "general" category to the skel_global_config type */
241static struct aco_type global_option = {
242 .type = ACO_GLOBAL,
243 .name = "globals",
244 .item_offset = offsetof(struct skel_config, global),
245 .category_match = ACO_WHITELIST_EXACT,
246 .category = "general",
247};
248
250
251/*! \brief An aco_type structure to link the "sounds" category to the skel_global_config type */
252static struct aco_type sound_option = {
253 .type = ACO_GLOBAL,
254 .name = "sounds",
255 .item_offset = offsetof(struct skel_config, global),
256 .category_match = ACO_WHITELIST_EXACT,
257 .category = "sounds",
258};
259
261
262static const char *level_categories[] = {
263 "general",
264 "sounds",
265 NULL,
266};
267
268/*! \brief An aco_type structure to link the everything but the "general" and "sounds" categories to the skel_level type */
269static struct aco_type level_option = {
270 .type = ACO_ITEM,
271 .name = "level",
272 .category_match = ACO_BLACKLIST_ARRAY,
273 .category = (const char *)level_categories,
276 .item_offset = offsetof(struct skel_config, levels),
277};
278
280
282 .filename = "app_skel.conf",
284};
285
286/*! \brief A global object container that will contain the skel_config that gets swapped out on reloads */
288
289/*! \brief The container of active games */
290static struct ao2_container *games;
291
292/*! \brief Register information about the configs being processed by this module */
294 .files = ACO_FILES(&app_skel_conf),
295);
296
297static void skel_global_config_destructor(void *obj)
298{
299 struct skel_global_config *global = obj;
301}
302
303static void skel_game_destructor(void *obj)
304{
305 struct skel_current_game *game = obj;
306 ao2_cleanup(game->level_info);
307}
308
309static void skel_state_destructor(void *obj)
310{
311 return;
312}
313
314static struct skel_current_game *skel_game_alloc(struct skel_level *level)
315{
316 struct skel_current_game *game;
317 if (!(game = ao2_alloc(sizeof(struct skel_current_game), skel_game_destructor))) {
318 return NULL;
319 }
320 ao2_ref(level, +1);
321 game->level_info = level;
322 return game;
323}
324
325static void skel_level_destructor(void *obj)
326{
327 struct skel_level *level = obj;
329 ao2_cleanup(level->state);
330}
331
332static int skel_level_hash(const void *obj, const int flags)
333{
334 const struct skel_level *level = obj;
335 const char *name = (flags & OBJ_KEY) ? obj : level->name;
336 return ast_str_case_hash(name);
337}
338
339static int skel_level_cmp(void *obj, void *arg, int flags)
340{
341 struct skel_level *one = obj, *two = arg;
342 const char *match = (flags & OBJ_KEY) ? arg : two->name;
343 return strcasecmp(one->name, match) ? 0 : (CMP_MATCH | CMP_STOP);
344}
345
346/*! \brief A custom bitfield handler
347 * \internal
348 * \note It is not possible to take the address of a bitfield, therefor all
349 * bitfields in the config struct will have to use a custom handler
350 * \param opt The opaque config option
351 * \param var The ast_variable containing the option name and value
352 * \param obj The object registerd for this option type
353 * \retval 0 Success
354 * \retval non-zero Failure
355 */
356static int custom_bitfield_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
357{
358 struct skel_global_config *global = obj;
359
360 if (!strcasecmp(var->name, "cheat")) {
361 global->cheat = ast_true(var->value);
362 } else {
363 return -1;
364 }
365
366 return 0;
367}
368
369static void play_files_helper(struct ast_channel *chan, const char *prompts)
370{
371 char *prompt, *rest = ast_strdupa(prompts);
372
373 ast_stopstream(chan);
374 while ((prompt = ast_strsep(&rest, '&', AST_STRSEP_STRIP | AST_STRSEP_TRIM))
375 && !ast_stream_and_wait(chan, prompt, "")) {
376 ast_stopstream(chan);
377 }
378}
379
380static int app_exec(struct ast_channel *chan, const char *data)
381{
382 int win = 0;
383 uint32_t guesses;
385 RAII_VAR(struct skel_level *, level, NULL, ao2_cleanup);
386 RAII_VAR(struct skel_current_game *, game, NULL, ao2_cleanup);
387 char *parse, *opts[OPTION_ARG_ARRAY_SIZE];
388 struct ast_flags flags;
390 AST_APP_ARG(level);
392 );
393
394 if (!cfg) {
395 ast_log(LOG_ERROR, "Couldn't access configuratino data!\n");
396 return -1;
397 }
398
399 if (ast_strlen_zero(data)) {
400 ast_log(LOG_WARNING, "%s requires an argument (level[,options])\n", app);
401 return -1;
402 }
403
404 /* We need to make a copy of the input string if we are going to modify it! */
405 parse = ast_strdupa(data);
406
408
409 if (args.argc == 2) {
410 ast_app_parse_options(app_opts, &flags, opts, args.options);
411 }
412
413 if (ast_strlen_zero(args.level)) {
414 ast_log(LOG_ERROR, "%s requires a level argument\n", app);
415 return -1;
416 }
417
418 if (!(level = ao2_find(cfg->levels, args.level, OBJ_KEY))) {
419 ast_log(LOG_ERROR, "Unknown level: %s\n", args.level);
420 return -1;
421 }
422
423 if (!(game = skel_game_alloc(level))) {
424 return -1;
425 }
426
427 ao2_link(games, game);
428
429 /* Use app-specified values, or the options specified in [general] if they aren't passed to the app */
432 ast_parse_arg(opts[OPTION_ARG_NUMGAMES], PARSE_UINT32, &game->total_games)) {
433 game->total_games = cfg->global->num_games;
434 }
435 game->games_left = game->total_games;
436 game->cheat = ast_test_flag(&flags, OPTION_CHEAT) || cfg->global->cheat;
437
438 for (game->games_left = game->total_games; game->games_left; game->games_left--) {
439 uint32_t num = ast_random() % level->max_num; /* random number between 0 and level->max_num */
440
441 ast_debug(1, "They should totally should guess %u\n", num);
442
443 /* Play the prompt */
444 play_files_helper(chan, cfg->global->prompt);
445 ast_say_number(chan, level->max_num, "", ast_channel_language(chan), "");
446
447 for (guesses = 0; guesses < level->max_guesses; guesses++) {
448 size_t buflen = log10(level->max_num) + 1;
449 char buf[buflen];
450 int guess;
451 buf[buflen] = '\0';
452
453 /* Read the number pressed */
454 ast_readstring(chan, buf, buflen - 1, 2000, 10000, "");
455 if (ast_parse_arg(buf, PARSE_INT32 | PARSE_IN_RANGE, &guess, 0, level->max_num)) {
456 if (guesses < level->max_guesses - 1) {
457 play_files_helper(chan, cfg->global->wrong);
458 }
459 continue;
460 }
461
462 /* Inform whether the guess was right, low, or high */
463 if (guess == num && !game->cheat) {
464 /* win */
465 win = 1;
466 play_files_helper(chan, cfg->global->right);
467 guesses++;
468 break;
469 } else if (guess < num) {
470 play_files_helper(chan, cfg->global->low);
471 } else {
472 play_files_helper(chan, cfg->global->high);
473 }
474
475 if (guesses < level->max_guesses - 1) {
476 play_files_helper(chan, cfg->global->wrong);
477 }
478 }
479
480 /* Process game stats */
481 ao2_lock(level->state);
482 if (win) {
483 ++level->state->wins;
484 level->state->avg_guesses = ((level->state->wins - 1) * level->state->avg_guesses + guesses) / level->state->wins;
485 } else {
486 /* lose */
487 level->state->losses++;
488 play_files_helper(chan, cfg->global->lose);
489 }
490 ao2_unlock(level->state);
491 }
492
493 ao2_unlink(games, game);
494
495 return 0;
496}
497
498static struct skel_level *skel_state_alloc(const char *name)
499{
500 struct skel_level *level;
501
502 if (!(level = ao2_alloc(sizeof(*level), skel_state_destructor))) {
503 return NULL;
504 }
505
506 return level;
507}
508
509static void *skel_level_find(struct ao2_container *tmp_container, const char *category)
510{
511 return ao2_find(tmp_container, category, OBJ_KEY);
512}
513
514/*! \brief Look up an existing state object, or create a new one
515 * \internal
516 * \note Since the reload code will create a new level from scratch, it
517 * is important for any state that must persist between reloads to be
518 * in a separate refcounted object. This function allows the level alloc
519 * function to get a ref to an existing state object if it exists,
520 * otherwise it will return a reference to a newly allocated state object.
521 */
522static void *skel_find_or_create_state(const char *category)
523{
525 RAII_VAR(struct skel_level *, level, NULL, ao2_cleanup);
526 if (!cfg || !cfg->levels || !(level = ao2_find(cfg->levels, category, OBJ_KEY))) {
527 return skel_state_alloc(category);
528 }
529 ao2_ref(level->state, +1);
530 return level->state;
531}
532
533static void *skel_level_alloc(const char *cat)
534{
535 struct skel_level *level;
536
537 if (!(level = ao2_alloc(sizeof(*level), skel_level_destructor))) {
538 return NULL;
539 }
540
541 if (ast_string_field_init(level, 128)) {
542 ao2_ref(level, -1);
543 return NULL;
544 }
545
546 /* Since the level has state information that needs to persist between reloads,
547 * it is important to handle that here in the level's allocation function.
548 * If not separated out into its own object, the data would be destroyed on
549 * reload. */
550 if (!(level->state = skel_find_or_create_state(cat))) {
551 ao2_ref(level, -1);
552 return NULL;
553 }
554
555 ast_string_field_set(level, name, cat);
556
557 return level;
558}
559
560static void skel_config_destructor(void *obj)
561{
562 struct skel_config *cfg = obj;
563 ao2_cleanup(cfg->global);
564 ao2_cleanup(cfg->levels);
565}
566
567static void *skel_config_alloc(void)
568{
569 struct skel_config *cfg;
570
571 if (!(cfg = ao2_alloc(sizeof(*cfg), skel_config_destructor))) {
572 return NULL;
573 }
574
575 /* Allocate/initialize memory */
576 if (!(cfg->global = ao2_alloc(sizeof(*cfg->global), skel_global_config_destructor))) {
577 goto error;
578 }
579
580 if (ast_string_field_init(cfg->global, 128)) {
581 goto error;
582 }
583
586 if (!cfg->levels) {
587 goto error;
588 }
589
590 return cfg;
591error:
592 ao2_ref(cfg, -1);
593 return NULL;
594}
595
596static char *handle_skel_show_config(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
597{
598 RAII_VAR(struct skel_config *, cfg, NULL, ao2_cleanup);
599
600 switch(cmd) {
601 case CLI_INIT:
602 e->command = "skel show config";
603 e->usage =
604 "Usage: skel show config\n"
605 " List app_skel global config\n";
606 return NULL;
607 case CLI_GENERATE:
608 return NULL;
609 }
610
611 if (!(cfg = ao2_global_obj_ref(globals)) || !cfg->global) {
612 return NULL;
613 }
614
615 ast_cli(a->fd, "games per call: %u\n", cfg->global->num_games);
616 ast_cli(a->fd, "computer cheats: %s\n", AST_CLI_YESNO(cfg->global->cheat));
617 ast_cli(a->fd, "\n");
618 ast_cli(a->fd, "Sounds\n");
619 ast_cli(a->fd, " prompt: %s\n", cfg->global->prompt);
620 ast_cli(a->fd, " wrong guess: %s\n", cfg->global->wrong);
621 ast_cli(a->fd, " right guess: %s\n", cfg->global->right);
622
623 return CLI_SUCCESS;
624}
625
626static char *handle_skel_show_games(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
627{
628 struct ao2_iterator iter;
629 struct skel_current_game *game;
630
631 switch(cmd) {
632 case CLI_INIT:
633 e->command = "skel show games";
634 e->usage =
635 "Usage: skel show games\n"
636 " List app_skel active games\n";
637 return NULL;
638 case CLI_GENERATE:
639 return NULL;
640 }
641
642#define SKEL_FORMAT "%-15.15s %-15.15s %-15.15s\n"
643#define SKEL_FORMAT1 "%-15.15s %-15u %-15u\n"
644 ast_cli(a->fd, SKEL_FORMAT, "Level", "Total Games", "Games Left");
645 iter = ao2_iterator_init(games, 0);
646 while ((game = ao2_iterator_next(&iter))) {
647 ast_cli(a->fd, SKEL_FORMAT1, game->level_info->name, game->total_games, game->games_left);
648 ao2_ref(game, -1);
649 }
651#undef SKEL_FORMAT
652#undef SKEL_FORMAT1
653 return CLI_SUCCESS;
654}
655
656static char *handle_skel_show_levels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
657{
658 RAII_VAR(struct skel_config *, cfg, NULL, ao2_cleanup);
659 struct ao2_iterator iter;
660 struct skel_level *level;
661
662 switch(cmd) {
663 case CLI_INIT:
664 e->command = "skel show levels";
665 e->usage =
666 "Usage: skel show levels\n"
667 " List the app_skel levels\n";
668 return NULL;
669 case CLI_GENERATE:
670 return NULL;
671 }
672
673 if (!(cfg = ao2_global_obj_ref(globals)) || !cfg->levels) {
674 return NULL;
675 }
676
677#define SKEL_FORMAT "%-15.15s %-11.11s %-12.12s %-8.8s %-8.8s %-12.12s\n"
678#define SKEL_FORMAT1 "%-15.15s %-11u %-12u %-8u %-8u %-8f\n"
679 ast_cli(a->fd, SKEL_FORMAT, "Name", "Max number", "Max Guesses", "Wins", "Losses", "Avg Guesses");
680 iter = ao2_iterator_init(cfg->levels, 0);
681 while ((level = ao2_iterator_next(&iter))) {
682 ast_cli(a->fd, SKEL_FORMAT1, level->name, level->max_num, level->max_guesses, level->state->wins, level->state->losses, level->state->avg_guesses);
683 ao2_ref(level, -1);
684 }
686#undef SKEL_FORMAT
687#undef SKEL_FORMAT1
688
689 return CLI_SUCCESS;
690}
691
692static struct ast_cli_entry skel_cli[] = {
693 AST_CLI_DEFINE(handle_skel_show_config, "Show app_skel global config options"),
694 AST_CLI_DEFINE(handle_skel_show_levels, "Show app_skel levels"),
695 AST_CLI_DEFINE(handle_skel_show_games, "Show app_skel active games"),
696};
697
698static int reload_module(void)
699{
700 if (aco_process_config(&cfg_info, 1) == ACO_PROCESS_ERROR) {
702 }
703
704 return 0;
705}
706
707static int unload_module(void)
708{
710 aco_info_destroy(&cfg_info);
714}
715
716/*!
717 * \brief Load the module
718 *
719 * Module loading including tests for configuration or dependencies.
720 * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
721 * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
722 * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
723 * configuration file or other non-critical problem return
724 * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
725 */
726static int load_module(void)
727{
728 if (aco_info_init(&cfg_info)) {
729 goto error;
730 }
731
733 if (!games) {
734 goto error;
735 }
736
737 /* Global options */
738 aco_option_register(&cfg_info, "games", ACO_EXACT, global_options, "3", OPT_UINT_T, 0, FLDSET(struct skel_global_config, num_games));
740
741 /* Sound options */
742 aco_option_register(&cfg_info, "prompt", ACO_EXACT, sound_options, "please-enter-your&number&queue-less-than", OPT_STRINGFIELD_T, 0, STRFLDSET(struct skel_global_config, prompt));
743 aco_option_register(&cfg_info, "wrong_guess", ACO_EXACT, sound_options, "vm-pls-try-again", OPT_STRINGFIELD_T, 0, STRFLDSET(struct skel_global_config, wrong));
744 aco_option_register(&cfg_info, "right_guess", ACO_EXACT, sound_options, "auth-thankyou", OPT_STRINGFIELD_T, 0, STRFLDSET(struct skel_global_config, right));
745 aco_option_register(&cfg_info, "too_high", ACO_EXACT, sound_options, "high", OPT_STRINGFIELD_T, 0, STRFLDSET(struct skel_global_config, high));
746 aco_option_register(&cfg_info, "too_low", ACO_EXACT, sound_options, "low", OPT_STRINGFIELD_T, 0, STRFLDSET(struct skel_global_config, low));
747 aco_option_register(&cfg_info, "lose", ACO_EXACT, sound_options, "vm-goodbye", OPT_STRINGFIELD_T, 0, STRFLDSET(struct skel_global_config, lose));
748
749 /* Level options */
750 aco_option_register(&cfg_info, "max_number", ACO_EXACT, level_options, NULL, OPT_UINT_T, 0, FLDSET(struct skel_level, max_num));
751 aco_option_register(&cfg_info, "max_guesses", ACO_EXACT, level_options, NULL, OPT_UINT_T, 0, FLDSET(struct skel_level, max_guesses));
752
753 if (aco_process_config(&cfg_info, 0) == ACO_PROCESS_ERROR) {
754 goto error;
755 }
756
759 goto error;
760 }
762
763error:
764 aco_info_destroy(&cfg_info);
767}
768
769AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Skeleton (sample) Application",
770 .support_level = AST_MODULE_SUPPORT_CORE,
771 .load = load_module,
772 .unload = unload_module,
Access Control of various sorts.
struct aco_type * global_options[]
Definition: app_skel.c:249
CONFIG_INFO_STANDARD(cfg_info, globals, skel_config_alloc,.files=ACO_FILES(&app_skel_conf),)
Register information about the configs being processed by this module.
static int skel_level_hash(const void *obj, const int flags)
Definition: app_skel.c:332
static int custom_bitfield_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
A custom bitfield handler.
Definition: app_skel.c:356
static struct skel_level * skel_state_alloc(const char *name)
Definition: app_skel.c:498
#define LEVEL_BUCKETS
Definition: app_skel.c:201
struct aco_type * level_options[]
Definition: app_skel.c:279
static void skel_global_config_destructor(void *obj)
Definition: app_skel.c:297
option_args
Definition: app_skel.c:141
@ OPTION_ARG_NUMGAMES
Definition: app_skel.c:142
@ OPTION_ARG_ARRAY_SIZE
Definition: app_skel.c:144
option_flags
Definition: app_skel.c:136
@ OPTION_NUMGAMES
Definition: app_skel.c:138
@ OPTION_CHEAT
Definition: app_skel.c:137
#define SKEL_FORMAT
static void * skel_level_find(struct ao2_container *tmp_container, const char *category)
Find a skel level in the specified container.
Definition: app_skel.c:509
static AO2_GLOBAL_OBJ_STATIC(globals)
A global object container that will contain the skel_config that gets swapped out on reloads.
static void skel_game_destructor(void *obj)
Definition: app_skel.c:303
#define SKEL_FORMAT1
static void skel_config_destructor(void *obj)
Definition: app_skel.c:560
static int reload_module(void)
Definition: app_skel.c:698
static void * skel_level_alloc(const char *cat)
Allocate a skel_level based on a category in a configuration file.
Definition: app_skel.c:533
static void play_files_helper(struct ast_channel *chan, const char *prompts)
Definition: app_skel.c:369
static char * handle_skel_show_games(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_skel.c:626
static struct aco_type sound_option
An aco_type structure to link the "sounds" category to the skel_global_config type.
Definition: app_skel.c:252
static struct ao2_container * games
The container of active games.
Definition: app_skel.c:290
static struct aco_type level_option
An aco_type structure to link the everything but the "general" and "sounds" categories to the skel_le...
Definition: app_skel.c:269
static void skel_level_destructor(void *obj)
Definition: app_skel.c:325
static struct ast_cli_entry skel_cli[]
Definition: app_skel.c:692
static const struct ast_app_option app_opts[128]
Definition: app_skel.c:150
static char * app
Definition: app_skel.c:134
static int app_exec(struct ast_channel *chan, const char *data)
Definition: app_skel.c:380
static char * handle_skel_show_config(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_skel.c:596
static void * skel_config_alloc(void)
Allocate a skel_config to hold a snapshot of the complete results of parsing a config.
Definition: app_skel.c:567
static struct skel_current_game * skel_game_alloc(struct skel_level *level)
Definition: app_skel.c:314
static void skel_state_destructor(void *obj)
Definition: app_skel.c:309
static int skel_level_cmp(void *obj, void *arg, int flags)
Definition: app_skel.c:339
struct aco_file app_skel_conf
Definition: app_skel.c:281
static int load_module(void)
Load the module.
Definition: app_skel.c:726
static char * handle_skel_show_levels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_skel.c:656
static int unload_module(void)
Definition: app_skel.c:707
static const char * level_categories[]
Definition: app_skel.c:262
static struct aco_type global_option
An aco_type structure to link the "general" category to the skel_global_config type.
Definition: app_skel.c:241
static void * skel_find_or_create_state(const char *category)
Look up an existing state object, or create a new one.
Definition: app_skel.c:522
struct aco_type * sound_options[]
Definition: app_skel.c:260
#define var
Definition: ast_expr2f.c:605
static struct ast_str * prompt
Definition: asterisk.c:2780
Asterisk main include file. File version handling, generic pbx functions.
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_log
Definition: astobj2.c:42
#define ao2_iterator_next(iter)
Definition: astobj2.h:1911
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
@ CMP_MATCH
Definition: astobj2.h:1027
@ CMP_STOP
Definition: astobj2.h:1028
#define OBJ_KEY
Definition: astobj2.h:1151
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition: astobj2.h:363
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_unlink(container, obj)
Remove an object from a container.
Definition: astobj2.h:1578
#define ao2_global_obj_ref(holder)
Get a reference to the object stored in the global holder.
Definition: astobj2.h:918
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_unlock(a)
Definition: astobj2.h:729
#define ao2_lock(a)
Definition: astobj2.h:717
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ao2_global_obj_release(holder)
Release the ao2 object held in the global holder.
Definition: astobj2.h:859
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
Definition: astobj2.h:1327
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Definition: astobj2.h:1303
static struct console_pvt globals
static int match(struct ast_sockaddr *addr, unsigned short callno, unsigned short dcallno, const struct chan_iax2_pvt *cur, int check_dcallno)
Definition: chan_iax2.c:2362
General Asterisk PBX channel definitions.
const char * ast_channel_language(const struct ast_channel *chan)
int ast_readstring(struct ast_channel *c, char *s, int len, int timeout, int rtimeout, char *enders)
Reads multiple digits.
Definition: channel.c:6577
Standard Command Line Interface.
#define AST_CLI_YESNO(x)
Return Yes or No depending on the argument.
Definition: cli.h:71
#define CLI_SUCCESS
Definition: cli.h:44
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
Configuration option-handling.
@ ACO_EXACT
void aco_info_destroy(struct aco_info *info)
Destroy an initialized aco_info struct.
@ ACO_PROCESS_ERROR
Their was an error and no changes were applied.
#define STRFLDSET(type,...)
Convert a struct and a list of stringfield fields to an argument list of field offsets.
int aco_info_init(struct aco_info *info)
Initialize an aco_info structure.
#define FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
#define aco_option_register(info, name, matchtype, types, default_val, opt_type, flags,...)
Register a config option.
#define ACO_FILES(...)
@ OPT_UINT_T
Type for default option handler for unsigned integers.
@ OPT_STRINGFIELD_T
Type for default option handler for stringfields.
#define aco_option_register_custom(info, name, matchtype, types, default_val, handler, flags)
Register a config option.
@ ACO_ITEM
@ ACO_GLOBAL
@ ACO_WHITELIST_EXACT
@ ACO_BLACKLIST_ARRAY
enum aco_process_status aco_process_config(struct aco_info *info, int reload)
Process a config info via the options registered with an aco_info.
#define ACO_TYPES(...)
A helper macro to ensure that aco_info types always have a sentinel.
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
Generic File Format Support. Should be included by clients of the file handling routines....
int ast_stopstream(struct ast_channel *c)
Stops a stream.
Definition: file.c:222
int ast_stream_and_wait(struct ast_channel *chan, const char *file, const char *digits)
stream file until digit If the file name is non-empty, try to play it.
Definition: file.c:1878
static const char name[]
Definition: format_mp3.c:68
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
#define AST_APP_ARG(name)
Define an application argument.
#define AST_APP_OPTIONS(holder, options...)
Declares an array of options for an application.
#define AST_APP_OPTION_ARG(option, flagno, argno)
Declares an application option that accepts an argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
#define AST_APP_OPTION(option, flagno)
Declares an application option that does not accept an argument.
int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
Parses a string containing application options and sets flags/arguments.
Definition: main/app.c:3066
Configuration File Parser.
int ast_parse_arg(const char *arg, enum ast_parse_flags flags, void *p_result,...)
The argument parsing routine.
Definition: main/config.c:3834
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define LOG_WARNING
Asterisk locking-related definitions:
static char * levels[NUMLOGLEVELS]
Logging channels used in the Asterisk logging system.
Definition: logger.c:214
Asterisk module definitions.
@ AST_MODFLAG_DEFAULT
Definition: module.h:329
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:557
@ AST_MODULE_SUPPORT_CORE
Definition: module.h:121
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:640
Network socket handling.
Core PBX routines and definitions.
static int reload(void)
#define NULL
Definition: resample.c:96
Say numbers and dates (maybe words one day too)
int ast_say_number(struct ast_channel *chan, int num, const char *ints, const char *lang, const char *options)
says a number
Definition: channel.c:8257
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
Definition: stringfields.h:341
#define AST_STRING_FIELD(name)
Declare a string field.
Definition: stringfields.h:303
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
String manipulation functions.
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition: utils.c:2199
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
@ AST_STRSEP_TRIM
Definition: strings.h:256
@ AST_STRSEP_STRIP
Definition: strings.h:255
static force_inline int attribute_pure ast_str_case_hash(const char *str)
Compute a hash value on a case-insensitive string.
Definition: strings.h:1303
char * ast_strsep(char **s, const char sep, uint32_t flags)
Act like strsep but ignore separators inside quotes.
Definition: utils.c:1835
The representation of a single configuration file to be processed.
const char * filename
Type information about a category-level configurable object.
aco_type_item_find item_find
enum aco_type_t type
aco_type_item_alloc item_alloc
size_t item_offset
Generic container type.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
Main Channel structure associated with a channel.
descriptor for a cli entry.
Definition: cli.h:171
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
Structure used to handle boolean flags.
Definition: utils.h:199
unsigned int flags
Definition: utils.h:200
Structure for variables, used for configurations and for channel variables.
A container that holds all config-related information.
Definition: app_skel.c:209
struct skel_global_config * global
Definition: app_skel.c:210
struct ao2_container * levels
Definition: app_skel.c:211
Information about a currently running set of games.
Definition: app_skel.c:193
struct skel_level * level_info
Definition: app_skel.c:197
uint32_t games_left
Definition: app_skel.c:195
uint32_t cheat
Definition: app_skel.c:196
uint32_t total_games
Definition: app_skel.c:194
A structure to hold global configuration-related options.
Definition: app_skel.c:153
const ast_string_field right
Definition: app_skel.c:161
uint32_t num_games
Definition: app_skel.c:162
const ast_string_field lose
Definition: app_skel.c:161
const ast_string_field low
Definition: app_skel.c:161
const ast_string_field wrong
Definition: app_skel.c:161
unsigned char cheat
Definition: app_skel.c:163
const ast_string_field prompt
Definition: app_skel.c:161
const ast_string_field high
Definition: app_skel.c:161
A structure to maintain level state across reloads.
Definition: app_skel.c:167
uint32_t wins
Definition: app_skel.c:168
double avg_guesses
Definition: app_skel.c:170
uint32_t losses
Definition: app_skel.c:169
Object to hold level config information.
Definition: app_skel.c:177
uint32_t max_guesses
Definition: app_skel.c:182
struct skel_level_state * state
Definition: app_skel.c:183
const ast_string_field name
Definition: app_skel.c:180
uint32_t max_num
Definition: app_skel.c:181
static struct aco_type global
Definition: test_config.c:1445
const char * args
static struct test_options options
static struct test_val a
int error(const char *format,...)
Definition: utils/frame.c:999
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941
long int ast_random(void)
Definition: utils.c:2312
#define ARRAY_LEN(a)
Definition: utils.h:666