441208fd9085b22d3eb407510df5af8161775f07
[asterisk/asterisk.git] / apps / app_page.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (c) 2004 - 2005 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  * \ingroup applications
24  */
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <unistd.h>
29 #include <string.h>
30 #include <errno.h>
31
32 #include "asterisk.h"
33
34 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
35
36 #include "asterisk/options.h"
37 #include "asterisk/logger.h"
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
44
45 static const char *tdesc = "Page Multiple Phones";
46
47 static const char *app_page= "Page";
48
49 static const char *page_synopsis = "Pages phones";
50
51 static const char *page_descrip =
52 "Page(Technology/Resource&Technology2/Resource2[|options])\n"
53 "  Places outbound calls to the given technology / resource and dumps\n"
54 "them into a conference bridge as muted participants.  The original\n"
55 "caller is dumped into the conference as a speaker and the room is\n"
56 "destroyed when the original caller leaves.  Valid options are:\n"
57 "        d - full duplex audio\n"
58 "        q - quiet, do not play beep to caller\n";
59
60 STANDARD_LOCAL_USER;
61
62 LOCAL_USER_DECL;
63
64 enum {
65         PAGE_DUPLEX = (1 << 0),
66         PAGE_QUIET = (1 << 1),
67 } page_opt_flags;
68
69 AST_APP_OPTIONS(page_opts, {
70         AST_APP_OPTION('d', PAGE_DUPLEX),
71         AST_APP_OPTION('q', PAGE_QUIET),
72 });
73
74 struct calloutdata {
75         char cidnum[64];
76         char cidname[64];
77         char tech[64];
78         char resource[256];
79         char meetmeopts[64];
80 };
81
82 static void *page_thread(void *data)
83 {
84         struct calloutdata *cd = data;
85         ast_pbx_outgoing_app(cd->tech, AST_FORMAT_SLINEAR, cd->resource, 30000,
86                 "MeetMe", cd->meetmeopts, NULL, 0, cd->cidnum, cd->cidname, NULL, NULL);
87         free(cd);
88         return NULL;
89 }
90
91 static void launch_page(struct ast_channel *chan, const char *meetmeopts, const char *tech, const char *resource)
92 {
93         struct calloutdata *cd;
94         pthread_t t;
95         pthread_attr_t attr;
96         cd = malloc(sizeof(struct calloutdata));
97         if (cd) {
98                 memset(cd, 0, sizeof(struct calloutdata));
99                 ast_copy_string(cd->cidnum, chan->cid.cid_num ? chan->cid.cid_num : "", sizeof(cd->cidnum));
100                 ast_copy_string(cd->cidname, chan->cid.cid_name ? chan->cid.cid_name : "", sizeof(cd->cidname));
101                 ast_copy_string(cd->tech, tech, sizeof(cd->tech));
102                 ast_copy_string(cd->resource, resource, sizeof(cd->resource));
103                 ast_copy_string(cd->meetmeopts, meetmeopts, sizeof(cd->meetmeopts));
104                 pthread_attr_init(&attr);
105                 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
106                 if (ast_pthread_create(&t, &attr, page_thread, cd)) {
107                         ast_log(LOG_WARNING, "Unable to create paging thread: %s\n", strerror(errno));
108                         free(cd);
109                 }
110         }
111 }
112
113 static int page_exec(struct ast_channel *chan, void *data)
114 {
115         struct localuser *u;
116         char *options;
117         char *tech, *resource;
118         char meetmeopts[80];
119         struct ast_flags flags = { 0 };
120         unsigned int confid = rand();
121         struct ast_app *app;
122         char *tmp;
123         int res=0;
124
125         if (ast_strlen_zero(data)) {
126                 ast_log(LOG_WARNING, "This application requires at least one argument (destination(s) to page)\n");
127                 return -1;
128         }
129
130         LOCAL_USER_ADD(u);
131
132         if (!(app = pbx_findapp("MeetMe"))) {
133                 ast_log(LOG_WARNING, "There is no MeetMe application available!\n");
134                 LOCAL_USER_REMOVE(u);
135                 return -1;
136         };
137
138         options = ast_strdupa(data);
139         if (!options) {
140                 ast_log(LOG_ERROR, "Out of memory\n");
141                 LOCAL_USER_REMOVE(u);
142                 return -1;
143         }
144
145         tmp = strsep(&options, "|");
146         if (options)
147                 ast_app_parse_options(page_opts, &flags, NULL, options);
148
149         snprintf(meetmeopts, sizeof(meetmeopts), "%ud|%sqxdw", confid, ast_test_flag(&flags, PAGE_DUPLEX) ? "" : "m");
150         while ((tech = strsep(&tmp, "&"))) {
151                 if ((resource = strchr(tech, '/'))) {
152                         *resource++ = '\0';
153                         launch_page(chan, meetmeopts, tech, resource);
154                 } else {
155                         ast_log(LOG_WARNING, "Incomplete destination '%s' supplied.\n", tech);
156                 }
157         }
158         if (!ast_test_flag(&flags, PAGE_QUIET)) {
159                 res = ast_streamfile(chan, "beep", chan->language);
160                 if (!res)
161                         res = ast_waitstream(chan, "");
162         }
163         if (!res) {
164                 snprintf(meetmeopts, sizeof(meetmeopts), "%ud|A%sqxd", confid, ast_test_flag(&flags, PAGE_DUPLEX) ? "" : "t");
165                 pbx_exec(chan, app, meetmeopts, 1);
166         }
167
168         LOCAL_USER_REMOVE(u);
169
170         return -1;
171 }
172
173 int unload_module(void)
174 {
175         int res;
176
177         res =  ast_unregister_application(app_page);
178
179         STANDARD_HANGUP_LOCALUSERS;
180
181         return res;
182 }
183
184 int load_module(void)
185 {
186         return ast_register_application(app_page, page_exec, page_synopsis, page_descrip);
187 }
188
189 char *description(void)
190 {
191         return (char *) tdesc;
192 }
193
194 int usecount(void)
195 {
196         int res;
197
198         STANDARD_USECOUNT(res);
199
200         return res;
201 }
202
203 char *key()
204 {
205         return ASTERISK_GPL_KEY;
206 }