Asterisk - The Open Source Telephony Project  18.5.0
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://wiki.asterisk.org/wiki/display/AST/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 
134 static 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  */
177 struct skel_level {
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. */
209 struct skel_config {
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  */
220 static 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  */
226 static 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  */
238 static 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 */
241 static 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 
249 struct aco_type *global_options[] = ACO_TYPES(&global_option);
250 
251 /*! \brief An aco_type structure to link the "sounds" category to the skel_global_config type */
252 static 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 
260 struct aco_type *sound_options[] = ACO_TYPES(&sound_option);
261 
262 static 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 */
269 static 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 
279 struct aco_type *level_options[] = ACO_TYPES(&level_option);
280 
282  .filename = "app_skel.conf",
283  .types = ACO_TYPES(&global_option, &sound_option, &level_option),
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 */
290 static 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 
297 static void skel_global_config_destructor(void *obj)
298 {
299  struct skel_global_config *global = obj;
301 }
302 
303 static void skel_game_destructor(void *obj)
304 {
305  struct skel_current_game *game = obj;
306  ao2_cleanup(game->level_info);
307 }
308 
309 static void skel_state_destructor(void *obj)
310 {
311  return;
312 }
313 
314 static 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 
325 static void skel_level_destructor(void *obj)
326 {
327  struct skel_level *level = obj;
329  ao2_cleanup(level->state);
330 }
331 
332 static 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 
339 static 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  */
356 static 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 
369 static 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 = strsep(&rest, "&")) && !ast_stream_and_wait(chan, prompt, "")) {
375  ast_stopstream(chan);
376  }
377 }
378 
379 static int app_exec(struct ast_channel *chan, const char *data)
380 {
381  int win = 0;
382  uint32_t guesses;
384  RAII_VAR(struct skel_level *, level, NULL, ao2_cleanup);
385  RAII_VAR(struct skel_current_game *, game, NULL, ao2_cleanup);
386  char *parse, *opts[OPTION_ARG_ARRAY_SIZE];
387  struct ast_flags flags;
389  AST_APP_ARG(level);
391  );
392 
393  if (!cfg) {
394  ast_log(LOG_ERROR, "Couldn't access configuratino data!\n");
395  return -1;
396  }
397 
398  if (ast_strlen_zero(data)) {
399  ast_log(LOG_WARNING, "%s requires an argument (level[,options])\n", app);
400  return -1;
401  }
402 
403  /* We need to make a copy of the input string if we are going to modify it! */
404  parse = ast_strdupa(data);
405 
406  AST_STANDARD_APP_ARGS(args, parse);
407 
408  if (args.argc == 2) {
409  ast_app_parse_options(app_opts, &flags, opts, args.options);
410  }
411 
412  if (ast_strlen_zero(args.level)) {
413  ast_log(LOG_ERROR, "%s requires a level argument\n", app);
414  return -1;
415  }
416 
417  if (!(level = ao2_find(cfg->levels, args.level, OBJ_KEY))) {
418  ast_log(LOG_ERROR, "Unknown level: %s\n", args.level);
419  return -1;
420  }
421 
422  if (!(game = skel_game_alloc(level))) {
423  return -1;
424  }
425 
426  ao2_link(games, game);
427 
428  /* Use app-specified values, or the options specified in [general] if they aren't passed to the app */
429  if (!ast_test_flag(&flags, OPTION_NUMGAMES) ||
431  ast_parse_arg(opts[OPTION_ARG_NUMGAMES], PARSE_UINT32, &game->total_games)) {
432  game->total_games = cfg->global->num_games;
433  }
434  game->games_left = game->total_games;
435  game->cheat = ast_test_flag(&flags, OPTION_CHEAT) || cfg->global->cheat;
436 
437  for (game->games_left = game->total_games; game->games_left; game->games_left--) {
438  uint32_t num = ast_random() % level->max_num; /* random number between 0 and level->max_num */
439 
440  ast_debug(1, "They should totally should guess %u\n", num);
441 
442  /* Play the prompt */
443  play_files_helper(chan, cfg->global->prompt);
444  ast_say_number(chan, level->max_num, "", ast_channel_language(chan), "");
445 
446  for (guesses = 0; guesses < level->max_guesses; guesses++) {
447  size_t buflen = log10(level->max_num) + 1;
448  char buf[buflen];
449  int guess;
450  buf[buflen] = '\0';
451 
452  /* Read the number pressed */
453  ast_readstring(chan, buf, buflen - 1, 2000, 10000, "");
454  if (ast_parse_arg(buf, PARSE_INT32 | PARSE_IN_RANGE, &guess, 0, level->max_num)) {
455  if (guesses < level->max_guesses - 1) {
456  play_files_helper(chan, cfg->global->wrong);
457  }
458  continue;
459  }
460 
461  /* Inform whether the guess was right, low, or high */
462  if (guess == num && !game->cheat) {
463  /* win */
464  win = 1;
465  play_files_helper(chan, cfg->global->right);
466  guesses++;
467  break;
468  } else if (guess < num) {
469  play_files_helper(chan, cfg->global->low);
470  } else {
471  play_files_helper(chan, cfg->global->high);
472  }
473 
474  if (guesses < level->max_guesses - 1) {
475  play_files_helper(chan, cfg->global->wrong);
476  }
477  }
478 
479  /* Process game stats */
480  ao2_lock(level->state);
481  if (win) {
482  ++level->state->wins;
483  level->state->avg_guesses = ((level->state->wins - 1) * level->state->avg_guesses + guesses) / level->state->wins;
484  } else {
485  /* lose */
486  level->state->losses++;
487  play_files_helper(chan, cfg->global->lose);
488  }
489  ao2_unlock(level->state);
490  }
491 
492  ao2_unlink(games, game);
493 
494  return 0;
495 }
496 
497 static struct skel_level *skel_state_alloc(const char *name)
498 {
499  struct skel_level *level;
500 
501  if (!(level = ao2_alloc(sizeof(*level), skel_state_destructor))) {
502  return NULL;
503  }
504 
505  return level;
506 }
507 
508 static void *skel_level_find(struct ao2_container *tmp_container, const char *category)
509 {
510  return ao2_find(tmp_container, category, OBJ_KEY);
511 }
512 
513 /*! \brief Look up an existing state object, or create a new one
514  * \internal
515  * \note Since the reload code will create a new level from scratch, it
516  * is important for any state that must persist between reloads to be
517  * in a separate refcounted object. This function allows the level alloc
518  * function to get a ref to an existing state object if it exists,
519  * otherwise it will return a reference to a newly allocated state object.
520  */
521 static void *skel_find_or_create_state(const char *category)
522 {
524  RAII_VAR(struct skel_level *, level, NULL, ao2_cleanup);
525  if (!cfg || !cfg->levels || !(level = ao2_find(cfg->levels, category, OBJ_KEY))) {
526  return skel_state_alloc(category);
527  }
528  ao2_ref(level->state, +1);
529  return level->state;
530 }
531 
532 static void *skel_level_alloc(const char *cat)
533 {
534  struct skel_level *level;
535 
536  if (!(level = ao2_alloc(sizeof(*level), skel_level_destructor))) {
537  return NULL;
538  }
539 
540  if (ast_string_field_init(level, 128)) {
541  ao2_ref(level, -1);
542  return NULL;
543  }
544 
545  /* Since the level has state information that needs to persist between reloads,
546  * it is important to handle that here in the level's allocation function.
547  * If not separated out into its own object, the data would be destroyed on
548  * reload. */
549  if (!(level->state = skel_find_or_create_state(cat))) {
550  ao2_ref(level, -1);
551  return NULL;
552  }
553 
554  ast_string_field_set(level, name, cat);
555 
556  return level;
557 }
558 
559 static void skel_config_destructor(void *obj)
560 {
561  struct skel_config *cfg = obj;
562  ao2_cleanup(cfg->global);
563  ao2_cleanup(cfg->levels);
564 }
565 
566 static void *skel_config_alloc(void)
567 {
568  struct skel_config *cfg;
569 
570  if (!(cfg = ao2_alloc(sizeof(*cfg), skel_config_destructor))) {
571  return NULL;
572  }
573 
574  /* Allocate/initialize memory */
575  if (!(cfg->global = ao2_alloc(sizeof(*cfg->global), skel_global_config_destructor))) {
576  goto error;
577  }
578 
579  if (ast_string_field_init(cfg->global, 128)) {
580  goto error;
581  }
582 
585  if (!cfg->levels) {
586  goto error;
587  }
588 
589  return cfg;
590 error:
591  ao2_ref(cfg, -1);
592  return NULL;
593 }
594 
595 static char *handle_skel_show_config(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
596 {
597  RAII_VAR(struct skel_config *, cfg, NULL, ao2_cleanup);
598 
599  switch(cmd) {
600  case CLI_INIT:
601  e->command = "skel show config";
602  e->usage =
603  "Usage: skel show config\n"
604  " List app_skel global config\n";
605  return NULL;
606  case CLI_GENERATE:
607  return NULL;
608  }
609 
610  if (!(cfg = ao2_global_obj_ref(globals)) || !cfg->global) {
611  return NULL;
612  }
613 
614  ast_cli(a->fd, "games per call: %u\n", cfg->global->num_games);
615  ast_cli(a->fd, "computer cheats: %s\n", AST_CLI_YESNO(cfg->global->cheat));
616  ast_cli(a->fd, "\n");
617  ast_cli(a->fd, "Sounds\n");
618  ast_cli(a->fd, " prompt: %s\n", cfg->global->prompt);
619  ast_cli(a->fd, " wrong guess: %s\n", cfg->global->wrong);
620  ast_cli(a->fd, " right guess: %s\n", cfg->global->right);
621 
622  return CLI_SUCCESS;
623 }
624 
625 static char *handle_skel_show_games(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
626 {
627  struct ao2_iterator iter;
628  struct skel_current_game *game;
629 
630  switch(cmd) {
631  case CLI_INIT:
632  e->command = "skel show games";
633  e->usage =
634  "Usage: skel show games\n"
635  " List app_skel active games\n";
636  return NULL;
637  case CLI_GENERATE:
638  return NULL;
639  }
640 
641 #define SKEL_FORMAT "%-15.15s %-15.15s %-15.15s\n"
642 #define SKEL_FORMAT1 "%-15.15s %-15u %-15u\n"
643  ast_cli(a->fd, SKEL_FORMAT, "Level", "Total Games", "Games Left");
644  iter = ao2_iterator_init(games, 0);
645  while ((game = ao2_iterator_next(&iter))) {
646  ast_cli(a->fd, SKEL_FORMAT1, game->level_info->name, game->total_games, game->games_left);
647  ao2_ref(game, -1);
648  }
649  ao2_iterator_destroy(&iter);
650 #undef SKEL_FORMAT
651 #undef SKEL_FORMAT1
652  return CLI_SUCCESS;
653 }
654 
655 static char *handle_skel_show_levels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
656 {
657  RAII_VAR(struct skel_config *, cfg, NULL, ao2_cleanup);
658  struct ao2_iterator iter;
659  struct skel_level *level;
660 
661  switch(cmd) {
662  case CLI_INIT:
663  e->command = "skel show levels";
664  e->usage =
665  "Usage: skel show levels\n"
666  " List the app_skel levels\n";
667  return NULL;
668  case CLI_GENERATE:
669  return NULL;
670  }
671 
672  if (!(cfg = ao2_global_obj_ref(globals)) || !cfg->levels) {
673  return NULL;
674  }
675 
676 #define SKEL_FORMAT "%-15.15s %-11.11s %-12.12s %-8.8s %-8.8s %-12.12s\n"
677 #define SKEL_FORMAT1 "%-15.15s %-11u %-12u %-8u %-8u %-8f\n"
678  ast_cli(a->fd, SKEL_FORMAT, "Name", "Max number", "Max Guesses", "Wins", "Losses", "Avg Guesses");
679  iter = ao2_iterator_init(cfg->levels, 0);
680  while ((level = ao2_iterator_next(&iter))) {
681  ast_cli(a->fd, SKEL_FORMAT1, level->name, level->max_num, level->max_guesses, level->state->wins, level->state->losses, level->state->avg_guesses);
682  ao2_ref(level, -1);
683  }
684  ao2_iterator_destroy(&iter);
685 #undef SKEL_FORMAT
686 #undef SKEL_FORMAT1
687 
688  return CLI_SUCCESS;
689 }
690 
691 static struct ast_cli_entry skel_cli[] = {
692  AST_CLI_DEFINE(handle_skel_show_config, "Show app_skel global config options"),
693  AST_CLI_DEFINE(handle_skel_show_levels, "Show app_skel levels"),
694  AST_CLI_DEFINE(handle_skel_show_games, "Show app_skel active games"),
695 };
696 
697 static int reload_module(void)
698 {
699  if (aco_process_config(&cfg_info, 1) == ACO_PROCESS_ERROR) {
701  }
702 
703  return 0;
704 }
705 
706 static int unload_module(void)
707 {
708  ast_cli_unregister_multiple(skel_cli, ARRAY_LEN(skel_cli));
709  aco_info_destroy(&cfg_info);
711  ao2_cleanup(games);
713 }
714 
715 /*!
716  * \brief Load the module
717  *
718  * Module loading including tests for configuration or dependencies.
719  * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
720  * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
721  * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
722  * configuration file or other non-critical problem return
723  * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
724  */
725 static int load_module(void)
726 {
727  if (aco_info_init(&cfg_info)) {
728  goto error;
729  }
730 
732  if (!games) {
733  goto error;
734  }
735 
736  /* Global options */
737  aco_option_register(&cfg_info, "games", ACO_EXACT, global_options, "3", OPT_UINT_T, 0, FLDSET(struct skel_global_config, num_games));
738  aco_option_register_custom(&cfg_info, "cheat", ACO_EXACT, global_options, "no", custom_bitfield_handler, 0);
739 
740  /* Sound options */
741  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));
742  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));
743  aco_option_register(&cfg_info, "right_guess", ACO_EXACT, sound_options, "auth-thankyou", OPT_STRINGFIELD_T, 0, STRFLDSET(struct skel_global_config, right));
744  aco_option_register(&cfg_info, "too_high", ACO_EXACT, sound_options, "high", OPT_STRINGFIELD_T, 0, STRFLDSET(struct skel_global_config, high));
745  aco_option_register(&cfg_info, "too_low", ACO_EXACT, sound_options, "low", OPT_STRINGFIELD_T, 0, STRFLDSET(struct skel_global_config, low));
746  aco_option_register(&cfg_info, "lose", ACO_EXACT, sound_options, "vm-goodbye", OPT_STRINGFIELD_T, 0, STRFLDSET(struct skel_global_config, lose));
747 
748  /* Level options */
749  aco_option_register(&cfg_info, "max_number", ACO_EXACT, level_options, NULL, OPT_UINT_T, 0, FLDSET(struct skel_level, max_num));
750  aco_option_register(&cfg_info, "max_guesses", ACO_EXACT, level_options, NULL, OPT_UINT_T, 0, FLDSET(struct skel_level, max_guesses));
751 
752  if (aco_process_config(&cfg_info, 0) == ACO_PROCESS_ERROR) {
753  goto error;
754  }
755 
756  ast_cli_register_multiple(skel_cli, ARRAY_LEN(skel_cli));
758  goto error;
759  }
761 
762 error:
763  aco_info_destroy(&cfg_info);
764  ao2_cleanup(games);
766 }
767 
768 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Skeleton (sample) Application",
769  .support_level = AST_MODULE_SUPPORT_CORE,
770  .load = load_module,
771  .unload = unload_module,
773 );
uint32_t num_games
Definition: app_skel.c:162
aco_type_item_find item_find
uint32_t total_games
Definition: app_skel.c:194
Main Channel structure associated with a channel.
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
Asterisk locking-related definitions:
const ast_string_field lose
Definition: app_skel.c:161
Asterisk main include file. File version handling, generic pbx functions.
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
static void skel_level_destructor(void *obj)
Definition: app_skel.c:325
unsigned char cheat
Definition: app_skel.c:163
static void skel_config_destructor(void *obj)
Definition: app_skel.c:559
const ast_string_field wrong
Definition: app_skel.c:161
static struct aco_type global
Definition: test_config.c:1445
String manipulation functions.
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
#define aco_option_register_custom(info, name, matchtype, types, default_val, handler, flags)
Register a config option.
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
static struct skel_current_game * skel_game_alloc(struct skel_level *level)
Definition: app_skel.c:314
#define ast_test_flag(p, flag)
Definition: utils.h:63
const ast_string_field right
Definition: app_skel.c:161
#define OBJ_KEY
Definition: astobj2.h:1155
uint32_t max_num
Definition: app_skel.c:181
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
uint32_t losses
Definition: app_skel.c:169
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
descriptor for a cli entry.
Definition: cli.h:171
#define LOG_WARNING
Definition: logger.h:274
static struct ast_cli_entry skel_cli[]
Definition: app_skel.c:691
#define aco_option_register(info, name, matchtype, types, default_val, opt_type, flags,...)
Register a config option.
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Definition: astobj2.h:1335
Structure for variables, used for configurations and for channel variables.
static int skel_level_hash(const void *obj, const int flags)
Definition: app_skel.c:332
#define var
Definition: ast_expr2f.c:614
struct ao2_container * levels
Definition: app_skel.c:211
Definition: cli.h:152
static char * levels[NUMLOGLEVELS]
Logging channels used in the Asterisk logging system.
Definition: logger.c:206
static void * skel_level_alloc(const char *cat)
Allocate a skel_level based on a category in a configuration file.
Definition: app_skel.c:532
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
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 ao2_global_obj_ref(holder)
Definition: astobj2.h:925
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
Definition: stringfields.h:337
const ast_string_field high
Definition: app_skel.c:161
#define ao2_unlock(a)
Definition: astobj2.h:730
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:2315
static char * handle_skel_show_games(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_skel.c:625
static AO2_GLOBAL_OBJ_STATIC(globals)
A global object container that will contain the skel_config that gets swapped out on reloads...
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
const char * args
const ast_string_field prompt
Definition: app_skel.c:161
#define NULL
Definition: resample.c:96
The representation of a single configuration file to be processed.
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
enum aco_type_t type
struct skel_level * level_info
Definition: app_skel.c:197
#define ACO_TYPES(...)
A helper macro to ensure that aco_info types always have a sentinel.
uint32_t max_guesses
Definition: app_skel.c:182
static struct ao2_container * games
The container of active games.
Definition: app_skel.c:290
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define AST_APP_OPTIONS(holder, options...)
Declares an array of options for an application.
struct aco_file app_skel_conf
Definition: app_skel.c:281
Configuration File Parser.
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
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
#define FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
int aco_info_init(struct aco_info *info)
Initialize an aco_info structure.
General Asterisk PBX channel definitions.
#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:911
Type for default option handler for unsigned integers.
static void play_files_helper(struct ast_channel *chan, const char *prompts)
Definition: app_skel.c:369
const int fd
Definition: cli.h:159
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:353
Access Control of various sorts.
#define AST_STRING_FIELD(name)
Declare a string field.
Definition: stringfields.h:299
double avg_guesses
Definition: app_skel.c:170
#define ao2_ref(o, delta)
Definition: astobj2.h:464
static struct skel_level * skel_state_alloc(const char *name)
Definition: app_skel.c:497
long int ast_random(void)
Definition: main/utils.c:2064
const ast_string_field low
Definition: app_skel.c:161
#define ao2_lock(a)
Definition: astobj2.h:718
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
static const char * level_categories[]
Definition: app_skel.c:262
#define LEVEL_BUCKETS
Definition: app_skel.c:201
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
uint32_t games_left
Definition: app_skel.c:195
aco_type_item_alloc item_alloc
static struct console_pvt globals
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:2906
Network socket handling.
Core PBX routines and definitions.
struct skel_level_state * state
Definition: app_skel.c:183
struct aco_type * global_options[]
Definition: app_skel.c:249
Their was an error and no changes were applied.
static int app_exec(struct ast_channel *chan, const char *data)
Definition: app_skel.c:379
Configuration option-handling.
static const struct ast_app_option app_opts[128]
Definition: app_skel.c:150
static char * handle_skel_show_levels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_skel.c:655
#define LOG_ERROR
Definition: logger.h:285
Object to hold level config information.
Definition: app_skel.c:177
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Definition: astobj2.h:1310
#define SKEL_FORMAT1
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: main/utils.c:1951
#define AST_APP_OPTION_ARG(option, flagno, argno)
Declares an application option that accepts an argument.
#define ao2_unlink(container, obj)
Definition: astobj2.h:1598
void aco_info_destroy(struct aco_info *info)
Destroy an initialized aco_info struct.
#define ao2_global_obj_release(holder)
Definition: astobj2.h:865
static char * handle_skel_show_config(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_skel.c:595
static void skel_state_destructor(void *obj)
Definition: app_skel.c:309
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1872
static const char name[]
Definition: cdr_mysql.c:74
char * command
Definition: cli.h:186
static int reload(void)
Definition: cdr_mysql.c:741
struct aco_type * sound_options[]
Definition: app_skel.c:260
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:1814
struct skel_global_config * global
Definition: app_skel.c:210
A container that holds all config-related information.
Definition: app_skel.c:209
int ast_parse_arg(const char *arg, enum ast_parse_flags flags, void *result,...)
The argument parsing routine.
Definition: main/config.c:3657
#define STRFLDSET(type,...)
Convert a struct and a list of stringfield fields to an argument list of field offsets.
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
#define SKEL_FORMAT
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
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 char * app
Definition: app_skel.c:134
Structure used to handle boolean flags.
Definition: utils.h:199
static int unload_module(void)
Definition: app_skel.c:706
uint32_t wins
Definition: app_skel.c:168
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS|AST_MODFLAG_LOAD_ORDER, "HTTP Phone Provisioning",.support_level=AST_MODULE_SUPPORT_EXTENDED,.load=load_module,.unload=unload_module,.reload=reload,.load_pri=AST_MODPRI_CHANNEL_DEPEND,.requires="http",)
const char * usage
Definition: cli.h:177
#define CLI_SUCCESS
Definition: cli.h:44
#define ACO_FILES(...)
char * strsep(char **str, const char *delims)
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:521
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
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:8337
Standard Command Line Interface.
static int skel_level_cmp(void *obj, void *arg, int flags)
Definition: app_skel.c:339
Type information about a category-level configurable object.
A structure to hold global configuration-related options.
Definition: app_skel.c:153
size_t item_offset
option_flags
Definition: app_skel.c:136
const char * filename
const ast_string_field name
Definition: app_skel.c:180
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:508
const char * ast_channel_language(const struct ast_channel *chan)
A structure to maintain level state across reloads.
Definition: app_skel.c:167
Type for default option handler for stringfields.
static int load_module(void)
Load the module.
Definition: app_skel.c:725
static void skel_game_destructor(void *obj)
Definition: app_skel.c:303
int error(const char *format,...)
Definition: utils/frame.c:999
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.
option_args
Definition: app_skel.c:141
Generic container type.
#define AST_CLI_YESNO(x)
Return Yes or No depending on the argument.
Definition: cli.h:71
static struct test_options options
int ast_readstring(struct ast_channel *c, char *s, int len, int timeout, int rtimeout, char *enders)
Reads multiple digits.
Definition: channel.c:6655
#define AST_APP_OPTION(option, flagno)
Declares an application option that does not accept an argument.
struct aco_type * level_options[]
Definition: app_skel.c:279
Say numbers and dates (maybe words one day too)
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
Asterisk module definitions.
static int reload_module(void)
Definition: app_skel.c:697
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:368
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
uint32_t cheat
Definition: app_skel.c:196
int ast_stopstream(struct ast_channel *c)
Stops a stream.
Definition: file.c:187
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:626
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:1250
#define AST_APP_ARG(name)
Define an application argument.
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:514
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:566
static void skel_global_config_destructor(void *obj)
Definition: app_skel.c:297
static struct test_val a
Information about a currently running set of games.
Definition: app_skel.c:193
#define ao2_link(container, obj)
Definition: astobj2.h:1549