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