/* * Shell CDR records. * * Copyright (c) 2004-2007 Anthony Minessale II * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Derived from cdr_csv.c by Mark Spencer */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* The values are as follows: "accountcode", // accountcode is the account name of detail records, Master.shell contains all records // Detail records are configured on a channel basis, IAX and SIP are determined by user // Zap is determined by channel in zaptel.conf "source", "destination", "destination context", "callerid", "channel", "destination channel", (if applicable) "last application", // Last application run on the channel "last app argument", // argument to the last channel "start time", "answer time", "end time", duration, // Duration is the whole length that the entire call lasted. ie. call rx'd to hangup // "end time" minus "start time" billable seconds, // the duration that a call was up after other end answered which will be <= to duration // "end time" minus "answer time" "disposition", // ANSWERED, NO ANSWER, BUSY "amaflags", // DOCUMENTATION, BILL, IGNORE etc, specified on a per channel basis like accountcode. "uniqueid", // unique call identifier "userfield" // user field set via SetCDRUserField */ static int active = 0; static char *desc = "Shell CDR Backend"; static char *name = "shell"; #define CDR_STRING_SIZE 128 #define MAX_REG 10 #define CDR_ELEM 19 static char registry[MAX_REG][CDR_STRING_SIZE]; static const char *BLANK_STRING = {""}; static int is_executable(char *pathname) { static struct stat buf ; int x ; if ( pathname == NULL || *pathname == '\0' ) return 0 ; x = stat( pathname , &buf ) ; if ( x ) return 0 ; x = (buf.st_mode & S_IXOTH) != 0 ; if ( x ) return x ; x = ( getuid() == buf.st_uid && (buf.st_mode & S_IXUSR) != 0 ) ; return x ; } static long tv_diff(struct timeval *ended,struct timeval *started) { return (((ended->tv_sec * 1000) + ended->tv_usec / 1000) - ((started->tv_sec * 1000) + started->tv_usec / 1000)); } static int shell_log(struct ast_cdr *cdr) { char buf[CDR_ELEM][CDR_STRING_SIZE]; int x = 1, pid = 0; memset(buf, 0, sizeof(buf)); /* Account code */ snprintf(buf[1],CDR_STRING_SIZE, "%s", cdr->accountcode && strlen(cdr->accountcode) ? cdr->accountcode : BLANK_STRING); /* Source */ snprintf(buf[2],CDR_STRING_SIZE, "%s", cdr->src && strlen(cdr->src) ? cdr->src : BLANK_STRING); /* Destination */ snprintf(buf[3],CDR_STRING_SIZE, "%s", cdr->dst && strlen(cdr->dst) ? cdr->dst : BLANK_STRING); /* Destination context */ snprintf(buf[4],CDR_STRING_SIZE, "%s", cdr->dcontext && strlen(cdr->dst) ? cdr->dst : BLANK_STRING); /* Caller*ID */ snprintf(buf[5],CDR_STRING_SIZE, "%s", cdr->clid && strlen(cdr->clid) ? cdr->clid : BLANK_STRING); /* Channel */ snprintf(buf[6],CDR_STRING_SIZE, "%s", cdr->channel && strlen(cdr->channel) ? cdr->channel : BLANK_STRING); /* Destination Channel */ snprintf(buf[7],CDR_STRING_SIZE, "%s", cdr->dstchannel && strlen(cdr->dstchannel) ? cdr->dstchannel : BLANK_STRING); /* Last Application */ snprintf(buf[8],CDR_STRING_SIZE, "%s", cdr->lastapp && strlen(cdr->lastapp) ? cdr->lastapp : BLANK_STRING); /* Last Data */ snprintf(buf[9],CDR_STRING_SIZE, "%s", cdr->lastdata && strlen(cdr->lastdata) ? cdr->lastdata : BLANK_STRING); /* Start Time */ snprintf(buf[10],CDR_STRING_SIZE, "%ld", cdr->start.tv_sec); /* Answer Time */ snprintf(buf[11],CDR_STRING_SIZE, "%ld", cdr->answer.tv_sec); /* End Time */ snprintf(buf[12],CDR_STRING_SIZE, "%ld", cdr->end.tv_sec); /* Duration */ snprintf(buf[13],CDR_STRING_SIZE, "%d", cdr->duration); /* Billable seconds */ snprintf(buf[14],CDR_STRING_SIZE, "%d", cdr->billsec); /* Disposition */ snprintf(buf[15],CDR_STRING_SIZE, "%s", ast_cdr_disp2str(cdr->disposition)); /* AMA Flags */ snprintf(buf[16],CDR_STRING_SIZE, "%s", ast_cdr_flags2str(cdr->amaflags)); /* Unique ID */ snprintf(buf[17],CDR_STRING_SIZE, "%s", cdr->uniqueid && strlen(cdr->uniqueid) ? cdr->uniqueid : BLANK_STRING); /* append the user field */ snprintf(buf[18],CDR_STRING_SIZE, "%s", cdr->userfield && strlen(cdr->userfield) ? cdr->userfield : BLANK_STRING); for (x=0; xnext) { if (!strcasecmp(var->name, "path")) { if (is_executable(var->value)) { strncpy(registry[x],var->value,CDR_STRING_SIZE); registry[x+1][0] = '\0'; ast_log(LOG_NOTICE, "Registered CDR process #%d %s\n", x+1,registry[x]); x++; } else ast_log(LOG_ERROR, "File: %s is not executable, Ignored...\n", registry[x]); } active = x; } ast_config_destroy(cfg); } if (!active) { res = -1; } else { res = ast_cdr_register(name, desc, shell_log); } if (res) { ast_log(LOG_ERROR, "Unable to register SHELL CDR handling\n"); } return res; } int reload(void) { return 0; } int usecount(void) { return 0; } char *key() { return ASTERISK_GPL_KEY; }