2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999-2010, Digium, Inc.
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.
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.
19 * \brief Party ID related dialplan functions (Caller-ID, Connected-line, Redirecting)
24 * \arg \ref AstCREDITS
28 <support_level>core</support_level>
33 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
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"
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.
48 * Do not document the CALLERID(ton) datatype.
49 * It is an alias for num-plan.
51 * Do not document the CALLERID(ANI-subaddr-...) datatype.
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.
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.
63 * Do not document the CONNECTEDLINE(ton) datatype.
64 * It is an alias for num-plan.
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.
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.
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.
81 <function name="CALLERID" language="en_US">
83 Gets or sets Caller*ID data on the channel.
86 <parameter name="datatype" required="true">
87 <para>The allowable datatypes are:</para>
90 <enum name = "name" />
91 <enum name = "name-valid" />
92 <enum name = "name-charset" />
93 <enum name = "name-pres" />
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" />
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>
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>
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>
146 <function name="CALLERPRES" language="en_US">
148 Gets or sets Caller*ID presentation on the channel.
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>
157 <enum name="allowed_not_screened">
158 <para>Presentation Allowed, Not Screened.</para>
160 <enum name="allowed_passed_screen">
161 <para>Presentation Allowed, Passed Screen.</para>
163 <enum name="allowed_failed_screen">
164 <para>Presentation Allowed, Failed Screen.</para>
166 <enum name="allowed">
167 <para>Presentation Allowed, Network Number.</para>
169 <enum name="prohib_not_screened">
170 <para>Presentation Prohibited, Not Screened.</para>
172 <enum name="prohib_passed_screen">
173 <para>Presentation Prohibited, Passed Screen.</para>
175 <enum name="prohib_failed_screen">
176 <para>Presentation Prohibited, Failed Screen.</para>
179 <para>Presentation Prohibited, Network Number.</para>
181 <enum name="unavailable">
182 <para>Number Unavailable.</para>
187 <function name="CONNECTEDLINE" language="en_US">
189 Gets or sets Connected Line data on the channel.
192 <parameter name="datatype" required="true">
193 <para>The allowable datatypes are:</para>
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" />
212 <para>If set, this will prevent the channel from sending out protocol
213 messages because of the value being set</para>
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>
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>
234 <function name="REDIRECTING" language="en_US">
236 Gets or sets Redirecting data on the channel.
239 <parameter name="datatype" required="true">
240 <para>The allowable datatypes are:</para>
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" />
275 <para>If set, this will prevent the channel from sending out protocol
276 messages because of the value being set</para>
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>
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>
297 <para>The allowable values for the <replaceable>xxx-name-charset</replaceable>
298 field are the following:</para>
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>
315 enum ID_FIELD_STATUS {
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 */
327 AST_DEFINE_APP_ARGS_TYPE(ast_party_members,
328 AST_APP_ARG(subnames[10]); /*!< Option member subnames */
331 enum CONNECTED_LINE_OPT_FLAGS {
332 CONNECTED_LINE_OPT_INHIBIT = (1 << 0),
334 enum CONNECTED_LINE_OPT_ARGS {
335 CONNECTED_LINE_OPT_DUMMY, /*!< Delete this if CONNECTED_LINE ever gets an option with parameters. */
337 /*! \note This entry _MUST_ be the last one in the enum */
338 CONNECTED_LINE_OPT_ARG_ARRAY_SIZE
341 AST_APP_OPTIONS(connectedline_opts, BEGIN_OPTIONS
342 AST_APP_OPTION('i', CONNECTED_LINE_OPT_INHIBIT),
345 enum REDIRECTING_OPT_FLAGS {
346 REDIRECTING_OPT_INHIBIT = (1 << 0),
348 enum REDIRECTING_OPT_ARGS {
349 REDIRECTING_OPT_DUMMY, /*!< Delete this if REDIRECTING ever gets an option with parameters. */
351 /*! \note This entry _MUST_ be the last one in the enum */
352 REDIRECTING_OPT_ARG_ARRAY_SIZE
355 AST_APP_OPTIONS(redirecting_opts, BEGIN_OPTIONS
356 AST_APP_OPTION('i', REDIRECTING_OPT_INHIBIT),
361 * \brief Read values from the party name struct.
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.
370 * \retval ID_FIELD_VALID on success.
371 * \retval ID_FIELD_UNKNOWN on unknown field name.
373 static enum ID_FIELD_STATUS party_name_read(char *buf, size_t len, int argc, char *argv[], const struct ast_party_name *name)
375 enum ID_FIELD_STATUS status;
377 status = ID_FIELD_VALID;
380 /* We want the name string */
381 if (name->valid && name->str) {
382 ast_copy_string(buf, name->str, len);
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);
392 status = ID_FIELD_UNKNOWN;
400 * \brief Read values from the party number struct.
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.
409 * \retval ID_FIELD_VALID on success.
410 * \retval ID_FIELD_UNKNOWN on unknown field name.
412 static enum ID_FIELD_STATUS party_number_read(char *buf, size_t len, int argc, char *argv[], const struct ast_party_number *number)
414 enum ID_FIELD_STATUS status;
416 status = ID_FIELD_VALID;
419 /* We want the number string */
420 if (number->valid && number->str) {
421 ast_copy_string(buf, number->str, len);
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);
431 status = ID_FIELD_UNKNOWN;
439 * \brief Read values from the party subaddress struct.
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.
448 * \retval ID_FIELD_VALID on success.
449 * \retval ID_FIELD_UNKNOWN on unknown field name.
451 static enum ID_FIELD_STATUS party_subaddress_read(char *buf, size_t len, int argc, char *argv[], const struct ast_party_subaddress *subaddress)
453 enum ID_FIELD_STATUS status;
455 status = ID_FIELD_VALID;
458 /* We want the subaddress string */
459 if (subaddress->str) {
460 ast_copy_string(buf, subaddress->str, len);
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);
469 status = ID_FIELD_UNKNOWN;
477 * \brief Read values from the party id struct.
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.
486 * \retval ID_FIELD_VALID on success.
487 * \retval ID_FIELD_UNKNOWN on unknown field name.
489 static enum ID_FIELD_STATUS party_id_read(char *buf, size_t len, int argc, char *argv[], const struct ast_party_id *id)
491 enum ID_FIELD_STATUS status;
494 /* Must have at least one subname. */
495 return ID_FIELD_UNKNOWN;
498 status = ID_FIELD_VALID;
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])) {
514 ast_copy_string(buf, id->tag, len);
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)) {
521 * Accept pres[entation]
522 * This is the combined name/number presentation.
525 ast_named_caller_presentation(ast_party_id_presentation(id)), len);
527 status = ID_FIELD_UNKNOWN;
535 * \brief Write new values to the party name struct
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.
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.
547 static enum ID_FIELD_STATUS party_name_write(struct ast_party_name *name, int argc, char *argv[], const char *value)
550 enum ID_FIELD_STATUS status;
552 status = ID_FIELD_VALID;
555 /* We are setting the name string */
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])) {
564 val = ast_strdupa(value);
565 ast_trim_blanks(val);
567 if (('0' <= val[0]) && (val[0] <= '9')) {
568 char_set = atoi(val);
570 char_set = ast_party_name_charset_parse(val);
575 "Unknown name char-set '%s', value unchanged\n", val);
576 status = ID_FIELD_INVALID;
578 name->char_set = char_set;
580 } else if (argc == 1 && !strncasecmp("pres", argv[0], 4)) {
583 /* Accept pres[entation] */
584 val = ast_strdupa(value);
585 ast_trim_blanks(val);
587 if (('0' <= val[0]) && (val[0] <= '9')) {
590 pres = ast_parse_caller_presentation(val);
595 "Unknown name presentation '%s', value unchanged\n", val);
596 status = ID_FIELD_INVALID;
598 name->presentation = pres;
601 status = ID_FIELD_UNKNOWN;
609 * \brief Write new values to the party number struct
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.
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.
621 static enum ID_FIELD_STATUS party_number_write(struct ast_party_number *number, int argc, char *argv[], const char *value)
624 enum ID_FIELD_STATUS status;
626 status = ID_FIELD_VALID;
629 /* We are setting the number string */
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);
639 if (('0' <= val[0]) && (val[0] <= '9')) {
640 number->plan = atoi(val);
643 "Unknown type-of-number/numbering-plan '%s', value unchanged\n", val);
644 status = ID_FIELD_INVALID;
646 } else if (argc == 1 && !strncasecmp("pres", argv[0], 4)) {
649 /* Accept pres[entation] */
650 val = ast_strdupa(value);
651 ast_trim_blanks(val);
653 if (('0' <= val[0]) && (val[0] <= '9')) {
656 pres = ast_parse_caller_presentation(val);
661 "Unknown number presentation '%s', value unchanged\n", val);
662 status = ID_FIELD_INVALID;
664 number->presentation = pres;
667 status = ID_FIELD_UNKNOWN;
675 * \brief Write new values to the party subaddress struct
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.
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.
687 static enum ID_FIELD_STATUS party_subaddress_write(struct ast_party_subaddress *subaddress, int argc, char *argv[], const char *value)
689 enum ID_FIELD_STATUS status;
691 status = ID_FIELD_VALID;
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;
704 status = ID_FIELD_UNKNOWN;
712 * \brief Write new values to the party id struct
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.
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.
724 static enum ID_FIELD_STATUS party_id_write(struct ast_party_id *id, int argc, char *argv[], const char *value)
727 enum ID_FIELD_STATUS status;
730 /* Must have at least one subname. */
731 return ID_FIELD_UNKNOWN;
734 status = ID_FIELD_VALID;
736 if (argc == 1 && !strcasecmp("all", argv[0])) {
740 ast_callerid_split(value, name, sizeof(name), num, sizeof(num));
742 id->name.str = ast_strdup(name);
744 return ID_FIELD_INVALID;
746 id->number.valid = 1;
747 id->number.str = ast_strdup(num);
748 if (!id->number.str) {
749 return ID_FIELD_INVALID;
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 */
765 status = party_number_write(&id->number, argc, argv, value);
766 } else if (argc == 1 && !strncasecmp("pres", argv[0], 4)) {
770 * Accept pres[entation]
771 * This is the combined name/number presentation.
773 val = ast_strdupa(value);
774 ast_trim_blanks(val);
776 if (('0' <= val[0]) && (val[0] <= '9')) {
779 pres = ast_parse_caller_presentation(val);
784 "Unknown combined presentation '%s', value unchanged\n", val);
785 status = ID_FIELD_INVALID;
787 id->name.presentation = pres;
788 id->number.presentation = pres;
791 status = ID_FIELD_UNKNOWN;
797 /*! TRUE if we have already notified about CALLERPRES being deprecated. */
798 static int callerpres_deprecate_notify;
802 * \brief Read values from the caller-id presentation information struct.
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
810 * \retval 0 on success.
811 * \retval -1 on error.
813 static int callerpres_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
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");
821 ast_named_caller_presentation(ast_party_id_presentation(&chan->caller.id)), len);
827 * \brief Write new values to the caller-id presentation information struct.
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.
834 * \retval 0 on success.
835 * \retval -1 on error.
837 static int callerpres_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
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");
847 pres = ast_parse_caller_presentation(value);
849 ast_log(LOG_WARNING, "'%s' is not a valid presentation (see 'show function CALLERPRES')\n", value);
851 chan->caller.id.name.presentation = pres;
852 chan->caller.id.number.presentation = pres;
859 * \brief Read values from the caller-id information struct.
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
867 * \retval 0 on success.
868 * \retval -1 on error.
870 static int callerid_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
872 enum ID_FIELD_STATUS status;
874 struct ast_party_members member;
875 AST_DECLARE_APP_ARGS(args,
876 AST_APP_ARG(member); /*!< Member name */
877 AST_APP_ARG(cid); /*!< Optional caller id to parse instead of from the channel. */
880 /* Ensure that the buffer is empty */
887 parms = ast_strdupa(data);
888 AST_STANDARD_APP_ARGS(args, parms);
889 if (args.argc == 0) {
890 /* Must have at least one argument. */
894 AST_NONSTANDARD_APP_ARGS(member, args.member, '-');
895 if (member.argc == 0 || ARRAY_LEN(member.subnames) <= member.argc) {
896 /* Too few or too many subnames */
900 if (args.argc == 2) {
904 ast_callerid_split(args.cid, name, sizeof(name), num, sizeof(num));
906 if (member.argc == 1 && !strcasecmp("all", member.argv[0])) {
907 snprintf(buf, len, "\"%s\" <%s>", name, num);
908 } else if (member.argc == 1 && !strcasecmp("name", member.argv[0])) {
909 ast_copy_string(buf, name, len);
910 } else if (member.argc == 1 && !strncasecmp("num", member.argv[0], 3)) {
911 /* Accept num[ber] */
912 ast_copy_string(buf, num, len);
914 ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
917 ast_channel_lock(chan);
919 if (member.argc == 1 && !strcasecmp("rdnis", member.argv[0])) {
920 if (chan->redirecting.from.number.valid
921 && chan->redirecting.from.number.str) {
922 ast_copy_string(buf, chan->redirecting.from.number.str, len);
924 } else if (!strcasecmp("dnid", member.argv[0])) {
925 if (member.argc == 1) {
926 /* Setup as if user had given dnid-num instead. */
928 member.argv[1] = "num";
930 if (!strncasecmp("num", member.argv[1], 3)) {
935 if (member.argc == 2) {
937 if (chan->dialed.number.str) {
938 ast_copy_string(buf, chan->dialed.number.str, len);
940 } else if (member.argc == 3 && !strcasecmp("plan", member.argv[2])) {
942 snprintf(buf, len, "%d", chan->dialed.number.plan);
944 ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
946 } else if (!strncasecmp("subaddr", member.argv[1], 7)) {
948 * Accept subaddr[ess]
951 status = party_subaddress_read(buf, len, member.argc - 2, member.argv + 2,
952 &chan->dialed.subaddress);
955 case ID_FIELD_INVALID:
958 ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
962 ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
964 } else if (member.argc == 1 && !strcasecmp("ani2", member.argv[0])) {
965 snprintf(buf, len, "%d", chan->caller.ani2);
966 } else if (!strcasecmp("ani", member.argv[0])) {
967 if (member.argc == 1) {
968 /* Setup as if user had given ani-num instead. */
970 member.argv[1] = "num";
972 status = party_id_read(buf, len, member.argc - 1, member.argv + 1,
976 case ID_FIELD_INVALID:
979 ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
983 status = party_id_read(buf, len, member.argc, member.argv, &chan->caller.id);
986 case ID_FIELD_INVALID:
989 ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
994 ast_channel_unlock(chan);
1002 * \brief Write new values to the caller-id information struct.
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.
1009 * \retval 0 on success.
1010 * \retval -1 on error.
1012 static int callerid_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
1014 struct ast_party_caller caller;
1015 struct ast_party_dialed dialed;
1016 enum ID_FIELD_STATUS status;
1019 struct ast_party_func_args args;
1020 struct ast_party_members member;
1022 if (!value || !chan) {
1026 parms = ast_strdupa(data);
1027 AST_STANDARD_APP_ARGS(args, parms);
1028 if (args.argc == 0) {
1029 /* Must have at least one argument. */
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 */
1039 value = ast_skip_blanks(value);
1041 ast_channel_lock(chan);
1042 if (member.argc == 1 && !strcasecmp("rdnis", member.argv[0])) {
1043 chan->redirecting.from.number.valid = 1;
1044 ast_free(chan->redirecting.from.number.str);
1045 chan->redirecting.from.number.str = ast_strdup(value);
1047 ast_cdr_setcid(chan->cdr, chan);
1049 } else if (!strcasecmp("dnid", member.argv[0])) {
1050 ast_party_dialed_set_init(&dialed, &chan->dialed);
1051 if (member.argc == 1) {
1052 /* Setup as if user had given dnid-num instead. */
1054 member.argv[1] = "num";
1056 if (!strncasecmp("num", member.argv[1], 3)) {
1061 if (member.argc == 2) {
1063 dialed.number.str = ast_strdup(value);
1064 ast_trim_blanks(dialed.number.str);
1065 ast_party_dialed_set(&chan->dialed, &dialed);
1067 ast_cdr_setcid(chan->cdr, chan);
1069 } else if (member.argc == 3 && !strcasecmp("plan", member.argv[2])) {
1071 val = ast_strdupa(value);
1072 ast_trim_blanks(val);
1074 if (('0' <= val[0]) && (val[0] <= '9')) {
1075 chan->dialed.number.plan = atoi(val);
1077 ast_cdr_setcid(chan->cdr, chan);
1081 "Unknown type-of-number/numbering-plan '%s', value unchanged\n", val);
1084 ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
1086 } else if (!strncasecmp("subaddr", member.argv[1], 7)) {
1088 * Accept subaddr[ess]
1091 status = party_subaddress_write(&dialed.subaddress, member.argc - 2,
1092 member.argv + 2, value);
1094 case ID_FIELD_VALID:
1095 ast_party_dialed_set(&chan->dialed, &dialed);
1097 ast_cdr_setcid(chan->cdr, chan);
1100 case ID_FIELD_INVALID:
1103 ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
1107 ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
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);
1114 if (('0' <= val[0]) && (val[0] <= '9')) {
1115 chan->caller.ani2 = atoi(val);
1117 ast_cdr_setcid(chan->cdr, chan);
1120 ast_log(LOG_ERROR, "Unknown callerid ani2 '%s', value unchanged\n", val);
1122 } else if (!strcasecmp("ani", member.argv[0])) {
1123 ast_party_caller_set_init(&caller, &chan->caller);
1124 if (member.argc == 1) {
1125 /* Setup as if user had given ani-num instead. */
1127 member.argv[1] = "num";
1129 status = party_id_write(&caller.ani, member.argc - 1, member.argv + 1, value);
1131 case ID_FIELD_VALID:
1132 ast_party_caller_set(&chan->caller, &caller, NULL);
1134 ast_cdr_setcid(chan->cdr, chan);
1137 case ID_FIELD_INVALID:
1140 ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
1143 ast_party_caller_free(&caller);
1145 ast_party_caller_set_init(&caller, &chan->caller);
1146 status = party_id_write(&caller.id, member.argc, member.argv, value);
1148 case ID_FIELD_VALID:
1149 ast_channel_set_caller_event(chan, &caller, NULL);
1151 ast_cdr_setcid(chan->cdr, chan);
1154 case ID_FIELD_INVALID:
1157 ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
1160 ast_party_caller_free(&caller);
1162 ast_channel_unlock(chan);
1169 * \brief Read values from the connected line information struct.
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
1177 * \retval 0 on success.
1178 * \retval -1 on error.
1180 static int connectedline_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
1182 struct ast_party_members member;
1184 enum ID_FIELD_STATUS status;
1186 /* Ensure that the buffer is empty */
1193 read_what = ast_strdupa(data);
1194 AST_NONSTANDARD_APP_ARGS(member, read_what, '-');
1195 if (member.argc == 0 || ARRAY_LEN(member.subnames) <= member.argc) {
1196 /* Too few or too many subnames */
1200 ast_channel_lock(chan);
1202 if (member.argc == 1 && !strcasecmp("source", member.argv[0])) {
1203 ast_copy_string(buf, ast_connected_line_source_name(chan->connected.source), len);
1205 status = party_id_read(buf, len, member.argc, member.argv, &chan->connected.id);
1207 case ID_FIELD_VALID:
1208 case ID_FIELD_INVALID:
1211 ast_log(LOG_ERROR, "Unknown connectedline data type '%s'.\n", data);
1216 ast_channel_unlock(chan);
1223 * \brief Write new values to the connected line information struct.
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.
1230 * \retval 0 on success.
1231 * \retval -1 on error.
1233 static int connectedline_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
1235 struct ast_party_connected_line connected;
1236 enum ID_FIELD_STATUS status;
1239 void (*set_it)(struct ast_channel *chan, const struct ast_party_connected_line *connected, const struct ast_set_party_connected_line *update);
1240 struct ast_party_func_args args;
1241 struct ast_party_members member;
1242 struct ast_flags opts;
1243 char *opt_args[CONNECTED_LINE_OPT_ARG_ARRAY_SIZE];
1245 if (!value || !chan) {
1249 parms = ast_strdupa(data);
1250 AST_STANDARD_APP_ARGS(args, parms);
1251 if (args.argc == 0) {
1252 /* Must have at least one argument. */
1256 AST_NONSTANDARD_APP_ARGS(member, args.member, '-');
1257 if (member.argc == 0 || ARRAY_LEN(member.subnames) <= member.argc) {
1258 /* Too few or too many subnames */
1262 if (ast_app_parse_options(connectedline_opts, &opts, opt_args, args.opts)) {
1263 /* General invalid option syntax. */
1267 /* Determine if the update indication inhibit option is present */
1268 if (ast_test_flag(&opts, CONNECTED_LINE_OPT_INHIBIT)) {
1269 set_it = ast_channel_set_connected_line;
1271 set_it = ast_channel_update_connected_line;
1274 ast_channel_lock(chan);
1275 ast_party_connected_line_set_init(&connected, &chan->connected);
1276 ast_channel_unlock(chan);
1278 value = ast_skip_blanks(value);
1280 if (member.argc == 1 && !strcasecmp("source", member.argv[0])) {
1283 val = ast_strdupa(value);
1284 ast_trim_blanks(val);
1286 if (('0' <= val[0]) && (val[0] <= '9')) {
1289 source = ast_connected_line_source_parse(val);
1293 ast_log(LOG_ERROR, "Unknown connectedline source '%s', value unchanged\n", val);
1295 connected.source = source;
1296 set_it(chan, &connected, NULL);
1299 status = party_id_write(&connected.id, member.argc, member.argv, value);
1301 case ID_FIELD_VALID:
1302 set_it(chan, &connected, NULL);
1304 case ID_FIELD_INVALID:
1307 ast_log(LOG_ERROR, "Unknown connectedline data type '%s'.\n", data);
1310 ast_party_connected_line_free(&connected);
1318 * \brief Read values from the redirecting information struct.
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
1326 * \retval 0 on success.
1327 * \retval -1 on error.
1329 static int redirecting_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
1331 struct ast_party_members member;
1333 enum ID_FIELD_STATUS status;
1335 /* Ensure that the buffer is empty */
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 */
1349 ast_channel_lock(chan);
1351 if (!strcasecmp("from", member.argv[0])) {
1352 status = party_id_read(buf, len, member.argc - 1, member.argv + 1,
1353 &chan->redirecting.from);
1355 case ID_FIELD_VALID:
1356 case ID_FIELD_INVALID:
1359 ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
1362 } else if (!strcasecmp("to", member.argv[0])) {
1363 status = party_id_read(buf, len, member.argc - 1, member.argv + 1,
1364 &chan->redirecting.to);
1366 case ID_FIELD_VALID:
1367 case ID_FIELD_INVALID:
1370 ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
1373 } else if (member.argc == 1 && !strncasecmp("pres", member.argv[0], 4)) {
1375 * Accept pres[entation]
1376 * This is the combined from name/number presentation.
1378 ast_copy_string(buf,
1379 ast_named_caller_presentation(
1380 ast_party_id_presentation(&chan->redirecting.from)), len);
1381 } else if (member.argc == 1 && !strcasecmp("reason", member.argv[0])) {
1382 ast_copy_string(buf, ast_redirecting_reason_name(chan->redirecting.reason), len);
1383 } else if (member.argc == 1 && !strcasecmp("count", member.argv[0])) {
1384 snprintf(buf, len, "%d", chan->redirecting.count);
1386 ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
1389 ast_channel_unlock(chan);
1396 * \brief Write new values to the redirecting information struct.
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.
1403 * \retval 0 on success.
1404 * \retval -1 on error.
1406 static int redirecting_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
1408 struct ast_party_redirecting redirecting;
1409 enum ID_FIELD_STATUS status;
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];
1418 if (!value || !chan) {
1422 parms = ast_strdupa(data);
1423 AST_STANDARD_APP_ARGS(args, parms);
1424 if (args.argc == 0) {
1425 /* Must have at least one argument. */
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 */
1435 if (ast_app_parse_options(redirecting_opts, &opts, opt_args, args.opts)) {
1436 /* General invalid option syntax. */
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;
1444 set_it = ast_channel_update_redirecting;
1447 ast_channel_lock(chan);
1448 ast_party_redirecting_set_init(&redirecting, &chan->redirecting);
1449 ast_channel_unlock(chan);
1451 value = ast_skip_blanks(value);
1453 if (!strcasecmp("from", member.argv[0])) {
1454 status = party_id_write(&redirecting.from, member.argc - 1, member.argv + 1,
1457 case ID_FIELD_VALID:
1458 set_it(chan, &redirecting, NULL);
1460 case ID_FIELD_INVALID:
1463 ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
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);
1470 case ID_FIELD_VALID:
1471 set_it(chan, &redirecting, NULL);
1473 case ID_FIELD_INVALID:
1476 ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
1479 ast_party_redirecting_free(&redirecting);
1480 } else if (member.argc == 1 && !strncasecmp("pres", member.argv[0], 4)) {
1483 val = ast_strdupa(value);
1484 ast_trim_blanks(val);
1486 if (('0' <= val[0]) && (val[0] <= '9')) {
1489 pres = ast_parse_caller_presentation(val);
1494 "Unknown redirecting combined presentation '%s', value unchanged\n", val);
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);
1502 } else if (member.argc == 1 && !strcasecmp("reason", member.argv[0])) {
1505 val = ast_strdupa(value);
1506 ast_trim_blanks(val);
1508 if (('0' <= val[0]) && (val[0] <= '9')) {
1511 reason = ast_redirecting_reason_parse(val);
1515 ast_log(LOG_ERROR, "Unknown redirecting reason '%s', value unchanged\n", val);
1517 redirecting.reason = reason;
1518 set_it(chan, &redirecting, NULL);
1520 } else if (member.argc == 1 && !strcasecmp("count", member.argv[0])) {
1521 val = ast_strdupa(value);
1522 ast_trim_blanks(val);
1524 if (('0' <= val[0]) && (val[0] <= '9')) {
1525 redirecting.count = atoi(val);
1526 set_it(chan, &redirecting, NULL);
1528 ast_log(LOG_ERROR, "Unknown redirecting count '%s', value unchanged\n", val);
1531 ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
1537 static struct ast_custom_function callerid_function = {
1539 .read = callerid_read,
1541 .write = callerid_write,
1544 static struct ast_custom_function callerpres_function = {
1545 .name = "CALLERPRES",
1546 .read = callerpres_read,
1548 .write = callerpres_write,
1551 static struct ast_custom_function connectedline_function = {
1552 .name = "CONNECTEDLINE",
1553 .read = connectedline_read,
1554 .write = connectedline_write,
1557 static struct ast_custom_function redirecting_function = {
1558 .name = "REDIRECTING",
1559 .read = redirecting_read,
1560 .write = redirecting_write,
1565 * \brief Unload the function module
1567 * \retval 0 on success.
1568 * \retval -1 on error.
1570 static int unload_module(void)
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);
1583 * \brief Load and initialize the function module.
1585 * \retval AST_MODULE_LOAD_SUCCESS on success.
1586 * \retval AST_MODULE_LOAD_DECLINE on error.
1588 static int load_module(void)
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;
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)");