Wed Jan 8 2020 09:49:40

Asterisk developer's documentation


app_page.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (c) 2004 - 2006 Digium, Inc. All rights reserved.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * This code is released under the GNU General Public License
9  * version 2.0. See LICENSE for more information.
10  *
11  * See http://www.asterisk.org for more information about
12  * the Asterisk project. Please do not directly contact
13  * any of the maintainers of this project for assistance;
14  * the project provides a web site, mailing lists and IRC
15  * channels for your use.
16  *
17  */
18 
19 /*! \file
20  *
21  * \brief page() - Paging application
22  *
23  * \author Mark Spencer <markster@digium.com>
24  *
25  * \ingroup applications
26  */
27 
28 /*** MODULEINFO
29  <depend>dahdi</depend>
30  <depend>app_meetme</depend>
31  <support_level>core</support_level>
32  ***/
33 
34 #include "asterisk.h"
35 
36 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 382513 $")
37 
38 #include "asterisk/channel.h"
39 #include "asterisk/pbx.h"
40 #include "asterisk/module.h"
41 #include "asterisk/file.h"
42 #include "asterisk/app.h"
43 #include "asterisk/chanvars.h"
44 #include "asterisk/utils.h"
45 #include "asterisk/devicestate.h"
46 #include "asterisk/dial.h"
47 
48 /*** DOCUMENTATION
49  <application name="Page" language="en_US">
50  <synopsis>
51  Page series of phones
52  </synopsis>
53  <syntax>
54  <parameter name="Technology/Resource" required="true" argsep="&amp;">
55  <argument name="Technology/Resource" required="true">
56  <para>Specification of the device(s) to dial. These must be in the format of
57  <literal>Technology/Resource</literal>, where <replaceable>Technology</replaceable>
58  represents a particular channel driver, and <replaceable>Resource</replaceable> represents a resource
59  available to that particular channel driver.</para>
60  </argument>
61  <argument name="Technology2/Resource2" multiple="true">
62  <para>Optional extra devices to dial inparallel</para>
63  <para>If you need more then one enter them as Technology2/Resource2&amp;
64  Technology3/Resourse3&amp;.....</para>
65  </argument>
66  </parameter>
67  <parameter name="options">
68  <optionlist>
69  <option name="d">
70  <para>Full duplex audio</para>
71  </option>
72  <option name="i">
73  <para>Ignore attempts to forward the call</para>
74  </option>
75  <option name="q">
76  <para>Quiet, do not play beep to caller</para>
77  </option>
78  <option name="r">
79  <para>Record the page into a file (meetme option <literal>r</literal>)</para>
80  </option>
81  <option name="s">
82  <para>Only dial a channel if its device state says that it is <literal>NOT_INUSE</literal></para>
83  </option>
84  <option name="A">
85  <argument name="x" required="true">
86  <para>The announcement to playback in all devices</para>
87  </argument>
88  <para>Play an announcement to all paged participants</para>
89  </option>
90  <option name="n">
91  <para>Do not play announcement to caller (implies <literal>A(x)</literal>)</para>
92  </option>
93  </optionlist>
94  </parameter>
95  <parameter name="timeout">
96  <para>Specify the length of time that the system will attempt to connect a call.
97  After this duration, any intercom calls that have not been answered will be hung up by the
98  system.</para>
99  </parameter>
100  </syntax>
101  <description>
102  <para>Places outbound calls to the given <replaceable>technology</replaceable>/<replaceable>resource</replaceable>
103  and dumps them into a conference bridge as muted participants. The original
104  caller is dumped into the conference as a speaker and the room is
105  destroyed when the original callers leaves.</para>
106  </description>
107  <see-also>
108  <ref type="application">MeetMe</ref>
109  </see-also>
110  </application>
111  ***/
112 static const char * const app_page= "Page";
113 
115  PAGE_DUPLEX = (1 << 0),
116  PAGE_QUIET = (1 << 1),
117  PAGE_RECORD = (1 << 2),
118  PAGE_SKIP = (1 << 3),
120  PAGE_ANNOUNCE = (1 << 5),
122 };
123 
124 enum {
127 };
128 
137 });
138 
139 
140 static int page_exec(struct ast_channel *chan, const char *data)
141 {
142  char *tech, *resource, *tmp;
143  char meetmeopts[128], originator[AST_CHANNEL_NAME], *opts[OPT_ARG_ARRAY_SIZE];
144  struct ast_flags flags = { 0 };
145  unsigned int confid = ast_random();
146  struct ast_app *app;
147  int res = 0, pos = 0, i = 0;
148  struct ast_dial **dial_list;
149  unsigned int num_dials;
150  int timeout = 0;
151  char *parse;
152 
156  AST_APP_ARG(timeout);
157  );
158 
159  if (ast_strlen_zero(data)) {
160  ast_log(LOG_WARNING, "This application requires at least one argument (destination(s) to page)\n");
161  return -1;
162  }
163 
164  if (!(app = pbx_findapp("MeetMe"))) {
165  ast_log(LOG_WARNING, "There is no MeetMe application available!\n");
166  return -1;
167  };
168 
169  parse = ast_strdupa(data);
170 
171  AST_STANDARD_APP_ARGS(args, parse);
172 
173  ast_copy_string(originator, chan->name, sizeof(originator));
174  if ((tmp = strchr(originator, '-'))) {
175  *tmp = '\0';
176  }
177 
178  if (!ast_strlen_zero(args.options)) {
179  ast_app_parse_options(page_opts, &flags, opts, args.options);
180  } else {
181  /* opts must be initialized if there wasn't an options string. */
182  for (i = 0; i < OPT_ARG_ARRAY_SIZE; i++) {
183  opts[i] = NULL;
184  }
185  }
186 
187  if (!ast_strlen_zero(args.timeout)) {
188  timeout = atoi(args.timeout);
189  }
190 
192  snprintf(meetmeopts, sizeof(meetmeopts), "MeetMe,%ud,%s%sqxdw(5)G(%s)", confid, (ast_test_flag(&flags, PAGE_DUPLEX) ? "" : "m"),
193  (ast_test_flag(&flags, PAGE_RECORD) ? "r" : ""), opts[OPT_ARG_ANNOUNCE] );
194  } else {
195  snprintf(meetmeopts, sizeof(meetmeopts), "MeetMe,%ud,%s%sqxdw(5)", confid, (ast_test_flag(&flags, PAGE_DUPLEX) ? "" : "m"),
196  (ast_test_flag(&flags, PAGE_RECORD) ? "r" : "") );
197  }
198 
199  /* Count number of extensions in list by number of ampersands + 1 */
200  num_dials = 1;
201  tmp = args.devices;
202  while (*tmp) {
203  if (*tmp == '&') {
204  num_dials++;
205  }
206  tmp++;
207  }
208 
209  if (!(dial_list = ast_calloc(num_dials, sizeof(struct ast_dial *)))) {
210  ast_log(LOG_ERROR, "Can't allocate %ld bytes for dial list\n", (long)(sizeof(struct ast_dial *) * num_dials));
211  return -1;
212  }
213 
214  /* Go through parsing/calling each device */
215  while ((tech = strsep(&args.devices, "&"))) {
216  int state = 0;
217  struct ast_dial *dial = NULL;
218 
219  /* don't call the originating device */
220  if (!strcasecmp(tech, originator))
221  continue;
222 
223  /* If no resource is available, continue on */
224  if (!(resource = strchr(tech, '/'))) {
225  ast_log(LOG_WARNING, "Incomplete destination '%s' supplied.\n", tech);
226  continue;
227  }
228 
229  /* Ensure device is not in use if skip option is enabled */
230  if (ast_test_flag(&flags, PAGE_SKIP)) {
231  state = ast_device_state(tech);
232  if (state == AST_DEVICE_UNKNOWN) {
233  ast_log(LOG_WARNING, "Destination '%s' has device state '%s'. Paging anyway.\n", tech, ast_devstate2str(state));
234  } else if (state != AST_DEVICE_NOT_INUSE) {
235  ast_log(LOG_WARNING, "Destination '%s' has device state '%s'.\n", tech, ast_devstate2str(state));
236  continue;
237  }
238  }
239 
240  *resource++ = '\0';
241 
242  /* Create a dialing structure */
243  if (!(dial = ast_dial_create())) {
244  ast_log(LOG_WARNING, "Failed to create dialing structure.\n");
245  continue;
246  }
247 
248  /* Append technology and resource */
249  if (ast_dial_append(dial, tech, resource) == -1) {
250  ast_log(LOG_ERROR, "Failed to add %s to outbound dial\n", tech);
251  ast_dial_destroy(dial);
252  continue;
253  }
254 
255  /* Set ANSWER_EXEC as global option */
257 
258  if (timeout) {
259  ast_dial_set_global_timeout(dial, timeout * 1000);
260  }
261 
262  if (ast_test_flag(&flags, PAGE_IGNORE_FORWARDS)) {
264  }
265 
266  /* Run this dial in async mode */
267  ast_dial_run(dial, chan, 1);
268 
269  /* Put in our dialing array */
270  dial_list[pos++] = dial;
271  }
272 
273  if (!ast_test_flag(&flags, PAGE_QUIET)) {
274  res = ast_streamfile(chan, "beep", chan->language);
275  if (!res)
276  res = ast_waitstream(chan, "");
277  }
278 
279  if (!res) {
280  /* Default behaviour */
281  snprintf(meetmeopts, sizeof(meetmeopts), "%ud,A%s%sqxd", confid, (ast_test_flag(&flags, PAGE_DUPLEX) ? "" : "t"),
282  (ast_test_flag(&flags, PAGE_RECORD) ? "r" : "") );
283  if (ast_test_flag(&flags, PAGE_ANNOUNCE) && !ast_strlen_zero(opts[OPT_ARG_ANNOUNCE]) &&
285  snprintf(meetmeopts, sizeof(meetmeopts), "%ud,A%s%sqxdG(%s)", confid, (ast_test_flag(&flags, PAGE_DUPLEX) ? "" : "t"),
286  (ast_test_flag(&flags, PAGE_RECORD) ? "r" : ""), opts[OPT_ARG_ANNOUNCE] );
287  }
288  pbx_exec(chan, app, meetmeopts);
289  }
290 
291  /* Go through each dial attempt cancelling, joining, and destroying */
292  for (i = 0; i < pos; i++) {
293  struct ast_dial *dial = dial_list[i];
294 
295  /* We have to wait for the async thread to exit as it's possible Meetme won't throw them out immediately */
296  ast_dial_join(dial);
297 
298  /* Hangup all channels */
299  ast_dial_hangup(dial);
300 
301  /* Destroy dialing structure */
302  ast_dial_destroy(dial);
303  }
304 
305  ast_free(dial_list);
306 
307  return -1;
308 }
309 
310 static int unload_module(void)
311 {
312  return ast_unregister_application(app_page);
313 }
314 
315 static int load_module(void)
316 {
317  return ast_register_application_xml(app_page, page_exec);
318 }
319 
321 
const char * ast_devstate2str(enum ast_device_state devstate) attribute_pure
Find devicestate as text message for output.
Definition: devicestate.c:215
Main Channel structure associated with a channel.
Definition: channel.h:742
ast_device_state
Device States.
Definition: devicestate.h:51
int ast_dial_destroy(struct ast_dial *dial)
Destroys a dialing structure.
Definition: dial.c:866
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:396
#define AST_APP_OPTION_ARG(option, flagno, argno)
Declares an application option that accepts an argument.
Definition: app.h:732
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Definition: file.c:946
int ast_dial_option_global_enable(struct ast_dial *dial, enum ast_dial_option option, void *data)
Enables an option globally.
Definition: dial.c:923
Asterisk main include file. File version handling, generic pbx functions.
#define AST_APP_OPTIONS(holder, options...)
Declares an array of options for an application.
Definition: app.h:712
char * strsep(char **str, const char *delims)
struct ast_app * pbx_findapp(const char *app)
Look up an application.
Definition: pbx.c:1537
int pbx_exec(struct ast_channel *c, struct ast_app *app, const char *data)
Execute an application.
Definition: pbx.c:1497
Main dialing structure. Contains global options, channels being dialed, and more! ...
Definition: dial.c:47
void ast_dial_set_global_timeout(struct ast_dial *dial, int timeout)
Set the maximum time (globally) allowed for trying to ring phones.
Definition: dial.c:1053
#define ast_test_flag(p, flag)
Definition: utils.h:63
Device state management.
void ast_dial_hangup(struct ast_dial *dial)
Hangup channels.
Definition: dial.c:842
Channel Variables.
static const char *const app_page
Definition: app_page.c:112
#define LOG_WARNING
Definition: logger.h:144
int ast_dial_append(struct ast_dial *dial, const char *tech, const char *device)
Append a channel.
Definition: dial.c:229
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: app.c:2101
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
Definition: app.h:572
Dialing API.
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx.c:7705
Utility functions.
void * options[AST_DIAL_OPTION_MAX]
Definition: dial.c:52
static const char app[]
Definition: app_adsiprog.c:49
enum ast_dial_result ast_dial_join(struct ast_dial *dial)
Cancel async thread.
Definition: dial.c:794
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
static int load_module(void)
Definition: app_page.c:315
static int unload_module(void)
Definition: app_page.c:310
long int ast_random(void)
Definition: utils.c:1640
static struct ast_app_option page_opts[128]
Definition: app_page.c:137
Core PBX routines and definitions.
enum ast_dial_result ast_dial_run(struct ast_dial *dial, struct ast_channel *chan, int async)
Execute dialing synchronously or asynchronously.
Definition: dial.c:714
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
#define LOG_ERROR
Definition: logger.h:155
static struct @350 args
const ast_string_field name
Definition: channel.h:787
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
page_opt_flags
Definition: app_page.c:114
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1858
#define ast_free(a)
Definition: astmm.h:97
struct ast_dial * ast_dial_create(void)
New dialing structure.
Definition: dial.c:201
#define AST_CHANNEL_NAME
Definition: channel.h:137
Structure used to handle boolean flags.
Definition: utils.h:200
#define ast_calloc(a, b)
Definition: astmm.h:82
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
ast_app: A registered application
Definition: pbx.c:971
int timeout
Definition: dial.c:49
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
Definition: file.c:1343
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
#define AST_APP_ARG(name)
Define an application argument.
Definition: app.h:555
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
Definition: app.h:604
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:38
Asterisk module definitions.
static int page_exec(struct ast_channel *chan, const char *data)
Definition: app_page.c:140
const ast_string_field language
Definition: channel.h:787
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:437
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
Definition: asterisk.h:180
#define AST_APP_OPTION(option, flagno)
Declares an application option that does not accept an argument.
Definition: app.h:721