Sat Apr 26 2014 22:01:36

Asterisk developer's documentation


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: 411314 $")
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       if (ast_channel_cdr(chan)) {
01156          ast_cdr_setcid(ast_channel_cdr(chan), chan);
01157       }
01158    } else if (!strcasecmp("dnid", member.argv[0])) {
01159       ast_party_dialed_set_init(&dialed, ast_channel_dialed(chan));
01160       if (member.argc == 1) {
01161          /* Setup as if user had given dnid-num instead. */
01162          member.argc = 2;
01163          member.argv[1] = "num";
01164       }
01165       if (!strncasecmp("num", member.argv[1], 3)) {
01166          /*
01167           * Accept num[ber]
01168           * dnid-num...
01169           */
01170          if (member.argc == 2) {
01171             /* dnid-num */
01172             dialed.number.str = ast_strdup(value);
01173             ast_trim_blanks(dialed.number.str);
01174             ast_party_dialed_set(ast_channel_dialed(chan), &dialed);
01175             if (ast_channel_cdr(chan)) {
01176                ast_cdr_setcid(ast_channel_cdr(chan), chan);
01177             }
01178          } else if (member.argc == 3 && !strcasecmp("plan", member.argv[2])) {
01179             /* dnid-num-plan */
01180             val = ast_strdupa(value);
01181             ast_trim_blanks(val);
01182 
01183             if (('0' <= val[0]) && (val[0] <= '9')) {
01184                ast_channel_dialed(chan)->number.plan = atoi(val);
01185                if (ast_channel_cdr(chan)) {
01186                   ast_cdr_setcid(ast_channel_cdr(chan), chan);
01187                }
01188             } else {
01189                ast_log(LOG_ERROR,
01190                   "Unknown type-of-number/numbering-plan '%s', value unchanged\n", val);
01191             }
01192          } else {
01193             ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
01194          }
01195       } else if (!strncasecmp("subaddr", member.argv[1], 7)) {
01196          /*
01197           * Accept subaddr[ess]
01198           * dnid-subaddr...
01199           */
01200          status = party_subaddress_write(&dialed.subaddress, member.argc - 2,
01201             member.argv + 2, value);
01202          switch (status) {
01203          case ID_FIELD_VALID:
01204             ast_party_dialed_set(ast_channel_dialed(chan), &dialed);
01205             if (ast_channel_cdr(chan)) {
01206                ast_cdr_setcid(ast_channel_cdr(chan), chan);
01207             }
01208             break;
01209          case ID_FIELD_INVALID:
01210             break;
01211          default:
01212             ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
01213             break;
01214          }
01215       } else {
01216          ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
01217       }
01218       ast_party_dialed_free(&dialed);
01219    } else if (member.argc == 1 && !strcasecmp("ani2", member.argv[0])) {
01220       val = ast_strdupa(value);
01221       ast_trim_blanks(val);
01222 
01223       if (('0' <= val[0]) && (val[0] <= '9')) {
01224          ast_channel_caller(chan)->ani2 = atoi(val);
01225          if (ast_channel_cdr(chan)) {
01226             ast_cdr_setcid(ast_channel_cdr(chan), chan);
01227          }
01228       } else {
01229          ast_log(LOG_ERROR, "Unknown callerid ani2 '%s', value unchanged\n", val);
01230       }
01231    } else if (!strcasecmp("ani", member.argv[0])) {
01232       ast_party_caller_set_init(&caller, ast_channel_caller(chan));
01233       if (member.argc == 1) {
01234          /* Setup as if user had given ani-num instead. */
01235          member.argc = 2;
01236          member.argv[1] = "num";
01237       }
01238       status = party_id_write(&caller.ani, member.argc - 1, member.argv + 1, value);
01239       switch (status) {
01240       case ID_FIELD_VALID:
01241          ast_party_caller_set(ast_channel_caller(chan), &caller, NULL);
01242          if (ast_channel_cdr(chan)) {
01243             ast_cdr_setcid(ast_channel_cdr(chan), chan);
01244          }
01245          break;
01246       case ID_FIELD_INVALID:
01247          break;
01248       default:
01249          ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
01250          break;
01251       }
01252       ast_party_caller_free(&caller);
01253    } else if (!strcasecmp("priv", member.argv[0])) {
01254       ast_party_caller_set_init(&caller, ast_channel_caller(chan));
01255       status = party_id_write(&caller.priv, member.argc - 1, member.argv + 1, value);
01256       switch (status) {
01257       case ID_FIELD_VALID:
01258          ast_party_caller_set(ast_channel_caller(chan), &caller, NULL);
01259          if (ast_channel_cdr(chan)) {
01260             ast_cdr_setcid(ast_channel_cdr(chan), chan);
01261          }
01262          break;
01263       case ID_FIELD_INVALID:
01264          break;
01265       default:
01266          ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
01267          break;
01268       }
01269       ast_party_caller_free(&caller);
01270    } else {
01271       ast_party_caller_set_init(&caller, ast_channel_caller(chan));
01272       status = party_id_write(&caller.id, member.argc, member.argv, value);
01273       switch (status) {
01274       case ID_FIELD_VALID:
01275          ast_channel_set_caller_event(chan, &caller, NULL);
01276          if (ast_channel_cdr(chan)) {
01277             ast_cdr_setcid(ast_channel_cdr(chan), chan);
01278          }
01279          break;
01280       case ID_FIELD_INVALID:
01281          break;
01282       default:
01283          ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
01284          break;
01285       }
01286       ast_party_caller_free(&caller);
01287    }
01288    ast_channel_unlock(chan);
01289 
01290    return 0;
01291 }
01292 
01293 /*!
01294  * \internal
01295  * \brief Read values from the connected line information struct.
01296  *
01297  * \param chan Asterisk channel to read
01298  * \param cmd Not used
01299  * \param data Connected line function datatype string
01300  * \param buf Buffer to fill with read value.
01301  * \param len Length of the buffer
01302  *
01303  * \retval 0 on success.
01304  * \retval -1 on error.
01305  */
01306 static int connectedline_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
01307 {
01308    struct ast_party_members member;
01309    char *read_what;
01310    enum ID_FIELD_STATUS status;
01311 
01312    /* Ensure that the buffer is empty */
01313    *buf = 0;
01314 
01315    if (!chan) {
01316       return -1;
01317    }
01318 
01319    read_what = ast_strdupa(data);
01320    AST_NONSTANDARD_APP_ARGS(member, read_what, '-');
01321    if (member.argc == 0 || ARRAY_LEN(member.subnames) <= member.argc) {
01322       /* Too few or too many subnames */
01323       return -1;
01324    }
01325 
01326    ast_channel_lock(chan);
01327 
01328    if (member.argc == 1 && !strcasecmp("source", member.argv[0])) {
01329       ast_copy_string(buf, ast_connected_line_source_name(ast_channel_connected(chan)->source), len);
01330    } else if (!strcasecmp("priv", member.argv[0])) {
01331       status = party_id_read(buf, len, member.argc - 1, member.argv + 1,
01332          &ast_channel_connected(chan)->priv);
01333       switch (status) {
01334       case ID_FIELD_VALID:
01335       case ID_FIELD_INVALID:
01336          break;
01337       default:
01338          ast_log(LOG_ERROR, "Unknown connectedline data type '%s'.\n", data);
01339          break;
01340       }
01341    } else {
01342       status = party_id_read(buf, len, member.argc, member.argv, &ast_channel_connected(chan)->id);
01343       switch (status) {
01344       case ID_FIELD_VALID:
01345       case ID_FIELD_INVALID:
01346          break;
01347       default:
01348          ast_log(LOG_ERROR, "Unknown connectedline data type '%s'.\n", data);
01349          break;
01350       }
01351    }
01352 
01353    ast_channel_unlock(chan);
01354 
01355    return 0;
01356 }
01357 
01358 /*!
01359  * \internal
01360  * \brief Write new values to the connected line information struct.
01361  *
01362  * \param chan Asterisk channel to update
01363  * \param cmd Not used
01364  * \param data Connected line function datatype string
01365  * \param value Value to assign to the connected line information struct.
01366  *
01367  * \retval 0 on success.
01368  * \retval -1 on error.
01369  */
01370 static int connectedline_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
01371 {
01372    struct ast_party_connected_line connected;
01373    char *val;
01374    char *parms;
01375    void (*set_it)(struct ast_channel *chan, const struct ast_party_connected_line *connected, const struct ast_set_party_connected_line *update);
01376    struct ast_party_func_args args;
01377    struct ast_party_members member;
01378    struct ast_flags opts;
01379    char *opt_args[CONNECTED_LINE_OPT_ARG_ARRAY_SIZE];
01380    enum ID_FIELD_STATUS status;
01381 
01382    if (!value || !chan) {
01383       return -1;
01384    }
01385 
01386    parms = ast_strdupa(data);
01387    AST_STANDARD_APP_ARGS(args, parms);
01388    if (args.argc == 0) {
01389       /* Must have at least one argument. */
01390       return -1;
01391    }
01392 
01393    AST_NONSTANDARD_APP_ARGS(member, args.member, '-');
01394    if (member.argc == 0 || ARRAY_LEN(member.subnames) <= member.argc) {
01395       /* Too few or too many subnames */
01396       return -1;
01397    }
01398 
01399    if (ast_app_parse_options(connectedline_opts, &opts, opt_args, args.opts)) {
01400       /* General invalid option syntax. */
01401       return -1;
01402    }
01403 
01404    /* Determine if the update indication inhibit option is present */
01405    if (ast_test_flag(&opts, CONNECTED_LINE_OPT_INHIBIT)) {
01406       set_it = ast_channel_set_connected_line;
01407    } else {
01408       set_it = ast_channel_update_connected_line;
01409    }
01410 
01411    ast_channel_lock(chan);
01412    ast_party_connected_line_set_init(&connected, ast_channel_connected(chan));
01413    ast_channel_unlock(chan);
01414 
01415    value = ast_skip_blanks(value);
01416 
01417    if (member.argc == 1 && !strcasecmp("source", member.argv[0])) {
01418       int source;
01419 
01420       val = ast_strdupa(value);
01421       ast_trim_blanks(val);
01422 
01423       if (('0' <= val[0]) && (val[0] <= '9')) {
01424          source = atoi(val);
01425       } else {
01426          source = ast_connected_line_source_parse(val);
01427       }
01428 
01429       if (source < 0) {
01430          ast_log(LOG_ERROR, "Unknown connectedline source '%s', value unchanged\n", val);
01431       } else {
01432          connected.source = source;
01433          set_it(chan, &connected, NULL);
01434       }
01435    } else if (!strcasecmp("priv", member.argv[0])) {
01436       status = party_id_write(&connected.priv, member.argc - 1, member.argv + 1, value);
01437       switch (status) {
01438       case ID_FIELD_VALID:
01439          set_it(chan, &connected, NULL);
01440          break;
01441       case ID_FIELD_INVALID:
01442          break;
01443       default:
01444          ast_log(LOG_ERROR, "Unknown connectedline data type '%s'.\n", data);
01445          break;
01446       }
01447       ast_party_connected_line_free(&connected);
01448    } else {
01449       status = party_id_write(&connected.id, member.argc, member.argv, value);
01450       switch (status) {
01451       case ID_FIELD_VALID:
01452          set_it(chan, &connected, NULL);
01453          break;
01454       case ID_FIELD_INVALID:
01455          break;
01456       default:
01457          ast_log(LOG_ERROR, "Unknown connectedline data type '%s'.\n", data);
01458          break;
01459       }
01460       ast_party_connected_line_free(&connected);
01461    }
01462 
01463    return 0;
01464 }
01465 
01466 /*!
01467  * \internal
01468  * \brief Read values from the redirecting information struct.
01469  *
01470  * \param chan Asterisk channel to read
01471  * \param cmd Not used
01472  * \param data Redirecting function datatype string
01473  * \param buf Buffer to fill with read value.
01474  * \param len Length of the buffer
01475  *
01476  * \retval 0 on success.
01477  * \retval -1 on error.
01478  */
01479 static int redirecting_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
01480 {
01481    struct ast_party_members member;
01482    char *read_what;
01483    const struct ast_party_redirecting *ast_redirecting;
01484    enum ID_FIELD_STATUS status;
01485 
01486    /* Ensure that the buffer is empty */
01487    *buf = 0;
01488 
01489    if (!chan) {
01490       return -1;
01491    }
01492 
01493    read_what = ast_strdupa(data);
01494    AST_NONSTANDARD_APP_ARGS(member, read_what, '-');
01495    if (member.argc == 0 || ARRAY_LEN(member.subnames) <= member.argc) {
01496       /* Too few or too many subnames */
01497       return -1;
01498    }
01499 
01500    ast_channel_lock(chan);
01501 
01502    ast_redirecting = ast_channel_redirecting(chan);
01503    if (!strcasecmp("orig", member.argv[0])) {
01504       if (member.argc == 2 && !strcasecmp("reason", member.argv[1])) {
01505          ast_copy_string(buf,
01506             ast_redirecting_reason_name(ast_redirecting->orig_reason), len);
01507       } else {
01508          status = party_id_read(buf, len, member.argc - 1, member.argv + 1,
01509             &ast_redirecting->orig);
01510          switch (status) {
01511          case ID_FIELD_VALID:
01512          case ID_FIELD_INVALID:
01513             break;
01514          default:
01515             ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
01516             break;
01517          }
01518       }
01519    } else if (!strcasecmp("from", member.argv[0])) {
01520       status = party_id_read(buf, len, member.argc - 1, member.argv + 1,
01521          &ast_redirecting->from);
01522       switch (status) {
01523       case ID_FIELD_VALID:
01524       case ID_FIELD_INVALID:
01525          break;
01526       default:
01527          ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
01528          break;
01529       }
01530    } else if (!strcasecmp("to", member.argv[0])) {
01531       status = party_id_read(buf, len, member.argc - 1, member.argv + 1,
01532          &ast_redirecting->to);
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 (member.argc == 1 && !strncasecmp("pres", member.argv[0], 4)) {
01542       /*
01543        * Accept pres[entation]
01544        * This is the combined from name/number presentation.
01545        */
01546       ast_copy_string(buf,
01547          ast_named_caller_presentation(
01548             ast_party_id_presentation(&ast_redirecting->from)), len);
01549    } else if (member.argc == 1 && !strcasecmp("reason", member.argv[0])) {
01550       ast_copy_string(buf, ast_redirecting_reason_name(ast_redirecting->reason), len);
01551    } else if (member.argc == 1 && !strcasecmp("count", member.argv[0])) {
01552       snprintf(buf, len, "%d", ast_redirecting->count);
01553    } else if (1 < member.argc && !strcasecmp("priv", member.argv[0])) {
01554       if (!strcasecmp("orig", member.argv[1])) {
01555          status = party_id_read(buf, len, member.argc - 2, member.argv + 2,
01556             &ast_redirecting->priv_orig);
01557          switch (status) {
01558          case ID_FIELD_VALID:
01559          case ID_FIELD_INVALID:
01560             break;
01561          default:
01562             ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
01563             break;
01564          }
01565       } else if (!strcasecmp("from", member.argv[1])) {
01566          status = party_id_read(buf, len, member.argc - 2, member.argv + 2,
01567             &ast_redirecting->priv_from);
01568          switch (status) {
01569          case ID_FIELD_VALID:
01570          case ID_FIELD_INVALID:
01571             break;
01572          default:
01573             ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
01574             break;
01575          }
01576       } else if (!strcasecmp("to", member.argv[1])) {
01577          status = party_id_read(buf, len, member.argc - 2, member.argv + 2,
01578             &ast_redirecting->priv_to);
01579          switch (status) {
01580          case ID_FIELD_VALID:
01581          case ID_FIELD_INVALID:
01582             break;
01583          default:
01584             ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
01585             break;
01586          }
01587       } else {
01588          ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
01589       }
01590    } else {
01591       ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
01592    }
01593 
01594    ast_channel_unlock(chan);
01595 
01596    return 0;
01597 }
01598 
01599 /*!
01600  * \internal
01601  * \brief Write new values to the redirecting information struct.
01602  *
01603  * \param chan Asterisk channel to update
01604  * \param cmd Not used
01605  * \param data Redirecting function datatype string
01606  * \param value Value to assign to the redirecting information struct.
01607  *
01608  * \retval 0 on success.
01609  * \retval -1 on error.
01610  */
01611 static int redirecting_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
01612 {
01613    struct ast_party_redirecting redirecting;
01614    enum ID_FIELD_STATUS status;
01615    char *val;
01616    char *parms;
01617    void (*set_it)(struct ast_channel *chan, const struct ast_party_redirecting *redirecting, const struct ast_set_party_redirecting *update);
01618    struct ast_party_func_args args;
01619    struct ast_party_members member;
01620    struct ast_flags opts;
01621    char *opt_args[REDIRECTING_OPT_ARG_ARRAY_SIZE];
01622 
01623    if (!value || !chan) {
01624       return -1;
01625    }
01626 
01627    parms = ast_strdupa(data);
01628    AST_STANDARD_APP_ARGS(args, parms);
01629    if (args.argc == 0) {
01630       /* Must have at least one argument. */
01631       return -1;
01632    }
01633 
01634    AST_NONSTANDARD_APP_ARGS(member, args.member, '-');
01635    if (member.argc == 0 || ARRAY_LEN(member.subnames) <= member.argc) {
01636       /* Too few or too many subnames */
01637       return -1;
01638    }
01639 
01640    if (ast_app_parse_options(redirecting_opts, &opts, opt_args, args.opts)) {
01641       /* General invalid option syntax. */
01642       return -1;
01643    }
01644 
01645    /* Determine if the update indication inhibit option is present */
01646    if (ast_test_flag(&opts, REDIRECTING_OPT_INHIBIT)) {
01647       set_it = ast_channel_set_redirecting;
01648    } else {
01649       set_it = ast_channel_update_redirecting;
01650    }
01651 
01652    ast_channel_lock(chan);
01653    ast_party_redirecting_set_init(&redirecting, ast_channel_redirecting(chan));
01654    ast_channel_unlock(chan);
01655 
01656    value = ast_skip_blanks(value);
01657 
01658    if (!strcasecmp("orig", member.argv[0])) {
01659       if (member.argc == 2 && !strcasecmp("reason", member.argv[1])) {
01660          int reason;
01661 
01662          val = ast_strdupa(value);
01663          ast_trim_blanks(val);
01664 
01665          if (('0' <= val[0]) && (val[0] <= '9')) {
01666             reason = atoi(val);
01667          } else {
01668             reason = ast_redirecting_reason_parse(val);
01669          }
01670 
01671          if (reason < 0) {
01672             ast_log(LOG_ERROR,
01673                "Unknown redirecting orig reason '%s', value unchanged\n", val);
01674          } else {
01675             redirecting.orig_reason = reason;
01676             set_it(chan, &redirecting, NULL);
01677          }
01678       } else {
01679          status = party_id_write(&redirecting.orig, member.argc - 1, member.argv + 1,
01680             value);
01681          switch (status) {
01682          case ID_FIELD_VALID:
01683             set_it(chan, &redirecting, NULL);
01684             break;
01685          case ID_FIELD_INVALID:
01686             break;
01687          default:
01688             ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
01689             break;
01690          }
01691          ast_party_redirecting_free(&redirecting);
01692       }
01693    } else if (!strcasecmp("from", member.argv[0])) {
01694       status = party_id_write(&redirecting.from, member.argc - 1, member.argv + 1,
01695          value);
01696       switch (status) {
01697       case ID_FIELD_VALID:
01698          set_it(chan, &redirecting, NULL);
01699          break;
01700       case ID_FIELD_INVALID:
01701          break;
01702       default:
01703          ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
01704          break;
01705       }
01706       ast_party_redirecting_free(&redirecting);
01707    } else if (!strcasecmp("to", member.argv[0])) {
01708       status = party_id_write(&redirecting.to, member.argc - 1, member.argv + 1, value);
01709       switch (status) {
01710       case ID_FIELD_VALID:
01711          set_it(chan, &redirecting, NULL);
01712          break;
01713       case ID_FIELD_INVALID:
01714          break;
01715       default:
01716          ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
01717          break;
01718       }
01719       ast_party_redirecting_free(&redirecting);
01720    } else if (member.argc == 1 && !strncasecmp("pres", member.argv[0], 4)) {
01721       int pres;
01722 
01723       val = ast_strdupa(value);
01724       ast_trim_blanks(val);
01725 
01726       if (('0' <= val[0]) && (val[0] <= '9')) {
01727          pres = atoi(val);
01728       } else {
01729          pres = ast_parse_caller_presentation(val);
01730       }
01731 
01732       if (pres < 0) {
01733          ast_log(LOG_ERROR,
01734             "Unknown redirecting combined presentation '%s', value unchanged\n", val);
01735       } else {
01736          redirecting.from.name.presentation = pres;
01737          redirecting.from.number.presentation = pres;
01738          redirecting.to.name.presentation = pres;
01739          redirecting.to.number.presentation = pres;
01740          set_it(chan, &redirecting, NULL);
01741       }
01742    } else if (member.argc == 1 && !strcasecmp("reason", member.argv[0])) {
01743       int reason;
01744 
01745       val = ast_strdupa(value);
01746       ast_trim_blanks(val);
01747 
01748       if (('0' <= val[0]) && (val[0] <= '9')) {
01749          reason = atoi(val);
01750       } else {
01751          reason = ast_redirecting_reason_parse(val);
01752       }
01753 
01754       if (reason < 0) {
01755          ast_log(LOG_ERROR, "Unknown redirecting reason '%s', value unchanged\n", val);
01756       } else {
01757          redirecting.reason = reason;
01758          set_it(chan, &redirecting, NULL);
01759       }
01760    } else if (member.argc == 1 && !strcasecmp("count", member.argv[0])) {
01761       val = ast_strdupa(value);
01762       ast_trim_blanks(val);
01763 
01764       if (('0' <= val[0]) && (val[0] <= '9')) {
01765          redirecting.count = atoi(val);
01766          set_it(chan, &redirecting, NULL);
01767       } else {
01768          ast_log(LOG_ERROR, "Unknown redirecting count '%s', value unchanged\n", val);
01769       }
01770    } else if (1 < member.argc && !strcasecmp("priv", member.argv[0])) {
01771       if (!strcasecmp("orig", member.argv[1])) {
01772          status = party_id_write(&redirecting.priv_orig, member.argc - 2, member.argv + 2,
01773             value);
01774          switch (status) {
01775          case ID_FIELD_VALID:
01776             set_it(chan, &redirecting, NULL);
01777             break;
01778          case ID_FIELD_INVALID:
01779             break;
01780          default:
01781             ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
01782             break;
01783          }
01784          ast_party_redirecting_free(&redirecting);
01785       } else if (!strcasecmp("from", member.argv[1])) {
01786          status = party_id_write(&redirecting.priv_from, member.argc - 2, member.argv + 2,
01787             value);
01788          switch (status) {
01789          case ID_FIELD_VALID:
01790             set_it(chan, &redirecting, NULL);
01791             break;
01792          case ID_FIELD_INVALID:
01793             break;
01794          default:
01795             ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
01796             break;
01797          }
01798          ast_party_redirecting_free(&redirecting);
01799       } else if (!strcasecmp("to", member.argv[1])) {
01800          status = party_id_write(&redirecting.priv_to, member.argc - 2, member.argv + 2, value);
01801          switch (status) {
01802          case ID_FIELD_VALID:
01803             set_it(chan, &redirecting, NULL);
01804             break;
01805          case ID_FIELD_INVALID:
01806             break;
01807          default:
01808             ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
01809             break;
01810          }
01811          ast_party_redirecting_free(&redirecting);
01812       } else {
01813          ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
01814       }
01815    } else {
01816       ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
01817    }
01818 
01819    return 0;
01820 }
01821 
01822 static struct ast_custom_function callerid_function = {
01823    .name = "CALLERID",
01824    .read = callerid_read,
01825    .read_max = 256,
01826    .write = callerid_write,
01827 };
01828 
01829 static struct ast_custom_function callerpres_function = {
01830    .name = "CALLERPRES",
01831    .read = callerpres_read,
01832    .read_max = 50,
01833    .write = callerpres_write,
01834 };
01835 
01836 static struct ast_custom_function connectedline_function = {
01837    .name = "CONNECTEDLINE",
01838    .read = connectedline_read,
01839    .write = connectedline_write,
01840 };
01841 
01842 static struct ast_custom_function redirecting_function = {
01843    .name = "REDIRECTING",
01844    .read = redirecting_read,
01845    .write = redirecting_write,
01846 };
01847 
01848 /*!
01849  * \internal
01850  * \brief Unload the function module
01851  *
01852  * \retval 0 on success.
01853  * \retval -1 on error.
01854  */
01855 static int unload_module(void)
01856 {
01857    int res;
01858 
01859    res = ast_custom_function_unregister(&callerpres_function);
01860    res |= ast_custom_function_unregister(&callerid_function);
01861    res |= ast_custom_function_unregister(&connectedline_function);
01862    res |= ast_custom_function_unregister(&redirecting_function);
01863    return res;
01864 }
01865 
01866 /*!
01867  * \internal
01868  * \brief Load and initialize the function module.
01869  *
01870  * \retval AST_MODULE_LOAD_SUCCESS on success.
01871  * \retval AST_MODULE_LOAD_DECLINE on error.
01872  */
01873 static int load_module(void)
01874 {
01875    int res;
01876 
01877    res = ast_custom_function_register(&callerpres_function);
01878    res |= ast_custom_function_register(&callerid_function);
01879    res |= ast_custom_function_register(&connectedline_function);
01880    res |= ast_custom_function_register(&redirecting_function);
01881    return res ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS;
01882 }
01883 
01884 /* Do not wrap the following line. */
01885 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Party ID related dialplan functions (Caller-ID, Connected-line, Redirecting)");