Setup environment variables for the benefit of child processes and disallow changing...
[asterisk/asterisk.git] / funcs / func_connectedline.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2007, Gareth Palmer
5  *
6  * Gareth Palmer <gareth@acsdata.co.nz>
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 Connected Line dialplan function
22  *
23  * \ingroup functions
24  */
25
26 #include "asterisk.h"
27
28 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
29
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <sys/types.h>
34
35 #include "asterisk/module.h"
36 #include "asterisk/channel.h"
37 #include "asterisk/pbx.h"
38 #include "asterisk/logger.h"
39 #include "asterisk/utils.h"
40 #include "asterisk/app.h"
41 #include "asterisk/options.h"
42 #include "asterisk/callerid.h"
43
44 /*
45  * Do not document the CONNECTEDLINE(source) datatype.
46  * It has turned out to not be needed.  The source value is really
47  * only useful as a possible tracing aid.
48  */
49 /*** DOCUMENTATION
50         <function name="CONNECTEDLINE" language="en_US">
51                 <synopsis>
52                         Gets or sets Connected Line data on the channel.
53                 </synopsis>
54                 <syntax>
55                         <parameter name="datatype" required="true">
56                                 <para>The allowable datatypes are:</para>
57                                 <enumlist>
58                                         <enum name = "all" />
59                                         <enum name = "num" />
60                                         <enum name = "name" />
61                                         <enum name = "tag" />
62                                         <enum name = "ton" />
63                                         <enum name = "pres" />
64                                         <enum name = "subaddr[-valid]|[-type]|[-odd]">
65                                                 <para>ISDN Connected line subaddress</para>
66                                         </enum>
67                                 </enumlist>
68                         </parameter>
69                         <parameter name="i">
70                                 <para>If set, this will prevent the channel from sending out protocol
71                                 messages because of the value being set</para>
72                         </parameter>
73                 </syntax>
74                 <description>
75                         <para>Gets or sets Connected Line data on the channel.</para>
76                 </description>
77         </function>
78  ***/
79
80 static int connectedline_read(struct ast_channel *chan, const char *cmd, char *data,
81                               char *buf, size_t len)
82 {
83         /* Ensure that the buffer is empty */
84         *buf = 0;
85
86         if (!chan)
87                 return -1;
88
89         ast_channel_lock(chan);
90
91         if (!strncasecmp("all", data, 3)) {
92                 snprintf(buf, len, "\"%s\" <%s>",
93                          S_OR(chan->connected.id.name, ""),
94                          S_OR(chan->connected.id.number, ""));
95         } else if (!strncasecmp("name", data, 4)) {
96                 if (chan->connected.id.name) {
97                         ast_copy_string(buf, chan->connected.id.name, len);
98                 }
99         } else if (!strncasecmp("num", data, 3)) {
100                 if (chan->connected.id.number) {
101                         ast_copy_string(buf, chan->connected.id.number, len);
102                 }
103         } else if (!strncasecmp("tag", data, 3)) {
104                 if (chan->connected.id.tag) {
105                         ast_copy_string(buf, chan->connected.id.tag, len);
106                 }
107         } else if (!strncasecmp("ton", data, 3)) {
108                 snprintf(buf, len, "%d", chan->connected.id.number_type);
109         } else if (!strncasecmp("pres", data, 4)) {
110                 ast_copy_string(buf, ast_named_caller_presentation(chan->connected.id.number_presentation), len);
111         } else if (!strncasecmp("source", data, 6)) {
112                 ast_copy_string(buf, ast_connected_line_source_name(chan->connected.source), len);
113         } else if (!strncasecmp("subaddr", data, 7)) {
114                 /* also matches subaddr-valid, subaddr-type, subaddr-odd, subaddr */
115                 if (!strncasecmp(data + 7 ,"-valid", 6)) {              /* subaddr-valid */
116                         snprintf(buf, len, "%d", chan->connected.id.subaddress.valid);
117                 } else if (!strncasecmp(data + 7 ,"-type", 5)) {        /* subaddr-type */
118                         snprintf(buf, len, "%d", chan->connected.id.subaddress.type);
119                 } else if (!strncasecmp(data + 7 ,"-odd", 4)) {         /* subaddr-odd */
120                         snprintf(buf, len, "%d", chan->connected.id.subaddress.odd_even_indicator);
121                 } else {                                                /* subaddr */
122                         if (chan->connected.id.subaddress.str) {
123                                 ast_copy_string(buf, chan->connected.id.subaddress.str, len);
124                         }
125                 }
126         } else {
127                 ast_log(LOG_ERROR, "Unknown connectedline data type '%s'.\n", data);
128         }
129
130         ast_channel_unlock(chan);
131
132         return 0;
133 }
134
135 static int connectedline_write(struct ast_channel *chan, const char *cmd, char *data,
136                                const char *value)
137 {
138         struct ast_party_connected_line connected;
139         char *val;
140         char *option;
141         void (*set_it)(struct ast_channel *chan, const struct ast_party_connected_line *connected);
142
143         if (!value || !chan) {
144                 return -1;
145         }
146
147         /* Determine if the update indication inhibit option is present */
148         option = strchr(data, ',');
149         if (option) {
150                 option = ast_skip_blanks(option + 1);
151                 switch (*option) {
152                 case 'i':
153                         set_it = ast_channel_set_connected_line;
154                         break;
155
156                 default:
157                         ast_log(LOG_ERROR, "Unknown connectedline option '%s'.\n", option);
158                         return 0;
159                 }
160         }
161         else {
162                 set_it = ast_channel_update_connected_line;
163         }
164
165         ast_channel_lock(chan);
166         ast_party_connected_line_set_init(&connected, &chan->connected);
167         ast_channel_unlock(chan);
168
169         value = ast_skip_blanks(value);
170
171         if (!strncasecmp("all", data, 3)) {
172                 char name[256];
173                 char num[256];
174
175                 ast_callerid_split(value, name, sizeof(name), num, sizeof(num));
176                 connected.id.name = name;
177                 connected.id.number = num;
178                 set_it(chan, &connected);
179         } else if (!strncasecmp("name", data, 4)) {
180                 connected.id.name = ast_strdupa(value);
181                 ast_trim_blanks(connected.id.name);
182                 set_it(chan, &connected);
183         } else if (!strncasecmp("num", data, 3)) {
184                 connected.id.number = ast_strdupa(value);
185                 ast_trim_blanks(connected.id.number);
186                 set_it(chan, &connected);
187         } else if (!strncasecmp("tag", data, 3)) {
188                 connected.id.tag = ast_strdupa(value);
189                 ast_trim_blanks(connected.id.tag);
190                 set_it(chan, &connected);
191         } else if (!strncasecmp("ton", data, 3)) {
192                 val = ast_strdupa(value);
193                 ast_trim_blanks(val);
194
195                 if (('0' <= val[0]) && (val[0] <= '9')) {
196                         connected.id.number_type = atoi(val);
197                         set_it(chan, &connected);
198                 } else {
199                         ast_log(LOG_ERROR, "Unknown connectedline type of number '%s', value unchanged\n", val);
200                 }
201         } else if (!strncasecmp("pres", data, 4)) {
202                 int pres;
203
204                 val = ast_strdupa(value);
205                 ast_trim_blanks(val);
206
207                 if (('0' <= val[0]) && (val[0] <= '9')) {
208                         pres = atoi(val);
209                 } else {
210                         pres = ast_parse_caller_presentation(val);
211                 }
212
213                 if (pres < 0) {
214                         ast_log(LOG_ERROR, "Unknown connectedline number presentation '%s', value unchanged\n", val);
215                 } else {
216                         connected.id.number_presentation = pres;
217                         set_it(chan, &connected);
218                 }
219         } else if (!strncasecmp("source", data, 6)) {
220                 int source;
221
222                 val = ast_strdupa(value);
223                 ast_trim_blanks(val);
224
225                 if (('0' <= val[0]) && (val[0] <= '9')) {
226                         source = atoi(val);
227                 } else {
228                         source = ast_connected_line_source_parse(val);
229                 }
230
231                 if (source < 0) {
232                         ast_log(LOG_ERROR, "Unknown connectedline source '%s', value unchanged\n", val);
233                 } else {
234                         connected.source = source;
235                         set_it(chan, &connected);
236                 }
237         } else if (!strncasecmp("subaddr", data, 7)) { /* outbound: set calling subaddress */
238                 /* also matches subaddr-valid, subaddr-type, subaddr-odd, subaddr */
239                 if (!strncasecmp(data + 7 ,"-valid", 6)) {              /* subaddr-valid */
240                         connected.id.subaddress.valid = atoi(value) ? 1 : 0;
241                 } else if (!strncasecmp(data + 7 ,"-type", 5)) {        /* subaddr-type */
242                         connected.id.subaddress.type = atoi(value) ? 2 : 0;
243                 } else if (!strncasecmp(data + 7 ,"-odd", 4)) {         /* subaddr-odd */
244                         connected.id.subaddress.odd_even_indicator = atoi(value) ? 1 : 0;
245                 } else {                                                /* subaddr */
246                         connected.id.subaddress.str = ast_strdupa(value);
247                         ast_trim_blanks(connected.id.subaddress.str);
248                 }
249                 set_it(chan, &connected);
250         } else {
251                 ast_log(LOG_ERROR, "Unknown connectedline data type '%s'.\n", data);
252         }
253
254         return 0;
255 }
256
257 static struct ast_custom_function connectedline_function = {
258         .name = "CONNECTEDLINE",
259         .read = connectedline_read,
260         .write = connectedline_write,
261 };
262
263 static int unload_module(void)
264 {
265         return ast_custom_function_unregister(&connectedline_function);
266 }
267
268 static int load_module(void)
269 {
270         return ast_custom_function_register(&connectedline_function)
271                 ? AST_MODULE_LOAD_DECLINE
272                 : AST_MODULE_LOAD_SUCCESS;
273 }
274
275 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Connected Line dialplan function");