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 #include "asterisk.h" 00029 00030 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 238234 $") 00031 00032 #include "asterisk/module.h" 00033 #include "asterisk/channel.h" 00034 #include "asterisk/pbx.h" 00035 #include "asterisk/utils.h" 00036 #include "asterisk/app.h" 00037 #include "asterisk/cdr.h" 00038 00039 /*** DOCUMENTATION 00040 <function name="CDR" language="en_US"> 00041 <synopsis> 00042 Gets or sets a CDR variable. 00043 </synopsis> 00044 <syntax> 00045 <parameter name="name" required="true"> 00046 <para>CDR field name:</para> 00047 <enumlist> 00048 <enum name="clid"> 00049 <para>Caller ID.</para> 00050 </enum> 00051 <enum name="lastdata"> 00052 <para>Last application arguments.</para> 00053 </enum> 00054 <enum name="disposition"> 00055 <para>ANSWERED, NO ANSWER, BUSY, FAILED.</para> 00056 </enum> 00057 <enum name="src"> 00058 <para>Source.</para> 00059 </enum> 00060 <enum name="start"> 00061 <para>Time the call started.</para> 00062 </enum> 00063 <enum name="amaflags"> 00064 <para>DOCUMENTATION, BILL, IGNORE, etc.</para> 00065 </enum> 00066 <enum name="dst"> 00067 <para>Destination.</para> 00068 </enum> 00069 <enum name="answer"> 00070 <para>Time the call was answered.</para> 00071 </enum> 00072 <enum name="accountcode"> 00073 <para>The channel's account code.</para> 00074 </enum> 00075 <enum name="dcontext"> 00076 <para>Destination context.</para> 00077 </enum> 00078 <enum name="end"> 00079 <para>Time the call ended.</para> 00080 </enum> 00081 <enum name="uniqueid"> 00082 <para>The channel's unique id.</para> 00083 </enum> 00084 <enum name="dstchannel"> 00085 <para>Destination channel.</para> 00086 </enum> 00087 <enum name="duration"> 00088 <para>Duration of the call.</para> 00089 </enum> 00090 <enum name="userfield"> 00091 <para>The channel's user specified field.</para> 00092 </enum> 00093 <enum name="lastapp"> 00094 <para>Last application.</para> 00095 </enum> 00096 <enum name="billsec"> 00097 <para>Duration of the call once it was answered.</para> 00098 </enum> 00099 <enum name="channel"> 00100 <para>Channel name.</para> 00101 </enum> 00102 </enumlist> 00103 </parameter> 00104 <parameter name="options" required="false"> 00105 <optionlist> 00106 <option name="l"> 00107 <para>Uses the most recent CDR on a channel with multiple records</para> 00108 </option> 00109 <option name="r"> 00110 <para>Searches the entire stack of CDRs on the channel.</para> 00111 </option> 00112 <option name="s"> 00113 <para>Skips any CDR's that are marked 'LOCKED' due to forkCDR() calls. 00114 (on setting/writing CDR vars only)</para> 00115 </option> 00116 <option name="u"> 00117 <para>Retrieves the raw, unprocessed value.</para> 00118 <para>For example, 'start', 'answer', and 'end' will be retrieved as epoch 00119 values, when the <literal>u</literal> option is passed, but formatted as YYYY-MM-DD HH:MM:SS 00120 otherwise. Similarly, disposition and amaflags will return their raw 00121 integral values.</para> 00122 </option> 00123 </optionlist> 00124 </parameter> 00125 </syntax> 00126 <description> 00127 <para>All of the CDR field names are read-only, except for <literal>accountcode</literal>, 00128 <literal>userfield</literal>, and <literal>amaflags</literal>. You may, however, supply 00129 a name not on the above list, and create your own variable, whose value can be changed 00130 with this function, and this variable will be stored on the cdr.</para> 00131 <note><para>For setting CDR values, the <literal>l</literal> flag does not apply to 00132 setting the <literal>accountcode</literal>, <literal>userfield</literal>, or 00133 <literal>amaflags</literal>.</para></note> 00134 <para>Raw values for <literal>disposition</literal>:</para> 00135 <enumlist> 00136 <enum name="0"> 00137 <para>NO ANSWER</para> 00138 </enum> 00139 <enum name="1"> 00140 <para>NO ANSWER (NULL record)</para> 00141 </enum> 00142 <enum name="2"> 00143 <para>FAILED</para> 00144 </enum> 00145 <enum name="4"> 00146 <para>BUSY</para> 00147 </enum> 00148 <enum name="8"> 00149 <para>ANSWERED</para> 00150 </enum> 00151 </enumlist> 00152 <para>Raw values for <literal>amaflags</literal>:</para> 00153 <enumlist> 00154 <enum name="1"> 00155 <para>OMIT</para> 00156 </enum> 00157 <enum name="2"> 00158 <para>BILLING</para> 00159 </enum> 00160 <enum name="3"> 00161 <para>DOCUMENTATION</para> 00162 </enum> 00163 </enumlist> 00164 <para>Example: exten => 1,1,Set(CDR(userfield)=test)</para> 00165 </description> 00166 </function> 00167 ***/ 00168 00169 enum { 00170 OPT_RECURSIVE = (1 << 0), 00171 OPT_UNPARSED = (1 << 1), 00172 OPT_LAST = (1 << 2), 00173 OPT_SKIPLOCKED = (1 << 3), 00174 } cdr_option_flags; 00175 00176 AST_APP_OPTIONS(cdr_func_options, { 00177 AST_APP_OPTION('l', OPT_LAST), 00178 AST_APP_OPTION('r', OPT_RECURSIVE), 00179 AST_APP_OPTION('s', OPT_SKIPLOCKED), 00180 AST_APP_OPTION('u', OPT_UNPARSED), 00181 }); 00182 00183 static int cdr_read(struct ast_channel *chan, const char *cmd, char *parse, 00184 char *buf, size_t len) 00185 { 00186 char *ret; 00187 struct ast_flags flags = { 0 }; 00188 struct ast_cdr *cdr = chan ? chan->cdr : NULL; 00189 AST_DECLARE_APP_ARGS(args, 00190 AST_APP_ARG(variable); 00191 AST_APP_ARG(options); 00192 ); 00193 00194 if (ast_strlen_zero(parse)) 00195 return -1; 00196 00197 if (!cdr) 00198 return -1; 00199 00200 AST_STANDARD_APP_ARGS(args, parse); 00201 00202 if (!ast_strlen_zero(args.options)) 00203 ast_app_parse_options(cdr_func_options, &flags, NULL, args.options); 00204 00205 if (ast_test_flag(&flags, OPT_LAST)) 00206 while (cdr->next) 00207 cdr = cdr->next; 00208 00209 if (ast_test_flag(&flags, OPT_SKIPLOCKED)) 00210 while (ast_test_flag(cdr, AST_CDR_FLAG_LOCKED) && cdr->next) 00211 cdr = cdr->next; 00212 00213 ast_cdr_getvar(cdr, args.variable, &ret, buf, len, 00214 ast_test_flag(&flags, OPT_RECURSIVE), 00215 ast_test_flag(&flags, OPT_UNPARSED)); 00216 00217 return ret ? 0 : -1; 00218 } 00219 00220 static int cdr_write(struct ast_channel *chan, const char *cmd, char *parse, 00221 const char *value) 00222 { 00223 struct ast_cdr *cdr = chan ? chan->cdr : NULL; 00224 struct ast_flags flags = { 0 }; 00225 AST_DECLARE_APP_ARGS(args, 00226 AST_APP_ARG(variable); 00227 AST_APP_ARG(options); 00228 ); 00229 00230 if (ast_strlen_zero(parse) || !value || !chan) 00231 return -1; 00232 00233 if (!cdr) 00234 return -1; 00235 00236 AST_STANDARD_APP_ARGS(args, parse); 00237 00238 if (!ast_strlen_zero(args.options)) 00239 ast_app_parse_options(cdr_func_options, &flags, NULL, args.options); 00240 00241 if (ast_test_flag(&flags, OPT_LAST)) 00242 while (cdr->next) 00243 cdr = cdr->next; 00244 00245 if (!strcasecmp(args.variable, "accountcode")) /* the 'l' flag doesn't apply to setting the accountcode, userfield, or amaflags */ 00246 ast_cdr_setaccount(chan, value); 00247 else if (!strcasecmp(args.variable, "userfield")) 00248 ast_cdr_setuserfield(chan, value); 00249 else if (!strcasecmp(args.variable, "amaflags")) 00250 ast_cdr_setamaflags(chan, value); 00251 else 00252 ast_cdr_setvar(cdr, args.variable, value, ast_test_flag(&flags, OPT_RECURSIVE)); 00253 /* No need to worry about the u flag, as all fields for which setting 00254 * 'u' would do anything are marked as readonly. */ 00255 00256 return 0; 00257 } 00258 00259 static struct ast_custom_function cdr_function = { 00260 .name = "CDR", 00261 .read = cdr_read, 00262 .write = cdr_write, 00263 }; 00264 00265 static int unload_module(void) 00266 { 00267 return ast_custom_function_unregister(&cdr_function); 00268 } 00269 00270 static int load_module(void) 00271 { 00272 return ast_custom_function_register(&cdr_function); 00273 } 00274 00275 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Call Detail Record (CDR) dialplan function");