00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include "asterisk.h"
00033
00034 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 337973 $")
00035
00036 #include <time.h>
00037
00038 #include "asterisk/channel.h"
00039 #include "asterisk/cdr.h"
00040 #include "asterisk/module.h"
00041 #include "asterisk/utils.h"
00042 #include "asterisk/manager.h"
00043 #include "asterisk/config.h"
00044 #include "asterisk/pbx.h"
00045
00046 #define DATE_FORMAT "%Y-%m-%d %T"
00047 #define CONF_FILE "cdr_manager.conf"
00048 #define CUSTOM_FIELDS_BUF_SIZE 1024
00049
00050 static const char name[] = "cdr_manager";
00051
00052 static int enablecdr = 0;
00053
00054 static struct ast_str *customfields;
00055 AST_RWLOCK_DEFINE_STATIC(customfields_lock);
00056
00057 static int manager_log(struct ast_cdr *cdr);
00058
00059 static int load_config(int reload)
00060 {
00061 char *cat = NULL;
00062 struct ast_config *cfg;
00063 struct ast_variable *v;
00064 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
00065 int newenablecdr = 0;
00066
00067 cfg = ast_config_load(CONF_FILE, config_flags);
00068 if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
00069 return 0;
00070 }
00071
00072 if (cfg == CONFIG_STATUS_FILEINVALID) {
00073 ast_log(LOG_ERROR, "Config file '%s' could not be parsed\n", CONF_FILE);
00074 return -1;
00075 }
00076
00077 if (!cfg) {
00078
00079 ast_log(LOG_WARNING, "Failed to load configuration file. Module not activated.\n");
00080 if (enablecdr)
00081 ast_cdr_unregister(name);
00082 enablecdr = 0;
00083 return -1;
00084 }
00085
00086 if (reload) {
00087 ast_rwlock_wrlock(&customfields_lock);
00088 }
00089
00090 if (reload && customfields) {
00091 ast_free(customfields);
00092 customfields = NULL;
00093 }
00094
00095 while ( (cat = ast_category_browse(cfg, cat)) ) {
00096 if (!strcasecmp(cat, "general")) {
00097 v = ast_variable_browse(cfg, cat);
00098 while (v) {
00099 if (!strcasecmp(v->name, "enabled"))
00100 newenablecdr = ast_true(v->value);
00101
00102 v = v->next;
00103 }
00104 } else if (!strcasecmp(cat, "mappings")) {
00105 customfields = ast_str_create(CUSTOM_FIELDS_BUF_SIZE);
00106 v = ast_variable_browse(cfg, cat);
00107 while (v) {
00108 if (customfields && !ast_strlen_zero(v->name) && !ast_strlen_zero(v->value)) {
00109 if ((ast_str_strlen(customfields) + strlen(v->value) + strlen(v->name) + 14) < ast_str_size(customfields)) {
00110 ast_str_append(&customfields, -1, "%s: ${CDR(%s)}\r\n", v->value, v->name);
00111 ast_log(LOG_NOTICE, "Added mapping %s: ${CDR(%s)}\n", v->value, v->name);
00112 } else {
00113 ast_log(LOG_WARNING, "No more buffer space to add other custom fields\n");
00114 break;
00115 }
00116
00117 }
00118 v = v->next;
00119 }
00120 }
00121 }
00122
00123 if (reload) {
00124 ast_rwlock_unlock(&customfields_lock);
00125 }
00126
00127 ast_config_destroy(cfg);
00128
00129 if (enablecdr && !newenablecdr)
00130 ast_cdr_unregister(name);
00131 else if (!enablecdr && newenablecdr)
00132 ast_cdr_register(name, "Asterisk Manager Interface CDR Backend", manager_log);
00133 enablecdr = newenablecdr;
00134
00135 return 0;
00136 }
00137
00138 static int manager_log(struct ast_cdr *cdr)
00139 {
00140 struct ast_tm timeresult;
00141 char strStartTime[80] = "";
00142 char strAnswerTime[80] = "";
00143 char strEndTime[80] = "";
00144 char buf[CUSTOM_FIELDS_BUF_SIZE];
00145
00146 if (!enablecdr)
00147 return 0;
00148
00149 ast_localtime(&cdr->start, &timeresult, NULL);
00150 ast_strftime(strStartTime, sizeof(strStartTime), DATE_FORMAT, &timeresult);
00151
00152 if (cdr->answer.tv_sec) {
00153 ast_localtime(&cdr->answer, &timeresult, NULL);
00154 ast_strftime(strAnswerTime, sizeof(strAnswerTime), DATE_FORMAT, &timeresult);
00155 }
00156
00157 ast_localtime(&cdr->end, &timeresult, NULL);
00158 ast_strftime(strEndTime, sizeof(strEndTime), DATE_FORMAT, &timeresult);
00159
00160 buf[0] = '\0';
00161 ast_rwlock_rdlock(&customfields_lock);
00162 if (customfields && ast_str_strlen(customfields)) {
00163 struct ast_channel *dummy = ast_dummy_channel_alloc();
00164 if (!dummy) {
00165 ast_log(LOG_ERROR, "Unable to allocate channel for variable substitution.\n");
00166 return 0;
00167 }
00168 dummy->cdr = ast_cdr_dup(cdr);
00169 pbx_substitute_variables_helper(dummy, ast_str_buffer(customfields), buf, sizeof(buf) - 1);
00170 ast_channel_unref(dummy);
00171 }
00172 ast_rwlock_unlock(&customfields_lock);
00173
00174 manager_event(EVENT_FLAG_CDR, "Cdr",
00175 "AccountCode: %s\r\n"
00176 "Source: %s\r\n"
00177 "Destination: %s\r\n"
00178 "DestinationContext: %s\r\n"
00179 "CallerID: %s\r\n"
00180 "Channel: %s\r\n"
00181 "DestinationChannel: %s\r\n"
00182 "LastApplication: %s\r\n"
00183 "LastData: %s\r\n"
00184 "StartTime: %s\r\n"
00185 "AnswerTime: %s\r\n"
00186 "EndTime: %s\r\n"
00187 "Duration: %ld\r\n"
00188 "BillableSeconds: %ld\r\n"
00189 "Disposition: %s\r\n"
00190 "AMAFlags: %s\r\n"
00191 "UniqueID: %s\r\n"
00192 "UserField: %s\r\n"
00193 "%s",
00194 cdr->accountcode, cdr->src, cdr->dst, cdr->dcontext, cdr->clid, cdr->channel,
00195 cdr->dstchannel, cdr->lastapp, cdr->lastdata, strStartTime, strAnswerTime, strEndTime,
00196 cdr->duration, cdr->billsec, ast_cdr_disp2str(cdr->disposition),
00197 ast_cdr_flags2str(cdr->amaflags), cdr->uniqueid, cdr->userfield,buf);
00198
00199 return 0;
00200 }
00201
00202 static int unload_module(void)
00203 {
00204 ast_cdr_unregister(name);
00205 if (customfields)
00206 ast_free(customfields);
00207
00208 return 0;
00209 }
00210
00211 static int load_module(void)
00212 {
00213 if (load_config(0)) {
00214 return AST_MODULE_LOAD_DECLINE;
00215 }
00216
00217 return AST_MODULE_LOAD_SUCCESS;
00218 }
00219
00220 static int reload(void)
00221 {
00222 return load_config(1);
00223 }
00224
00225 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Asterisk Manager Interface CDR Backend",
00226 .load = load_module,
00227 .unload = unload_module,
00228 .reload = reload,
00229 .load_pri = AST_MODPRI_CDR_DRIVER,
00230 );