Asterisk - The Open Source Telephony Project  21.4.1
app_sendtext.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2005, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
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 
19 /*! \file
20  *
21  * \brief App to transmit a text message
22  *
23  * \author Mark Spencer <markster@digium.com>
24  * \author Naveen Albert <asterisk@phreaknet.org>
25  *
26  * \note Requires support of sending text messages from channel driver
27  *
28  * \ingroup applications
29  */
30 
31 /*** MODULEINFO
32  <support_level>core</support_level>
33  ***/
34 
35 #include "asterisk.h"
36 
37 #include "asterisk/file.h"
38 #include "asterisk/channel.h"
39 #include "asterisk/pbx.h"
40 #include "asterisk/module.h"
41 #include "asterisk/app.h"
42 #include "asterisk/message.h"
43 
44 /*** DOCUMENTATION
45  <application name="SendText" language="en_US">
46  <synopsis>
47  Send a Text Message on a channel.
48  </synopsis>
49  <syntax>
50  <parameter name="text" required="false" />
51  </syntax>
52  <description>
53  <para>Sends <replaceable>text</replaceable> to the current channel.</para>
54  <note><para><literal>current channel</literal> could be the caller or callee depending
55  on the context in which this application is called.</para></note>
56  <para>
57  </para>
58  <para>The following variables can be set:</para>
59  <variablelist>
60  <variable name="SENDTEXT_FROM_DISPLAYNAME">
61  <para>If set and this channel supports enhanced messaging, this value will be
62  used as the <literal>From</literal> display name.</para>
63  </variable>
64  <variable name="SENDTEXT_TO_DISPLAYNAME">
65  <para>If set and this channel supports enhanced messaging, this value will be
66  used as the <literal>To</literal> display name.</para>
67  </variable>
68  <variable name="SENDTEXT_CONTENT_TYPE">
69  <para>If set and this channel supports enhanced messaging, this value will be
70  used as the message <literal>Content-Type</literal>. If not specified, the
71  default of <literal>text/plain</literal> will be used.</para>
72  <para><emphasis>Warning:</emphasis> Messages of types other than
73  <literal>text/&#42;</literal> cannot be sent via channel drivers that do not
74  support Enhanced Messaging. An attempt to do so will be ignored and will result
75  in the <literal>SENDTEXTSTATUS</literal> variable being set to
76  <literal>UNSUPPORTED</literal>.</para>
77  </variable>
78  <variable name="SENDTEXT_BODY">
79  <para>If set this value will be used as the message body and any text supplied
80  as a function parameter will be ignored.
81  </para>
82  </variable>
83  </variablelist>
84  <para>
85  </para>
86  <para>Result of transmission will be stored in the following variables:</para>
87  <variablelist>
88  <variable name="SENDTEXTTYPE">
89  <value name="NONE">
90  No message sent.
91  </value>
92  <value name="BASIC">
93  Message body sent without attributes because the channel driver
94  doesn't support enhanced messaging.
95  </value>
96  <value name="ENHANCED">
97  The message was sent using enhanced messaging.
98  </value>
99  </variable>
100  <variable name="SENDTEXTSTATUS">
101  <value name="SUCCESS">
102  Transmission succeeded.
103  </value>
104  <value name="FAILURE">
105  Transmission failed.
106  </value>
107  <value name="UNSUPPORTED">
108  Text transmission not supported by channel.
109  </value>
110  </variable>
111  </variablelist>
112  <para>
113  </para>
114  <note><para>The text encoding and transmission method is completely at the
115  discretion of the channel driver. chan_pjsip will use in-dialog SIP MESSAGE
116  messages always.</para></note>
117  <para>
118  </para>
119  <para>Examples:
120  </para>
121  <example title="Send a simple message">
122  same => n,SendText(Your Text Here)
123  </example>
124  <para>If the channel driver supports enhanced messaging (currently only chan_pjsip),
125  you can set additional variables:</para>
126  <example title="Alter the From display name">
127  same => n,Set(SENDTEXT_FROM_DISPLAYNAME=Really From Bob)
128  same => n,SendText(Your Text Here)
129  </example>
130  <example title="Send a JSON String">
131  same => n,Set(SENDTEXT_CONTENT_TYPE=text/json)
132  same => n,SendText({"foo":a, "bar":23})
133  </example>
134  <example title="Send a JSON String (alternate)">
135  same => n,Set(SENDTEXT_CONTENT_TYPE=text/json)
136  same => n,Set(SENDTEXT_BODY={"foo":a, "bar":23})
137  same => n,SendText()
138  </example>
139  </description>
140  <see-also>
141  <ref type="application">ReceiveText</ref>
142  </see-also>
143  </application>
144  <application name="ReceiveText" language="en_US">
145  <since>
146  <version>16.24.0</version>
147  <version>18.10.0</version>
148  <version>19.2.0</version>
149  </since>
150  <synopsis>
151  Receive a Text Message on a channel.
152  </synopsis>
153  <syntax>
154  <parameter name="timeout" required="false">
155  <para>Time in seconds to wait for text. Default is 0 (forever).</para>
156  </parameter>
157  </syntax>
158  <description>
159  <para>Waits for <replaceable>timeout</replaceable> seconds on the current channel
160  to receive text.</para>
161  <para>Result of transmission will be stored in the following variables:</para>
162  <variablelist>
163  <variable name="RECEIVETEXTMESSAGE">
164  <para>The received text message.</para>
165  </variable>
166  <variable name="RECEIVETEXTSTATUS">
167  <value name="SUCCESS">
168  Transmission succeeded.
169  </value>
170  <value name="FAILURE">
171  Transmission failed or timed out.
172  </value>
173  </variable>
174  </variablelist>
175  <example title="Receive message on channel">
176  same => n,ReceiveText()
177  same => n,NoOp(${RECEIVETEXTMESSAGE})
178  </example>
179  </description>
180  <see-also>
181  <ref type="application">SendText</ref>
182  </see-also>
183  </application>
184  ***/
185 
186 static const char * const app = "SendText";
187 static const char * const app2 = "ReceiveText";
188 
189 static int sendtext_exec(struct ast_channel *chan, const char *data)
190 {
191  char *status;
192  char *msg_type;
193  struct ast_str *str;
194  const char *from;
195  const char *to;
196  const char *content_type;
197  const char *body;
198  int rc = 0;
199 
200  ast_channel_lock(chan);
201  from = pbx_builtin_getvar_helper(chan, "SENDTEXT_FROM_DISPLAYNAME");
202  to = pbx_builtin_getvar_helper(chan, "SENDTEXT_TO_DISPLAYNAME");
203  content_type = pbx_builtin_getvar_helper(chan, "SENDTEXT_CONTENT_TYPE");
204  body = S_OR(pbx_builtin_getvar_helper(chan, "SENDTEXT_BODY"), data);
205  body = S_OR(body, "");
206 
207  if (!(str = ast_str_alloca(strlen(body) + 1))) {
208  rc = -1;
209  goto cleanup;
210  }
211  ast_str_get_encoded_str(&str, -1, body);
212  body = ast_str_buffer(str);
213 
214  msg_type = "NONE";
215  status = "UNSUPPORTED";
216  if (ast_channel_tech(chan)->send_text_data) {
217  struct ast_msg_data *msg;
218  struct ast_msg_data_attribute attrs[] =
219  {
220  {
221  .type = AST_MSG_DATA_ATTR_FROM,
222  .value = (char *)S_OR(from, ""),
223  },
224  {
225  .type = AST_MSG_DATA_ATTR_TO,
226  .value = (char *)S_OR(to, ""),
227  },
228  {
229  .type = AST_MSG_DATA_ATTR_CONTENT_TYPE,
230  .value = (char *)S_OR(content_type, ""),
231  },
232  {
233  .type = AST_MSG_DATA_ATTR_BODY,
234  .value = (char *)S_OR(body, ""),
235  },
236  };
237 
238  msg_type = "ENHANCED";
239  msg = ast_msg_data_alloc(AST_MSG_DATA_SOURCE_TYPE_IN_DIALOG, attrs, ARRAY_LEN(attrs));
240  if (msg) {
241  if (ast_sendtext_data(chan, msg) == 0) {
242  status = "SUCCESS";
243  } else {
244  status = "FAILURE";
245  }
246 
247  ast_free(msg);
248  } else {
249  rc = -1;
250  goto cleanup;
251  }
252 
253  } else if (ast_channel_tech(chan)->send_text) {
254  if (!ast_strlen_zero(content_type) && !ast_begins_with(content_type, "text/")) {
255  rc = -1;
256  goto cleanup;
257  }
258 
259  msg_type = "BASIC";
260  if (ast_sendtext(chan, body) == 0) {
261  status = "SUCCESS";
262  } else {
263  status = "FAILURE";
264  }
265  }
266 
267  pbx_builtin_setvar_helper(chan, "SENDTEXTTYPE", msg_type);
268  pbx_builtin_setvar_helper(chan, "SENDTEXTSTATUS", status);
269 
270 cleanup:
271  pbx_builtin_setvar_helper(chan, "SENDTEXT_FROM_DISPLAYNAME", NULL);
272  pbx_builtin_setvar_helper(chan, "SENDTEXT_TO_DISPLAYNAME", NULL);
273  pbx_builtin_setvar_helper(chan, "SENDTEXT_CONTENT_TYPE", NULL);
274  pbx_builtin_setvar_helper(chan, "SENDTEXT_BODY", NULL);
275  ast_channel_unlock(chan);
276 
277  return rc;
278 }
279 
280 static int recvtext_exec(struct ast_channel *chan, const char *data)
281 {
282  double timeout = 0, timeout_ms = 0;
283  char *parse, *buf;
284 
286  AST_APP_ARG(timeout);
287  );
288 
289  parse = ast_strdupa(data);
290 
291  AST_STANDARD_APP_ARGS(args, parse);
292 
293  if (!ast_strlen_zero(args.timeout)) {
294  if (sscanf(args.timeout, "%30lg", &timeout) != 1) {
295  ast_log(LOG_WARNING, "Invalid timeout provided: %s. No timeout set.\n", args.timeout);
296  return -1;
297  }
298  timeout_ms = timeout * 1000.0;
299  }
300 
301  buf = ast_recvtext(chan, timeout_ms);
302  pbx_builtin_setvar_helper(chan, "RECEIVETEXTSTATUS", buf ? "SUCCESS" : "FAILURE");
303  if (buf) {
304  pbx_builtin_setvar_helper(chan, "RECEIVETEXTMESSAGE", buf);
305  ast_free(buf);
306  }
307 
308  return 0;
309 }
310 
311 static int unload_module(void)
312 {
313  int res;
314 
315  res = ast_unregister_application(app);
316  res |= ast_unregister_application(app2);
317 
318  return res;
319 }
320 
321 static int load_module(void)
322 {
323  int res;
324 
325  res = ast_register_application_xml(app, sendtext_exec);
326  res |= ast_register_application_xml(app2, recvtext_exec);
327 
328  return res;
329 }
330 
331 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Send and Receive Text Applications");
Main Channel structure associated with a channel.
Asterisk main include file. File version handling, generic pbx functions.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
Structure used to transport a message through the frame core.
struct ast_msg_data * ast_msg_data_alloc(enum ast_msg_data_source_type source, struct ast_msg_data_attribute attributes[], size_t count)
Allocates an ast_msg_data structure.
int ast_sendtext_data(struct ast_channel *chan, struct ast_msg_data *msg)
Sends text to a channel in an ast_msg_data structure wrapper with ast_sendtext as fallback...
Definition: channel.c:4751
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
Out-of-call text message support.
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
int ast_str_get_encoded_str(struct ast_str **str, int maxlen, const char *stream)
Decode a stream of encoded control or extended ASCII characters.
Definition: main/app.c:3175
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
static void cleanup(void)
Clean up any old apps that we don't need any more.
Definition: res_stasis.c:327
General Asterisk PBX channel definitions.
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
Structure to describe a channel "technology", ie a channel driver See for examples: ...
Definition: channel.h:628
Core PBX routines and definitions.
Support for dynamic strings.
Definition: strings.h:623
char * ast_recvtext(struct ast_channel *chan, int timeout)
Receives a text string from a channel Read a string of text from a channel.
Definition: channel.c:4717
union ast_frame::@224 data
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name...
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:80
static int force_inline attribute_pure ast_begins_with(const char *str, const char *prefix)
Checks whether a string begins with another.
Definition: strings.h:97
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
Asterisk module definitions.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:640
int ast_sendtext(struct ast_channel *chan, const char *text)
Sends text to a channel.
Definition: channel.c:4809
#define AST_APP_ARG(name)
Define an application argument.