func_callerid.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999-2010, Digium, Inc.
00005  *
00006  * See http://www.asterisk.org for more information about
00007  * the Asterisk project. Please do not directly contact
00008  * any of the maintainers of this project for assistance;
00009  * the project provides a web site, mailing lists and IRC
00010  * channels for your use.
00011  *
00012  * This program is free software, distributed under the terms of
00013  * the GNU General Public License Version 2. See the LICENSE file
00014  * at the top of the source tree.
00015  */
00016 
00017 /*! \file
00018  *
00019  * \brief Party ID related dialplan functions (Caller-ID, Connected-line, Redirecting)
00020  *
00021  * \ingroup functions
00022  *
00023  * See Also:
00024  * \arg \ref AstCREDITS
00025  */
00026 
00027 /*** MODULEINFO
00028    <support_level>core</support_level>
00029  ***/
00030 
00031 #include "asterisk.h"
00032 
00033 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 411328 $")
00034 
00035 #include "asterisk/module.h"
00036 #include "asterisk/channel.h"
00037 #include "asterisk/pbx.h"
00038 #include "asterisk/utils.h"
00039 #include "asterisk/app.h"
00040 #include "asterisk/callerid.h"
00041 
00042 /*
00043  * Do not document the CALLERID(pres) datatype.
00044  * The name and number now have their own presentation value.  The pres
00045  * option will simply live on as a historical relic with as best
00046  * as can be managed backward compatible meaning.
00047  *
00048  * Do not document the CALLERID(ton) datatype.
00049  * It is an alias for num-plan.
00050  *
00051  * Do not document the CALLERID(ANI-subaddr-...) datatype.
00052  * This is not used.
00053  *
00054  * Do not document the CONNECTEDLINE(source) datatype.
00055  * It has turned out to not be needed.  The source value is really
00056  * only useful as a possible tracing aid.
00057  *
00058  * Do not document the CONNECTEDLINE(pres) datatype.
00059  * The name and number now have their own presentation value.  The pres
00060  * option will simply live on as a historical relic with as best
00061  * as can be managed backward compatible meaning.
00062  *
00063  * Do not document the CONNECTEDLINE(ton) datatype.
00064  * It is an alias for num-plan.
00065  *
00066  * Do not document the REDIRECTING(pres) datatype.
00067  * It has turned out that the from-pres and to-pres values must be kept
00068  * separate.  They represent two different parties and there is a case when
00069  * they are active at the same time.  The plain pres option will simply
00070  * live on as a historical relic.
00071  *
00072  * Do not document the REDIRECTING(orig-pres), REDIRECTING(from-pres),
00073  * or REDIRECTING(to-pres) datatypes.
00074  * The name and number now have their own presentation value.  The orig-pres,
00075  * from-pres, and to-pres options will simply live on as a historical relic
00076  * with as best as can be managed backward compatible meaning.
00077  *
00078  * Do not document the REDIRECTING(orig-ton), REDIRECTING(from-ton),
00079  * or REDIRECTING(to-ton) datatypes.
00080  * They are aliases for orig-num-plan, from-num-plan, and to-num-plan
00081  * respectively.
00082  */
00083 /*** DOCUMENTATION
00084    <function name="CALLERID" language="en_US">
00085       <synopsis>
00086          Gets or sets Caller*ID data on the channel.
00087       </synopsis>
00088       <syntax>
00089          <parameter name="datatype" required="true">
00090             <para>The allowable datatypes are:</para>
00091             <enumlist>
00092                <enum name = "all" />
00093                <enum name = "name" />
00094                <enum name = "name-valid" />
00095                <enum name = "name-charset" />
00096                <enum name = "name-pres" />
00097                <enum name = "num" />
00098                <enum name = "num-valid" />
00099                <enum name = "num-plan" />
00100                <enum name = "num-pres" />
00101                <enum name = "subaddr" />
00102                <enum name = "subaddr-valid" />
00103                <enum name = "subaddr-type" />
00104                <enum name = "subaddr-odd" />
00105                <enum name = "tag" />
00106                <enum name = "priv-all" />
00107                <enum name = "priv-name" />
00108                <enum name = "priv-name-valid" />
00109                <enum name = "priv-name-charset" />
00110                <enum name = "priv-name-pres" />
00111                <enum name = "priv-num" />
00112                <enum name = "priv-num-valid" />
00113                <enum name = "priv-num-plan" />
00114                <enum name = "priv-num-pres" />
00115                <enum name = "priv-subaddr" />
00116                <enum name = "priv-subaddr-valid" />
00117                <enum name = "priv-subaddr-type" />
00118                <enum name = "priv-subaddr-odd" />
00119                <enum name = "priv-tag" />
00120                <enum name = "ANI-all" />
00121                <enum name = "ANI-name" />
00122                <enum name = "ANI-name-valid" />
00123                <enum name = "ANI-name-charset" />
00124                <enum name = "ANI-name-pres" />
00125                <enum name = "ANI-num" />
00126                <enum name = "ANI-num-valid" />
00127                <enum name = "ANI-num-plan" />
00128                <enum name = "ANI-num-pres" />
00129                <enum name = "ANI-tag" />
00130                <enum name = "RDNIS" />
00131                <enum name = "DNID" />
00132                <enum name = "dnid-num-plan" />
00133                <enum name = "dnid-subaddr" />
00134                <enum name = "dnid-subaddr-valid" />
00135                <enum name = "dnid-subaddr-type" />
00136                <enum name = "dnid-subaddr-odd" />
00137             </enumlist>
00138          </parameter>
00139          <parameter name="CID">
00140             <para>Optional Caller*ID to parse instead of using the Caller*ID from the
00141             channel. This parameter is only optional when reading the Caller*ID.</para>
00142          </parameter>
00143       </syntax>
00144       <description>
00145          <para>Gets or sets Caller*ID data on the channel. Uses channel callerid by
00146          default or optional callerid, if specified.</para>
00147          <para>The allowable values for the <replaceable>name-charset</replaceable>
00148          field are the following:</para>
00149          <enumlist>
00150             <enum name = "unknown"><para>Unknown</para></enum>
00151             <enum name = "iso8859-1"><para>ISO8859-1</para></enum>
00152             <enum name = "withdrawn"><para>Withdrawn</para></enum>
00153             <enum name = "iso8859-2"><para>ISO8859-2</para></enum>
00154             <enum name = "iso8859-3"><para>ISO8859-3</para></enum>
00155             <enum name = "iso8859-4"><para>ISO8859-4</para></enum>
00156             <enum name = "iso8859-5"><para>ISO8859-5</para></enum>
00157             <enum name = "iso8859-7"><para>ISO8859-7</para></enum>
00158             <enum name = "bmp"><para>ISO10646 Bmp String</para></enum>
00159             <enum name = "utf8"><para>ISO10646 UTF-8 String</para></enum>
00160          </enumlist>
00161       </description>
00162    </function>
00163    <function name="CALLERPRES" language="en_US">
00164       <synopsis>
00165          Gets or sets Caller*ID presentation on the channel.
00166       </synopsis>
00167       <syntax />
00168       <description>
00169          <para>Gets or sets Caller*ID presentation on the channel.
00170          This function is deprecated in favor of CALLERID(num-pres)
00171          and CALLERID(name-pres).
00172          The following values are valid:</para>
00173          <enumlist>
00174             <enum name="allowed_not_screened">
00175                <para>Presentation Allowed, Not Screened.</para>
00176             </enum>
00177             <enum name="allowed_passed_screen">
00178                <para>Presentation Allowed, Passed Screen.</para>
00179             </enum>
00180             <enum name="allowed_failed_screen">
00181                <para>Presentation Allowed, Failed Screen.</para>
00182             </enum>
00183             <enum name="allowed">
00184                <para>Presentation Allowed, Network Number.</para>
00185             </enum>
00186             <enum name="prohib_not_screened">
00187                <para>Presentation Prohibited, Not Screened.</para>
00188             </enum>
00189             <enum name="prohib_passed_screen">
00190                <para>Presentation Prohibited, Passed Screen.</para>
00191             </enum>
00192             <enum name="prohib_failed_screen">
00193                <para>Presentation Prohibited, Failed Screen.</para>
00194             </enum>
00195             <enum name="prohib">
00196                <para>Presentation Prohibited, Network Number.</para>
00197             </enum>
00198             <enum name="unavailable">
00199                <para>Number Unavailable.</para>
00200             </enum>
00201          </enumlist>
00202       </description>
00203    </function>
00204    <function name="CONNECTEDLINE" language="en_US">
00205       <synopsis>
00206          Gets or sets Connected Line data on the channel.
00207       </synopsis>
00208       <syntax>
00209          <parameter name="datatype" required="true">
00210             <para>The allowable datatypes are:</para>
00211             <enumlist>
00212                <enum name = "all" />
00213                <enum name = "name" />
00214                <enum name = "name-valid" />
00215                <enum name = "name-charset" />
00216                <enum name = "name-pres" />
00217                <enum name = "num" />
00218                <enum name = "num-valid" />
00219                <enum name = "num-plan" />
00220                <enum name = "num-pres" />
00221                <enum name = "subaddr" />
00222                <enum name = "subaddr-valid" />
00223                <enum name = "subaddr-type" />
00224                <enum name = "subaddr-odd" />
00225                <enum name = "tag" />
00226                <enum name = "priv-all" />
00227                <enum name = "priv-name" />
00228                <enum name = "priv-name-valid" />
00229                <enum name = "priv-name-charset" />
00230                <enum name = "priv-name-pres" />
00231                <enum name = "priv-num" />
00232                <enum name = "priv-num-valid" />
00233                <enum name = "priv-num-plan" />
00234                <enum name = "priv-num-pres" />
00235                <enum name = "priv-subaddr" />
00236                <enum name = "priv-subaddr-valid" />
00237                <enum name = "priv-subaddr-type" />
00238                <enum name = "priv-subaddr-odd" />
00239                <enum name = "priv-tag" />
00240             </enumlist>
00241          </parameter>
00242          <parameter name="i">
00243             <para>If set, this will prevent the channel from sending out protocol
00244             messages because of the value being set</para>
00245          </parameter>
00246       </syntax>
00247       <description>
00248          <para>Gets or sets Connected Line data on the channel.</para>
00249          <para>The allowable values for the <replaceable>name-charset</replaceable>
00250          field are the following:</para>
00251          <enumlist>
00252             <enum name = "unknown"><para>Unknown</para></enum>
00253             <enum name = "iso8859-1"><para>ISO8859-1</para></enum>
00254             <enum name = "withdrawn"><para>Withdrawn</para></enum>
00255             <enum name = "iso8859-2"><para>ISO8859-2</para></enum>
00256             <enum name = "iso8859-3"><para>ISO8859-3</para></enum>
00257             <enum name = "iso8859-4"><para>ISO8859-4</para></enum>
00258             <enum name = "iso8859-5"><para>ISO8859-5</para></enum>
00259             <enum name = "iso8859-7"><para>ISO8859-7</para></enum>
00260             <enum name = "bmp"><para>ISO10646 Bmp String</para></enum>
00261             <enum name = "utf8"><para>ISO10646 UTF-8 String</para></enum>
00262          </enumlist>
00263       </description>
00264    </function>
00265    <function name="REDIRECTING" language="en_US">
00266       <synopsis>
00267          Gets or sets Redirecting data on the channel.
00268       </synopsis>
00269       <syntax>
00270          <parameter name="datatype" required="true">
00271             <para>The allowable datatypes are:</para>
00272             <enumlist>
00273                <enum name = "orig-all" />
00274                <enum name = "orig-name" />
00275                <enum name = "orig-name-valid" />
00276                <enum name = "orig-name-charset" />
00277                <enum name = "orig-name-pres" />
00278                <enum name = "orig-num" />
00279                <enum name = "orig-num-valid" />
00280                <enum name = "orig-num-plan" />
00281                <enum name = "orig-num-pres" />
00282                <enum name = "orig-subaddr" />
00283                <enum name = "orig-subaddr-valid" />
00284                <enum name = "orig-subaddr-type" />
00285                <enum name = "orig-subaddr-odd" />
00286                <enum name = "orig-tag" />
00287                <enum name = "orig-reason" />
00288                <enum name = "from-all" />
00289                <enum name = "from-name" />
00290                <enum name = "from-name-valid" />
00291                <enum name = "from-name-charset" />
00292                <enum name = "from-name-pres" />
00293                <enum name = "from-num" />
00294                <enum name = "from-num-valid" />
00295                <enum name = "from-num-plan" />
00296                <enum name = "from-num-pres" />
00297                <enum name = "from-subaddr" />
00298                <enum name = "from-subaddr-valid" />
00299                <enum name = "from-subaddr-type" />
00300                <enum name = "from-subaddr-odd" />
00301                <enum name = "from-tag" />
00302                <enum name = "to-all" />
00303                <enum name = "to-name" />
00304                <enum name = "to-name-valid" />
00305                <enum name = "to-name-charset" />
00306                <enum name = "to-name-pres" />
00307                <enum name = "to-num" />
00308                <enum name = "to-num-valid" />
00309                <enum name = "to-num-plan" />
00310                <enum name = "to-num-pres" />
00311                <enum name = "to-subaddr" />
00312                <enum name = "to-subaddr-valid" />
00313                <enum name = "to-subaddr-type" />
00314                <enum name = "to-subaddr-odd" />
00315                <enum name = "to-tag" />
00316                <enum name = "priv-orig-all" />
00317                <enum name = "priv-orig-name" />
00318                <enum name = "priv-orig-name-valid" />
00319                <enum name = "priv-orig-name-charset" />
00320                <enum name = "priv-orig-name-pres" />
00321                <enum name = "priv-orig-num" />
00322                <enum name = "priv-orig-num-valid" />
00323                <enum name = "priv-orig-num-plan" />
00324                <enum name = "priv-orig-num-pres" />
00325                <enum name = "priv-orig-subaddr" />
00326                <enum name = "priv-orig-subaddr-valid" />
00327                <enum name = "priv-orig-subaddr-type" />
00328                <enum name = "priv-orig-subaddr-odd" />
00329                <enum name = "priv-orig-tag" />
00330                <enum name = "priv-from-all" />
00331                <enum name = "priv-from-name" />
00332                <enum name = "priv-from-name-valid" />
00333                <enum name = "priv-from-name-charset" />
00334                <enum name = "priv-from-name-pres" />
00335                <enum name = "priv-from-num" />
00336                <enum name = "priv-from-num-valid" />
00337                <enum name = "priv-from-num-plan" />
00338                <enum name = "priv-from-num-pres" />
00339                <enum name = "priv-from-subaddr" />
00340                <enum name = "priv-from-subaddr-valid" />
00341                <enum name = "priv-from-subaddr-type" />
00342                <enum name = "priv-from-subaddr-odd" />
00343                <enum name = "priv-from-tag" />
00344                <enum name = "priv-to-all" />
00345                <enum name = "priv-to-name" />
00346                <enum name = "priv-to-name-valid" />
00347                <enum name = "priv-to-name-charset" />
00348                <enum name = "priv-to-name-pres" />
00349                <enum name = "priv-to-num" />
00350                <enum name = "priv-to-num-valid" />
00351                <enum name = "priv-to-num-plan" />
00352                <enum name = "priv-to-num-pres" />
00353                <enum name = "priv-to-subaddr" />
00354                <enum name = "priv-to-subaddr-valid" />
00355                <enum name = "priv-to-subaddr-type" />
00356                <enum name = "priv-to-subaddr-odd" />
00357                <enum name = "priv-to-tag" />
00358                <enum name = "reason" />
00359                <enum name = "count" />
00360             </enumlist>
00361          </parameter>
00362          <parameter name="i">
00363             <para>If set, this will prevent the channel from sending out protocol
00364             messages because of the value being set</para>
00365          </parameter>
00366       </syntax>
00367       <description>
00368          <para>Gets or sets Redirecting data on the channel.</para>
00369          <para>The allowable values for the <replaceable>reason</replaceable>
00370          and <replaceable>orig-reason</replaceable> fields are the following:</para>
00371          <enumlist>
00372             <enum name = "unknown"><para>Unknown</para></enum>
00373             <enum name = "cfb"><para>Call Forwarding Busy</para></enum>
00374             <enum name = "cfnr"><para>Call Forwarding No Reply</para></enum>
00375             <enum name = "unavailable"><para>Callee is Unavailable</para></enum>
00376             <enum name = "time_of_day"><para>Time of Day</para></enum>
00377             <enum name = "dnd"><para>Do Not Disturb</para></enum>
00378             <enum name = "deflection"><para>Call Deflection</para></enum>
00379             <enum name = "follow_me"><para>Follow Me</para></enum>
00380             <enum name = "out_of_order"><para>Called DTE Out-Of-Order</para></enum>
00381             <enum name = "away"><para>Callee is Away</para></enum>
00382             <enum name = "cf_dte"><para>Call Forwarding By The Called DTE</para></enum>
00383             <enum name = "cfu"><para>Call Forwarding Unconditional</para></enum>
00384          </enumlist>
00385          <para>The allowable values for the <replaceable>xxx-name-charset</replaceable>
00386          field are the following:</para>
00387          <enumlist>
00388             <enum name = "unknown"><para>Unknown</para></enum>
00389             <enum name = "iso8859-1"><para>ISO8859-1</para></enum>
00390             <enum name = "withdrawn"><para>Withdrawn</para></enum>
00391             <enum name = "iso8859-2"><para>ISO8859-2</para></enum>
00392             <enum name = "iso8859-3"><para>ISO8859-3</para></enum>
00393             <enum name = "iso8859-4"><para>ISO8859-4</para></enum>
00394             <enum name = "iso8859-5"><para>ISO8859-5</para></enum>
00395             <enum name = "iso8859-7"><para>ISO8859-7</para></enum>
00396             <enum name = "bmp"><para>ISO10646 Bmp String</para></enum>
00397             <enum name = "utf8"><para>ISO10646 UTF-8 String</para></enum>
00398          </enumlist>
00399       </description>
00400    </function>
00401  ***/
00402 
00403 enum ID_FIELD_STATUS {
00404    ID_FIELD_VALID,
00405    ID_FIELD_INVALID,
00406    ID_FIELD_UNKNOWN
00407 };
00408 
00409 AST_DEFINE_APP_ARGS_TYPE(ast_party_func_args,
00410    AST_APP_ARG(member); /*!< Member name */
00411    AST_APP_ARG(opts);      /*!< Options token */
00412    AST_APP_ARG(other);     /*!< Any remining unused arguments */
00413    );
00414 
00415 AST_DEFINE_APP_ARGS_TYPE(ast_party_members,
00416    AST_APP_ARG(subnames[10]); /*!< Option member subnames */
00417    );
00418 
00419 enum CONNECTED_LINE_OPT_FLAGS {
00420    CONNECTED_LINE_OPT_INHIBIT = (1 << 0),
00421 };
00422 enum CONNECTED_LINE_OPT_ARGS {
00423    CONNECTED_LINE_OPT_DUMMY,  /*!< Delete this if CONNECTED_LINE ever gets an option with parameters. */
00424 
00425    /*! \note This entry _MUST_ be the last one in the enum */
00426    CONNECTED_LINE_OPT_ARG_ARRAY_SIZE
00427 };
00428 
00429 AST_APP_OPTIONS(connectedline_opts, BEGIN_OPTIONS
00430    AST_APP_OPTION('i', CONNECTED_LINE_OPT_INHIBIT),
00431 END_OPTIONS);
00432 
00433 enum REDIRECTING_OPT_FLAGS {
00434    REDIRECTING_OPT_INHIBIT = (1 << 0),
00435 };
00436 enum REDIRECTING_OPT_ARGS {
00437    REDIRECTING_OPT_DUMMY,  /*!< Delete this if REDIRECTING ever gets an option with parameters. */
00438 
00439    /*! \note This entry _MUST_ be the last one in the enum */
00440    REDIRECTING_OPT_ARG_ARRAY_SIZE
00441 };
00442 
00443 AST_APP_OPTIONS(redirecting_opts, BEGIN_OPTIONS
00444    AST_APP_OPTION('i', REDIRECTING_OPT_INHIBIT),
00445 END_OPTIONS);
00446 
00447 /*!
00448  * \internal
00449  * \brief Read values from the party name struct.
00450  * \since 1.8
00451  *
00452  * \param buf Buffer to fill with read value.
00453  * \param len Length of the buffer.
00454  * \param argc Number of party member subnames.
00455  * \param argv Party member subnames given.
00456  * \param name Party name to get values from.
00457  *
00458  * \retval ID_FIELD_VALID on success.
00459  * \retval ID_FIELD_UNKNOWN on unknown field name.
00460  */
00461 static enum ID_FIELD_STATUS party_name_read(char *buf, size_t len, int argc, char *argv[], const struct ast_party_name *name)
00462 {
00463    enum ID_FIELD_STATUS status;
00464 
00465    status = ID_FIELD_VALID;
00466 
00467    if (argc == 0) {
00468       /* We want the name string */
00469       if (name->valid && name->str) {
00470          ast_copy_string(buf, name->str, len);
00471       }
00472    } else if (argc == 1 && !strcasecmp("valid", argv[0])) {
00473       snprintf(buf, len, "%d", name->valid);
00474    } else if (argc == 1 && !strcasecmp("charset", argv[0])) {
00475       ast_copy_string(buf, ast_party_name_charset_str(name->char_set), len);
00476    } else if (argc == 1 && !strncasecmp("pres", argv[0], 4)) {
00477       /* Accept pres[entation] */
00478       ast_copy_string(buf, ast_named_caller_presentation(name->presentation), len);
00479    } else {
00480       status = ID_FIELD_UNKNOWN;
00481    }
00482 
00483    return status;
00484 }
00485 
00486 /*!
00487  * \internal
00488  * \brief Read values from the party number struct.
00489  * \since 1.8
00490  *
00491  * \param buf Buffer to fill with read value.
00492  * \param len Length of the buffer.
00493  * \param argc Number of party member subnames.
00494  * \param argv Party member subnames given.
00495  * \param number Party number to get values from.
00496  *
00497  * \retval ID_FIELD_VALID on success.
00498  * \retval ID_FIELD_UNKNOWN on unknown field name.
00499  */
00500 static enum ID_FIELD_STATUS party_number_read(char *buf, size_t len, int argc, char *argv[], const struct ast_party_number *number)
00501 {
00502    enum ID_FIELD_STATUS status;
00503 
00504    status = ID_FIELD_VALID;
00505 
00506    if (argc == 0) {
00507       /* We want the number string */
00508       if (number->valid && number->str) {
00509          ast_copy_string(buf, number->str, len);
00510       }
00511    } else if (argc == 1 && !strcasecmp("valid", argv[0])) {
00512       snprintf(buf, len, "%d", number->valid);
00513    } else if (argc == 1 && !strcasecmp("plan", argv[0])) {
00514       snprintf(buf, len, "%d", number->plan);
00515    } else if (argc == 1 && !strncasecmp("pres", argv[0], 4)) {
00516       /* Accept pres[entation] */
00517       ast_copy_string(buf, ast_named_caller_presentation(number->presentation), len);
00518    } else {
00519       status = ID_FIELD_UNKNOWN;
00520    }
00521 
00522    return status;
00523 }
00524 
00525 /*!
00526  * \internal
00527  * \brief Read values from the party subaddress struct.
00528  * \since 1.8
00529  *
00530  * \param buf Buffer to fill with read value.
00531  * \param len Length of the buffer.
00532  * \param argc Number of party member subnames.
00533  * \param argv Party member subnames given.
00534  * \param subaddress Party subaddress to get values from.
00535  *
00536  * \retval ID_FIELD_VALID on success.
00537  * \retval ID_FIELD_UNKNOWN on unknown field name.
00538  */
00539 static enum ID_FIELD_STATUS party_subaddress_read(char *buf, size_t len, int argc, char *argv[], const struct ast_party_subaddress *subaddress)
00540 {
00541    enum ID_FIELD_STATUS status;
00542 
00543    status = ID_FIELD_VALID;
00544 
00545    if (argc == 0) {
00546       /* We want the subaddress string */
00547       if (subaddress->str) {
00548          ast_copy_string(buf, subaddress->str, len);
00549       }
00550    } else if (argc == 1 && !strcasecmp("valid", argv[0])) {
00551       snprintf(buf, len, "%d", subaddress->valid);
00552    } else if (argc == 1 && !strcasecmp("type", argv[0])) {
00553       snprintf(buf, len, "%d", subaddress->type);
00554    } else if (argc == 1 && !strcasecmp("odd", argv[0])) {
00555       snprintf(buf, len, "%d", subaddress->odd_even_indicator);
00556    } else {
00557       status = ID_FIELD_UNKNOWN;
00558    }
00559 
00560    return status;
00561 }
00562 
00563 /*!
00564  * \internal
00565  * \brief Read values from the party id struct.
00566  * \since 1.8
00567  *
00568  * \param buf Buffer to fill with read value.
00569  * \param len Length of the buffer.
00570  * \param argc Number of party member subnames.
00571  * \param argv Party member subnames given.
00572  * \param id Party id to get values from.
00573  *
00574  * \retval ID_FIELD_VALID on success.
00575  * \retval ID_FIELD_UNKNOWN on unknown field name.
00576  */
00577 static enum ID_FIELD_STATUS party_id_read(char *buf, size_t len, int argc, char *argv[], const struct ast_party_id *id)
00578 {
00579    enum ID_FIELD_STATUS status;
00580 
00581    if (argc == 0) {
00582       /* Must have at least one subname. */
00583       return ID_FIELD_UNKNOWN;
00584    }
00585 
00586    status = ID_FIELD_VALID;
00587 
00588    if (argc == 1 && !strcasecmp("all", argv[0])) {
00589       snprintf(buf, len, "\"%s\" <%s>",
00590           S_COR(id->name.valid, id->name.str, ""),
00591           S_COR(id->number.valid, id->number.str, ""));
00592    } else if (!strcasecmp("name", argv[0])) {
00593       status = party_name_read(buf, len, argc - 1, argv + 1, &id->name);
00594    } else if (!strncasecmp("num", argv[0], 3)) {
00595       /* Accept num[ber] */
00596       status = party_number_read(buf, len, argc - 1, argv + 1, &id->number);
00597    } else if (!strncasecmp("subaddr", argv[0], 7)) {
00598       /* Accept subaddr[ess] */
00599       status = party_subaddress_read(buf, len, argc - 1, argv + 1, &id->subaddress);
00600    } else if (argc == 1 && !strcasecmp("tag", argv[0])) {
00601       if (id->tag) {
00602          ast_copy_string(buf, id->tag, len);
00603       }
00604    } else if (argc == 1 && !strcasecmp("ton", argv[0])) {
00605       /* ton is an alias for num-plan */
00606       snprintf(buf, len, "%d", id->number.plan);
00607    } else if (argc == 1 && !strncasecmp("pres", argv[0], 4)) {
00608       /*
00609        * Accept pres[entation]
00610        * This is the combined name/number presentation.
00611        */
00612       ast_copy_string(buf,
00613          ast_named_caller_presentation(ast_party_id_presentation(id)), len);
00614    } else {
00615       status = ID_FIELD_UNKNOWN;
00616    }
00617 
00618    return status;
00619 }
00620 
00621 /*!
00622  * \internal
00623  * \brief Write new values to the party name struct
00624  * \since 1.8
00625  *
00626  * \param name Party name struct to write values
00627  * \param argc Number of party member subnames.
00628  * \param argv Party member subnames given.
00629  * \param value Value to assign to the party name.
00630  *
00631  * \retval ID_FIELD_VALID on success.
00632  * \retval ID_FIELD_INVALID on error with field value.
00633  * \retval ID_FIELD_UNKNOWN on unknown field name.
00634  */
00635 static enum ID_FIELD_STATUS party_name_write(struct ast_party_name *name, int argc, char *argv[], const char *value)
00636 {
00637    char *val;
00638    enum ID_FIELD_STATUS status;
00639 
00640    status = ID_FIELD_VALID;
00641 
00642    if (argc == 0) {
00643       /* We are setting the name string */
00644       name->valid = 1;
00645       name->str = ast_strdup(value);
00646       ast_trim_blanks(name->str);
00647    } else if (argc == 1 && !strcasecmp("valid", argv[0])) {
00648       name->valid = atoi(value) ? 1 : 0;
00649    } else if (argc == 1 && !strcasecmp("charset", argv[0])) {
00650       int char_set;
00651 
00652       val = ast_strdupa(value);
00653       ast_trim_blanks(val);
00654 
00655       if (('0' <= val[0]) && (val[0] <= '9')) {
00656          char_set = atoi(val);
00657       } else {
00658          char_set = ast_party_name_charset_parse(val);
00659       }
00660 
00661       if (char_set < 0) {
00662          ast_log(LOG_ERROR,
00663             "Unknown name char-set '%s', value unchanged\n", val);
00664          status = ID_FIELD_INVALID;
00665       } else {
00666          name->char_set = char_set;
00667       }
00668    } else if (argc == 1 && !strncasecmp("pres", argv[0], 4)) {
00669       int pres;
00670 
00671       /* Accept pres[entation] */
00672       val = ast_strdupa(value);
00673       ast_trim_blanks(val);
00674 
00675       if (('0' <= val[0]) && (val[0] <= '9')) {
00676          pres = atoi(val);
00677       } else {
00678          pres = ast_parse_caller_presentation(val);
00679       }
00680 
00681       if (pres < 0) {
00682          ast_log(LOG_ERROR,
00683             "Unknown name presentation '%s', value unchanged\n", val);
00684          status = ID_FIELD_INVALID;
00685       } else {
00686          name->presentation = pres;
00687       }
00688    } else {
00689       status = ID_FIELD_UNKNOWN;
00690    }
00691 
00692    return status;
00693 }
00694 
00695 /*!
00696  * \internal
00697  * \brief Write new values to the party number struct
00698  * \since 1.8
00699  *
00700  * \param number Party number struct to write values
00701  * \param argc Number of party member subnames.
00702  * \param argv Party member subnames given.
00703  * \param value Value to assign to the party number.
00704  *
00705  * \retval ID_FIELD_VALID on success.
00706  * \retval ID_FIELD_INVALID on error with field value.
00707  * \retval ID_FIELD_UNKNOWN on unknown field name.
00708  */
00709 static enum ID_FIELD_STATUS party_number_write(struct ast_party_number *number, int argc, char *argv[], const char *value)
00710 {
00711    char *val;
00712    enum ID_FIELD_STATUS status;
00713 
00714    status = ID_FIELD_VALID;
00715 
00716    if (argc == 0) {
00717       /* We are setting the number string */
00718       number->valid = 1;
00719       number->str = ast_strdup(value);
00720       ast_trim_blanks(number->str);
00721    } else if (argc == 1 && !strcasecmp("valid", argv[0])) {
00722       number->valid = atoi(value) ? 1 : 0;
00723    } else if (argc == 1 && !strcasecmp("plan", argv[0])) {
00724       val = ast_strdupa(value);
00725       ast_trim_blanks(val);
00726 
00727       if (('0' <= val[0]) && (val[0] <= '9')) {
00728          number->plan = atoi(val);
00729       } else {
00730          ast_log(LOG_ERROR,
00731             "Unknown type-of-number/numbering-plan '%s', value unchanged\n", val);
00732          status = ID_FIELD_INVALID;
00733       }
00734    } else if (argc == 1 && !strncasecmp("pres", argv[0], 4)) {
00735       int pres;
00736 
00737       /* Accept pres[entation] */
00738       val = ast_strdupa(value);
00739       ast_trim_blanks(val);
00740 
00741       if (('0' <= val[0]) && (val[0] <= '9')) {
00742          pres = atoi(val);
00743       } else {
00744          pres = ast_parse_caller_presentation(val);
00745       }
00746 
00747       if (pres < 0) {
00748          ast_log(LOG_ERROR,
00749             "Unknown number presentation '%s', value unchanged\n", val);
00750          status = ID_FIELD_INVALID;
00751       } else {
00752          number->presentation = pres;
00753       }
00754    } else {
00755       status = ID_FIELD_UNKNOWN;
00756    }
00757 
00758    return status;
00759 }
00760 
00761 /*!
00762  * \internal
00763  * \brief Write new values to the party subaddress struct
00764  * \since 1.8
00765  *
00766  * \param subaddress Party subaddress struct to write values
00767  * \param argc Number of party member subnames.
00768  * \param argv Party member subnames given.
00769  * \param value Value to assign to the party subaddress.
00770  *
00771  * \retval ID_FIELD_VALID on success.
00772  * \retval ID_FIELD_INVALID on error with field value.
00773  * \retval ID_FIELD_UNKNOWN on unknown field name.
00774  */
00775 static enum ID_FIELD_STATUS party_subaddress_write(struct ast_party_subaddress *subaddress, int argc, char *argv[], const char *value)
00776 {
00777    enum ID_FIELD_STATUS status;
00778 
00779    status = ID_FIELD_VALID;
00780 
00781    if (argc == 0) {
00782       /* We are setting the subaddress string */
00783       subaddress->str = ast_strdup(value);
00784       ast_trim_blanks(subaddress->str);
00785    } else if (argc == 1 && !strcasecmp("valid", argv[0])) {
00786       subaddress->valid = atoi(value) ? 1 : 0;
00787    } else if (argc == 1 && !strcasecmp("type", argv[0])) {
00788       subaddress->type = atoi(value) ? 2 : 0;
00789    } else if (argc == 1 && !strcasecmp("odd", argv[0])) {
00790       subaddress->odd_even_indicator = atoi(value) ? 1 : 0;
00791    } else {
00792       status = ID_FIELD_UNKNOWN;
00793    }
00794 
00795    return status;
00796 }
00797 
00798 /*!
00799  * \internal
00800  * \brief Write new values to the party id struct
00801  * \since 1.8
00802  *
00803  * \param id Party ID struct to write values
00804  * \param argc Number of party member subnames.
00805  * \param argv Party member subnames given.
00806  * \param value Value to assign to the party id.
00807  *
00808  * \retval ID_FIELD_VALID on success.
00809  * \retval ID_FIELD_INVALID on error with field value.
00810  * \retval ID_FIELD_UNKNOWN on unknown field name.
00811  */
00812 static enum ID_FIELD_STATUS party_id_write(struct ast_party_id *id, int argc, char *argv[], const char *value)
00813 {
00814    char *val;
00815    enum ID_FIELD_STATUS status;
00816 
00817    if (argc == 0) {
00818       /* Must have at least one subname. */
00819       return ID_FIELD_UNKNOWN;
00820    }
00821 
00822    status = ID_FIELD_VALID;
00823 
00824    if (argc == 1 && !strcasecmp("all", argv[0])) {
00825       char name[256];
00826       char num[256];
00827 
00828       ast_callerid_split(value, name, sizeof(name), num, sizeof(num));
00829       id->name.valid = 1;
00830       id->name.str = ast_strdup(name);
00831       if (!id->name.str) {
00832          return ID_FIELD_INVALID;
00833       }
00834       id->number.valid = 1;
00835       id->number.str = ast_strdup(num);
00836       if (!id->number.str) {
00837          return ID_FIELD_INVALID;
00838       }
00839    } else if (!strcasecmp("name", argv[0])) {
00840       status = party_name_write(&id->name, argc - 1, argv + 1, value);
00841    } else if (!strncasecmp("num", argv[0], 3)) {
00842       /* Accept num[ber] */
00843       status = party_number_write(&id->number, argc - 1, argv + 1, value);
00844    } else if (!strncasecmp("subaddr", argv[0], 7)) {
00845       /* Accept subaddr[ess] */
00846       status = party_subaddress_write(&id->subaddress, argc - 1, argv + 1, value);
00847    } else if (argc == 1 && !strcasecmp("tag", argv[0])) {
00848       id->tag = ast_strdup(value);
00849       ast_trim_blanks(id->tag);
00850    } else if (argc == 1 && !strcasecmp("ton", argv[0])) {
00851       /* ton is an alias for num-plan */
00852       argv[0] = "plan";
00853       status = party_number_write(&id->number, argc, argv, value);
00854    } else if (argc == 1 && !strncasecmp("pres", argv[0], 4)) {
00855       int pres;
00856 
00857       /*
00858        * Accept pres[entation]
00859        * This is the combined name/number presentation.
00860        */
00861       val = ast_strdupa(value);
00862       ast_trim_blanks(val);
00863 
00864       if (('0' <= val[0]) && (val[0] <= '9')) {
00865          pres = atoi(val);
00866       } else {
00867          pres = ast_parse_caller_presentation(val);
00868       }
00869 
00870       if (pres < 0) {
00871          ast_log(LOG_ERROR,
00872             "Unknown combined presentation '%s', value unchanged\n", val);
00873          status = ID_FIELD_INVALID;
00874       } else {
00875          id->name.presentation = pres;
00876          id->number.presentation = pres;
00877       }
00878    } else {
00879       status = ID_FIELD_UNKNOWN;
00880    }
00881 
00882    return status;
00883 }
00884 
00885 /*! TRUE if we have already notified about CALLERPRES being deprecated. */
00886 static int callerpres_deprecate_notify;
00887 
00888 /*!
00889  * \internal
00890  * \brief Read values from the caller-id presentation information struct.
00891  *
00892  * \param chan Asterisk channel to read
00893  * \param cmd Not used
00894  * \param data Caller-id presentation function datatype string
00895  * \param buf Buffer to fill with read value.
00896  * \param len Length of the buffer
00897  *
00898  * \retval 0 on success.
00899  * \retval -1 on error.
00900  */
00901 static int callerpres_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00902 {
00903    if (!chan) {
00904       ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
00905       return -1;
00906    }
00907 
00908    if (!callerpres_deprecate_notify) {
00909       callerpres_deprecate_notify = 1;
00910       ast_log(LOG_WARNING, "CALLERPRES is deprecated."
00911          "  Use CALLERID(name-pres) or CALLERID(num-pres) instead.\n");
00912    }
00913    ast_copy_string(buf,
00914       ast_named_caller_presentation(ast_party_id_presentation(&ast_channel_caller(chan)->id)), len);
00915    return 0;
00916 }
00917 
00918 /*!
00919  * \internal
00920  * \brief Write new values to the caller-id presentation information struct.
00921  *
00922  * \param chan Asterisk channel to update
00923  * \param cmd Not used
00924  * \param data Caller-id presentation function datatype string
00925  * \param value Value to assign to the caller-id presentation information struct.
00926  *
00927  * \retval 0 on success.
00928  * \retval -1 on error.
00929  */
00930 static int callerpres_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
00931 {
00932    int pres;
00933 
00934    if (!chan) {
00935       ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
00936       return -1;
00937    }
00938 
00939    if (!callerpres_deprecate_notify) {
00940       callerpres_deprecate_notify = 1;
00941       ast_log(LOG_WARNING, "CALLERPRES is deprecated."
00942          "  Use CALLERID(name-pres) or CALLERID(num-pres) instead.\n");
00943    }
00944 
00945    pres = ast_parse_caller_presentation(value);
00946    if (pres < 0) {
00947       ast_log(LOG_WARNING, "'%s' is not a valid presentation (see 'show function CALLERPRES')\n", value);
00948    } else {
00949       ast_channel_caller(chan)->id.name.presentation = pres;
00950       ast_channel_caller(chan)->id.number.presentation = pres;
00951    }
00952    return 0;
00953 }
00954 
00955 /*!
00956  * \internal
00957  * \brief Read values from the caller-id information struct.
00958  *
00959  * \param chan Asterisk channel to read
00960  * \param cmd Not used
00961  * \param data Caller-id function datatype string
00962  * \param buf Buffer to fill with read value.
00963  * \param len Length of the buffer
00964  *
00965  * \retval 0 on success.
00966  * \retval -1 on error.
00967  */
00968 static int callerid_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00969 {
00970    char *parms;
00971    struct ast_party_members member;
00972    AST_DECLARE_APP_ARGS(args,
00973       AST_APP_ARG(member); /*!< Member name */
00974       AST_APP_ARG(cid);    /*!< Optional caller id to parse instead of from the channel. */
00975       );
00976 
00977    /* Ensure that the buffer is empty */
00978    *buf = 0;
00979 
00980    if (!chan) {
00981       return -1;
00982    }
00983 
00984    parms = ast_strdupa(data);
00985    AST_STANDARD_APP_ARGS(args, parms);
00986    if (args.argc == 0) {
00987       /* Must have at least one argument. */
00988       return -1;
00989    }
00990 
00991    AST_NONSTANDARD_APP_ARGS(member, args.member, '-');
00992    if (member.argc == 0 || ARRAY_LEN(member.subnames) <= member.argc) {
00993       /* Too few or too many subnames */
00994       return -1;
00995    }
00996 
00997    if (args.argc == 2) {
00998       char name[80];
00999       char num[80];
01000 
01001       ast_callerid_split(args.cid, name, sizeof(name), num, sizeof(num));
01002 
01003       if (member.argc == 1 && !strcasecmp("all", member.argv[0])) {
01004          snprintf(buf, len, "\"%s\" <%s>", name, num);
01005       } else if (member.argc == 1 && !strcasecmp("name", member.argv[0])) {
01006          ast_copy_string(buf, name, len);
01007       } else if (member.argc == 1 && !strncasecmp("num", member.argv[0], 3)) {
01008          /* Accept num[ber] */
01009          ast_copy_string(buf, num, len);
01010       } else {
01011          ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
01012       }
01013    } else {
01014       enum ID_FIELD_STATUS status;
01015       ast_channel_lock(chan);
01016 
01017       if (member.argc == 1 && !strcasecmp("rdnis", member.argv[0])) {
01018          if (ast_channel_redirecting(chan)->from.number.valid
01019             && ast_channel_redirecting(chan)->from.number.str) {
01020             ast_copy_string(buf, ast_channel_redirecting(chan)->from.number.str, len);
01021          }
01022       } else if (!strcasecmp("dnid", member.argv[0])) {
01023          if (member.argc == 1) {
01024             /* Setup as if user had given dnid-num instead. */
01025             member.argc = 2;
01026             member.argv[1] = "num";
01027          }
01028          if (!strncasecmp("num", member.argv[1], 3)) {
01029             /*
01030              * Accept num[ber]
01031              * dnid-num...
01032              */
01033             if (member.argc == 2) {
01034                /* dnid-num */
01035                if (ast_channel_dialed(chan)->number.str) {
01036                   ast_copy_string(buf, ast_channel_dialed(chan)->number.str, len);
01037                }
01038             } else if (member.argc == 3 && !strcasecmp("plan", member.argv[2])) {
01039                /* dnid-num-plan */
01040                snprintf(buf, len, "%d", ast_channel_dialed(chan)->number.plan);
01041             } else {
01042                ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
01043             }
01044          } else if (!strncasecmp("subaddr", member.argv[1], 7)) {
01045             /*
01046              * Accept subaddr[ess]
01047              * dnid-subaddr...
01048              */
01049             status = party_subaddress_read(buf, len, member.argc - 2, member.argv + 2,
01050                &ast_channel_dialed(chan)->subaddress);
01051             switch (status) {
01052             case ID_FIELD_VALID:
01053             case ID_FIELD_INVALID:
01054                break;
01055             default:
01056                ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
01057                break;
01058             }
01059          } else {
01060             ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
01061          }
01062       } else if (member.argc == 1 && !strcasecmp("ani2", member.argv[0])) {
01063          snprintf(buf, len, "%d", ast_channel_caller(chan)->ani2);
01064       } else if (!strcasecmp("ani", member.argv[0])) {
01065          if (member.argc == 1) {
01066             /* Setup as if user had given ani-num instead. */
01067             member.argc = 2;
01068             member.argv[1] = "num";
01069          }
01070          status = party_id_read(buf, len, member.argc - 1, member.argv + 1,
01071             &ast_channel_caller(chan)->ani);
01072          switch (status) {
01073          case ID_FIELD_VALID:
01074          case ID_FIELD_INVALID:
01075             break;
01076          default:
01077             ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
01078             break;
01079          }
01080       } else if (!strcasecmp("priv", member.argv[0])) {
01081          status = party_id_read(buf, len, member.argc - 1, member.argv + 1,
01082             &ast_channel_caller(chan)->priv);
01083          switch (status) {
01084          case ID_FIELD_VALID:
01085          case ID_FIELD_INVALID:
01086             break;
01087          default:
01088             ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
01089             break;
01090          }
01091       } else {
01092          status = party_id_read(buf, len, member.argc, member.argv, &ast_channel_caller(chan)->id);
01093          switch (status) {
01094          case ID_FIELD_VALID:
01095          case ID_FIELD_INVALID:
01096             break;
01097          default:
01098             ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
01099             break;
01100          }
01101       }
01102 
01103       ast_channel_unlock(chan);
01104    }
01105 
01106    return 0;
01107 }
01108 
01109 /*!
01110  * \internal
01111  * \brief Write new values to the caller-id information struct.
01112  *
01113  * \param chan Asterisk channel to update
01114  * \param cmd Not used
01115  * \param data Caller-id function datatype string
01116  * \param value Value to assign to the caller-id information struct.
01117  *
01118  * \retval 0 on success.
01119  * \retval -1 on error.
01120  */
01121 static int callerid_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
01122 {
01123    struct ast_party_caller caller;
01124    struct ast_party_dialed dialed;
01125    enum ID_FIELD_STATUS status;
01126    char *val;
01127    char *parms;
01128    struct ast_party_func_args args;
01129    struct ast_party_members member;
01130 
01131    if (!value || !chan) {
01132       return -1;
01133    }
01134 
01135    parms = ast_strdupa(data);
01136    AST_STANDARD_APP_ARGS(args, parms);
01137    if (args.argc == 0) {
01138       /* Must have at least one argument. */
01139       return -1;
01140    }
01141 
01142    AST_NONSTANDARD_APP_ARGS(member, args.member, '-');
01143    if (member.argc == 0 || ARRAY_LEN(member.subnames) <= member.argc) {
01144       /* Too few or too many subnames */
01145       return -1;
01146    }
01147 
01148    value = ast_skip_blanks(value);
01149 
01150    ast_channel_lock(chan);
01151    if (member.argc == 1 && !strcasecmp("rdnis", member.argv[0])) {
01152       ast_channel_redirecting(chan)->from.number.valid = 1;
01153       ast_free(ast_channel_redirecting(chan)->from.number.str);
01154       ast_channel_redirecting(chan)->from.number.str = ast_strdup(value);
01155    } else if (!strcasecmp("dnid", member.argv[0])) {
01156       ast_party_dialed_set_init(&dialed, ast_channel_dialed(chan));
01157       if (member.argc == 1) {
01158          /* Setup as if user had given dnid-num instead. */
01159          member.argc = 2;
01160          member.argv[1] = "num";
01161       }
01162       if (!strncasecmp("num", member.argv[1], 3)) {
01163          /*
01164           * Accept num[ber]
01165           * dnid-num...
01166           */
01167          if (member.argc == 2) {
01168             /* dnid-num */
01169             dialed.number.str = ast_strdup(value);
01170             ast_trim_blanks(dialed.number.str);
01171             ast_party_dialed_set(ast_channel_dialed(chan), &dialed);
01172          } else if (member.argc == 3 && !strcasecmp("plan", member.argv[2])) {
01173             /* dnid-num-plan */
01174             val = ast_strdupa(value);
01175             ast_trim_blanks(val);
01176 
01177             if (('0' <= val[0]) && (val[0] <= '9')) {
01178                ast_channel_dialed(chan)->number.plan = atoi(val);
01179             } else {
01180                ast_log(LOG_ERROR,
01181                   "Unknown type-of-number/numbering-plan '%s', value unchanged\n", val);
01182             }
01183          } else {
01184             ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
01185          }
01186       } else if (!strncasecmp("subaddr", member.argv[1], 7)) {
01187          /*
01188           * Accept subaddr[ess]
01189           * dnid-subaddr...
01190           */
01191          status = party_subaddress_write(&dialed.subaddress, member.argc - 2,
01192             member.argv + 2, value);
01193          switch (status) {
01194          case ID_FIELD_VALID:
01195             ast_party_dialed_set(ast_channel_dialed(chan), &dialed);
01196             break;
01197          case ID_FIELD_INVALID:
01198             break;
01199          default:
01200             ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
01201             break;
01202          }
01203       } else {
01204          ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
01205       }
01206       ast_party_dialed_free(&dialed);
01207    } else if (member.argc == 1 && !strcasecmp("ani2", member.argv[0])) {
01208       val = ast_strdupa(value);
01209       ast_trim_blanks(val);
01210 
01211       if (('0' <= val[0]) && (val[0] <= '9')) {
01212          ast_channel_caller(chan)->ani2 = atoi(val);
01213       } else {
01214          ast_log(LOG_ERROR, "Unknown callerid ani2 '%s', value unchanged\n", val);
01215       }
01216    } else if (!strcasecmp("ani", member.argv[0])) {
01217       ast_party_caller_set_init(&caller, ast_channel_caller(chan));
01218       if (member.argc == 1) {
01219          /* Setup as if user had given ani-num instead. */
01220          member.argc = 2;
01221          member.argv[1] = "num";
01222       }
01223       status = party_id_write(&caller.ani, member.argc - 1, member.argv + 1, value);
01224       switch (status) {
01225       case ID_FIELD_VALID:
01226          ast_party_caller_set(ast_channel_caller(chan), &caller, NULL);
01227          break;
01228       case ID_FIELD_INVALID:
01229          break;
01230       default:
01231          ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
01232          break;
01233       }
01234       ast_party_caller_free(&caller);
01235    } else if (!strcasecmp("priv", member.argv[0])) {
01236       ast_party_caller_set_init(&caller, ast_channel_caller(chan));
01237       status = party_id_write(&caller.priv, member.argc - 1, member.argv + 1, value);
01238       switch (status) {
01239       case ID_FIELD_VALID:
01240          ast_party_caller_set(ast_channel_caller(chan), &caller, NULL);
01241          break;
01242       case ID_FIELD_INVALID:
01243          break;
01244       default:
01245          ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
01246          break;
01247       }
01248       ast_party_caller_free(&caller);
01249    } else {
01250       ast_party_caller_set_init(&caller, ast_channel_caller(chan));
01251       status = party_id_write(&caller.id, member.argc, member.argv, value);
01252       switch (status) {
01253       case ID_FIELD_VALID:
01254          ast_channel_set_caller_event(chan, &caller, NULL);
01255          break;
01256       case ID_FIELD_INVALID:
01257          break;
01258       default:
01259          ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
01260          break;
01261       }
01262       ast_party_caller_free(&caller);
01263    }
01264    ast_channel_unlock(chan);
01265 
01266    return 0;
01267 }
01268 
01269 /*!
01270  * \internal
01271  * \brief Read values from the connected line information struct.
01272  *
01273  * \param chan Asterisk channel to read
01274  * \param cmd Not used
01275  * \param data Connected line function datatype string
01276  * \param buf Buffer to fill with read value.
01277  * \param len Length of the buffer
01278  *
01279  * \retval 0 on success.
01280  * \retval -1 on error.
01281  */
01282 static int connectedline_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
01283 {
01284    struct ast_party_members member;
01285    char *read_what;
01286    enum ID_FIELD_STATUS status;
01287 
01288    /* Ensure that the buffer is empty */
01289    *buf = 0;
01290 
01291    if (!chan) {
01292       return -1;
01293    }
01294 
01295    read_what = ast_strdupa(data);
01296    AST_NONSTANDARD_APP_ARGS(member, read_what, '-');
01297    if (member.argc == 0 || ARRAY_LEN(member.subnames) <= member.argc) {
01298       /* Too few or too many subnames */
01299       return -1;
01300    }
01301 
01302    ast_channel_lock(chan);
01303 
01304    if (member.argc == 1 && !strcasecmp("source", member.argv[0])) {
01305       ast_copy_string(buf, ast_connected_line_source_name(ast_channel_connected(chan)->source), len);
01306    } else if (!strcasecmp("priv", member.argv[0])) {
01307       status = party_id_read(buf, len, member.argc - 1, member.argv + 1,
01308          &ast_channel_connected(chan)->priv);
01309       switch (status) {
01310       case ID_FIELD_VALID:
01311       case ID_FIELD_INVALID:
01312          break;
01313       default:
01314          ast_log(LOG_ERROR, "Unknown connectedline data type '%s'.\n", data);
01315          break;
01316       }
01317    } else {
01318       status = party_id_read(buf, len, member.argc, member.argv, &ast_channel_connected(chan)->id);
01319       switch (status) {
01320       case ID_FIELD_VALID:
01321       case ID_FIELD_INVALID:
01322          break;
01323       default:
01324          ast_log(LOG_ERROR, "Unknown connectedline data type '%s'.\n", data);
01325          break;
01326       }
01327    }
01328 
01329    ast_channel_unlock(chan);
01330 
01331    return 0;
01332 }
01333 
01334 /*!
01335  * \internal
01336  * \brief Write new values to the connected line information struct.
01337  *
01338  * \param chan Asterisk channel to update
01339  * \param cmd Not used
01340  * \param data Connected line function datatype string
01341  * \param value Value to assign to the connected line information struct.
01342  *
01343  * \retval 0 on success.
01344  * \retval -1 on error.
01345  */
01346 static int connectedline_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
01347 {
01348    struct ast_party_connected_line connected;
01349    char *val;
01350    char *parms;
01351    void (*set_it)(struct ast_channel *chan, const struct ast_party_connected_line *connected, const struct ast_set_party_connected_line *update);
01352    struct ast_party_func_args args;
01353    struct ast_party_members member;
01354    struct ast_flags opts;
01355    char *opt_args[CONNECTED_LINE_OPT_ARG_ARRAY_SIZE];
01356    enum ID_FIELD_STATUS status;
01357 
01358    if (!value || !chan) {
01359       return -1;
01360    }
01361 
01362    parms = ast_strdupa(data);
01363    AST_STANDARD_APP_ARGS(args, parms);
01364    if (args.argc == 0) {
01365       /* Must have at least one argument. */
01366       return -1;
01367    }
01368 
01369    AST_NONSTANDARD_APP_ARGS(member, args.member, '-');
01370    if (member.argc == 0 || ARRAY_LEN(member.subnames) <= member.argc) {
01371       /* Too few or too many subnames */
01372       return -1;
01373    }
01374 
01375    if (ast_app_parse_options(connectedline_opts, &opts, opt_args, args.opts)) {
01376       /* General invalid option syntax. */
01377       return -1;
01378    }
01379 
01380    /* Determine if the update indication inhibit option is present */
01381    if (ast_test_flag(&opts, CONNECTED_LINE_OPT_INHIBIT)) {
01382       set_it = ast_channel_set_connected_line;
01383    } else {
01384       set_it = ast_channel_update_connected_line;
01385    }
01386 
01387    ast_channel_lock(chan);
01388    ast_party_connected_line_set_init(&connected, ast_channel_connected(chan));
01389    ast_channel_unlock(chan);
01390 
01391    value = ast_skip_blanks(value);
01392 
01393    if (member.argc == 1 && !strcasecmp("source", member.argv[0])) {
01394       int source;
01395 
01396       val = ast_strdupa(value);
01397       ast_trim_blanks(val);
01398 
01399       if (('0' <= val[0]) && (val[0] <= '9')) {
01400          source = atoi(val);
01401       } else {
01402          source = ast_connected_line_source_parse(val);
01403       }
01404 
01405       if (source < 0) {
01406          ast_log(LOG_ERROR, "Unknown connectedline source '%s', value unchanged\n", val);
01407       } else {
01408          connected.source = source;
01409          set_it(chan, &connected, NULL);
01410       }
01411    } else if (!strcasecmp("priv", member.argv[0])) {
01412       status = party_id_write(&connected.priv, member.argc - 1, member.argv + 1, value);
01413       switch (status) {
01414       case ID_FIELD_VALID:
01415          set_it(chan, &connected, NULL);
01416          break;
01417       case ID_FIELD_INVALID:
01418          break;
01419       default:
01420          ast_log(LOG_ERROR, "Unknown connectedline data type '%s'.\n", data);
01421          break;
01422       }
01423       ast_party_connected_line_free(&connected);
01424    } else {
01425       status = party_id_write(&connected.id, member.argc, member.argv, value);
01426       switch (status) {
01427       case ID_FIELD_VALID:
01428          set_it(chan, &connected, NULL);
01429          break;
01430       case ID_FIELD_INVALID:
01431          break;
01432       default:
01433          ast_log(LOG_ERROR, "Unknown connectedline data type '%s'.\n", data);
01434          break;
01435       }
01436       ast_party_connected_line_free(&connected);
01437    }
01438 
01439    return 0;
01440 }
01441 
01442 /*!
01443  * \internal
01444  * \brief Read values from the redirecting information struct.
01445  *
01446  * \param chan Asterisk channel to read
01447  * \param cmd Not used
01448  * \param data Redirecting function datatype string
01449  * \param buf Buffer to fill with read value.
01450  * \param len Length of the buffer
01451  *
01452  * \retval 0 on success.
01453  * \retval -1 on error.
01454  */
01455 static int redirecting_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
01456 {
01457    struct ast_party_members member;
01458    char *read_what;
01459    const struct ast_party_redirecting *ast_redirecting;
01460    enum ID_FIELD_STATUS status;
01461 
01462    /* Ensure that the buffer is empty */
01463    *buf = 0;
01464 
01465    if (!chan) {
01466       return -1;
01467    }
01468 
01469    read_what = ast_strdupa(data);
01470    AST_NONSTANDARD_APP_ARGS(member, read_what, '-');
01471    if (member.argc == 0 || ARRAY_LEN(member.subnames) <= member.argc) {
01472       /* Too few or too many subnames */
01473       return -1;
01474    }
01475 
01476    ast_channel_lock(chan);
01477 
01478    ast_redirecting = ast_channel_redirecting(chan);
01479    if (!strcasecmp("orig", member.argv[0])) {
01480       if (member.argc == 2 && !strcasecmp("reason", member.argv[1])) {
01481          ast_copy_string(buf,
01482             ast_redirecting_reason_name(&ast_redirecting->orig_reason), len);
01483       } else {
01484          status = party_id_read(buf, len, member.argc - 1, member.argv + 1,
01485             &ast_redirecting->orig);
01486          switch (status) {
01487          case ID_FIELD_VALID:
01488          case ID_FIELD_INVALID:
01489             break;
01490          default:
01491             ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
01492             break;
01493          }
01494       }
01495    } else if (!strcasecmp("from", member.argv[0])) {
01496       status = party_id_read(buf, len, member.argc - 1, member.argv + 1,
01497          &ast_redirecting->from);
01498       switch (status) {
01499       case ID_FIELD_VALID:
01500       case ID_FIELD_INVALID:
01501          break;
01502       default:
01503          ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
01504          break;
01505       }
01506    } else if (!strcasecmp("to", member.argv[0])) {
01507       status = party_id_read(buf, len, member.argc - 1, member.argv + 1,
01508          &ast_redirecting->to);
01509       switch (status) {
01510       case ID_FIELD_VALID:
01511       case ID_FIELD_INVALID:
01512          break;
01513       default:
01514          ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
01515          break;
01516       }
01517    } else if (member.argc == 1 && !strncasecmp("pres", member.argv[0], 4)) {
01518       /*
01519        * Accept pres[entation]
01520        * This is the combined from name/number presentation.
01521        */
01522       ast_copy_string(buf,
01523          ast_named_caller_presentation(
01524             ast_party_id_presentation(&ast_redirecting->from)), len);
01525    } else if (member.argc == 1 && !strcasecmp("reason", member.argv[0])) {
01526       ast_copy_string(buf, ast_redirecting_reason_name(&ast_redirecting->reason), len);
01527    } else if (member.argc == 1 && !strcasecmp("count", member.argv[0])) {
01528       snprintf(buf, len, "%d", ast_redirecting->count);
01529    } else if (1 < member.argc && !strcasecmp("priv", member.argv[0])) {
01530       if (!strcasecmp("orig", member.argv[1])) {
01531          status = party_id_read(buf, len, member.argc - 2, member.argv + 2,
01532             &ast_redirecting->priv_orig);
01533          switch (status) {
01534          case ID_FIELD_VALID:
01535          case ID_FIELD_INVALID:
01536             break;
01537          default:
01538             ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
01539             break;
01540          }
01541       } else if (!strcasecmp("from", member.argv[1])) {
01542          status = party_id_read(buf, len, member.argc - 2, member.argv + 2,
01543             &ast_redirecting->priv_from);
01544          switch (status) {
01545          case ID_FIELD_VALID:
01546          case ID_FIELD_INVALID:
01547             break;
01548          default:
01549             ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
01550             break;
01551          }
01552       } else if (!strcasecmp("to", member.argv[1])) {
01553          status = party_id_read(buf, len, member.argc - 2, member.argv + 2,
01554             &ast_redirecting->priv_to);
01555          switch (status) {
01556          case ID_FIELD_VALID:
01557          case ID_FIELD_INVALID:
01558             break;
01559          default:
01560             ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
01561             break;
01562          }
01563       } else {
01564          ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
01565       }
01566    } else {
01567       ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
01568    }
01569 
01570    ast_channel_unlock(chan);
01571 
01572    return 0;
01573 }
01574 
01575 /*!
01576  * \internal
01577  * \brief Write new values to the redirecting information struct.
01578  *
01579  * \param chan Asterisk channel to update
01580  * \param cmd Not used
01581  * \param data Redirecting function datatype string
01582  * \param value Value to assign to the redirecting information struct.
01583  *
01584  * \retval 0 on success.
01585  * \retval -1 on error.
01586  */
01587 static int redirecting_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
01588 {
01589    struct ast_party_redirecting redirecting;
01590    enum ID_FIELD_STATUS status;
01591    char *val;
01592    char *parms;
01593    void (*set_it)(struct ast_channel *chan, const struct ast_party_redirecting *redirecting, const struct ast_set_party_redirecting *update);
01594    struct ast_party_func_args args;
01595    struct ast_party_members member;
01596    struct ast_flags opts;
01597    char *opt_args[REDIRECTING_OPT_ARG_ARRAY_SIZE];
01598 
01599    if (!value || !chan) {
01600       return -1;
01601    }
01602 
01603    parms = ast_strdupa(data);
01604    AST_STANDARD_APP_ARGS(args, parms);
01605    if (args.argc == 0) {
01606       /* Must have at least one argument. */
01607       return -1;
01608    }
01609 
01610    AST_NONSTANDARD_APP_ARGS(member, args.member, '-');
01611    if (member.argc == 0 || ARRAY_LEN(member.subnames) <= member.argc) {
01612       /* Too few or too many subnames */
01613       return -1;
01614    }
01615 
01616    if (ast_app_parse_options(redirecting_opts, &opts, opt_args, args.opts)) {
01617       /* General invalid option syntax. */
01618       return -1;
01619    }
01620 
01621    /* Determine if the update indication inhibit option is present */
01622    if (ast_test_flag(&opts, REDIRECTING_OPT_INHIBIT)) {
01623       set_it = ast_channel_set_redirecting;
01624    } else {
01625       set_it = ast_channel_update_redirecting;
01626    }
01627 
01628    ast_channel_lock(chan);
01629    ast_party_redirecting_set_init(&redirecting, ast_channel_redirecting(chan));
01630    ast_channel_unlock(chan);
01631 
01632    value = ast_skip_blanks(value);
01633 
01634    if (!strcasecmp("orig", member.argv[0])) {
01635       if (member.argc == 2 && !strcasecmp("reason", member.argv[1])) {
01636          int reason;
01637 
01638          val = ast_strdupa(value);
01639          ast_trim_blanks(val);
01640 
01641          if (('0' <= val[0]) && (val[0] <= '9')) {
01642             reason = atoi(val);
01643          } else {
01644             reason = ast_redirecting_reason_parse(val);
01645          }
01646 
01647          if (reason < 0) {
01648          /* The argument passed into the function does not correspond to a pre-defined
01649           * reason, so we can just set the reason string to what was given and set the
01650           * code to be unknown
01651           */
01652             redirecting.orig_reason.code = AST_REDIRECTING_REASON_UNKNOWN;
01653             redirecting.orig_reason.str = val;
01654             set_it(chan, &redirecting, NULL);
01655          } else {
01656             redirecting.orig_reason.code = reason;
01657             redirecting.orig_reason.str = "";
01658             set_it(chan, &redirecting, NULL);
01659          }
01660       } else {
01661          status = party_id_write(&redirecting.orig, member.argc - 1, member.argv + 1,
01662             value);
01663          switch (status) {
01664          case ID_FIELD_VALID:
01665             set_it(chan, &redirecting, NULL);
01666             break;
01667          case ID_FIELD_INVALID:
01668             break;
01669          default:
01670             ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
01671             break;
01672          }
01673          ast_party_redirecting_free(&redirecting);
01674       }
01675    } else if (!strcasecmp("from", member.argv[0])) {
01676       status = party_id_write(&redirecting.from, member.argc - 1, member.argv + 1,
01677          value);
01678       switch (status) {
01679       case ID_FIELD_VALID:
01680          set_it(chan, &redirecting, NULL);
01681          break;
01682       case ID_FIELD_INVALID:
01683          break;
01684       default:
01685          ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
01686          break;
01687       }
01688       ast_party_redirecting_free(&redirecting);
01689    } else if (!strcasecmp("to", member.argv[0])) {
01690       status = party_id_write(&redirecting.to, member.argc - 1, member.argv + 1, value);
01691       switch (status) {
01692       case ID_FIELD_VALID:
01693          set_it(chan, &redirecting, NULL);
01694          break;
01695       case ID_FIELD_INVALID:
01696          break;
01697       default:
01698          ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
01699          break;
01700       }
01701       ast_party_redirecting_free(&redirecting);
01702    } else if (member.argc == 1 && !strncasecmp("pres", member.argv[0], 4)) {
01703       int pres;
01704 
01705       val = ast_strdupa(value);
01706       ast_trim_blanks(val);
01707 
01708       if (('0' <= val[0]) && (val[0] <= '9')) {
01709          pres = atoi(val);
01710       } else {
01711          pres = ast_parse_caller_presentation(val);
01712       }
01713 
01714       if (pres < 0) {
01715          ast_log(LOG_ERROR,
01716             "Unknown redirecting combined presentation '%s', value unchanged\n", val);
01717       } else {
01718          redirecting.from.name.presentation = pres;
01719          redirecting.from.number.presentation = pres;
01720          redirecting.to.name.presentation = pres;
01721          redirecting.to.number.presentation = pres;
01722          set_it(chan, &redirecting, NULL);
01723       }
01724    } else if (member.argc == 1 && !strcasecmp("reason", member.argv[0])) {
01725       int reason;
01726 
01727       val = ast_strdupa(value);
01728       ast_trim_blanks(val);
01729 
01730       if (('0' <= val[0]) && (val[0] <= '9')) {
01731          reason = atoi(val);
01732       } else {
01733          reason = ast_redirecting_reason_parse(val);
01734       }
01735 
01736       if (reason < 0) {
01737          /* The argument passed into the function does not correspond to a pre-defined
01738           * reason, so we can just set the reason string to what was given and set the
01739           * code to be unknown
01740           */
01741          redirecting.reason.code = AST_REDIRECTING_REASON_UNKNOWN;
01742          redirecting.reason.str = val;
01743          set_it(chan, &redirecting, NULL);
01744       } else {
01745          redirecting.reason.code = reason;
01746          redirecting.reason.str = "";
01747          set_it(chan, &redirecting, NULL);
01748       }
01749    } else if (member.argc == 1 && !strcasecmp("count", member.argv[0])) {
01750       val = ast_strdupa(value);
01751       ast_trim_blanks(val);
01752 
01753       if (('0' <= val[0]) && (val[0] <= '9')) {
01754          redirecting.count = atoi(val);
01755          set_it(chan, &redirecting, NULL);
01756       } else {
01757          ast_log(LOG_ERROR, "Unknown redirecting count '%s', value unchanged\n", val);
01758       }
01759    } else if (1 < member.argc && !strcasecmp("priv", member.argv[0])) {
01760       if (!strcasecmp("orig", member.argv[1])) {
01761          status = party_id_write(&redirecting.priv_orig, member.argc - 2, member.argv + 2,
01762             value);
01763          switch (status) {
01764          case ID_FIELD_VALID:
01765             set_it(chan, &redirecting, NULL);
01766             break;
01767          case ID_FIELD_INVALID:
01768             break;
01769          default:
01770             ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
01771             break;
01772          }
01773          ast_party_redirecting_free(&redirecting);
01774       } else if (!strcasecmp("from", member.argv[1])) {
01775          status = party_id_write(&redirecting.priv_from, member.argc - 2, member.argv + 2,
01776             value);
01777          switch (status) {
01778          case ID_FIELD_VALID:
01779             set_it(chan, &redirecting, NULL);
01780             break;
01781          case ID_FIELD_INVALID:
01782             break;
01783          default:
01784             ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
01785             break;
01786          }
01787          ast_party_redirecting_free(&redirecting);
01788       } else if (!strcasecmp("to", member.argv[1])) {
01789          status = party_id_write(&redirecting.priv_to, member.argc - 2, member.argv + 2, value);
01790          switch (status) {
01791          case ID_FIELD_VALID:
01792             set_it(chan, &redirecting, NULL);
01793             break;
01794          case ID_FIELD_INVALID:
01795             break;
01796          default:
01797             ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
01798             break;
01799          }
01800          ast_party_redirecting_free(&redirecting);
01801       } else {
01802          ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
01803       }
01804    } else {
01805       ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
01806    }
01807 
01808    return 0;
01809 }
01810 
01811 static struct ast_custom_function callerid_function = {
01812    .name = "CALLERID",
01813    .read = callerid_read,
01814    .read_max = 256,
01815    .write = callerid_write,
01816 };
01817 
01818 static struct ast_custom_function callerpres_function = {
01819    .name = "CALLERPRES",
01820    .read = callerpres_read,
01821    .read_max = 50,
01822    .write = callerpres_write,
01823 };
01824 
01825 static struct ast_custom_function connectedline_function = {
01826    .name = "CONNECTEDLINE",
01827    .read = connectedline_read,
01828    .write = connectedline_write,
01829 };
01830 
01831 static struct ast_custom_function redirecting_function = {
01832    .name = "REDIRECTING",
01833    .read = redirecting_read,
01834    .write = redirecting_write,
01835 };
01836 
01837 /*!
01838  * \internal
01839  * \brief Unload the function module
01840  *
01841  * \retval 0 on success.
01842  * \retval -1 on error.
01843  */
01844 static int unload_module(void)
01845 {
01846    int res;
01847 
01848    res = ast_custom_function_unregister(&callerpres_function);
01849    res |= ast_custom_function_unregister(&callerid_function);
01850    res |= ast_custom_function_unregister(&connectedline_function);
01851    res |= ast_custom_function_unregister(&redirecting_function);
01852    return res;
01853 }
01854 
01855 /*!
01856  * \internal
01857  * \brief Load and initialize the function module.
01858  *
01859  * \retval AST_MODULE_LOAD_SUCCESS on success.
01860  * \retval AST_MODULE_LOAD_DECLINE on error.
01861  */
01862 static int load_module(void)
01863 {
01864    int res;
01865 
01866    res = ast_custom_function_register(&callerpres_function);
01867    res |= ast_custom_function_register(&callerid_function);
01868    res |= ast_custom_function_register(&connectedline_function);
01869    res |= ast_custom_function_register(&redirecting_function);
01870    return res ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS;
01871 }
01872 
01873 /* Do not wrap the following line. */
01874 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Party ID related dialplan functions (Caller-ID, Connected-line, Redirecting)");

Generated on Thu Apr 16 06:27:35 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6