Setup environment variables for the benefit of child processes and disallow changing...
[asterisk/asterisk.git] / funcs / func_callerid.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999-2006, Digium, Inc.
5  *
6  * See http://www.asterisk.org for more information about
7  * the Asterisk project. Please do not directly contact
8  * any of the maintainers of this project for assistance;
9  * the project provides a web site, mailing lists and IRC
10  * channels for your use.
11  *
12  * This program is free software, distributed under the terms of
13  * the GNU General Public License Version 2. See the LICENSE file
14  * at the top of the source tree.
15  */
16
17 /*! \file
18  *
19  * \brief Caller ID related dialplan functions
20  *
21  * \ingroup functions
22  */
23
24 #include "asterisk.h"
25
26 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
27
28 #include "asterisk/module.h"
29 #include "asterisk/channel.h"
30 #include "asterisk/pbx.h"
31 #include "asterisk/utils.h"
32 #include "asterisk/app.h"
33 #include "asterisk/callerid.h"
34
35 /*** DOCUMENTATION
36         <function name="CALLERID" language="en_US">
37                 <synopsis>
38                         Gets or sets Caller*ID data on the channel.
39                 </synopsis>
40                 <syntax>
41                         <parameter name="datatype" required="true">
42                                 <para>The allowable datatypes are:</para>
43                                 <enumlist>
44                                         <enum name="all" />
45                                         <enum name="num" />
46                                         <enum name="name" />
47                                         <enum name="tag" />
48                                         <enum name="ANI" />
49                                         <enum name="DNID" />
50                                         <enum name="RDNIS" />
51                                         <enum name="pres" />
52                                         <enum name="ton" />
53                                         <enum name="subaddr[-valid]|[-type]|[-odd]">
54                                                 <para>ISDN Calling Subaddress</para>
55                                         </enum>
56                                         <enum name="dnid-subaddr[-valid]|[-type]|[-odd]">
57                                                 <para>ISDN Called Subaddress</para>
58                                         </enum>
59                                 </enumlist>
60                         </parameter>
61                         <parameter name="CID">
62                                 <para>Optional Caller*ID</para>
63                         </parameter>
64                 </syntax>
65                 <description>
66                         <para>Gets or sets Caller*ID data on the channel. Uses channel callerid by default or optional
67                         callerid, if specified.</para>
68                 </description>
69         </function>
70         <function name="CALLERPRES" language="en_US">
71                 <synopsis>
72                         Gets or sets Caller*ID presentation on the channel.
73                 </synopsis>
74                 <syntax />
75                 <description>
76                         <para>Gets or sets Caller*ID presentation on the channel. The following values
77                         are valid:</para>
78                         <enumlist>
79                                 <enum name="allowed_not_screened">
80                                         <para>Presentation Allowed, Not Screened.</para>
81                                 </enum>
82                                 <enum name="allowed_passed_screen">
83                                         <para>Presentation Allowed, Passed Screen.</para>
84                                 </enum>
85                                 <enum name="allowed_failed_screen">
86                                         <para>Presentation Allowed, Failed Screen.</para>
87                                 </enum>
88                                 <enum name="allowed">
89                                         <para>Presentation Allowed, Network Number.</para>
90                                 </enum>
91                                 <enum name="prohib_not_screened">
92                                         <para>Presentation Prohibited, Not Screened.</para>
93                                 </enum>
94                                 <enum name="prohib_passed_screen">
95                                         <para>Presentation Prohibited, Passed Screen.</para>
96                                 </enum>
97                                 <enum name="prohib_failed_screen">
98                                         <para>Presentation Prohibited, Failed Screen.</para>
99                                 </enum>
100                                 <enum name="prohib">
101                                         <para>Presentation Prohibited, Network Number.</para>
102                                 </enum>
103                                 <enum name="unavailable">
104                                         <para>Number Unavailable.</para>
105                                 </enum>
106                         </enumlist>
107                 </description>
108         </function>
109  ***/
110
111 static int callerpres_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
112 {
113         ast_copy_string(buf, ast_named_caller_presentation(chan->cid.cid_pres), len);
114         return 0;
115 }
116
117 static int callerpres_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
118 {
119         int pres = ast_parse_caller_presentation(value);
120         if (pres < 0)
121                 ast_log(LOG_WARNING, "'%s' is not a valid presentation (see 'show function CALLERPRES')\n", value);
122         else
123                 chan->cid.cid_pres = pres;
124         return 0;
125 }
126
127 static int callerid_read(struct ast_channel *chan, const char *cmd, char *data,
128                          char *buf, size_t len)
129 {
130         char *opt = data;
131
132         /* Ensure that the buffer is empty */
133         *buf = 0;
134
135         if (!chan)
136                 return -1;
137
138         if (strchr(opt, ',')) {
139                 char name[80], num[80];
140
141                 data = strsep(&opt, ",");
142                 ast_callerid_split(opt, name, sizeof(name), num, sizeof(num));
143
144                 if (!strncasecmp("all", data, 3)) {
145                         snprintf(buf, len, "\"%s\" <%s>", name, num);
146                 } else if (!strncasecmp("name", data, 4)) {
147                         ast_copy_string(buf, name, len);
148                 } else if (!strncasecmp("num", data, 3)) {
149                         /* also matches "number" */
150                         ast_copy_string(buf, num, len);
151                 } else {
152                         ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
153                 }
154         } else {
155                 ast_channel_lock(chan);
156
157                 if (!strncasecmp("all", data, 3)) {
158                         snprintf(buf, len, "\"%s\" <%s>",
159                                 S_OR(chan->cid.cid_name, ""),
160                                 S_OR(chan->cid.cid_num, ""));
161                 } else if (!strncasecmp("name", data, 4)) {
162                         if (chan->cid.cid_name) {
163                                 ast_copy_string(buf, chan->cid.cid_name, len);
164                         }
165                 } else if (!strncasecmp("tag", data, 3)) {
166                         if (chan->cid.cid_tag) {
167                                 ast_copy_string(buf, chan->cid.cid_tag, len);
168                         }
169                 } else if (!strncasecmp("num", data, 3)) {
170                         /* also matches "number" */
171                         if (chan->cid.cid_num) {
172                                 ast_copy_string(buf, chan->cid.cid_num, len);
173                         }
174                 } else if (!strncasecmp("ani", data, 3)) {
175                         if (!strncasecmp(data + 3, "2", 1)) {
176                                 snprintf(buf, len, "%d", chan->cid.cid_ani2);
177                         } else if (chan->cid.cid_ani) {
178                                 ast_copy_string(buf, chan->cid.cid_ani, len);
179                         }
180                 } else if (!strncasecmp("dnid", data, 4)) {
181                         /* Called parties info */
182
183                         /* also matches dnid-subaddr-valid, dnid-subaddr-type, dnid-subaddr-odd, dnid-subaddr */
184                         if (!strncasecmp(data + 4 ,"-subaddr", 8)) {
185                                 if (!strncasecmp(data + 12 ,"-valid", 6)) {             /* dnid-subaddr-valid */
186                                         snprintf(buf, len, "%d", chan->cid.dialed_subaddress.valid);
187                                 } else if (!strncasecmp(data + 12 ,"-type", 5)) {       /* dnid-subaddr-type */
188                                         snprintf(buf, len, "%d", chan->cid.dialed_subaddress.type);
189                                 } else if (!strncasecmp(data + 12 ,"-odd", 4)) {        /* dnid-subaddr-odd */
190                                         snprintf(buf, len, "%d", chan->cid.dialed_subaddress.odd_even_indicator);
191                                 } else {                                                /* dnid-subaddr */
192                                         if (chan->cid.dialed_subaddress.str) {
193                                                 ast_copy_string(buf, chan->cid.dialed_subaddress.str, len);
194                                         }
195                                 }
196                         } else {                                                        /* dnid */
197                                 if (chan->cid.cid_dnid) {
198                                         ast_copy_string(buf, chan->cid.cid_dnid, len);
199                                 }
200                         }
201                 } else if (!strncasecmp("subaddr", data, 7)) {
202                         /* Calling parties info */
203
204                         /* also matches subaddr-valid, subaddr-type, subaddr-odd, subaddr */
205                         if (!strncasecmp(data + 7 ,"-valid", 6)) {              /* subaddr-valid */
206                                 snprintf(buf, len, "%d", chan->cid.subaddress.valid);
207                         } else if (!strncasecmp(data + 7 ,"-type", 5)) {        /* subaddr-type */
208                                 snprintf(buf, len, "%d", chan->cid.subaddress.type);
209                         } else if (!strncasecmp(data + 7 ,"-odd", 4)) {         /* subaddr-odd */
210                                 snprintf(buf, len, "%d", chan->cid.subaddress.odd_even_indicator);
211                         } else {                                                /* subaddr */
212                                 if (chan->cid.subaddress.str) {
213                                         ast_copy_string(buf, chan->cid.subaddress.str, len);
214                                 }
215                         }
216                 } else if (!strncasecmp("rdnis", data, 5)) {
217                         if (chan->redirecting.from.number) {
218                                 ast_copy_string(buf, chan->redirecting.from.number, len);
219                         }
220                 } else if (!strncasecmp("pres", data, 4)) {
221                         ast_copy_string(buf, ast_named_caller_presentation(chan->cid.cid_pres), len);
222                 } else if (!strncasecmp("ton", data, 3)) {
223                         snprintf(buf, len, "%d", chan->cid.cid_ton);
224                 } else {
225                         ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
226                 }
227
228                 ast_channel_unlock(chan);
229         }
230
231         return 0;
232 }
233
234 static int callerid_write(struct ast_channel *chan, const char *cmd, char *data,
235                           const char *value)
236 {
237         if (!value || !chan)
238                 return -1;
239
240         value = ast_skip_blanks(value);
241
242         if (!strncasecmp("all", data, 3)) {
243                 char name[256];
244                 char num[256];
245
246                 ast_callerid_split(value, name, sizeof(name), num, sizeof(num));
247                 ast_set_callerid(chan, num, name, num);
248                 if (chan->cdr) {
249                         ast_cdr_setcid(chan->cdr, chan);
250                 }
251         } else if (!strncasecmp("name", data, 4)) {
252                 ast_set_callerid(chan, NULL, value, NULL);
253                 if (chan->cdr) {
254                         ast_cdr_setcid(chan->cdr, chan);
255                 }
256         } else if (!strncasecmp("num", data, 3)) {
257                 /* also matches "number" */
258                 ast_set_callerid(chan, value, NULL, NULL);
259                 if (chan->cdr) {
260                         ast_cdr_setcid(chan->cdr, chan);
261                 }
262         } else if (!strncasecmp("tag", data, 3)) {
263                 ast_channel_lock(chan);
264                 if (chan->cid.cid_tag) {
265                         ast_free(chan->cid.cid_tag);
266                 }
267                 chan->cid.cid_tag = ast_strdup(value);
268                 ast_channel_unlock(chan);
269         } else if (!strncasecmp("ani", data, 3)) {
270                 if (!strncasecmp(data + 3, "2", 1)) {
271                         chan->cid.cid_ani2 = atoi(value);
272                 } else {
273                         ast_set_callerid(chan, NULL, NULL, value);
274                 }
275                 if (chan->cdr) {
276                         ast_cdr_setcid(chan->cdr, chan);
277                 }
278         } else if (!strncasecmp("dnid", data, 4)) {
279                 ast_channel_lock(chan);
280                 /* also matches dnid-subaddr-valid, dnid-subaddr-type, dnid-subaddr-odd, dnid-subaddr */
281                 if (!strncasecmp(data + 4 ,"-subaddr", 8)) {
282                         if (!strncasecmp(data + 12 ,"-valid", 6)) {             /* dnid-subaddr-valid */
283                                 chan->cid.dialed_subaddress.valid = atoi(value) ? 1 : 0;
284                         } else if (!strncasecmp(data + 12 ,"-type", 5)) {       /* dnid-subaddr-type */
285                                 chan->cid.dialed_subaddress.type = atoi(value) ? 2 : 0;
286                         } else if (!strncasecmp(data + 12 ,"-odd", 4)) {        /* dnid-subaddr-odd */
287                                 chan->cid.dialed_subaddress.odd_even_indicator = atoi(value) ? 1 : 0;
288                         } else {                                                /* dnid-subaddr */
289                                 if (chan->cid.dialed_subaddress.str) {
290                                         ast_free(chan->cid.dialed_subaddress.str);
291                                 }
292                                 chan->cid.dialed_subaddress.str = ast_strdup(value);
293                         }
294                 } else {                                                        /* dnid */
295                         if (chan->cid.cid_dnid) {
296                                 ast_free(chan->cid.cid_dnid);
297                         }
298                         chan->cid.cid_dnid = ast_strdup(value);
299                 }
300
301                 if (chan->cdr) {
302                         ast_cdr_setcid(chan->cdr, chan);
303                 }
304                 ast_channel_unlock(chan);
305         } else if (!strncasecmp("subaddr", data, 7)) {
306                 ast_channel_lock(chan);
307                 /* also matches subaddr-valid, subaddr-type, subaddr-odd, subaddr */
308                 if (!strncasecmp(data + 7 ,"-valid", 6)) {              /* subaddr-valid */
309                         chan->cid.subaddress.valid = atoi(value) ? 1 : 0;
310                 } else if (!strncasecmp(data + 7 ,"-type", 5)) {        /* subaddr-type */
311                         chan->cid.subaddress.type = atoi(value) ? 2 : 0;
312                 } else if (!strncasecmp(data + 7 ,"-odd", 4)) {         /* subaddr-odd */
313                         chan->cid.subaddress.odd_even_indicator = atoi(value) ? 1 : 0;
314                 } else {                                                /* subaddr */
315                         if (chan->cid.subaddress.str) {
316                                 ast_free(chan->cid.subaddress.str);
317                         }
318                         chan->cid.subaddress.str = ast_strdup(value);
319                 }
320                 if (chan->cdr) {
321                         ast_cdr_setcid(chan->cdr, chan);
322                 }
323                 ast_channel_unlock(chan);
324         } else if (!strncasecmp("rdnis", data, 5)) {
325                 ast_channel_lock(chan);
326                 ast_free(chan->redirecting.from.number);
327                 chan->redirecting.from.number = ast_strdup(value);
328                 if (chan->cdr) {
329                         ast_cdr_setcid(chan->cdr, chan);
330                 }
331                 ast_channel_unlock(chan);
332         } else if (!strncasecmp("pres", data, 4)) {
333                 int i;
334                 char *val;
335
336                 val = ast_strdupa(value);
337                 ast_trim_blanks(val);
338
339                 if ((val[0] >= '0') && (val[0] <= '9')) {
340                         i = atoi(val);
341                 } else {
342                         i = ast_parse_caller_presentation(val);
343                 }
344
345                 if (i < 0) {
346                         ast_log(LOG_ERROR, "Unknown calling number presentation '%s', value unchanged\n", val);
347                 } else {
348                         chan->cid.cid_pres = i;
349                 }
350         } else if (!strncasecmp("ton", data, 3)) {
351                 chan->cid.cid_ton = atoi(value);
352         } else {
353                 ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
354         }
355
356         return 0;
357 }
358
359 static struct ast_custom_function callerid_function = {
360         .name = "CALLERID",
361         .read = callerid_read,
362         .read_max = 256,
363         .write = callerid_write,
364 };
365
366 static struct ast_custom_function callerpres_function = {
367         .name = "CALLERPRES",
368         .read = callerpres_read,
369         .read_max = 50,
370         .write = callerpres_write,
371 };
372
373 static int unload_module(void)
374 {
375         int res = ast_custom_function_unregister(&callerpres_function);
376         res |= ast_custom_function_unregister(&callerid_function);
377         return res;
378 }
379
380 static int load_module(void)
381 {
382         int res = ast_custom_function_register(&callerpres_function);
383         res |= ast_custom_function_register(&callerid_function);
384         return res;
385 }
386
387 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Caller ID related dialplan functions");