Sat Apr 26 2014 22:01:49

Asterisk developer's documentation


app_page.c File Reference

page() - Paging application More...

#include "asterisk.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/file.h"
#include "asterisk/app.h"
#include "asterisk/chanvars.h"
#include "asterisk/utils.h"
#include "asterisk/devicestate.h"
#include "asterisk/dial.h"
Include dependency graph for app_page.c:

Go to the source code of this file.

Data Structures

struct  page_options

Enumerations

enum  { OPT_ARG_ANNOUNCE = 0, OPT_ARG_ARRAY_SIZE = 1 }
enum  page_opt_flags {
  PAGE_DUPLEX = (1 << 0), PAGE_QUIET = (1 << 1), PAGE_RECORD = (1 << 2), PAGE_SKIP = (1 << 3),
  PAGE_IGNORE_FORWARDS = (1 << 4), PAGE_ANNOUNCE = (1 << 5), PAGE_NOCALLERANNOUNCE = (1 << 6)
}

Functions

static void __reg_module (void)
static void __unreg_module (void)
static int load_module (void)
static int page_exec (struct ast_channel *chan, const char *data)
static void page_state_callback (struct ast_dial *dial)
static void setup_profile_bridge (struct ast_channel *chan, struct page_options *options)
static void setup_profile_caller (struct ast_channel *chan, struct page_options *options)
static void setup_profile_paged (struct ast_channel *chan, struct page_options *options)
static int unload_module (void)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Page Multiple Phones" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, }
static const char *const app_page = "Page"
static struct ast_module_infoast_module_info = &__mod_info
static struct ast_app_option page_opts [128] = { [ 'd' ] = { .flag = PAGE_DUPLEX }, [ 'q' ] = { .flag = PAGE_QUIET }, [ 'r' ] = { .flag = PAGE_RECORD }, [ 's' ] = { .flag = PAGE_SKIP }, [ 'i' ] = { .flag = PAGE_IGNORE_FORWARDS }, [ 'A' ] = { .flag = PAGE_ANNOUNCE , .arg_index = OPT_ARG_ANNOUNCE + 1 }, [ 'n' ] = { .flag = PAGE_NOCALLERANNOUNCE },}

Detailed Description

page() - Paging application

Author:
Mark Spencer <markster@digium.com>

Definition in file app_page.c.


Enumeration Type Documentation

anonymous enum
Enumerator:
OPT_ARG_ANNOUNCE 
OPT_ARG_ARRAY_SIZE 

Definition at line 123 of file app_page.c.

Enumerator:
PAGE_DUPLEX 
PAGE_QUIET 
PAGE_RECORD 
PAGE_SKIP 
PAGE_IGNORE_FORWARDS 
PAGE_ANNOUNCE 
PAGE_NOCALLERANNOUNCE 

Definition at line 113 of file app_page.c.

                    {
   PAGE_DUPLEX = (1 << 0),
   PAGE_QUIET = (1 << 1),
   PAGE_RECORD = (1 << 2),
   PAGE_SKIP = (1 << 3),
   PAGE_IGNORE_FORWARDS = (1 << 4),
   PAGE_ANNOUNCE = (1 << 5),
   PAGE_NOCALLERANNOUNCE = (1 << 6),
};

Function Documentation

static void __reg_module ( void  ) [static]

Definition at line 391 of file app_page.c.

static void __unreg_module ( void  ) [static]

Definition at line 391 of file app_page.c.

static int load_module ( void  ) [static]

Definition at line 386 of file app_page.c.

References ast_register_application_xml, and page_exec().

static int page_exec ( struct ast_channel chan,
const char *  data 
) [static]

Definition at line 223 of file app_page.c.

References app, args, AST_APP_ARG, ast_app_parse_options(), ast_calloc, ast_channel_language(), AST_CHANNEL_NAME, ast_channel_name(), ast_copy_string(), AST_DECLARE_APP_ARGS, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNKNOWN, ast_devstate2str(), ast_dial_append(), ast_dial_create(), ast_dial_destroy(), ast_dial_hangup(), ast_dial_join(), AST_DIAL_OPTION_ANSWER_EXEC, AST_DIAL_OPTION_DISABLE_CALL_FORWARDING, ast_dial_option_global_enable(), ast_dial_run(), ast_dial_set_global_timeout(), ast_dial_set_state_callback(), ast_dial_set_user_data(), ast_free, ast_log(), ast_random(), AST_STANDARD_APP_ARGS, ast_streamfile(), ast_strlen_zero(), ast_test_flag, ast_waitstream(), page_options::flags, LOG_ERROR, LOG_WARNING, page_options::opts, PAGE_IGNORE_FORWARDS, page_opts, PAGE_QUIET, PAGE_SKIP, page_state_callback(), parse(), pbx_exec(), pbx_findapp(), setup_profile_bridge(), setup_profile_caller(), and ast_dial::timeout.

Referenced by load_module().

{
   char *tech, *resource, *tmp;
   char confbridgeopts[128], originator[AST_CHANNEL_NAME];
   struct page_options options = { { 0, }, { 0, } };
   unsigned int confid = ast_random();
   struct ast_app *app;
   int res = 0, pos = 0, i = 0;
   struct ast_dial **dial_list;
   unsigned int num_dials;
   int timeout = 0;
   char *parse;

   AST_DECLARE_APP_ARGS(args,
      AST_APP_ARG(devices);
      AST_APP_ARG(options);
      AST_APP_ARG(timeout);
   );

   if (ast_strlen_zero(data)) {
      ast_log(LOG_WARNING, "This application requires at least one argument (destination(s) to page)\n");
      return -1;
   }

   if (!(app = pbx_findapp("ConfBridge"))) {
      ast_log(LOG_WARNING, "There is no ConfBridge application available!\n");
      return -1;
   };

   parse = ast_strdupa(data);

   AST_STANDARD_APP_ARGS(args, parse);

   ast_copy_string(originator, ast_channel_name(chan), sizeof(originator));
   if ((tmp = strchr(originator, '-'))) {
      *tmp = '\0';
   }

   if (!ast_strlen_zero(args.options)) {
      ast_app_parse_options(page_opts, &options.flags, options.opts, args.options);
   }

   if (!ast_strlen_zero(args.timeout)) {
      timeout = atoi(args.timeout);
   }

   snprintf(confbridgeopts, sizeof(confbridgeopts), "ConfBridge,%u", confid);

   /* Count number of extensions in list by number of ampersands + 1 */
   num_dials = 1;
   tmp = args.devices;
   while (*tmp) {
      if (*tmp == '&') {
         num_dials++;
      }
      tmp++;
   }

   if (!(dial_list = ast_calloc(num_dials, sizeof(struct ast_dial *)))) {
      ast_log(LOG_ERROR, "Can't allocate %ld bytes for dial list\n", (long)(sizeof(struct ast_dial *) * num_dials));
      return -1;
   }

   /* Go through parsing/calling each device */
   while ((tech = strsep(&args.devices, "&"))) {
      int state = 0;
      struct ast_dial *dial = NULL;

      /* don't call the originating device */
      if (!strcasecmp(tech, originator))
         continue;

      /* If no resource is available, continue on */
      if (!(resource = strchr(tech, '/'))) {
         ast_log(LOG_WARNING, "Incomplete destination '%s' supplied.\n", tech);
         continue;
      }

      /* Ensure device is not in use if skip option is enabled */
      if (ast_test_flag(&options.flags, PAGE_SKIP)) {
         state = ast_device_state(tech);
         if (state == AST_DEVICE_UNKNOWN) {
            ast_log(LOG_WARNING, "Destination '%s' has device state '%s'. Paging anyway.\n", tech, ast_devstate2str(state));
         } else if (state != AST_DEVICE_NOT_INUSE) {
            ast_log(LOG_WARNING, "Destination '%s' has device state '%s'.\n", tech, ast_devstate2str(state));
            continue;
         }
      }

      *resource++ = '\0';

      /* Create a dialing structure */
      if (!(dial = ast_dial_create())) {
         ast_log(LOG_WARNING, "Failed to create dialing structure.\n");
         continue;
      }

      /* Append technology and resource */
      if (ast_dial_append(dial, tech, resource) == -1) {
         ast_log(LOG_ERROR, "Failed to add %s to outbound dial\n", tech);
         ast_dial_destroy(dial);
         continue;
      }

      /* Set ANSWER_EXEC as global option */
      ast_dial_option_global_enable(dial, AST_DIAL_OPTION_ANSWER_EXEC, confbridgeopts);

      if (timeout) {
         ast_dial_set_global_timeout(dial, timeout * 1000);
      }

      if (ast_test_flag(&options.flags, PAGE_IGNORE_FORWARDS)) {
         ast_dial_option_global_enable(dial, AST_DIAL_OPTION_DISABLE_CALL_FORWARDING, NULL);
      }

      ast_dial_set_state_callback(dial, &page_state_callback);
      ast_dial_set_user_data(dial, &options);

      /* Run this dial in async mode */
      ast_dial_run(dial, chan, 1);

      /* Put in our dialing array */
      dial_list[pos++] = dial;
   }

   if (!ast_test_flag(&options.flags, PAGE_QUIET)) {
      res = ast_streamfile(chan, "beep", ast_channel_language(chan));
      if (!res)
         res = ast_waitstream(chan, "");
   }

   if (!res) {
      setup_profile_bridge(chan, &options);
      setup_profile_caller(chan, &options);

      snprintf(confbridgeopts, sizeof(confbridgeopts), "%u", confid);
      pbx_exec(chan, app, confbridgeopts);
   }

   /* Go through each dial attempt cancelling, joining, and destroying */
   for (i = 0; i < pos; i++) {
      struct ast_dial *dial = dial_list[i];

      /* We have to wait for the async thread to exit as it's possible ConfBridge won't throw them out immediately */
      ast_dial_join(dial);

      /* Hangup all channels */
      ast_dial_hangup(dial);

      /* Destroy dialing structure */
      ast_dial_destroy(dial);
   }

   ast_free(dial_list);

   return -1;
}
static void page_state_callback ( struct ast_dial dial) [static]

Definition at line 208 of file app_page.c.

References ast_dial_answered(), ast_dial_get_user_data(), AST_DIAL_RESULT_ANSWERED, ast_dial_state(), setup_profile_bridge(), and setup_profile_paged().

Referenced by page_exec().

{
   struct ast_channel *chan;
   struct page_options *options;

   if (ast_dial_state(dial) != AST_DIAL_RESULT_ANSWERED ||
       !(chan = ast_dial_answered(dial)) ||
       !(options = ast_dial_get_user_data(dial))) {
      return;
   }

   setup_profile_bridge(chan, options);
   setup_profile_paged(chan, options);
}
static void setup_profile_bridge ( struct ast_channel chan,
struct page_options options 
) [static]

Definition at line 153 of file app_page.c.

References ast_func_write(), ast_test_flag, page_options::flags, and PAGE_RECORD.

Referenced by page_exec(), and page_state_callback().

{
   /* Use default_bridge as a starting point */
   ast_func_write(chan, "CONFBRIDGE(bridge,template)", "");
   if (ast_test_flag(&options->flags, PAGE_RECORD)) {
      ast_func_write(chan, "CONFBRIDGE(bridge,record_conference)", "yes");
   }
}
static void setup_profile_caller ( struct ast_channel chan,
struct page_options options 
) [static]

Definition at line 195 of file app_page.c.

References ast_func_write(), ast_strlen_zero(), ast_test_flag, page_options::flags, OPT_ARG_ANNOUNCE, page_options::opts, PAGE_ANNOUNCE, and PAGE_NOCALLERANNOUNCE.

Referenced by page_exec().

{
   /* Use default_user as a starting point if not already setup. */
   ast_func_write(chan, "CONFBRIDGE(user,template)", "");
   ast_func_write(chan, "CONFBRIDGE(user,quiet)", "yes");
   ast_func_write(chan, "CONFBRIDGE(user,marked)", "yes");
   if (!ast_test_flag(&options->flags, PAGE_NOCALLERANNOUNCE)
      && ast_test_flag(&options->flags, PAGE_ANNOUNCE)
      && !ast_strlen_zero(options->opts[OPT_ARG_ANNOUNCE])) {
      ast_func_write(chan, "CONFBRIDGE(user,announcement)", options->opts[OPT_ARG_ANNOUNCE]);
   }
}
static void setup_profile_paged ( struct ast_channel chan,
struct page_options options 
) [static]

Definition at line 171 of file app_page.c.

References ast_func_write(), ast_strlen_zero(), ast_test_flag, page_options::flags, OPT_ARG_ANNOUNCE, page_options::opts, PAGE_ANNOUNCE, and PAGE_DUPLEX.

Referenced by page_state_callback().

{
   /* Use default_user as a starting point */
   ast_func_write(chan, "CONFBRIDGE(user,template)", "");
   ast_func_write(chan, "CONFBRIDGE(user,quiet)", "yes");
   ast_func_write(chan, "CONFBRIDGE(user,end_marked)", "yes");
   if (!ast_test_flag(&options->flags, PAGE_DUPLEX)) {
      ast_func_write(chan, "CONFBRIDGE(user,startmuted)", "yes");
   }
   if (ast_test_flag(&options->flags, PAGE_ANNOUNCE)
      && !ast_strlen_zero(options->opts[OPT_ARG_ANNOUNCE])) {
      ast_func_write(chan, "CONFBRIDGE(user,announcement)", options->opts[OPT_ARG_ANNOUNCE]);
   }
}
static int unload_module ( void  ) [static]

Definition at line 381 of file app_page.c.

References ast_unregister_application().


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Page Multiple Phones" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, } [static]

Definition at line 391 of file app_page.c.

const char* const app_page = "Page" [static]

Definition at line 111 of file app_page.c.

Definition at line 391 of file app_page.c.

struct ast_app_option page_opts[128] = { [ 'd' ] = { .flag = PAGE_DUPLEX }, [ 'q' ] = { .flag = PAGE_QUIET }, [ 'r' ] = { .flag = PAGE_RECORD }, [ 's' ] = { .flag = PAGE_SKIP }, [ 'i' ] = { .flag = PAGE_IGNORE_FORWARDS }, [ 'A' ] = { .flag = PAGE_ANNOUNCE , .arg_index = OPT_ARG_ANNOUNCE + 1 }, [ 'n' ] = { .flag = PAGE_NOCALLERANNOUNCE },} [static]

Definition at line 136 of file app_page.c.

Referenced by page_exec().