Allow for redirecting reasons to be set to arbitrary strings.
[asterisk/asterisk.git] / funcs / func_callerid.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999-2010, 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 Party ID related dialplan functions (Caller-ID, Connected-line, Redirecting)
20  *
21  * \ingroup functions
22  *
23  * See Also:
24  * \arg \ref AstCREDITS
25  */
26
27 /*** MODULEINFO
28         <support_level>core</support_level>
29  ***/
30
31 #include "asterisk.h"
32
33 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
34
35 #include "asterisk/module.h"
36 #include "asterisk/channel.h"
37 #include "asterisk/pbx.h"
38 #include "asterisk/utils.h"
39 #include "asterisk/app.h"
40 #include "asterisk/callerid.h"
41
42 /*
43  * Do not document the CALLERID(pres) datatype.
44  * The name and number now have their own presentation value.  The pres
45  * option will simply live on as a historical relic with as best
46  * as can be managed backward compatible meaning.
47  *
48  * Do not document the CALLERID(ton) datatype.
49  * It is an alias for num-plan.
50  *
51  * Do not document the CALLERID(ANI-subaddr-...) datatype.
52  * This is not used.
53  *
54  * Do not document the CONNECTEDLINE(source) datatype.
55  * It has turned out to not be needed.  The source value is really
56  * only useful as a possible tracing aid.
57  *
58  * Do not document the CONNECTEDLINE(pres) datatype.
59  * The name and number now have their own presentation value.  The pres
60  * option will simply live on as a historical relic with as best
61  * as can be managed backward compatible meaning.
62  *
63  * Do not document the CONNECTEDLINE(ton) datatype.
64  * It is an alias for num-plan.
65  *
66  * Do not document the REDIRECTING(pres) datatype.
67  * It has turned out that the from-pres and to-pres values must be kept
68  * separate.  They represent two different parties and there is a case when
69  * they are active at the same time.  The plain pres option will simply
70  * live on as a historical relic.
71  *
72  * Do not document the REDIRECTING(orig-pres), REDIRECTING(from-pres),
73  * or REDIRECTING(to-pres) datatypes.
74  * The name and number now have their own presentation value.  The orig-pres,
75  * from-pres, and to-pres options will simply live on as a historical relic
76  * with as best as can be managed backward compatible meaning.
77  *
78  * Do not document the REDIRECTING(orig-ton), REDIRECTING(from-ton),
79  * or REDIRECTING(to-ton) datatypes.
80  * They are aliases for orig-num-plan, from-num-plan, and to-num-plan
81  * respectively.
82  */
83 /*** DOCUMENTATION
84         <function name="CALLERID" language="en_US">
85                 <synopsis>
86                         Gets or sets Caller*ID data on the channel.
87                 </synopsis>
88                 <syntax>
89                         <parameter name="datatype" required="true">
90                                 <para>The allowable datatypes are:</para>
91                                 <enumlist>
92                                         <enum name = "all" />
93                                         <enum name = "name" />
94                                         <enum name = "name-valid" />
95                                         <enum name = "name-charset" />
96                                         <enum name = "name-pres" />
97                                         <enum name = "num" />
98                                         <enum name = "num-valid" />
99                                         <enum name = "num-plan" />
100                                         <enum name = "num-pres" />
101                                         <enum name = "subaddr" />
102                                         <enum name = "subaddr-valid" />
103                                         <enum name = "subaddr-type" />
104                                         <enum name = "subaddr-odd" />
105                                         <enum name = "tag" />
106                                         <enum name = "priv-all" />
107                                         <enum name = "priv-name" />
108                                         <enum name = "priv-name-valid" />
109                                         <enum name = "priv-name-charset" />
110                                         <enum name = "priv-name-pres" />
111                                         <enum name = "priv-num" />
112                                         <enum name = "priv-num-valid" />
113                                         <enum name = "priv-num-plan" />
114                                         <enum name = "priv-num-pres" />
115                                         <enum name = "priv-subaddr" />
116                                         <enum name = "priv-subaddr-valid" />
117                                         <enum name = "priv-subaddr-type" />
118                                         <enum name = "priv-subaddr-odd" />
119                                         <enum name = "priv-tag" />
120                                         <enum name = "ANI-all" />
121                                         <enum name = "ANI-name" />
122                                         <enum name = "ANI-name-valid" />
123                                         <enum name = "ANI-name-charset" />
124                                         <enum name = "ANI-name-pres" />
125                                         <enum name = "ANI-num" />
126                                         <enum name = "ANI-num-valid" />
127                                         <enum name = "ANI-num-plan" />
128                                         <enum name = "ANI-num-pres" />
129                                         <enum name = "ANI-tag" />
130                                         <enum name = "RDNIS" />
131                                         <enum name = "DNID" />
132                                         <enum name = "dnid-num-plan" />
133                                         <enum name = "dnid-subaddr" />
134                                         <enum name = "dnid-subaddr-valid" />
135                                         <enum name = "dnid-subaddr-type" />
136                                         <enum name = "dnid-subaddr-odd" />
137                                 </enumlist>
138                         </parameter>
139                         <parameter name="CID">
140                                 <para>Optional Caller*ID to parse instead of using the Caller*ID from the
141                                 channel. This parameter is only optional when reading the Caller*ID.</para>
142                         </parameter>
143                 </syntax>
144                 <description>
145                         <para>Gets or sets Caller*ID data on the channel. Uses channel callerid by
146                         default or optional callerid, if specified.</para>
147                         <para>The allowable values for the <replaceable>name-charset</replaceable>
148                         field are the following:</para>
149                         <enumlist>
150                                 <enum name = "unknown"><para>Unknown</para></enum>
151                                 <enum name = "iso8859-1"><para>ISO8859-1</para></enum>
152                                 <enum name = "withdrawn"><para>Withdrawn</para></enum>
153                                 <enum name = "iso8859-2"><para>ISO8859-2</para></enum>
154                                 <enum name = "iso8859-3"><para>ISO8859-3</para></enum>
155                                 <enum name = "iso8859-4"><para>ISO8859-4</para></enum>
156                                 <enum name = "iso8859-5"><para>ISO8859-5</para></enum>
157                                 <enum name = "iso8859-7"><para>ISO8859-7</para></enum>
158                                 <enum name = "bmp"><para>ISO10646 Bmp String</para></enum>
159                                 <enum name = "utf8"><para>ISO10646 UTF-8 String</para></enum>
160                         </enumlist>
161                 </description>
162         </function>
163         <function name="CALLERPRES" language="en_US">
164                 <synopsis>
165                         Gets or sets Caller*ID presentation on the channel.
166                 </synopsis>
167                 <syntax />
168                 <description>
169                         <para>Gets or sets Caller*ID presentation on the channel.
170                         This function is deprecated in favor of CALLERID(num-pres)
171                         and CALLERID(name-pres).
172                         The following values are valid:</para>
173                         <enumlist>
174                                 <enum name="allowed_not_screened">
175                                         <para>Presentation Allowed, Not Screened.</para>
176                                 </enum>
177                                 <enum name="allowed_passed_screen">
178                                         <para>Presentation Allowed, Passed Screen.</para>
179                                 </enum>
180                                 <enum name="allowed_failed_screen">
181                                         <para>Presentation Allowed, Failed Screen.</para>
182                                 </enum>
183                                 <enum name="allowed">
184                                         <para>Presentation Allowed, Network Number.</para>
185                                 </enum>
186                                 <enum name="prohib_not_screened">
187                                         <para>Presentation Prohibited, Not Screened.</para>
188                                 </enum>
189                                 <enum name="prohib_passed_screen">
190                                         <para>Presentation Prohibited, Passed Screen.</para>
191                                 </enum>
192                                 <enum name="prohib_failed_screen">
193                                         <para>Presentation Prohibited, Failed Screen.</para>
194                                 </enum>
195                                 <enum name="prohib">
196                                         <para>Presentation Prohibited, Network Number.</para>
197                                 </enum>
198                                 <enum name="unavailable">
199                                         <para>Number Unavailable.</para>
200                                 </enum>
201                         </enumlist>
202                 </description>
203         </function>
204         <function name="CONNECTEDLINE" language="en_US">
205                 <synopsis>
206                         Gets or sets Connected Line data on the channel.
207                 </synopsis>
208                 <syntax>
209                         <parameter name="datatype" required="true">
210                                 <para>The allowable datatypes are:</para>
211                                 <enumlist>
212                                         <enum name = "all" />
213                                         <enum name = "name" />
214                                         <enum name = "name-valid" />
215                                         <enum name = "name-charset" />
216                                         <enum name = "name-pres" />
217                                         <enum name = "num" />
218                                         <enum name = "num-valid" />
219                                         <enum name = "num-plan" />
220                                         <enum name = "num-pres" />
221                                         <enum name = "subaddr" />
222                                         <enum name = "subaddr-valid" />
223                                         <enum name = "subaddr-type" />
224                                         <enum name = "subaddr-odd" />
225                                         <enum name = "tag" />
226                                         <enum name = "priv-all" />
227                                         <enum name = "priv-name" />
228                                         <enum name = "priv-name-valid" />
229                                         <enum name = "priv-name-charset" />
230                                         <enum name = "priv-name-pres" />
231                                         <enum name = "priv-num" />
232                                         <enum name = "priv-num-valid" />
233                                         <enum name = "priv-num-plan" />
234                                         <enum name = "priv-num-pres" />
235                                         <enum name = "priv-subaddr" />
236                                         <enum name = "priv-subaddr-valid" />
237                                         <enum name = "priv-subaddr-type" />
238                                         <enum name = "priv-subaddr-odd" />
239                                         <enum name = "priv-tag" />
240                                 </enumlist>
241                         </parameter>
242                         <parameter name="i">
243                                 <para>If set, this will prevent the channel from sending out protocol
244                                 messages because of the value being set</para>
245                         </parameter>
246                 </syntax>
247                 <description>
248                         <para>Gets or sets Connected Line data on the channel.</para>
249                         <para>The allowable values for the <replaceable>name-charset</replaceable>
250                         field are the following:</para>
251                         <enumlist>
252                                 <enum name = "unknown"><para>Unknown</para></enum>
253                                 <enum name = "iso8859-1"><para>ISO8859-1</para></enum>
254                                 <enum name = "withdrawn"><para>Withdrawn</para></enum>
255                                 <enum name = "iso8859-2"><para>ISO8859-2</para></enum>
256                                 <enum name = "iso8859-3"><para>ISO8859-3</para></enum>
257                                 <enum name = "iso8859-4"><para>ISO8859-4</para></enum>
258                                 <enum name = "iso8859-5"><para>ISO8859-5</para></enum>
259                                 <enum name = "iso8859-7"><para>ISO8859-7</para></enum>
260                                 <enum name = "bmp"><para>ISO10646 Bmp String</para></enum>
261                                 <enum name = "utf8"><para>ISO10646 UTF-8 String</para></enum>
262                         </enumlist>
263                 </description>
264         </function>
265         <function name="REDIRECTING" language="en_US">
266                 <synopsis>
267                         Gets or sets Redirecting data on the channel.
268                 </synopsis>
269                 <syntax>
270                         <parameter name="datatype" required="true">
271                                 <para>The allowable datatypes are:</para>
272                                 <enumlist>
273                                         <enum name = "orig-all" />
274                                         <enum name = "orig-name" />
275                                         <enum name = "orig-name-valid" />
276                                         <enum name = "orig-name-charset" />
277                                         <enum name = "orig-name-pres" />
278                                         <enum name = "orig-num" />
279                                         <enum name = "orig-num-valid" />
280                                         <enum name = "orig-num-plan" />
281                                         <enum name = "orig-num-pres" />
282                                         <enum name = "orig-subaddr" />
283                                         <enum name = "orig-subaddr-valid" />
284                                         <enum name = "orig-subaddr-type" />
285                                         <enum name = "orig-subaddr-odd" />
286                                         <enum name = "orig-tag" />
287                                         <enum name = "orig-reason" />
288                                         <enum name = "from-all" />
289                                         <enum name = "from-name" />
290                                         <enum name = "from-name-valid" />
291                                         <enum name = "from-name-charset" />
292                                         <enum name = "from-name-pres" />
293                                         <enum name = "from-num" />
294                                         <enum name = "from-num-valid" />
295                                         <enum name = "from-num-plan" />
296                                         <enum name = "from-num-pres" />
297                                         <enum name = "from-subaddr" />
298                                         <enum name = "from-subaddr-valid" />
299                                         <enum name = "from-subaddr-type" />
300                                         <enum name = "from-subaddr-odd" />
301                                         <enum name = "from-tag" />
302                                         <enum name = "to-all" />
303                                         <enum name = "to-name" />
304                                         <enum name = "to-name-valid" />
305                                         <enum name = "to-name-charset" />
306                                         <enum name = "to-name-pres" />
307                                         <enum name = "to-num" />
308                                         <enum name = "to-num-valid" />
309                                         <enum name = "to-num-plan" />
310                                         <enum name = "to-num-pres" />
311                                         <enum name = "to-subaddr" />
312                                         <enum name = "to-subaddr-valid" />
313                                         <enum name = "to-subaddr-type" />
314                                         <enum name = "to-subaddr-odd" />
315                                         <enum name = "to-tag" />
316                                         <enum name = "priv-orig-all" />
317                                         <enum name = "priv-orig-name" />
318                                         <enum name = "priv-orig-name-valid" />
319                                         <enum name = "priv-orig-name-charset" />
320                                         <enum name = "priv-orig-name-pres" />
321                                         <enum name = "priv-orig-num" />
322                                         <enum name = "priv-orig-num-valid" />
323                                         <enum name = "priv-orig-num-plan" />
324                                         <enum name = "priv-orig-num-pres" />
325                                         <enum name = "priv-orig-subaddr" />
326                                         <enum name = "priv-orig-subaddr-valid" />
327                                         <enum name = "priv-orig-subaddr-type" />
328                                         <enum name = "priv-orig-subaddr-odd" />
329                                         <enum name = "priv-orig-tag" />
330                                         <enum name = "priv-from-all" />
331                                         <enum name = "priv-from-name" />
332                                         <enum name = "priv-from-name-valid" />
333                                         <enum name = "priv-from-name-charset" />
334                                         <enum name = "priv-from-name-pres" />
335                                         <enum name = "priv-from-num" />
336                                         <enum name = "priv-from-num-valid" />
337                                         <enum name = "priv-from-num-plan" />
338                                         <enum name = "priv-from-num-pres" />
339                                         <enum name = "priv-from-subaddr" />
340                                         <enum name = "priv-from-subaddr-valid" />
341                                         <enum name = "priv-from-subaddr-type" />
342                                         <enum name = "priv-from-subaddr-odd" />
343                                         <enum name = "priv-from-tag" />
344                                         <enum name = "priv-to-all" />
345                                         <enum name = "priv-to-name" />
346                                         <enum name = "priv-to-name-valid" />
347                                         <enum name = "priv-to-name-charset" />
348                                         <enum name = "priv-to-name-pres" />
349                                         <enum name = "priv-to-num" />
350                                         <enum name = "priv-to-num-valid" />
351                                         <enum name = "priv-to-num-plan" />
352                                         <enum name = "priv-to-num-pres" />
353                                         <enum name = "priv-to-subaddr" />
354                                         <enum name = "priv-to-subaddr-valid" />
355                                         <enum name = "priv-to-subaddr-type" />
356                                         <enum name = "priv-to-subaddr-odd" />
357                                         <enum name = "priv-to-tag" />
358                                         <enum name = "reason" />
359                                         <enum name = "count" />
360                                 </enumlist>
361                         </parameter>
362                         <parameter name="i">
363                                 <para>If set, this will prevent the channel from sending out protocol
364                                 messages because of the value being set</para>
365                         </parameter>
366                 </syntax>
367                 <description>
368                         <para>Gets or sets Redirecting data on the channel.</para>
369                         <para>The allowable values for the <replaceable>reason</replaceable>
370                         and <replaceable>orig-reason</replaceable> fields are the following:</para>
371                         <enumlist>
372                                 <enum name = "unknown"><para>Unknown</para></enum>
373                                 <enum name = "cfb"><para>Call Forwarding Busy</para></enum>
374                                 <enum name = "cfnr"><para>Call Forwarding No Reply</para></enum>
375                                 <enum name = "unavailable"><para>Callee is Unavailable</para></enum>
376                                 <enum name = "time_of_day"><para>Time of Day</para></enum>
377                                 <enum name = "dnd"><para>Do Not Disturb</para></enum>
378                                 <enum name = "deflection"><para>Call Deflection</para></enum>
379                                 <enum name = "follow_me"><para>Follow Me</para></enum>
380                                 <enum name = "out_of_order"><para>Called DTE Out-Of-Order</para></enum>
381                                 <enum name = "away"><para>Callee is Away</para></enum>
382                                 <enum name = "cf_dte"><para>Call Forwarding By The Called DTE</para></enum>
383                                 <enum name = "cfu"><para>Call Forwarding Unconditional</para></enum>
384                         </enumlist>
385                         <para>The allowable values for the <replaceable>xxx-name-charset</replaceable>
386                         field are the following:</para>
387                         <enumlist>
388                                 <enum name = "unknown"><para>Unknown</para></enum>
389                                 <enum name = "iso8859-1"><para>ISO8859-1</para></enum>
390                                 <enum name = "withdrawn"><para>Withdrawn</para></enum>
391                                 <enum name = "iso8859-2"><para>ISO8859-2</para></enum>
392                                 <enum name = "iso8859-3"><para>ISO8859-3</para></enum>
393                                 <enum name = "iso8859-4"><para>ISO8859-4</para></enum>
394                                 <enum name = "iso8859-5"><para>ISO8859-5</para></enum>
395                                 <enum name = "iso8859-7"><para>ISO8859-7</para></enum>
396                                 <enum name = "bmp"><para>ISO10646 Bmp String</para></enum>
397                                 <enum name = "utf8"><para>ISO10646 UTF-8 String</para></enum>
398                         </enumlist>
399                 </description>
400         </function>
401  ***/
402
403 enum ID_FIELD_STATUS {
404         ID_FIELD_VALID,
405         ID_FIELD_INVALID,
406         ID_FIELD_UNKNOWN
407 };
408
409 AST_DEFINE_APP_ARGS_TYPE(ast_party_func_args,
410         AST_APP_ARG(member);    /*!< Member name */
411         AST_APP_ARG(opts);              /*!< Options token */
412         AST_APP_ARG(other);             /*!< Any remining unused arguments */
413         );
414
415 AST_DEFINE_APP_ARGS_TYPE(ast_party_members,
416         AST_APP_ARG(subnames[10]);      /*!< Option member subnames */
417         );
418
419 enum CONNECTED_LINE_OPT_FLAGS {
420         CONNECTED_LINE_OPT_INHIBIT = (1 << 0),
421 };
422 enum CONNECTED_LINE_OPT_ARGS {
423         CONNECTED_LINE_OPT_DUMMY,       /*!< Delete this if CONNECTED_LINE ever gets an option with parameters. */
424
425         /*! \note This entry _MUST_ be the last one in the enum */
426         CONNECTED_LINE_OPT_ARG_ARRAY_SIZE
427 };
428
429 AST_APP_OPTIONS(connectedline_opts, BEGIN_OPTIONS
430         AST_APP_OPTION('i', CONNECTED_LINE_OPT_INHIBIT),
431 END_OPTIONS);
432
433 enum REDIRECTING_OPT_FLAGS {
434         REDIRECTING_OPT_INHIBIT = (1 << 0),
435 };
436 enum REDIRECTING_OPT_ARGS {
437         REDIRECTING_OPT_DUMMY,  /*!< Delete this if REDIRECTING ever gets an option with parameters. */
438
439         /*! \note This entry _MUST_ be the last one in the enum */
440         REDIRECTING_OPT_ARG_ARRAY_SIZE
441 };
442
443 AST_APP_OPTIONS(redirecting_opts, BEGIN_OPTIONS
444         AST_APP_OPTION('i', REDIRECTING_OPT_INHIBIT),
445 END_OPTIONS);
446
447 /*!
448  * \internal
449  * \brief Read values from the party name struct.
450  * \since 1.8
451  *
452  * \param buf Buffer to fill with read value.
453  * \param len Length of the buffer.
454  * \param argc Number of party member subnames.
455  * \param argv Party member subnames given.
456  * \param name Party name to get values from.
457  *
458  * \retval ID_FIELD_VALID on success.
459  * \retval ID_FIELD_UNKNOWN on unknown field name.
460  */
461 static enum ID_FIELD_STATUS party_name_read(char *buf, size_t len, int argc, char *argv[], const struct ast_party_name *name)
462 {
463         enum ID_FIELD_STATUS status;
464
465         status = ID_FIELD_VALID;
466
467         if (argc == 0) {
468                 /* We want the name string */
469                 if (name->valid && name->str) {
470                         ast_copy_string(buf, name->str, len);
471                 }
472         } else if (argc == 1 && !strcasecmp("valid", argv[0])) {
473                 snprintf(buf, len, "%d", name->valid);
474         } else if (argc == 1 && !strcasecmp("charset", argv[0])) {
475                 ast_copy_string(buf, ast_party_name_charset_str(name->char_set), len);
476         } else if (argc == 1 && !strncasecmp("pres", argv[0], 4)) {
477                 /* Accept pres[entation] */
478                 ast_copy_string(buf, ast_named_caller_presentation(name->presentation), len);
479         } else {
480                 status = ID_FIELD_UNKNOWN;
481         }
482
483         return status;
484 }
485
486 /*!
487  * \internal
488  * \brief Read values from the party number struct.
489  * \since 1.8
490  *
491  * \param buf Buffer to fill with read value.
492  * \param len Length of the buffer.
493  * \param argc Number of party member subnames.
494  * \param argv Party member subnames given.
495  * \param number Party number to get values from.
496  *
497  * \retval ID_FIELD_VALID on success.
498  * \retval ID_FIELD_UNKNOWN on unknown field name.
499  */
500 static enum ID_FIELD_STATUS party_number_read(char *buf, size_t len, int argc, char *argv[], const struct ast_party_number *number)
501 {
502         enum ID_FIELD_STATUS status;
503
504         status = ID_FIELD_VALID;
505
506         if (argc == 0) {
507                 /* We want the number string */
508                 if (number->valid && number->str) {
509                         ast_copy_string(buf, number->str, len);
510                 }
511         } else if (argc == 1 && !strcasecmp("valid", argv[0])) {
512                 snprintf(buf, len, "%d", number->valid);
513         } else if (argc == 1 && !strcasecmp("plan", argv[0])) {
514                 snprintf(buf, len, "%d", number->plan);
515         } else if (argc == 1 && !strncasecmp("pres", argv[0], 4)) {
516                 /* Accept pres[entation] */
517                 ast_copy_string(buf, ast_named_caller_presentation(number->presentation), len);
518         } else {
519                 status = ID_FIELD_UNKNOWN;
520         }
521
522         return status;
523 }
524
525 /*!
526  * \internal
527  * \brief Read values from the party subaddress struct.
528  * \since 1.8
529  *
530  * \param buf Buffer to fill with read value.
531  * \param len Length of the buffer.
532  * \param argc Number of party member subnames.
533  * \param argv Party member subnames given.
534  * \param subaddress Party subaddress to get values from.
535  *
536  * \retval ID_FIELD_VALID on success.
537  * \retval ID_FIELD_UNKNOWN on unknown field name.
538  */
539 static enum ID_FIELD_STATUS party_subaddress_read(char *buf, size_t len, int argc, char *argv[], const struct ast_party_subaddress *subaddress)
540 {
541         enum ID_FIELD_STATUS status;
542
543         status = ID_FIELD_VALID;
544
545         if (argc == 0) {
546                 /* We want the subaddress string */
547                 if (subaddress->str) {
548                         ast_copy_string(buf, subaddress->str, len);
549                 }
550         } else if (argc == 1 && !strcasecmp("valid", argv[0])) {
551                 snprintf(buf, len, "%d", subaddress->valid);
552         } else if (argc == 1 && !strcasecmp("type", argv[0])) {
553                 snprintf(buf, len, "%d", subaddress->type);
554         } else if (argc == 1 && !strcasecmp("odd", argv[0])) {
555                 snprintf(buf, len, "%d", subaddress->odd_even_indicator);
556         } else {
557                 status = ID_FIELD_UNKNOWN;
558         }
559
560         return status;
561 }
562
563 /*!
564  * \internal
565  * \brief Read values from the party id struct.
566  * \since 1.8
567  *
568  * \param buf Buffer to fill with read value.
569  * \param len Length of the buffer.
570  * \param argc Number of party member subnames.
571  * \param argv Party member subnames given.
572  * \param id Party id to get values from.
573  *
574  * \retval ID_FIELD_VALID on success.
575  * \retval ID_FIELD_UNKNOWN on unknown field name.
576  */
577 static enum ID_FIELD_STATUS party_id_read(char *buf, size_t len, int argc, char *argv[], const struct ast_party_id *id)
578 {
579         enum ID_FIELD_STATUS status;
580
581         if (argc == 0) {
582                 /* Must have at least one subname. */
583                 return ID_FIELD_UNKNOWN;
584         }
585
586         status = ID_FIELD_VALID;
587
588         if (argc == 1 && !strcasecmp("all", argv[0])) {
589                 snprintf(buf, len, "\"%s\" <%s>",
590                          S_COR(id->name.valid, id->name.str, ""),
591                          S_COR(id->number.valid, id->number.str, ""));
592         } else if (!strcasecmp("name", argv[0])) {
593                 status = party_name_read(buf, len, argc - 1, argv + 1, &id->name);
594         } else if (!strncasecmp("num", argv[0], 3)) {
595                 /* Accept num[ber] */
596                 status = party_number_read(buf, len, argc - 1, argv + 1, &id->number);
597         } else if (!strncasecmp("subaddr", argv[0], 7)) {
598                 /* Accept subaddr[ess] */
599                 status = party_subaddress_read(buf, len, argc - 1, argv + 1, &id->subaddress);
600         } else if (argc == 1 && !strcasecmp("tag", argv[0])) {
601                 if (id->tag) {
602                         ast_copy_string(buf, id->tag, len);
603                 }
604         } else if (argc == 1 && !strcasecmp("ton", argv[0])) {
605                 /* ton is an alias for num-plan */
606                 snprintf(buf, len, "%d", id->number.plan);
607         } else if (argc == 1 && !strncasecmp("pres", argv[0], 4)) {
608                 /*
609                  * Accept pres[entation]
610                  * This is the combined name/number presentation.
611                  */
612                 ast_copy_string(buf,
613                         ast_named_caller_presentation(ast_party_id_presentation(id)), len);
614         } else {
615                 status = ID_FIELD_UNKNOWN;
616         }
617
618         return status;
619 }
620
621 /*!
622  * \internal
623  * \brief Write new values to the party name struct
624  * \since 1.8
625  *
626  * \param name Party name struct to write values
627  * \param argc Number of party member subnames.
628  * \param argv Party member subnames given.
629  * \param value Value to assign to the party name.
630  *
631  * \retval ID_FIELD_VALID on success.
632  * \retval ID_FIELD_INVALID on error with field value.
633  * \retval ID_FIELD_UNKNOWN on unknown field name.
634  */
635 static enum ID_FIELD_STATUS party_name_write(struct ast_party_name *name, int argc, char *argv[], const char *value)
636 {
637         char *val;
638         enum ID_FIELD_STATUS status;
639
640         status = ID_FIELD_VALID;
641
642         if (argc == 0) {
643                 /* We are setting the name string */
644                 name->valid = 1;
645                 name->str = ast_strdup(value);
646                 ast_trim_blanks(name->str);
647         } else if (argc == 1 && !strcasecmp("valid", argv[0])) {
648                 name->valid = atoi(value) ? 1 : 0;
649         } else if (argc == 1 && !strcasecmp("charset", argv[0])) {
650                 int char_set;
651
652                 val = ast_strdupa(value);
653                 ast_trim_blanks(val);
654
655                 if (('0' <= val[0]) && (val[0] <= '9')) {
656                         char_set = atoi(val);
657                 } else {
658                         char_set = ast_party_name_charset_parse(val);
659                 }
660
661                 if (char_set < 0) {
662                         ast_log(LOG_ERROR,
663                                 "Unknown name char-set '%s', value unchanged\n", val);
664                         status = ID_FIELD_INVALID;
665                 } else {
666                         name->char_set = char_set;
667                 }
668         } else if (argc == 1 && !strncasecmp("pres", argv[0], 4)) {
669                 int pres;
670
671                 /* Accept pres[entation] */
672                 val = ast_strdupa(value);
673                 ast_trim_blanks(val);
674
675                 if (('0' <= val[0]) && (val[0] <= '9')) {
676                         pres = atoi(val);
677                 } else {
678                         pres = ast_parse_caller_presentation(val);
679                 }
680
681                 if (pres < 0) {
682                         ast_log(LOG_ERROR,
683                                 "Unknown name presentation '%s', value unchanged\n", val);
684                         status = ID_FIELD_INVALID;
685                 } else {
686                         name->presentation = pres;
687                 }
688         } else {
689                 status = ID_FIELD_UNKNOWN;
690         }
691
692         return status;
693 }
694
695 /*!
696  * \internal
697  * \brief Write new values to the party number struct
698  * \since 1.8
699  *
700  * \param number Party number struct to write values
701  * \param argc Number of party member subnames.
702  * \param argv Party member subnames given.
703  * \param value Value to assign to the party number.
704  *
705  * \retval ID_FIELD_VALID on success.
706  * \retval ID_FIELD_INVALID on error with field value.
707  * \retval ID_FIELD_UNKNOWN on unknown field name.
708  */
709 static enum ID_FIELD_STATUS party_number_write(struct ast_party_number *number, int argc, char *argv[], const char *value)
710 {
711         char *val;
712         enum ID_FIELD_STATUS status;
713
714         status = ID_FIELD_VALID;
715
716         if (argc == 0) {
717                 /* We are setting the number string */
718                 number->valid = 1;
719                 number->str = ast_strdup(value);
720                 ast_trim_blanks(number->str);
721         } else if (argc == 1 && !strcasecmp("valid", argv[0])) {
722                 number->valid = atoi(value) ? 1 : 0;
723         } else if (argc == 1 && !strcasecmp("plan", argv[0])) {
724                 val = ast_strdupa(value);
725                 ast_trim_blanks(val);
726
727                 if (('0' <= val[0]) && (val[0] <= '9')) {
728                         number->plan = atoi(val);
729                 } else {
730                         ast_log(LOG_ERROR,
731                                 "Unknown type-of-number/numbering-plan '%s', value unchanged\n", val);
732                         status = ID_FIELD_INVALID;
733                 }
734         } else if (argc == 1 && !strncasecmp("pres", argv[0], 4)) {
735                 int pres;
736
737                 /* Accept pres[entation] */
738                 val = ast_strdupa(value);
739                 ast_trim_blanks(val);
740
741                 if (('0' <= val[0]) && (val[0] <= '9')) {
742                         pres = atoi(val);
743                 } else {
744                         pres = ast_parse_caller_presentation(val);
745                 }
746
747                 if (pres < 0) {
748                         ast_log(LOG_ERROR,
749                                 "Unknown number presentation '%s', value unchanged\n", val);
750                         status = ID_FIELD_INVALID;
751                 } else {
752                         number->presentation = pres;
753                 }
754         } else {
755                 status = ID_FIELD_UNKNOWN;
756         }
757
758         return status;
759 }
760
761 /*!
762  * \internal
763  * \brief Write new values to the party subaddress struct
764  * \since 1.8
765  *
766  * \param subaddress Party subaddress struct to write values
767  * \param argc Number of party member subnames.
768  * \param argv Party member subnames given.
769  * \param value Value to assign to the party subaddress.
770  *
771  * \retval ID_FIELD_VALID on success.
772  * \retval ID_FIELD_INVALID on error with field value.
773  * \retval ID_FIELD_UNKNOWN on unknown field name.
774  */
775 static enum ID_FIELD_STATUS party_subaddress_write(struct ast_party_subaddress *subaddress, int argc, char *argv[], const char *value)
776 {
777         enum ID_FIELD_STATUS status;
778
779         status = ID_FIELD_VALID;
780
781         if (argc == 0) {
782                 /* We are setting the subaddress string */
783                 subaddress->str = ast_strdup(value);
784                 ast_trim_blanks(subaddress->str);
785         } else if (argc == 1 && !strcasecmp("valid", argv[0])) {
786                 subaddress->valid = atoi(value) ? 1 : 0;
787         } else if (argc == 1 && !strcasecmp("type", argv[0])) {
788                 subaddress->type = atoi(value) ? 2 : 0;
789         } else if (argc == 1 && !strcasecmp("odd", argv[0])) {
790                 subaddress->odd_even_indicator = atoi(value) ? 1 : 0;
791         } else {
792                 status = ID_FIELD_UNKNOWN;
793         }
794
795         return status;
796 }
797
798 /*!
799  * \internal
800  * \brief Write new values to the party id struct
801  * \since 1.8
802  *
803  * \param id Party ID struct to write values
804  * \param argc Number of party member subnames.
805  * \param argv Party member subnames given.
806  * \param value Value to assign to the party id.
807  *
808  * \retval ID_FIELD_VALID on success.
809  * \retval ID_FIELD_INVALID on error with field value.
810  * \retval ID_FIELD_UNKNOWN on unknown field name.
811  */
812 static enum ID_FIELD_STATUS party_id_write(struct ast_party_id *id, int argc, char *argv[], const char *value)
813 {
814         char *val;
815         enum ID_FIELD_STATUS status;
816
817         if (argc == 0) {
818                 /* Must have at least one subname. */
819                 return ID_FIELD_UNKNOWN;
820         }
821
822         status = ID_FIELD_VALID;
823
824         if (argc == 1 && !strcasecmp("all", argv[0])) {
825                 char name[256];
826                 char num[256];
827
828                 ast_callerid_split(value, name, sizeof(name), num, sizeof(num));
829                 id->name.valid = 1;
830                 id->name.str = ast_strdup(name);
831                 if (!id->name.str) {
832                         return ID_FIELD_INVALID;
833                 }
834                 id->number.valid = 1;
835                 id->number.str = ast_strdup(num);
836                 if (!id->number.str) {
837                         return ID_FIELD_INVALID;
838                 }
839         } else if (!strcasecmp("name", argv[0])) {
840                 status = party_name_write(&id->name, argc - 1, argv + 1, value);
841         } else if (!strncasecmp("num", argv[0], 3)) {
842                 /* Accept num[ber] */
843                 status = party_number_write(&id->number, argc - 1, argv + 1, value);
844         } else if (!strncasecmp("subaddr", argv[0], 7)) {
845                 /* Accept subaddr[ess] */
846                 status = party_subaddress_write(&id->subaddress, argc - 1, argv + 1, value);
847         } else if (argc == 1 && !strcasecmp("tag", argv[0])) {
848                 id->tag = ast_strdup(value);
849                 ast_trim_blanks(id->tag);
850         } else if (argc == 1 && !strcasecmp("ton", argv[0])) {
851                 /* ton is an alias for num-plan */
852                 argv[0] = "plan";
853                 status = party_number_write(&id->number, argc, argv, value);
854         } else if (argc == 1 && !strncasecmp("pres", argv[0], 4)) {
855                 int pres;
856
857                 /*
858                  * Accept pres[entation]
859                  * This is the combined name/number presentation.
860                  */
861                 val = ast_strdupa(value);
862                 ast_trim_blanks(val);
863
864                 if (('0' <= val[0]) && (val[0] <= '9')) {
865                         pres = atoi(val);
866                 } else {
867                         pres = ast_parse_caller_presentation(val);
868                 }
869
870                 if (pres < 0) {
871                         ast_log(LOG_ERROR,
872                                 "Unknown combined presentation '%s', value unchanged\n", val);
873                         status = ID_FIELD_INVALID;
874                 } else {
875                         id->name.presentation = pres;
876                         id->number.presentation = pres;
877                 }
878         } else {
879                 status = ID_FIELD_UNKNOWN;
880         }
881
882         return status;
883 }
884
885 /*! TRUE if we have already notified about CALLERPRES being deprecated. */
886 static int callerpres_deprecate_notify;
887
888 /*!
889  * \internal
890  * \brief Read values from the caller-id presentation information struct.
891  *
892  * \param chan Asterisk channel to read
893  * \param cmd Not used
894  * \param data Caller-id presentation function datatype string
895  * \param buf Buffer to fill with read value.
896  * \param len Length of the buffer
897  *
898  * \retval 0 on success.
899  * \retval -1 on error.
900  */
901 static int callerpres_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
902 {
903         if (!callerpres_deprecate_notify) {
904                 callerpres_deprecate_notify = 1;
905                 ast_log(LOG_WARNING, "CALLERPRES is deprecated."
906                         "  Use CALLERID(name-pres) or CALLERID(num-pres) instead.\n");
907         }
908         ast_copy_string(buf,
909                 ast_named_caller_presentation(ast_party_id_presentation(&ast_channel_caller(chan)->id)), len);
910         return 0;
911 }
912
913 /*!
914  * \internal
915  * \brief Write new values to the caller-id presentation information struct.
916  *
917  * \param chan Asterisk channel to update
918  * \param cmd Not used
919  * \param data Caller-id presentation function datatype string
920  * \param value Value to assign to the caller-id presentation information struct.
921  *
922  * \retval 0 on success.
923  * \retval -1 on error.
924  */
925 static int callerpres_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
926 {
927         int pres;
928
929         if (!callerpres_deprecate_notify) {
930                 callerpres_deprecate_notify = 1;
931                 ast_log(LOG_WARNING, "CALLERPRES is deprecated."
932                         "  Use CALLERID(name-pres) or CALLERID(num-pres) instead.\n");
933         }
934
935         pres = ast_parse_caller_presentation(value);
936         if (pres < 0) {
937                 ast_log(LOG_WARNING, "'%s' is not a valid presentation (see 'show function CALLERPRES')\n", value);
938         } else {
939                 ast_channel_caller(chan)->id.name.presentation = pres;
940                 ast_channel_caller(chan)->id.number.presentation = pres;
941         }
942         return 0;
943 }
944
945 /*!
946  * \internal
947  * \brief Read values from the caller-id information struct.
948  *
949  * \param chan Asterisk channel to read
950  * \param cmd Not used
951  * \param data Caller-id function datatype string
952  * \param buf Buffer to fill with read value.
953  * \param len Length of the buffer
954  *
955  * \retval 0 on success.
956  * \retval -1 on error.
957  */
958 static int callerid_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
959 {
960         char *parms;
961         struct ast_party_members member;
962         AST_DECLARE_APP_ARGS(args,
963                 AST_APP_ARG(member);    /*!< Member name */
964                 AST_APP_ARG(cid);               /*!< Optional caller id to parse instead of from the channel. */
965                 );
966
967         /* Ensure that the buffer is empty */
968         *buf = 0;
969
970         if (!chan) {
971                 return -1;
972         }
973
974         parms = ast_strdupa(data);
975         AST_STANDARD_APP_ARGS(args, parms);
976         if (args.argc == 0) {
977                 /* Must have at least one argument. */
978                 return -1;
979         }
980
981         AST_NONSTANDARD_APP_ARGS(member, args.member, '-');
982         if (member.argc == 0 || ARRAY_LEN(member.subnames) <= member.argc) {
983                 /* Too few or too many subnames */
984                 return -1;
985         }
986
987         if (args.argc == 2) {
988                 char name[80];
989                 char num[80];
990
991                 ast_callerid_split(args.cid, name, sizeof(name), num, sizeof(num));
992
993                 if (member.argc == 1 && !strcasecmp("all", member.argv[0])) {
994                         snprintf(buf, len, "\"%s\" <%s>", name, num);
995                 } else if (member.argc == 1 && !strcasecmp("name", member.argv[0])) {
996                         ast_copy_string(buf, name, len);
997                 } else if (member.argc == 1 && !strncasecmp("num", member.argv[0], 3)) {
998                         /* Accept num[ber] */
999                         ast_copy_string(buf, num, len);
1000                 } else {
1001                         ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
1002                 }
1003         } else {
1004                 enum ID_FIELD_STATUS status;
1005                 ast_channel_lock(chan);
1006
1007                 if (member.argc == 1 && !strcasecmp("rdnis", member.argv[0])) {
1008                         if (ast_channel_redirecting(chan)->from.number.valid
1009                                 && ast_channel_redirecting(chan)->from.number.str) {
1010                                 ast_copy_string(buf, ast_channel_redirecting(chan)->from.number.str, len);
1011                         }
1012                 } else if (!strcasecmp("dnid", member.argv[0])) {
1013                         if (member.argc == 1) {
1014                                 /* Setup as if user had given dnid-num instead. */
1015                                 member.argc = 2;
1016                                 member.argv[1] = "num";
1017                         }
1018                         if (!strncasecmp("num", member.argv[1], 3)) {
1019                                 /*
1020                                  * Accept num[ber]
1021                                  * dnid-num...
1022                                  */
1023                                 if (member.argc == 2) {
1024                                         /* dnid-num */
1025                                         if (ast_channel_dialed(chan)->number.str) {
1026                                                 ast_copy_string(buf, ast_channel_dialed(chan)->number.str, len);
1027                                         }
1028                                 } else if (member.argc == 3 && !strcasecmp("plan", member.argv[2])) {
1029                                         /* dnid-num-plan */
1030                                         snprintf(buf, len, "%d", ast_channel_dialed(chan)->number.plan);
1031                                 } else {
1032                                         ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
1033                                 }
1034                         } else if (!strncasecmp("subaddr", member.argv[1], 7)) {
1035                                 /*
1036                                  * Accept subaddr[ess]
1037                                  * dnid-subaddr...
1038                                  */
1039                                 status = party_subaddress_read(buf, len, member.argc - 2, member.argv + 2,
1040                                         &ast_channel_dialed(chan)->subaddress);
1041                                 switch (status) {
1042                                 case ID_FIELD_VALID:
1043                                 case ID_FIELD_INVALID:
1044                                         break;
1045                                 default:
1046                                         ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
1047                                         break;
1048                                 }
1049                         } else {
1050                                 ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
1051                         }
1052                 } else if (member.argc == 1 && !strcasecmp("ani2", member.argv[0])) {
1053                         snprintf(buf, len, "%d", ast_channel_caller(chan)->ani2);
1054                 } else if (!strcasecmp("ani", member.argv[0])) {
1055                         if (member.argc == 1) {
1056                                 /* Setup as if user had given ani-num instead. */
1057                                 member.argc = 2;
1058                                 member.argv[1] = "num";
1059                         }
1060                         status = party_id_read(buf, len, member.argc - 1, member.argv + 1,
1061                                 &ast_channel_caller(chan)->ani);
1062                         switch (status) {
1063                         case ID_FIELD_VALID:
1064                         case ID_FIELD_INVALID:
1065                                 break;
1066                         default:
1067                                 ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
1068                                 break;
1069                         }
1070                 } else if (!strcasecmp("priv", member.argv[0])) {
1071                         status = party_id_read(buf, len, member.argc - 1, member.argv + 1,
1072                                 &ast_channel_caller(chan)->priv);
1073                         switch (status) {
1074                         case ID_FIELD_VALID:
1075                         case ID_FIELD_INVALID:
1076                                 break;
1077                         default:
1078                                 ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
1079                                 break;
1080                         }
1081                 } else {
1082                         status = party_id_read(buf, len, member.argc, member.argv, &ast_channel_caller(chan)->id);
1083                         switch (status) {
1084                         case ID_FIELD_VALID:
1085                         case ID_FIELD_INVALID:
1086                                 break;
1087                         default:
1088                                 ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
1089                                 break;
1090                         }
1091                 }
1092
1093                 ast_channel_unlock(chan);
1094         }
1095
1096         return 0;
1097 }
1098
1099 /*!
1100  * \internal
1101  * \brief Write new values to the caller-id information struct.
1102  *
1103  * \param chan Asterisk channel to update
1104  * \param cmd Not used
1105  * \param data Caller-id function datatype string
1106  * \param value Value to assign to the caller-id information struct.
1107  *
1108  * \retval 0 on success.
1109  * \retval -1 on error.
1110  */
1111 static int callerid_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
1112 {
1113         struct ast_party_caller caller;
1114         struct ast_party_dialed dialed;
1115         enum ID_FIELD_STATUS status;
1116         char *val;
1117         char *parms;
1118         struct ast_party_func_args args;
1119         struct ast_party_members member;
1120
1121         if (!value || !chan) {
1122                 return -1;
1123         }
1124
1125         parms = ast_strdupa(data);
1126         AST_STANDARD_APP_ARGS(args, parms);
1127         if (args.argc == 0) {
1128                 /* Must have at least one argument. */
1129                 return -1;
1130         }
1131
1132         AST_NONSTANDARD_APP_ARGS(member, args.member, '-');
1133         if (member.argc == 0 || ARRAY_LEN(member.subnames) <= member.argc) {
1134                 /* Too few or too many subnames */
1135                 return -1;
1136         }
1137
1138         value = ast_skip_blanks(value);
1139
1140         ast_channel_lock(chan);
1141         if (member.argc == 1 && !strcasecmp("rdnis", member.argv[0])) {
1142                 ast_channel_redirecting(chan)->from.number.valid = 1;
1143                 ast_free(ast_channel_redirecting(chan)->from.number.str);
1144                 ast_channel_redirecting(chan)->from.number.str = ast_strdup(value);
1145                 if (ast_channel_cdr(chan)) {
1146                         ast_cdr_setcid(ast_channel_cdr(chan), chan);
1147                 }
1148         } else if (!strcasecmp("dnid", member.argv[0])) {
1149                 ast_party_dialed_set_init(&dialed, ast_channel_dialed(chan));
1150                 if (member.argc == 1) {
1151                         /* Setup as if user had given dnid-num instead. */
1152                         member.argc = 2;
1153                         member.argv[1] = "num";
1154                 }
1155                 if (!strncasecmp("num", member.argv[1], 3)) {
1156                         /*
1157                          * Accept num[ber]
1158                          * dnid-num...
1159                          */
1160                         if (member.argc == 2) {
1161                                 /* dnid-num */
1162                                 dialed.number.str = ast_strdup(value);
1163                                 ast_trim_blanks(dialed.number.str);
1164                                 ast_party_dialed_set(ast_channel_dialed(chan), &dialed);
1165                                 if (ast_channel_cdr(chan)) {
1166                                         ast_cdr_setcid(ast_channel_cdr(chan), chan);
1167                                 }
1168                         } else if (member.argc == 3 && !strcasecmp("plan", member.argv[2])) {
1169                                 /* dnid-num-plan */
1170                                 val = ast_strdupa(value);
1171                                 ast_trim_blanks(val);
1172
1173                                 if (('0' <= val[0]) && (val[0] <= '9')) {
1174                                         ast_channel_dialed(chan)->number.plan = atoi(val);
1175                                         if (ast_channel_cdr(chan)) {
1176                                                 ast_cdr_setcid(ast_channel_cdr(chan), chan);
1177                                         }
1178                                 } else {
1179                                         ast_log(LOG_ERROR,
1180                                                 "Unknown type-of-number/numbering-plan '%s', value unchanged\n", val);
1181                                 }
1182                         } else {
1183                                 ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
1184                         }
1185                 } else if (!strncasecmp("subaddr", member.argv[1], 7)) {
1186                         /*
1187                          * Accept subaddr[ess]
1188                          * dnid-subaddr...
1189                          */
1190                         status = party_subaddress_write(&dialed.subaddress, member.argc - 2,
1191                                 member.argv + 2, value);
1192                         switch (status) {
1193                         case ID_FIELD_VALID:
1194                                 ast_party_dialed_set(ast_channel_dialed(chan), &dialed);
1195                                 if (ast_channel_cdr(chan)) {
1196                                         ast_cdr_setcid(ast_channel_cdr(chan), chan);
1197                                 }
1198                                 break;
1199                         case ID_FIELD_INVALID:
1200                                 break;
1201                         default:
1202                                 ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
1203                                 break;
1204                         }
1205                 } else {
1206                         ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
1207                 }
1208                 ast_party_dialed_free(&dialed);
1209         } else if (member.argc == 1 && !strcasecmp("ani2", member.argv[0])) {
1210                 val = ast_strdupa(value);
1211                 ast_trim_blanks(val);
1212
1213                 if (('0' <= val[0]) && (val[0] <= '9')) {
1214                         ast_channel_caller(chan)->ani2 = atoi(val);
1215                         if (ast_channel_cdr(chan)) {
1216                                 ast_cdr_setcid(ast_channel_cdr(chan), chan);
1217                         }
1218                 } else {
1219                         ast_log(LOG_ERROR, "Unknown callerid ani2 '%s', value unchanged\n", val);
1220                 }
1221         } else if (!strcasecmp("ani", member.argv[0])) {
1222                 ast_party_caller_set_init(&caller, ast_channel_caller(chan));
1223                 if (member.argc == 1) {
1224                         /* Setup as if user had given ani-num instead. */
1225                         member.argc = 2;
1226                         member.argv[1] = "num";
1227                 }
1228                 status = party_id_write(&caller.ani, member.argc - 1, member.argv + 1, value);
1229                 switch (status) {
1230                 case ID_FIELD_VALID:
1231                         ast_party_caller_set(ast_channel_caller(chan), &caller, NULL);
1232                         if (ast_channel_cdr(chan)) {
1233                                 ast_cdr_setcid(ast_channel_cdr(chan), chan);
1234                         }
1235                         break;
1236                 case ID_FIELD_INVALID:
1237                         break;
1238                 default:
1239                         ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
1240                         break;
1241                 }
1242                 ast_party_caller_free(&caller);
1243         } else if (!strcasecmp("priv", member.argv[0])) {
1244                 ast_party_caller_set_init(&caller, ast_channel_caller(chan));
1245                 status = party_id_write(&caller.priv, member.argc - 1, member.argv + 1, value);
1246                 switch (status) {
1247                 case ID_FIELD_VALID:
1248                         ast_party_caller_set(ast_channel_caller(chan), &caller, NULL);
1249                         if (ast_channel_cdr(chan)) {
1250                                 ast_cdr_setcid(ast_channel_cdr(chan), chan);
1251                         }
1252                         break;
1253                 case ID_FIELD_INVALID:
1254                         break;
1255                 default:
1256                         ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
1257                         break;
1258                 }
1259                 ast_party_caller_free(&caller);
1260         } else {
1261                 ast_party_caller_set_init(&caller, ast_channel_caller(chan));
1262                 status = party_id_write(&caller.id, member.argc, member.argv, value);
1263                 switch (status) {
1264                 case ID_FIELD_VALID:
1265                         ast_channel_set_caller_event(chan, &caller, NULL);
1266                         if (ast_channel_cdr(chan)) {
1267                                 ast_cdr_setcid(ast_channel_cdr(chan), chan);
1268                         }
1269                         break;
1270                 case ID_FIELD_INVALID:
1271                         break;
1272                 default:
1273                         ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
1274                         break;
1275                 }
1276                 ast_party_caller_free(&caller);
1277         }
1278         ast_channel_unlock(chan);
1279
1280         return 0;
1281 }
1282
1283 /*!
1284  * \internal
1285  * \brief Read values from the connected line information struct.
1286  *
1287  * \param chan Asterisk channel to read
1288  * \param cmd Not used
1289  * \param data Connected line function datatype string
1290  * \param buf Buffer to fill with read value.
1291  * \param len Length of the buffer
1292  *
1293  * \retval 0 on success.
1294  * \retval -1 on error.
1295  */
1296 static int connectedline_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
1297 {
1298         struct ast_party_members member;
1299         char *read_what;
1300         enum ID_FIELD_STATUS status;
1301
1302         /* Ensure that the buffer is empty */
1303         *buf = 0;
1304
1305         if (!chan) {
1306                 return -1;
1307         }
1308
1309         read_what = ast_strdupa(data);
1310         AST_NONSTANDARD_APP_ARGS(member, read_what, '-');
1311         if (member.argc == 0 || ARRAY_LEN(member.subnames) <= member.argc) {
1312                 /* Too few or too many subnames */
1313                 return -1;
1314         }
1315
1316         ast_channel_lock(chan);
1317
1318         if (member.argc == 1 && !strcasecmp("source", member.argv[0])) {
1319                 ast_copy_string(buf, ast_connected_line_source_name(ast_channel_connected(chan)->source), len);
1320         } else if (!strcasecmp("priv", member.argv[0])) {
1321                 status = party_id_read(buf, len, member.argc - 1, member.argv + 1,
1322                         &ast_channel_connected(chan)->priv);
1323                 switch (status) {
1324                 case ID_FIELD_VALID:
1325                 case ID_FIELD_INVALID:
1326                         break;
1327                 default:
1328                         ast_log(LOG_ERROR, "Unknown connectedline data type '%s'.\n", data);
1329                         break;
1330                 }
1331         } else {
1332                 status = party_id_read(buf, len, member.argc, member.argv, &ast_channel_connected(chan)->id);
1333                 switch (status) {
1334                 case ID_FIELD_VALID:
1335                 case ID_FIELD_INVALID:
1336                         break;
1337                 default:
1338                         ast_log(LOG_ERROR, "Unknown connectedline data type '%s'.\n", data);
1339                         break;
1340                 }
1341         }
1342
1343         ast_channel_unlock(chan);
1344
1345         return 0;
1346 }
1347
1348 /*!
1349  * \internal
1350  * \brief Write new values to the connected line information struct.
1351  *
1352  * \param chan Asterisk channel to update
1353  * \param cmd Not used
1354  * \param data Connected line function datatype string
1355  * \param value Value to assign to the connected line information struct.
1356  *
1357  * \retval 0 on success.
1358  * \retval -1 on error.
1359  */
1360 static int connectedline_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
1361 {
1362         struct ast_party_connected_line connected;
1363         char *val;
1364         char *parms;
1365         void (*set_it)(struct ast_channel *chan, const struct ast_party_connected_line *connected, const struct ast_set_party_connected_line *update);
1366         struct ast_party_func_args args;
1367         struct ast_party_members member;
1368         struct ast_flags opts;
1369         char *opt_args[CONNECTED_LINE_OPT_ARG_ARRAY_SIZE];
1370         enum ID_FIELD_STATUS status;
1371
1372         if (!value || !chan) {
1373                 return -1;
1374         }
1375
1376         parms = ast_strdupa(data);
1377         AST_STANDARD_APP_ARGS(args, parms);
1378         if (args.argc == 0) {
1379                 /* Must have at least one argument. */
1380                 return -1;
1381         }
1382
1383         AST_NONSTANDARD_APP_ARGS(member, args.member, '-');
1384         if (member.argc == 0 || ARRAY_LEN(member.subnames) <= member.argc) {
1385                 /* Too few or too many subnames */
1386                 return -1;
1387         }
1388
1389         if (ast_app_parse_options(connectedline_opts, &opts, opt_args, args.opts)) {
1390                 /* General invalid option syntax. */
1391                 return -1;
1392         }
1393
1394         /* Determine if the update indication inhibit option is present */
1395         if (ast_test_flag(&opts, CONNECTED_LINE_OPT_INHIBIT)) {
1396                 set_it = ast_channel_set_connected_line;
1397         } else {
1398                 set_it = ast_channel_update_connected_line;
1399         }
1400
1401         ast_channel_lock(chan);
1402         ast_party_connected_line_set_init(&connected, ast_channel_connected(chan));
1403         ast_channel_unlock(chan);
1404
1405         value = ast_skip_blanks(value);
1406
1407         if (member.argc == 1 && !strcasecmp("source", member.argv[0])) {
1408                 int source;
1409
1410                 val = ast_strdupa(value);
1411                 ast_trim_blanks(val);
1412
1413                 if (('0' <= val[0]) && (val[0] <= '9')) {
1414                         source = atoi(val);
1415                 } else {
1416                         source = ast_connected_line_source_parse(val);
1417                 }
1418
1419                 if (source < 0) {
1420                         ast_log(LOG_ERROR, "Unknown connectedline source '%s', value unchanged\n", val);
1421                 } else {
1422                         connected.source = source;
1423                         set_it(chan, &connected, NULL);
1424                 }
1425         } else if (!strcasecmp("priv", member.argv[0])) {
1426                 status = party_id_write(&connected.priv, member.argc - 1, member.argv + 1, value);
1427                 switch (status) {
1428                 case ID_FIELD_VALID:
1429                         set_it(chan, &connected, NULL);
1430                         break;
1431                 case ID_FIELD_INVALID:
1432                         break;
1433                 default:
1434                         ast_log(LOG_ERROR, "Unknown connectedline data type '%s'.\n", data);
1435                         break;
1436                 }
1437                 ast_party_connected_line_free(&connected);
1438         } else {
1439                 status = party_id_write(&connected.id, member.argc, member.argv, value);
1440                 switch (status) {
1441                 case ID_FIELD_VALID:
1442                         set_it(chan, &connected, NULL);
1443                         break;
1444                 case ID_FIELD_INVALID:
1445                         break;
1446                 default:
1447                         ast_log(LOG_ERROR, "Unknown connectedline data type '%s'.\n", data);
1448                         break;
1449                 }
1450                 ast_party_connected_line_free(&connected);
1451         }
1452
1453         return 0;
1454 }
1455
1456 /*!
1457  * \internal
1458  * \brief Read values from the redirecting information struct.
1459  *
1460  * \param chan Asterisk channel to read
1461  * \param cmd Not used
1462  * \param data Redirecting function datatype string
1463  * \param buf Buffer to fill with read value.
1464  * \param len Length of the buffer
1465  *
1466  * \retval 0 on success.
1467  * \retval -1 on error.
1468  */
1469 static int redirecting_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
1470 {
1471         struct ast_party_members member;
1472         char *read_what;
1473         const struct ast_party_redirecting *ast_redirecting;
1474         enum ID_FIELD_STATUS status;
1475
1476         /* Ensure that the buffer is empty */
1477         *buf = 0;
1478
1479         if (!chan) {
1480                 return -1;
1481         }
1482
1483         read_what = ast_strdupa(data);
1484         AST_NONSTANDARD_APP_ARGS(member, read_what, '-');
1485         if (member.argc == 0 || ARRAY_LEN(member.subnames) <= member.argc) {
1486                 /* Too few or too many subnames */
1487                 return -1;
1488         }
1489
1490         ast_channel_lock(chan);
1491
1492         ast_redirecting = ast_channel_redirecting(chan);
1493         if (!strcasecmp("orig", member.argv[0])) {
1494                 if (member.argc == 2 && !strcasecmp("reason", member.argv[1])) {
1495                         ast_copy_string(buf,
1496                                 ast_redirecting_reason_name(&ast_redirecting->orig_reason), len);
1497                 } else {
1498                         status = party_id_read(buf, len, member.argc - 1, member.argv + 1,
1499                                 &ast_redirecting->orig);
1500                         switch (status) {
1501                         case ID_FIELD_VALID:
1502                         case ID_FIELD_INVALID:
1503                                 break;
1504                         default:
1505                                 ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
1506                                 break;
1507                         }
1508                 }
1509         } else if (!strcasecmp("from", member.argv[0])) {
1510                 status = party_id_read(buf, len, member.argc - 1, member.argv + 1,
1511                         &ast_redirecting->from);
1512                 switch (status) {
1513                 case ID_FIELD_VALID:
1514                 case ID_FIELD_INVALID:
1515                         break;
1516                 default:
1517                         ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
1518                         break;
1519                 }
1520         } else if (!strcasecmp("to", member.argv[0])) {
1521                 status = party_id_read(buf, len, member.argc - 1, member.argv + 1,
1522                         &ast_redirecting->to);
1523                 switch (status) {
1524                 case ID_FIELD_VALID:
1525                 case ID_FIELD_INVALID:
1526                         break;
1527                 default:
1528                         ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
1529                         break;
1530                 }
1531         } else if (member.argc == 1 && !strncasecmp("pres", member.argv[0], 4)) {
1532                 /*
1533                  * Accept pres[entation]
1534                  * This is the combined from name/number presentation.
1535                  */
1536                 ast_copy_string(buf,
1537                         ast_named_caller_presentation(
1538                                 ast_party_id_presentation(&ast_redirecting->from)), len);
1539         } else if (member.argc == 1 && !strcasecmp("reason", member.argv[0])) {
1540                 ast_copy_string(buf, ast_redirecting_reason_name(&ast_redirecting->reason), len);
1541         } else if (member.argc == 1 && !strcasecmp("count", member.argv[0])) {
1542                 snprintf(buf, len, "%d", ast_redirecting->count);
1543         } else if (1 < member.argc && !strcasecmp("priv", member.argv[0])) {
1544                 if (!strcasecmp("orig", member.argv[1])) {
1545                         status = party_id_read(buf, len, member.argc - 2, member.argv + 2,
1546                                 &ast_redirecting->priv_orig);
1547                         switch (status) {
1548                         case ID_FIELD_VALID:
1549                         case ID_FIELD_INVALID:
1550                                 break;
1551                         default:
1552                                 ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
1553                                 break;
1554                         }
1555                 } else if (!strcasecmp("from", member.argv[1])) {
1556                         status = party_id_read(buf, len, member.argc - 2, member.argv + 2,
1557                                 &ast_redirecting->priv_from);
1558                         switch (status) {
1559                         case ID_FIELD_VALID:
1560                         case ID_FIELD_INVALID:
1561                                 break;
1562                         default:
1563                                 ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
1564                                 break;
1565                         }
1566                 } else if (!strcasecmp("to", member.argv[1])) {
1567                         status = party_id_read(buf, len, member.argc - 2, member.argv + 2,
1568                                 &ast_redirecting->priv_to);
1569                         switch (status) {
1570                         case ID_FIELD_VALID:
1571                         case ID_FIELD_INVALID:
1572                                 break;
1573                         default:
1574                                 ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
1575                                 break;
1576                         }
1577                 } else {
1578                         ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
1579                 }
1580         } else {
1581                 ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
1582         }
1583
1584         ast_channel_unlock(chan);
1585
1586         return 0;
1587 }
1588
1589 /*!
1590  * \internal
1591  * \brief Write new values to the redirecting information struct.
1592  *
1593  * \param chan Asterisk channel to update
1594  * \param cmd Not used
1595  * \param data Redirecting function datatype string
1596  * \param value Value to assign to the redirecting information struct.
1597  *
1598  * \retval 0 on success.
1599  * \retval -1 on error.
1600  */
1601 static int redirecting_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
1602 {
1603         struct ast_party_redirecting redirecting;
1604         enum ID_FIELD_STATUS status;
1605         char *val;
1606         char *parms;
1607         void (*set_it)(struct ast_channel *chan, const struct ast_party_redirecting *redirecting, const struct ast_set_party_redirecting *update);
1608         struct ast_party_func_args args;
1609         struct ast_party_members member;
1610         struct ast_flags opts;
1611         char *opt_args[REDIRECTING_OPT_ARG_ARRAY_SIZE];
1612
1613         if (!value || !chan) {
1614                 return -1;
1615         }
1616
1617         parms = ast_strdupa(data);
1618         AST_STANDARD_APP_ARGS(args, parms);
1619         if (args.argc == 0) {
1620                 /* Must have at least one argument. */
1621                 return -1;
1622         }
1623
1624         AST_NONSTANDARD_APP_ARGS(member, args.member, '-');
1625         if (member.argc == 0 || ARRAY_LEN(member.subnames) <= member.argc) {
1626                 /* Too few or too many subnames */
1627                 return -1;
1628         }
1629
1630         if (ast_app_parse_options(redirecting_opts, &opts, opt_args, args.opts)) {
1631                 /* General invalid option syntax. */
1632                 return -1;
1633         }
1634
1635         /* Determine if the update indication inhibit option is present */
1636         if (ast_test_flag(&opts, REDIRECTING_OPT_INHIBIT)) {
1637                 set_it = ast_channel_set_redirecting;
1638         } else {
1639                 set_it = ast_channel_update_redirecting;
1640         }
1641
1642         ast_channel_lock(chan);
1643         ast_party_redirecting_set_init(&redirecting, ast_channel_redirecting(chan));
1644         ast_channel_unlock(chan);
1645
1646         value = ast_skip_blanks(value);
1647
1648         if (!strcasecmp("orig", member.argv[0])) {
1649                 if (member.argc == 2 && !strcasecmp("reason", member.argv[1])) {
1650                         int reason;
1651
1652                         val = ast_strdupa(value);
1653                         ast_trim_blanks(val);
1654
1655                         if (('0' <= val[0]) && (val[0] <= '9')) {
1656                                 reason = atoi(val);
1657                         } else {
1658                                 reason = ast_redirecting_reason_parse(val);
1659                         }
1660
1661                         if (reason < 0) {
1662                         /* The argument passed into the function does not correspond to a pre-defined
1663                          * reason, so we can just set the reason string to what was given and set the
1664                          * code to be unknown
1665                          */
1666                                 redirecting.orig_reason.code = AST_REDIRECTING_REASON_UNKNOWN;
1667                                 redirecting.orig_reason.str = val;
1668                                 set_it(chan, &redirecting, NULL);
1669                         } else {
1670                                 redirecting.orig_reason.code = reason;
1671                                 redirecting.orig_reason.str = "";
1672                                 set_it(chan, &redirecting, NULL);
1673                         }
1674                 } else {
1675                         status = party_id_write(&redirecting.orig, member.argc - 1, member.argv + 1,
1676                                 value);
1677                         switch (status) {
1678                         case ID_FIELD_VALID:
1679                                 set_it(chan, &redirecting, NULL);
1680                                 break;
1681                         case ID_FIELD_INVALID:
1682                                 break;
1683                         default:
1684                                 ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
1685                                 break;
1686                         }
1687                         ast_party_redirecting_free(&redirecting);
1688                 }
1689         } else if (!strcasecmp("from", member.argv[0])) {
1690                 status = party_id_write(&redirecting.from, member.argc - 1, member.argv + 1,
1691                         value);
1692                 switch (status) {
1693                 case ID_FIELD_VALID:
1694                         set_it(chan, &redirecting, NULL);
1695                         break;
1696                 case ID_FIELD_INVALID:
1697                         break;
1698                 default:
1699                         ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
1700                         break;
1701                 }
1702                 ast_party_redirecting_free(&redirecting);
1703         } else if (!strcasecmp("to", member.argv[0])) {
1704                 status = party_id_write(&redirecting.to, member.argc - 1, member.argv + 1, value);
1705                 switch (status) {
1706                 case ID_FIELD_VALID:
1707                         set_it(chan, &redirecting, NULL);
1708                         break;
1709                 case ID_FIELD_INVALID:
1710                         break;
1711                 default:
1712                         ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
1713                         break;
1714                 }
1715                 ast_party_redirecting_free(&redirecting);
1716         } else if (member.argc == 1 && !strncasecmp("pres", member.argv[0], 4)) {
1717                 int pres;
1718
1719                 val = ast_strdupa(value);
1720                 ast_trim_blanks(val);
1721
1722                 if (('0' <= val[0]) && (val[0] <= '9')) {
1723                         pres = atoi(val);
1724                 } else {
1725                         pres = ast_parse_caller_presentation(val);
1726                 }
1727
1728                 if (pres < 0) {
1729                         ast_log(LOG_ERROR,
1730                                 "Unknown redirecting combined presentation '%s', value unchanged\n", val);
1731                 } else {
1732                         redirecting.from.name.presentation = pres;
1733                         redirecting.from.number.presentation = pres;
1734                         redirecting.to.name.presentation = pres;
1735                         redirecting.to.number.presentation = pres;
1736                         set_it(chan, &redirecting, NULL);
1737                 }
1738         } else if (member.argc == 1 && !strcasecmp("reason", member.argv[0])) {
1739                 int reason;
1740
1741                 val = ast_strdupa(value);
1742                 ast_trim_blanks(val);
1743
1744                 if (('0' <= val[0]) && (val[0] <= '9')) {
1745                         reason = atoi(val);
1746                 } else {
1747                         reason = ast_redirecting_reason_parse(val);
1748                 }
1749
1750                 if (reason < 0) {
1751                         /* The argument passed into the function does not correspond to a pre-defined
1752                          * reason, so we can just set the reason string to what was given and set the
1753                          * code to be unknown
1754                          */
1755                         redirecting.reason.code = AST_REDIRECTING_REASON_UNKNOWN;
1756                         redirecting.reason.str = val;
1757                         set_it(chan, &redirecting, NULL);
1758                 } else {
1759                         redirecting.reason.code = reason;
1760                         redirecting.reason.str = "";
1761                         set_it(chan, &redirecting, NULL);
1762                 }
1763         } else if (member.argc == 1 && !strcasecmp("count", member.argv[0])) {
1764                 val = ast_strdupa(value);
1765                 ast_trim_blanks(val);
1766
1767                 if (('0' <= val[0]) && (val[0] <= '9')) {
1768                         redirecting.count = atoi(val);
1769                         set_it(chan, &redirecting, NULL);
1770                 } else {
1771                         ast_log(LOG_ERROR, "Unknown redirecting count '%s', value unchanged\n", val);
1772                 }
1773         } else if (1 < member.argc && !strcasecmp("priv", member.argv[0])) {
1774                 if (!strcasecmp("orig", member.argv[1])) {
1775                         status = party_id_write(&redirecting.priv_orig, member.argc - 2, member.argv + 2,
1776                                 value);
1777                         switch (status) {
1778                         case ID_FIELD_VALID:
1779                                 set_it(chan, &redirecting, NULL);
1780                                 break;
1781                         case ID_FIELD_INVALID:
1782                                 break;
1783                         default:
1784                                 ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
1785                                 break;
1786                         }
1787                         ast_party_redirecting_free(&redirecting);
1788                 } else if (!strcasecmp("from", member.argv[1])) {
1789                         status = party_id_write(&redirecting.priv_from, member.argc - 2, member.argv + 2,
1790                                 value);
1791                         switch (status) {
1792                         case ID_FIELD_VALID:
1793                                 set_it(chan, &redirecting, NULL);
1794                                 break;
1795                         case ID_FIELD_INVALID:
1796                                 break;
1797                         default:
1798                                 ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
1799                                 break;
1800                         }
1801                         ast_party_redirecting_free(&redirecting);
1802                 } else if (!strcasecmp("to", member.argv[1])) {
1803                         status = party_id_write(&redirecting.priv_to, member.argc - 2, member.argv + 2, value);
1804                         switch (status) {
1805                         case ID_FIELD_VALID:
1806                                 set_it(chan, &redirecting, NULL);
1807                                 break;
1808                         case ID_FIELD_INVALID:
1809                                 break;
1810                         default:
1811                                 ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
1812                                 break;
1813                         }
1814                         ast_party_redirecting_free(&redirecting);
1815                 } else {
1816                         ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
1817                 }
1818         } else {
1819                 ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
1820         }
1821
1822         return 0;
1823 }
1824
1825 static struct ast_custom_function callerid_function = {
1826         .name = "CALLERID",
1827         .read = callerid_read,
1828         .read_max = 256,
1829         .write = callerid_write,
1830 };
1831
1832 static struct ast_custom_function callerpres_function = {
1833         .name = "CALLERPRES",
1834         .read = callerpres_read,
1835         .read_max = 50,
1836         .write = callerpres_write,
1837 };
1838
1839 static struct ast_custom_function connectedline_function = {
1840         .name = "CONNECTEDLINE",
1841         .read = connectedline_read,
1842         .write = connectedline_write,
1843 };
1844
1845 static struct ast_custom_function redirecting_function = {
1846         .name = "REDIRECTING",
1847         .read = redirecting_read,
1848         .write = redirecting_write,
1849 };
1850
1851 /*!
1852  * \internal
1853  * \brief Unload the function module
1854  *
1855  * \retval 0 on success.
1856  * \retval -1 on error.
1857  */
1858 static int unload_module(void)
1859 {
1860         int res;
1861
1862         res = ast_custom_function_unregister(&callerpres_function);
1863         res |= ast_custom_function_unregister(&callerid_function);
1864         res |= ast_custom_function_unregister(&connectedline_function);
1865         res |= ast_custom_function_unregister(&redirecting_function);
1866         return res;
1867 }
1868
1869 /*!
1870  * \internal
1871  * \brief Load and initialize the function module.
1872  *
1873  * \retval AST_MODULE_LOAD_SUCCESS on success.
1874  * \retval AST_MODULE_LOAD_DECLINE on error.
1875  */
1876 static int load_module(void)
1877 {
1878         int res;
1879
1880         res = ast_custom_function_register(&callerpres_function);
1881         res |= ast_custom_function_register(&callerid_function);
1882         res |= ast_custom_function_register(&connectedline_function);
1883         res |= ast_custom_function_register(&redirecting_function);
1884         return res ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS;
1885 }
1886
1887 /* Do not wrap the following line. */
1888 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Party ID related dialplan functions (Caller-ID, Connected-line, Redirecting)");