func_cdr.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999-2006, Digium, Inc.
00005  *
00006  * Portions Copyright (C) 2005, Anthony Minessale II
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief  Call Detail Record related dialplan functions
00022  *
00023  * \author Anthony Minessale II
00024  *
00025  * \ingroup functions
00026  */
00027 
00028 /*** MODULEINFO
00029    <support_level>core</support_level>
00030  ***/
00031 
00032 #include "asterisk.h"
00033 
00034 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 433270 $")
00035 
00036 #include "asterisk/module.h"
00037 #include "asterisk/channel.h"
00038 #include "asterisk/pbx.h"
00039 #include "asterisk/utils.h"
00040 #include "asterisk/app.h"
00041 #include "asterisk/cdr.h"
00042 #include "asterisk/stasis.h"
00043 #include "asterisk/stasis_message_router.h"
00044 
00045 /*** DOCUMENTATION
00046    <function name="CDR" language="en_US">
00047       <synopsis>
00048          Gets or sets a CDR variable.
00049       </synopsis>
00050       <syntax>
00051          <parameter name="name" required="true">
00052             <para>CDR field name:</para>
00053             <enumlist>
00054                <enum name="clid">
00055                   <para>Caller ID.</para>
00056                </enum>
00057                <enum name="lastdata">
00058                   <para>Last application arguments.</para>
00059                </enum>
00060                <enum name="disposition">
00061                   <para>The final state of the CDR.</para>
00062                   <enumlist>
00063                      <enum name="0">
00064                         <para><literal>NO ANSWER</literal></para>
00065                      </enum>
00066                      <enum name="1">
00067                         <para><literal>NO ANSWER</literal> (NULL record)</para>
00068                      </enum>
00069                      <enum name="2">
00070                         <para><literal>FAILED</literal></para>
00071                      </enum>
00072                      <enum name="4">
00073                         <para><literal>BUSY</literal></para>
00074                      </enum>
00075                      <enum name="8">
00076                         <para><literal>ANSWERED</literal></para>
00077                      </enum>
00078                      <enum name="16">
00079                         <para><literal>CONGESTION</literal></para>
00080                      </enum>
00081                   </enumlist>
00082                </enum>
00083                <enum name="src">
00084                   <para>Source.</para>
00085                </enum>
00086                <enum name="start">
00087                   <para>Time the call started.</para>
00088                </enum>
00089                <enum name="amaflags">
00090                   <para>R/W the Automatic Message Accounting (AMA) flags on the channel.
00091                   When read from a channel, the integer value will always be returned.
00092                   When written to a channel, both the string format or integer value
00093                   is accepted.</para>
00094                   <enumlist>
00095                      <enum name="1"><para><literal>OMIT</literal></para></enum>
00096                      <enum name="2"><para><literal>BILLING</literal></para></enum>
00097                      <enum name="3"><para><literal>DOCUMENTATION</literal></para></enum>
00098                   </enumlist>
00099                   <warning><para>Accessing this setting is deprecated in CDR. Please use the CHANNEL function instead.</para></warning>
00100                </enum>
00101                <enum name="dst">
00102                   <para>Destination.</para>
00103                </enum>
00104                <enum name="answer">
00105                   <para>Time the call was answered.</para>
00106                </enum>
00107                <enum name="accountcode">
00108                   <para>The channel's account code.</para>
00109                   <warning><para>Accessing this setting is deprecated in CDR. Please use the CHANNEL function instead.</para></warning>
00110                </enum>
00111                <enum name="dcontext">
00112                   <para>Destination context.</para>
00113                </enum>
00114                <enum name="end">
00115                   <para>Time the call ended.</para>
00116                </enum>
00117                <enum name="uniqueid">
00118                   <para>The channel's unique id.</para>
00119                </enum>
00120                <enum name="dstchannel">
00121                   <para>Destination channel.</para>
00122                </enum>
00123                <enum name="duration">
00124                   <para>Duration of the call.</para>
00125                </enum>
00126                <enum name="userfield">
00127                   <para>The channel's user specified field.</para>
00128                </enum>
00129                <enum name="lastapp">
00130                   <para>Last application.</para>
00131                </enum>
00132                <enum name="billsec">
00133                   <para>Duration of the call once it was answered.</para>
00134                </enum>
00135                <enum name="channel">
00136                   <para>Channel name.</para>
00137                </enum>
00138                <enum name="sequence">
00139                   <para>CDR sequence number.</para>
00140                </enum>
00141             </enumlist>
00142          </parameter>
00143          <parameter name="options" required="false">
00144             <optionlist>
00145                <option name="f">
00146                   <para>Returns billsec or duration fields as floating point values.</para>
00147                </option>
00148                <option name="u">
00149                   <para>Retrieves the raw, unprocessed value.</para>
00150                   <para>For example, 'start', 'answer', and 'end' will be retrieved as epoch
00151                   values, when the <literal>u</literal> option is passed, but formatted as YYYY-MM-DD HH:MM:SS
00152                   otherwise.  Similarly, disposition and amaflags will return their raw
00153                   integral values.</para>
00154                </option>
00155             </optionlist>
00156          </parameter>
00157       </syntax>
00158       <description>
00159          <para>All of the CDR field names are read-only, except for <literal>accountcode</literal>,
00160          <literal>userfield</literal>, and <literal>amaflags</literal>. You may, however, supply
00161          a name not on the above list, and create your own variable, whose value can be changed
00162          with this function, and this variable will be stored on the CDR.</para>
00163          <note><para>CDRs can only be modified before the bridge between two channels is
00164          torn down. For example, CDRs may not be modified after the <literal>Dial</literal>
00165          application has returned.</para></note>
00166          <para>Example: exten => 1,1,Set(CDR(userfield)=test)</para>
00167       </description>
00168    </function>
00169    <function name="CDR_PROP" language="en_US">
00170       <synopsis>
00171          Set a property on a channel's CDR.
00172       </synopsis>
00173       <syntax>
00174          <parameter name="name" required="true">
00175             <para>The property to set on the CDR.</para>
00176             <enumlist>
00177                <enum name="party_a">
00178                   <para>Set this channel as the preferred Party A when
00179                   channels are associated together.</para>
00180                   <para>Write-Only</para>
00181                </enum>
00182                <enum name="disable">
00183                   <para>Disable CDRs for this channel.</para>
00184                   <para>Write-Only</para>
00185                </enum>
00186             </enumlist>
00187          </parameter>
00188       </syntax>
00189       <description>
00190          <para>This function sets a property on a channel's CDR. Properties
00191          alter the behavior of how the CDR operates for that channel.</para>
00192       </description>
00193    </function>
00194  ***/
00195 
00196 enum cdr_option_flags {
00197    OPT_UNPARSED = (1 << 1),
00198    OPT_FLOAT = (1 << 2),
00199 };
00200 
00201 AST_APP_OPTIONS(cdr_func_options, {
00202    AST_APP_OPTION('f', OPT_FLOAT),
00203    AST_APP_OPTION('u', OPT_UNPARSED),
00204 });
00205 
00206 struct cdr_func_payload {
00207    struct ast_channel *chan;
00208    const char *cmd;
00209    const char *arguments;
00210    const char *value;
00211    void *data;
00212 };
00213 
00214 struct cdr_func_data {
00215    char *buf;
00216    size_t len;
00217 };
00218 
00219 STASIS_MESSAGE_TYPE_DEFN_LOCAL(cdr_read_message_type);
00220 STASIS_MESSAGE_TYPE_DEFN_LOCAL(cdr_write_message_type);
00221 STASIS_MESSAGE_TYPE_DEFN_LOCAL(cdr_prop_write_message_type);
00222 
00223 static void cdr_read_callback(void *data, struct stasis_subscription *sub, struct stasis_message *message)
00224 {
00225    struct cdr_func_payload *payload = stasis_message_data(message);
00226    struct cdr_func_data *output;
00227    char *info;
00228    char *value = NULL;
00229    struct ast_flags flags = { 0 };
00230    char tempbuf[512];
00231    AST_DECLARE_APP_ARGS(args,
00232       AST_APP_ARG(variable);
00233       AST_APP_ARG(options);
00234    );
00235 
00236    if (cdr_read_message_type() != stasis_message_type(message)) {
00237       return;
00238    }
00239 
00240    ast_assert(payload != NULL);
00241    output = payload->data;
00242    ast_assert(output != NULL);
00243 
00244    if (ast_strlen_zero(payload->arguments)) {
00245       ast_log(AST_LOG_WARNING, "%s requires a variable (%s(variable[,option]))\n)",
00246          payload->cmd, payload->cmd);
00247       return;
00248    }
00249    info = ast_strdupa(payload->arguments);
00250    AST_STANDARD_APP_ARGS(args, info);
00251 
00252    if (!ast_strlen_zero(args.options)) {
00253       ast_app_parse_options(cdr_func_options, &flags, NULL, args.options);
00254    }
00255 
00256    if (ast_strlen_zero(ast_channel_name(payload->chan))) {
00257       /* Format request on a dummy channel */
00258       ast_cdr_format_var(ast_channel_cdr(payload->chan), args.variable, &value, tempbuf, sizeof(tempbuf), 0);
00259       if (ast_strlen_zero(value)) {
00260          return;
00261       }
00262       ast_copy_string(tempbuf, value, sizeof(tempbuf));
00263       ast_set_flag(&flags, OPT_UNPARSED);
00264    } else if (ast_cdr_getvar(ast_channel_name(payload->chan), args.variable, tempbuf, sizeof(tempbuf))) {
00265       return;
00266    }
00267 
00268    if (ast_test_flag(&flags, OPT_FLOAT)
00269       && (!strcasecmp("billsec", args.variable) || !strcasecmp("duration", args.variable))) {
00270       long ms;
00271       double dtime;
00272 
00273       if (sscanf(tempbuf, "%30ld", &ms) != 1) {
00274          ast_log(AST_LOG_WARNING, "Unable to parse %s (%s) from the CDR for channel %s\n",
00275             args.variable, tempbuf, ast_channel_name(payload->chan));
00276          return;
00277       }
00278       dtime = (double)(ms / 1000.0);
00279       snprintf(tempbuf, sizeof(tempbuf), "%lf", dtime);
00280    } else if (!ast_test_flag(&flags, OPT_UNPARSED)) {
00281       if (!strcasecmp("start", args.variable)
00282          || !strcasecmp("end", args.variable)
00283          || !strcasecmp("answer", args.variable)) {
00284          struct timeval fmt_time;
00285          struct ast_tm tm;
00286          /* tv_usec is suseconds_t, which could be int or long */
00287          long int tv_sec;
00288          long int tv_usec;
00289 
00290          if (sscanf(tempbuf, "%ld.%ld", &tv_sec, &tv_usec) != 2) {
00291             ast_log(AST_LOG_WARNING, "Unable to parse %s (%s) from the CDR for channel %s\n",
00292                args.variable, tempbuf, ast_channel_name(payload->chan));
00293             return;
00294          }
00295          if (tv_sec) {
00296             fmt_time.tv_sec = tv_sec;
00297             fmt_time.tv_usec = tv_usec;
00298             ast_localtime(&fmt_time, &tm, NULL);
00299             ast_strftime(tempbuf, sizeof(tempbuf), "%Y-%m-%d %T", &tm);
00300          } else {
00301             tempbuf[0] = '\0';
00302          }
00303       } else if (!strcasecmp("disposition", args.variable)) {
00304          int disposition;
00305 
00306          if (sscanf(tempbuf, "%8d", &disposition) != 1) {
00307             ast_log(AST_LOG_WARNING, "Unable to parse %s (%s) from the CDR for channel %s\n",
00308                args.variable, tempbuf, ast_channel_name(payload->chan));
00309             return;
00310          }
00311          snprintf(tempbuf, sizeof(tempbuf), "%s", ast_cdr_disp2str(disposition));
00312       } else if (!strcasecmp("amaflags", args.variable)) {
00313          int amaflags;
00314 
00315          if (sscanf(tempbuf, "%8d", &amaflags) != 1) {
00316             ast_log(AST_LOG_WARNING, "Unable to parse %s (%s) from the CDR for channel %s\n",
00317                args.variable, tempbuf, ast_channel_name(payload->chan));
00318             return;
00319          }
00320          snprintf(tempbuf, sizeof(tempbuf), "%s", ast_channel_amaflags2string(amaflags));
00321       }
00322    }
00323 
00324    ast_copy_string(output->buf, tempbuf, output->len);
00325 }
00326 
00327 static void cdr_write_callback(void *data, struct stasis_subscription *sub, struct stasis_message *message)
00328 {
00329    struct cdr_func_payload *payload = stasis_message_data(message);
00330    struct ast_flags flags = { 0 };
00331    AST_DECLARE_APP_ARGS(args,
00332       AST_APP_ARG(variable);
00333       AST_APP_ARG(options);
00334    );
00335    char *parse;
00336 
00337    if (cdr_write_message_type() != stasis_message_type(message)) {
00338       return;
00339    }
00340 
00341    if (!payload) {
00342       return;
00343    }
00344 
00345    if (ast_strlen_zero(payload->arguments)) {
00346       ast_log(AST_LOG_WARNING, "%s requires a variable (%s(variable)=value)\n)",
00347          payload->cmd, payload->cmd);
00348       return;
00349    }
00350    if (ast_strlen_zero(payload->value)) {
00351       ast_log(AST_LOG_WARNING, "%s requires a value (%s(variable)=value)\n)",
00352          payload->cmd, payload->cmd);
00353       return;
00354    }
00355    parse = ast_strdupa(payload->arguments);
00356    AST_STANDARD_APP_ARGS(args, parse);
00357 
00358    if (!ast_strlen_zero(args.options)) {
00359       ast_app_parse_options(cdr_func_options, &flags, NULL, args.options);
00360    }
00361 
00362    if (!strcasecmp(args.variable, "accountcode")) {
00363       ast_log(AST_LOG_WARNING, "Using the CDR function to set 'accountcode' is deprecated. Please use the CHANNEL function instead.\n");
00364       ast_channel_lock(payload->chan);
00365       ast_channel_accountcode_set(payload->chan, payload->value);
00366       ast_channel_unlock(payload->chan);
00367    } else if (!strcasecmp(args.variable, "peeraccount")) {
00368       ast_log(AST_LOG_WARNING, "The 'peeraccount' setting is not supported. Please set the 'accountcode' on the appropriate channel using the CHANNEL function.\n");
00369    } else if (!strcasecmp(args.variable, "userfield")) {
00370       ast_cdr_setuserfield(ast_channel_name(payload->chan), payload->value);
00371    } else if (!strcasecmp(args.variable, "amaflags")) {
00372       ast_log(AST_LOG_WARNING, "Using the CDR function to set 'amaflags' is deprecated. Please use the CHANNEL function instead.\n");
00373       if (isdigit(*payload->value)) {
00374          int amaflags;
00375          sscanf(payload->value, "%30d", &amaflags);
00376          ast_channel_lock(payload->chan);
00377          ast_channel_amaflags_set(payload->chan, amaflags);
00378          ast_channel_unlock(payload->chan);
00379       } else {
00380          ast_channel_lock(payload->chan);
00381          ast_channel_amaflags_set(payload->chan, ast_channel_string2amaflag(payload->value));
00382          ast_channel_unlock(payload->chan);
00383       }
00384    } else {
00385       ast_cdr_setvar(ast_channel_name(payload->chan), args.variable, payload->value);
00386    }
00387    return;
00388 }
00389 
00390 static void cdr_prop_write_callback(void *data, struct stasis_subscription *sub, struct stasis_message *message)
00391 {
00392    struct cdr_func_payload *payload = stasis_message_data(message);
00393    enum ast_cdr_options option;
00394    char *parse;
00395    AST_DECLARE_APP_ARGS(args,
00396       AST_APP_ARG(variable);
00397       AST_APP_ARG(options);
00398    );
00399 
00400    if (cdr_prop_write_message_type() != stasis_message_type(message)) {
00401       return;
00402    }
00403 
00404    if (!payload) {
00405       return;
00406    }
00407 
00408    if (ast_strlen_zero(payload->arguments)) {
00409       ast_log(AST_LOG_WARNING, "%s requires a variable (%s(variable)=value)\n)",
00410          payload->cmd, payload->cmd);
00411       return;
00412    }
00413    if (ast_strlen_zero(payload->value)) {
00414       ast_log(AST_LOG_WARNING, "%s requires a value (%s(variable)=value)\n)",
00415          payload->cmd, payload->cmd);
00416       return;
00417    }
00418    parse = ast_strdupa(payload->arguments);
00419    AST_STANDARD_APP_ARGS(args, parse);
00420 
00421    if (!strcasecmp("party_a", args.variable)) {
00422       option = AST_CDR_FLAG_PARTY_A;
00423    } else if (!strcasecmp("disable", args.variable)) {
00424       option = AST_CDR_FLAG_DISABLE_ALL;
00425    } else {
00426       ast_log(AST_LOG_WARNING, "Unknown option %s used with %s\n", args.variable, payload->cmd);
00427       return;
00428    }
00429 
00430    if (ast_true(payload->value)) {
00431       ast_cdr_set_property(ast_channel_name(payload->chan), option);
00432    } else {
00433       ast_cdr_clear_property(ast_channel_name(payload->chan), option);
00434    }
00435 }
00436 
00437 
00438 static int cdr_read(struct ast_channel *chan, const char *cmd, char *parse,
00439           char *buf, size_t len)
00440 {
00441    RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
00442    RAII_VAR(struct cdr_func_payload *, payload, NULL, ao2_cleanup);
00443    struct cdr_func_data output = { 0, };
00444 
00445    if (!chan) {
00446       ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
00447       return -1;
00448    }
00449 
00450    if (!cdr_read_message_type()) {
00451       ast_log(AST_LOG_WARNING, "Failed to manipulate CDR for channel %s: message type not available\n",
00452          ast_channel_name(chan));
00453       return -1;
00454    }
00455 
00456    payload = ao2_alloc(sizeof(*payload), NULL);
00457    if (!payload) {
00458       return -1;
00459    }
00460    payload->chan = chan;
00461    payload->cmd = cmd;
00462    payload->arguments = parse;
00463    payload->data = &output;
00464 
00465    buf[0] = '\0';/* Ensure the buffer is initialized. */
00466    output.buf = buf;
00467    output.len = len;
00468 
00469    message = stasis_message_create(cdr_read_message_type(), payload);
00470    if (!message) {
00471       ast_log(AST_LOG_WARNING, "Failed to manipulate CDR for channel %s: unable to create message\n",
00472          ast_channel_name(chan));
00473       return -1;
00474    }
00475 
00476    /* If this is a request on a dummy channel, we're doing post-processing on an
00477     * already dispatched CDR. Simply call the callback to calculate the value and
00478     * return, instead of posting to Stasis as we would for a running channel.
00479     */
00480    if (ast_strlen_zero(ast_channel_name(chan))) {
00481       cdr_read_callback(NULL, NULL, message);
00482    } else {
00483       RAII_VAR(struct stasis_message_router *, router, ast_cdr_message_router(), ao2_cleanup);
00484 
00485       if (!router) {
00486          ast_log(AST_LOG_WARNING, "Failed to manipulate CDR for channel %s: no message router\n",
00487             ast_channel_name(chan));
00488          return -1;
00489       }
00490       stasis_message_router_publish_sync(router, message);
00491    }
00492 
00493    return 0;
00494 }
00495 
00496 static int cdr_write(struct ast_channel *chan, const char *cmd, char *parse,
00497            const char *value)
00498 {
00499    RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
00500    RAII_VAR(struct cdr_func_payload *, payload, NULL, ao2_cleanup);
00501    RAII_VAR(struct stasis_message_router *, router,
00502            ast_cdr_message_router(), ao2_cleanup);
00503 
00504    if (!chan) {
00505       ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
00506       return -1;
00507    }
00508 
00509    if (!router) {
00510       ast_log(AST_LOG_WARNING, "Failed to manipulate CDR for channel %s: no message router\n",
00511          ast_channel_name(chan));
00512       return -1;
00513    }
00514 
00515    if (!cdr_write_message_type()) {
00516       ast_log(AST_LOG_WARNING, "Failed to manipulate CDR for channel %s: message type not available\n",
00517          ast_channel_name(chan));
00518       return -1;
00519    }
00520 
00521    payload = ao2_alloc(sizeof(*payload), NULL);
00522    if (!payload) {
00523       return -1;
00524    }
00525    payload->chan = chan;
00526    payload->cmd = cmd;
00527    payload->arguments = parse;
00528    payload->value = value;
00529 
00530    message = stasis_message_create(cdr_write_message_type(), payload);
00531    if (!message) {
00532       ast_log(AST_LOG_WARNING, "Failed to manipulate CDR for channel %s: unable to create message\n",
00533          ast_channel_name(chan));
00534       return -1;
00535    }
00536    stasis_message_router_publish_sync(router, message);
00537 
00538    return 0;
00539 }
00540 
00541 static int cdr_prop_write(struct ast_channel *chan, const char *cmd, char *parse,
00542            const char *value)
00543 {
00544    RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
00545    RAII_VAR(struct cdr_func_payload *, payload, NULL, ao2_cleanup);
00546    RAII_VAR(struct stasis_message_router *, router, ast_cdr_message_router(), ao2_cleanup);
00547 
00548    if (!chan) {
00549       ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
00550       return -1;
00551    }
00552 
00553    if (!router) {
00554       ast_log(AST_LOG_WARNING, "Failed to manipulate CDR for channel %s: no message router\n",
00555          ast_channel_name(chan));
00556       return -1;
00557    }
00558 
00559    if (!cdr_write_message_type()) {
00560       ast_log(AST_LOG_WARNING, "Failed to manipulate CDR for channel %s: message type not available\n",
00561          ast_channel_name(chan));
00562       return -1;
00563    }
00564 
00565    payload = ao2_alloc(sizeof(*payload), NULL);
00566    if (!payload) {
00567       return -1;
00568    }
00569    payload->chan = chan;
00570    payload->cmd = cmd;
00571    payload->arguments = parse;
00572    payload->value = value;
00573 
00574    message = stasis_message_create(cdr_prop_write_message_type(), payload);
00575    if (!message) {
00576       ast_log(AST_LOG_WARNING, "Failed to manipulate CDR for channel %s: unable to create message\n",
00577          ast_channel_name(chan));
00578       return -1;
00579    }
00580    stasis_message_router_publish_sync(router, message);
00581 
00582    return 0;
00583 }
00584 
00585 static struct ast_custom_function cdr_function = {
00586    .name = "CDR",
00587    .read = cdr_read,
00588    .write = cdr_write,
00589 };
00590 
00591 static struct ast_custom_function cdr_prop_function = {
00592    .name = "CDR_PROP",
00593    .read = NULL,
00594    .write = cdr_prop_write,
00595 };
00596 
00597 static int unload_module(void)
00598 {
00599    RAII_VAR(struct stasis_message_router *, router, ast_cdr_message_router(), ao2_cleanup);
00600    int res = 0;
00601 
00602    if (router) {
00603       stasis_message_router_remove(router, cdr_prop_write_message_type());
00604       stasis_message_router_remove(router, cdr_write_message_type());
00605       stasis_message_router_remove(router, cdr_read_message_type());
00606    }
00607    STASIS_MESSAGE_TYPE_CLEANUP(cdr_read_message_type);
00608    STASIS_MESSAGE_TYPE_CLEANUP(cdr_write_message_type);
00609    STASIS_MESSAGE_TYPE_CLEANUP(cdr_prop_write_message_type);
00610    res |= ast_custom_function_unregister(&cdr_function);
00611    res |= ast_custom_function_unregister(&cdr_prop_function);
00612 
00613    return res;
00614 }
00615 
00616 static int load_module(void)
00617 {
00618    RAII_VAR(struct stasis_message_router *, router, ast_cdr_message_router(), ao2_cleanup);
00619    int res = 0;
00620 
00621    if (!router) {
00622       return AST_MODULE_LOAD_FAILURE;
00623    }
00624 
00625    res |= STASIS_MESSAGE_TYPE_INIT(cdr_read_message_type);
00626    res |= STASIS_MESSAGE_TYPE_INIT(cdr_write_message_type);
00627    res |= STASIS_MESSAGE_TYPE_INIT(cdr_prop_write_message_type);
00628    res |= ast_custom_function_register(&cdr_function);
00629    res |= ast_custom_function_register(&cdr_prop_function);
00630    res |= stasis_message_router_add(router, cdr_prop_write_message_type(),
00631                                     cdr_prop_write_callback, NULL);
00632    res |= stasis_message_router_add(router, cdr_write_message_type(),
00633                                     cdr_write_callback, NULL);
00634    res |= stasis_message_router_add(router, cdr_read_message_type(),
00635                                     cdr_read_callback, NULL);
00636 
00637    if (res) {
00638       return AST_MODULE_LOAD_FAILURE;
00639    }
00640    return AST_MODULE_LOAD_SUCCESS;
00641 }
00642 
00643 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Call Detail Record (CDR) dialplan functions");

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